40
Full site 8M members (33.4K online) 422 Sign out Home Articles Quick Answers Discussions Learning Zones Features Help! The Lounge Inject your code to a Portable Executable file Downloads PE Viewer PE Maker - Step 1 - Add new Section. PE Maker - Step 2 - Travel towards OEP. PE Maker - Step 3 - Support Import Table. PE Maker - Step 4 - Support DLL and OCX. PE Maker - Step 5 - Final work. CALC.EXE - test file Contents 0. Preface 1. Prerequisite 2. Portable Executable file format 2.1 The MS-DOS data 2.2 The Windows NT data 2.3 The Section Headers and Sections 3. Debugger, Disassembler and some Useful Tools 3.1 Debuggers 3.1.1 SoftICE 3.1.2 OllyDbg 3.1.3 Which parts are important in a debugger interface? 3.2 Disassembler 3.2.1 Proview disassembler 3.2.2 W32Dasm 3.2.3 IDA Pro 3.3 Some Useful Tools 3.3.1 LordPE 3.3.2 PEiD 3.3.3 Resource Hacker 3.3.4 WinHex 3.3.5 CFF Explorer 4. Add new section and Change OEP 4.1 Retrieve and Rebuild PE file 4.2 Create Data for new Section 4.3 Some notes regarding creating a new PE file 4.4 Some notes regarding linking this VC Project doicanhden 1 of 40

Inject your code to a Portable Executable file - CodeProject®

Embed Size (px)

Citation preview

Page 1: Inject your code to a Portable Executable file - CodeProject®

Full site 8M members (33.4K online) 422 Sign out

Home Articles Quick Answers Discussions Learning Zones Features Help! The Lounge

Inject your code to a Portable Executable fileDownloads

PE ViewerPE Maker - Step 1 - Add new Section.PE Maker - Step 2 - Travel towards OEP.PE Maker - Step 3 - Support Import Table.PE Maker - Step 4 - Support DLL and OCX.PE Maker - Step 5 - Final work.CALC.EXE - test file

Contents

0. Preface1. Prerequisite2. Portable Executable file format

2.1 The MS-DOS data2.2 The Windows NT data2.3 The Section Headers and Sections

3. Debugger, Disassembler and some Useful Tools3.1 Debuggers

3.1.1 SoftICE3.1.2 OllyDbg3.1.3 Which parts are important in a debugger interface?

3.2 Disassembler3.2.1 Proview disassembler3.2.2 W32Dasm3.2.3 IDA Pro

3.3 Some Useful Tools3.3.1 LordPE3.3.2 PEiD3.3.3 Resource Hacker3.3.4 WinHex3.3.5 CFF Explorer

4. Add new section and Change OEP4.1 Retrieve and Rebuild PE file4.2 Create Data for new Section4.3 Some notes regarding creating a new PE file4.4 Some notes regarding linking this VC Project

doicanhden

1 of 40

Page 2: Inject your code to a Portable Executable file - CodeProject®

5. Store Important Data and Reach Original OEP5.1 Restore the first Registers Context5.2 Restore the Original Stack5.3 Approach OEP by Structured Exception Handling

5.3.1 Implement Exception Handler5.3.2 Attain OEP by adjusting the Thread Context

6. Build an Import Table and Reconstruct the Original Import Table6.1 Construct the Client Import Table6.2 Using other API functions in run-time6.3 Fix up the Original Import Table

7. Support DLL and OCX7.1 Twice OEP approach7.2 Implement Relocation Table7.3 Build a Special Import table

8. Preserve the Thread Local Storage9. Inject your code10. Conclusion

0 Preface

It might be, you demand to comprehend the ways a virus program injects its procedure in to theinterior of a portable executable file and corrupts it, or you are interested in implementing a packer ora protector for your specific intention to encrypt the data of your portable executable (PE) file. Thisarticle is committed to represent a brief intuition to realize the performance which is accomplished byEXE tools or some kind of mal-wares.

You can employ the source code of this article to create your custom EXE builder. It could be used tomake an EXE protector in the right way, or with a wrong intention, to pullulate a virus. However, mypurpose of writing this article has been to gaze on the first application, so I will not be responsible forthe immoral usage of these methods.

1 Prerequisite

There are no specific mandatory prerequisites to follow the topics in this article. If you are familiar withdebugger and also the portable file format, I suggest you to drop the sections 2 and 3, the whole ofthese sections have been made for people who don�t have any knowledge regarding the EXE fileformat and also debuggers.

2 Portable Executable file format

The Portable Executable file format was defined to provide the best way for the Windows OperatingSystem to execute code and also to store the essential data which is needed to run a program, forexample constant data, variable data, import library links, and resource data. It consists of MS-DOS fileinformation, Windows NT file information, Section Headers, and Section images, Table 1.

2.1 The MS-DOS data

These data let you remember the first days of developing the Windows Operating System, the days. Wewere at the beginning of a way to achieve a complete Operating System like Windows NT 3.51 (I mean,Win3.1, Win95, Win98 were not perfect OSs). The MS-DOS data causes that your executable file callsa function inside MS-DOS and the MS-DOS Stub program lets it display: "This program can not berun in MS-DOS mode" or "This program can be run only in Windows mode", or some things likethese comments when you try to run a Windows EXE file inside MS-DOS 6.0, where there is nofootstep of Windows. Thus, this data is reserved for the code to indicate these comments in theMS-DOS operating system. The most interesting part of the MS-DOS data is "MZ"! Can you believe, itrefers to the name of "Mark Zbikowski", one of the first Microsoft programmers?

To me, only the offset of the PE signature in the MS-DOS data is important, so I can use it to find theposition of the Windows NT data. I just recommend you to take a look at Table 1, then observe thestructure of IMAGE_DOS_HEADER in the <winnt.h> header in the <Microsoft Visual Studio .netpath>\VC7\PlatformSDK\include\ folder or the <Microsoft Visual Studio 6.0 path>\VC98\include\ folder.I do not know why the Microsoft team has forgotten to provide some comment about this structure in

2 of 40

Page 3: Inject your code to a Portable Executable file - CodeProject®

the MSDN library!

typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header "MZ" WORD e_magic; // Magic number WORD e_cblp; // Bytes on last page of file WORD e_cp; // Pages in file WORD e_crlc; // Relocations WORD e_cparhdr; // Size of header in paragraphs WORD e_minalloc; // Minimum extra paragraphs needed WORD e_maxalloc; // Maximum extra paragraphs needed WORD e_ss; // Initial (relative) SS value WORD e_sp; // Initial SP value WORD e_csum; // Checksum WORD e_ip; // Initial IP value WORD e_cs; // Initial (relative) CS value WORD e_lfarlc; // File address of relocation table WORD e_ovno; // Overlay number WORD e_res[4]; // Reserved words WORD e_oemid; // OEM identifier (for e_oeminfo) WORD e_oeminfo; // OEM information; e_oemid specific WORD e_res2[10]; // Reserved words LONG e_lfanew; // File address of the new exe header } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

e_lfanew is the offset which refers to the position of the Windows NT data. I have provided a programto obtain the header information from an EXE file and to display it to you. To use the program, just try:

PE Viewer

Download source files - 132 Kb

3 of 40

Page 4: Inject your code to a Portable Executable file - CodeProject®

This sample is useful for the whole of this article.

Table 1 - Portable Executable file format structure

MS-DOSinformation

IMAGE_DOS_HEADER

DOS EXE Signature00000000 ASCII "MZ"00000002 DW 009000000004 DW 000300000006 DW 000000000008 DW 0004

DOS_PartPagDOS_PageCntDOS_ReloCntDOS_HdrSizeDOS_MinMem

4 of 40

Page 5: Inject your code to a Portable Executable file - CodeProject®

0000000A DW 00000000000C DW FFFF0000000E DW 000000000010 DW 00B800000012 DW 000000000014 DW 000000000016 DW 000000000018 DW 00400000001A DW 00000000001C DB 00��0000003B DB 000000003C DD 000000F0

DOS_MaxMemDOS_ReloSSDOS_ExeSPDOS_ChkSumDOS_ExeIPPDOS_ReloCSDOS_TablOffDOS_Overlay�Reserved words�Offset to PE signature

MS-DOS StubProgram

00000040 � .�.�!�\L�!This program canno00000060 t be run in DOS mode....$.......

Windows NTinformation

IMAGE_NT_HEADERS

Signature PE signature (PE) 000000F0 ASCII "PE"

IMAGE_FILE_HEADER

Machine000000F4 DW 014C000000F6 DW 0003000000F8 DD 3B7D8410000000FC DD 0000000000000100 DD 0000000000000104 DW 00E000000106 DW 010F

NumberOfSectionsTimeDateStampPointerToSymbolTableNumberOfSymbolsSizeOfOptionalHeaderCharacteristics

IMAGE_OPTIONAL_HEADER32

MagicNumber

00000108 DW 010B0000010A DB 070000010B DB 000000010C DD 0001280000000110 DD 00009C0000000114 DD 0000000000000118 DD 000124750000011C DD 0000100000000120 DD 0001400000000124 DD 0100000000000128 DD 000010000000012C DD 0000020000000130 DW 000500000132 DW 000100000134 DW 000500000136 DW 000100000138 DW 00040000013A DW 00000000013C DD 0000000000000140 DD 0001F00000000144 DD 0000040000000148 DD 0001D7FC0000014C DW 00020000014E DW 800000000150 DD 0004000000000154 DD 0000100000000158 DD 001000000000015C DD 0000100000000160 DD 0000000000000164 DD 00000010

MajorLinkerVersionMinorLinkerVersionSizeOfCodeSizeOfInitializedDataSizeOfUninitializedDataAddressOfEntryPointBaseOfCodeBaseOfDataImageBaseSectionAlignmentFileAlignmentMajorOSVersionMinorOSVersionMajorImageVersionMinorImageVersionMajorSubsystemVersionMinorSubsystemVersionReservedSizeOfImageSizeOfHeadersCheckSumSubsystemDLLCharacteristicsSizeOfStackReserveSizeOfStackCommitSizeOfHeapReserveSizeOfHeapCommitLoaderFlagsNumberOfRvaAndSizesIMAGE_DATA_DIRECTORY[16]

Export TableImport Table

5 of 40

Page 6: Inject your code to a Portable Executable file - CodeProject®

Resource TableException TableCertificate FileRelocation TableDebug DataArchitecture DataGlobal PtrTLS TableLoad Config TableBound Import TableImport Address TableDelay Import DescriptorCOM+ Runtime HeaderReserved

Sectionsinformation

IMAGE_SECTION_HEADER[0]

Name[8]000001E8 ASCII".text"000001F0 DD 000126B0000001F4 DD 00001000000001F8 DD 00012800000001FC DD 0000040000000200 DD 0000000000000204 DD 0000000000000208 DW 00000000020A DW 00000000020C DD 60000020 CODE|EXECUTE|READ

VirtualSizeVirtualAddressSizeOfRawDataPointerToRawDataPointerToRelocationsPointerToLineNumbersNumberOfRelocationsNumberOfLineNumbersCharacteristics

���IMAGE_SECTION_HEADER[n]

00000210 ASCII".data"; SECTION00000218 DD 0000101C ; VirtualSize = 0x101C0000021C DD 00014000 ; VirtualAddress = 0x1400000000220 DD 00000A00 ; SizeOfRawData = 0xA0000000224 DD 00012C00 ; PointerToRawData = 0x12C0000000228 DD 00000000 ; PointerToRelocations = 0x00000022C DD 00000000 ; PointerToLineNumbers = 0x000000230 DW 0000 ; NumberOfRelocations = 0x000000232 DW 0000 ; NumberOfLineNumbers = 0x000000234 DD C0000040 ; Characteristics = INITIALIZED_DATA|READ|WRITE00000238 ASCII".rsrc"; SECTION00000240 DD 00008960 ; VirtualSize = 0x896000000244 DD 00016000 ; VirtualAddress = 0x1600000000248 DD 00008A00 ; SizeOfRawData = 0x8A000000024C DD 00013600 ; PointerToRawData = 0x1360000000250 DD 00000000 ; PointerToRelocations = 0x000000254 DD 00000000 ; PointerToLineNumbers = 0x000000258 DW 0000 ; NumberOfRelocations = 0x00000025A DW 0000 ; NumberOfLineNumbers = 0x00000025C DD 40000040 ; Characteristics = INITIALIZED_DATA|READ

SECTION[0]

00000400 EA 22 DD 77 D7 23 DD 77 �"�w�#�w00000408 9A 18 DD 77 00 00 00 00 � �w....00000410 2E 1E C7 77 83 1D C7 77 .�w��w00000418 FF 1E C7 77 00 00 00 00 ��w....00000420 93 9F E7 77 D8 05 E8 77 ���w� �w00000428 FD A5 E7 77 AD A9 E9 77 ���w&shy;��w00000430 A3 36 E7 77 03 38 E7 77 �6�w>8�w00000438 41 E3 E6 77 60 8D E7 77 A��w`��w00000440 E6 1B E6 77 2B 2A E7 77 � �w+*�w00000448 7A 17 E6 77 79 C8 E6 77 z �wy��w00000450 14 1B E7 77 C1 30 E7 77 �w�0�w�

6 of 40

Page 7: Inject your code to a Portable Executable file - CodeProject®

���SECTION[n]

�0001BF00 63 00 2E 00 63 00 68 00 c...c.h.0001BF08 6D 00 0A 00 43 00 61 00 m...C.a.0001BF10 6C 00 63 00 75 00 6C 00 l.c.u.l.0001BF18 61 00 74 00 6F 00 72 00 a.t.o.r.0001BF20 11 00 4E 00 6F 00 74 00 .N.o.t.0001BF28 20 00 45 00 6E 00 6F 00 .E.n.o.0001BF30 75 00 67 00 68 00 20 00 u.g.h. .0001BF38 4D 00 65 00 6D 00 6F 00 M.e.m.o.0001BF40 72 00 79 00 00 00 00 00 r.y.....0001BF48 00 00 00 00 00 00 00 00 ........0001BF50 00 00 00 00 00 00 00 00 ........0001BF58 00 00 00 00 00 00 00 00 ........0001BF60 00 00 00 00 00 00 00 00 ........0001BF68 00 00 00 00 00 00 00 00 ........0001BF70 00 00 00 00 00 00 00 00 ........0001BF78 00 00 00 00 00 00 00 00 ........

2.2 The Windows NT data

As mentioned in the preceding section, e_lfanew storage in the MS-DOS data structure refers to thelocation of the Windows NT information. Hence, if you assume that the pMem pointer relates the startpoint of the memory space for a selected portable executable file, you can retrieve the MS-DOS headerand also the Windows NT headers by the following lines, which you also can perceive in the PE viewersample (pelib.cpp, PEStructure::OpenFileName()):

IMAGE_DOS_HEADER image_dos_header;IMAGE_NT_HEADERS image_nt_headers;PCHAR pMem;�memcpy(&image_dos_header, pMem, sizeof(IMAGE_DOS_HEADER));memcpy(&image_nt_headers, pMem+image_dos_header.e_lfanew, sizeof(IMAGE_NT_HEADERS));

It seems to be very simple, the retrieval of the headers information. I recommend inspecting the MSDNlibrary regarding the IMAGE_NT_HEADERS structure definition. It makes comprehensible to grasp whatthe image NT header maintains to execute a code inside the Windows NT OS. Now, you are conversantwith the Windows NT structure, it consists of the "PE" Signature, the File Header, and the OptionalHeader. Do not forget to take a glimpse at their comments in the MSDN Library and besides in Table 1.

One the whole, I consider merely, on the most circumstances, the following cells of theIMAGE_NT_HEADERS structure:

FileHeader->NumberOfSectionsOptionalHeader->AddressOfEntryPointOptionalHeader->ImageBaseOptionalHeader->SectionAlignmentOptionalHeader->FileAlignmentOptionalHeader->SizeOfImageOptionalHeader-> DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]->VirtualAddressOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]->Size

You can observe clearly, the main purpose of these values, and their role when the internal virtualmemory space allocated for an EXE file by the Windows OS is fully allocated, if you pay attention totheir explanations in MSDN library, so I am not going to repeat the MSDN annotations here.

I should mention a brief comment regarding the PE data directories, or OptionalHeader->DataDirectory[], as I think there are a few aspects of interest concerning them. When you come tosurvey the Optional header through the Windows NT information, you will find that there are 16directories at the end of the Optional Header, where you can find the consecutive directories, includingtheir Relative Virtual Address and Size. I just mention here, the notes from <winnt.h> to clarify theseinformation:

7 of 40

Page 8: Inject your code to a Portable Executable file - CodeProject®

#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory

#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory

#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory

#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory

#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory

#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table

#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory

#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data

#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP

#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory

#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory

#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers

#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table

#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors

#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor

The last one (15) was reserved for use in future; I have not yet seen any purpose to use it even inPE64.

For instance, if you desire to perceive the relative virtual address (RVA) and the size of the resourcedata, it is enough to retrieve them by:

DWORD dwRVA = image_nt_headers.OptionalHeader-> DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]->VirtualAddress;DWORD dwSize = image_nt_headers.OptionalHeader-> DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]->Size;

To comprehend more regarding the significance of data directories, I forward you to section 3.4.3,Microsoft Portable Executable and the Common Object File Format Specification document by Microsoft,and furthermore section 6 of this document, where you discern the various types of sections and theirapplications. We will discuss the section's advantage subsequently.

2.3 The Section Headers and Sections

We currently observe how the portable executable files declare the location and the size of a section ona disk storage file and inside the virtual memory space allocated for the program withIMAGE_NT_HEADERS-> OptionalHeader->SizeOfImage by the Windows task manager, as well thecharacteristics to demonstrate the type of the section. To understand better the Section header as myprevious declaration, I suggest having a short gape on the IMAGE_SECTION_HEADER structuredefinition in the MSDN library. For an EXE packer developer, VirtualSize, VirtualAddress,SizeOfRawData, PointerToRawData, and Characteristics cells have significant rules. Whiledeveloping an EXE packer, you should be clever enough to play with them. There are somethings to benoted while you modify them; you should take care to align the VirtualSize and VirtualAddressaccording to OptionalHeader->SectionAlignment, as well as SizeOfRawData andPointerToRawData in line with OptionalHeader->FileAlignment. Otherwise, you will corruptyour target EXE file and it will never run. Regarding Characteristics, I pay attention mostly toestablish a section by IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE |IMAGE_SCN_CNT_INITIALIZED_DATA, I prefer my new section has ability to initialize such data duringrunning process; such as import table; besides, I need it to be able to modify itself by the loader withmy settings in the section characteristics to read- and writeable.

Moreover, you should pay attention to the section names, you can know the purpose of each section byits name. I will just forward you to section 6: Microsoft Portable Executable and the Common Object

8 of 40

Page 9: Inject your code to a Portable Executable file - CodeProject®

File Format Specification documents. I believe, it represents the totality of sections by their names,Table 2.

Table 2 - Section names

".text" Code Section"CODE" Code Section of file linked by Borland Delphi or Borland Pascal".data" Data Section"DATA" Data Section of file linked by Borland Delphi or Borland Pascal".rdata" Section for Constant Data".idata" Import Table".edata"Export Table".tls" TLS Table".reloc" Relocation Information".rsrc" Resource Information

To comprehend the section headers and also the sections, you can run the sample PE viewer. By thisPE viewer, you only can realize the application of the section headers in a file image, so to observe themain significance in the Virtual Memory, you should try to load a PE file by a debugger, and the nextsection represents the main idea of using the virtual address and �size in the virtual memory by usinga debugger. The last note is about IMAGE_NT_HEADERS-> FileHeader-><CODE>NumberOfSections,that provides a number of sections in a PE file, do not forget to adjust it whenever you remove or addsome sections to a PE file, I am talking about section injection!

3 Debugger, Disassembler and some Useful Tools

In this part, you will become familiar with the necessary and essential equipments to develop your PEtools.

3.1 Debuggers

The first essential prerequisite, to become a PE tools developer, is to have enough experience with bugtracer tools. Furthermore, you should know most of the assembly instructions. To me, the Inteldocuments are the best references. You can obtain them from the Intel site for IA-32, and on top ofthat IA-64; the future belongs to IA-64 CPUs, Windows XP 64-bit, and also PE64!

IA-32 Intel Architecture Software Developer�s Manuals.Intel Itanium Architecture Assembly Language Reference Guide.The Intel Itanium Processor Developer Resource Guide.

To trace a PE file, SoftICE by Compuware Corporation, I knew it also as named NuMega when I was athigh school, is the best debugger in the world. It implements process tracing by using kernel modemethod debugging without applying Windows debugging application programming interface (API)functions. In addition, I am going to introduce one perfect debugger in user mode level. It utilizes theWindows debugging API to trace a PE file and also attaches itself to an active process. These APIfunctions have been provided by Microsoft teams, inside the Windows Kernel32 library, to trace aspecific process, by using Microsoft tools, or perhaps, to make your own debugger! Some of those APIfunctions inlude: CreateThread(), CreateProcess(), OpenProcess(), DebugActiveProcess(),GetThreadContext(), SetThreadContext(), ContinueDebugEvent(), DebugBreak(),ReadProcessMemory(), WriteProcessMemory(), SuspendThread(), and ResumeThread().

3.1.1 SoftICE

It was in 1987; Frank Grossman and Jim Moskun decided to establish a company called NuMegaTechnologies in Nashua, NH, in order to develop some equipments to trace and test the reliability ofMicrosoft Windows software programs. Now, it is a part of Compuware Corporation and its product hasparticipated to accelerate the reliability in Windows software, and additionally in Windows driverdevelopments. Currently, everyone knows the Compuware DriverStudio which is used to establish anenvironment for implementing the elaboration of a kernel driver or a system file by aiding the WindowsDriver Development Kit (DDK). It bypasses the involvement of DDK to implement a portable executablefile of kernel level for a Windows system software developer. For us, only one instrument of

9 of 40

Page 10: Inject your code to a Portable Executable file - CodeProject®

DriverStudio is important, SoftICE, this debugger can be used to trace every portable executable file, aPE file for user mode level or a PE file for kernel mode level.

Figure 1 - SoftICE Window

EAX=00000000 EBX=7FFDD000 ECX=0007FFB0 EDX=7C90EB94 ESI=FFFFFFFFEDI=7C919738 EBP=0007FFF0 ESP=0007FFC4 EIP=010119E0 o d i s z a p cCS=0008 DS=0023 SS=0010 ES=0023 FS=0030 GS=0000 SS:0007FFC4=87C816D4F0023:01013000 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................0023:01013010 01 00 00 00 20 00 00 00-0A 00 00 00 0A 00 00 00 ................0023:01013020 20 00 00 00 00 00 00 00-53 63 69 43 61 6C 63 00 ........SciCalc.0023:01013030 00 00 00 00 00 00 00 00-62 61 63 6B 67 72 6F 75 ........backgrou0023:01013040 6E 64 00 00 00 00 00 00-2E 00 00 00 00 00 00 00 nd..............0010:0007FFC4 4F 6D 81 7C 38 07 91 7C-FF FF FF FF 00 90 FD 7F Om |8 �| .0010:0007FFD4 ED A6 54 80 C8 FF 07 00-E8 B4 F5 81 FF FF FF FF T .0010:0007FFE4 F3 99 83 7C 58 6D 81 7C-00 00 00 00 00 00 00 00 Xm |........0010:0007FFF4 00 00 00 00 E0 19 01 01-00 00 00 00 00 00 00 00 .... ....010119E0 PUSH EBP010119E1 MOV EBP,ESP010119E3 PUSH -1010119E5 PUSH 01001570010119EA PUSH 01011D60010119EF MOV EAX,DWORD PTR FS:[0]010119F5 PUSH EAX010119F6 MOV DWORD PTR FS:[0],ESP010119FD ADD ESP,-6801011A00 PUSH EBX01011A01 PUSH ESI01011A02 PUSH EDI01011A03 MOV DWORD PTR SS:[EBP-18],ESP01011A06 MOV DWORD PTR SS:[EBP-4],0:_

3.1.2 OllyDbg

It was about 4 years ago, that I first saw this debugger by chance. For me, it was the best choice, I wasnot so wealthy to purchase SoftICE, and at that time, SoftICE only had good functions for DOS,Windows 98, and Windows 2000. I found that this debugger supported all kinds of Windows versions.Therefore, I started to learn it very fast, and now it is my favorite debugger for the Windows OS. It is adebugger that can be used to trace all kinds of portable executable files except a Common LanguageInfrastructure (CLI) file format in user mode level, by using the Windows debugging API. OlehYuschuk, the author, is one of worthiest software developers I have seen in my life. He is a Ukrainianwho now lives in Germany. I should mention here that his debugger is the best choice for hacker andcracker parties around the world! It is a freeware! You can try it from OllyDbg Homepage.

Figure 2 - OllyDbg CPU Window

10 of 40

Page 11: Inject your code to a Portable Executable file - CodeProject®

3.1.3 Which parts are important in a debugger interface?

I have introduced two debuggers without talking about how you can employ them, and also which partsyou should pay attention more. Regarding using debuggers, I refer you to their instructions in helpdocuments. However, I want to explain shortly the important parts of a debugger; of course, I amtalking about low-level debuggers, or in other words, machine-language debuggers of the x86 CPUfamilies.

All of low-level debuggers consist of the following subdivisions:

Registers viewer.

EAXECXEDXEBXESPEBPESIEDIEIP

o d t s z a p c

1.

Disassembler or Code viewer.

010119E0 PUSH EBP

2.

11 of 40

Page 12: Inject your code to a Portable Executable file - CodeProject®

010119E1 MOV EBP,ESP010119E3 PUSH -1010119E5 PUSH 01001570010119EA PUSH 01011D60010119EF MOV EAX,DWORD PTR FS:[0]010119F5 PUSH EAX010119F6 MOV DWORD PTR FS:[0],ESP010119FD ADD ESP,-6801011A00 PUSH EBX01011A01 PUSH ESI01011A02 PUSH EDI01011A03 MOV DWORD PTR SS:[EBP-18],ESP01011A06 MOV DWORD PTR SS:[EBP-4],0

Memory watcher.

0023:01013000 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................0023:01013010 01 00 00 00 20 00 00 00-0A 00 00 00 0A 00 00 00 ................0023:01013020 20 00 00 00 00 00 00 00-53 63 69 43 61 6C 63 00........SciCalc.0023:01013030 00 00 00 00 00 00 00 00-62 61 63 6B 67 72 6F 75........backgrou0023:01013040 6E 64 00 00 00 00 00 00-2E 00 00 00 00 00 00 00 nd..............

3.

Stack viewer.

0010:0007FFC4 4F 6D 81 7C 38 07 91 7C-FF FF FF FF 00 90 FD 7F Om |8 �| .0010:0007FFD4 ED A6 54 80 C8 FF 07 00-E8 B4 F5 81 FF FF FF FF T .0010:0007FFE4 F3 99 83 7C 58 6D 81 7C-00 00 00 00 00 00 00 00 Xm |........0010:0007FFF4 00 00 00 00 E0 19 01 01-00 00 00 00 00 00 00 00 .... ....

4.

Command line, command buttons, or shortcut keys to follow the debugging process.

Command SoftICE OllyDbgRun F5 F9

Step Into F11 F7Step Over F10 F8

Set Break Point F8 F2

5.

You can compare Figure 1 and Figure 2 to distinguish the difference between SoftICE and OllyDbg.When you want to trace a PE file, you should mostly consider these five subdivisions. Furthermore,every debugger comprises of some other useful parts; you should discover them by yourself.

3.2 Disassembler

We can consider OllyDbg and SoftICE as excellent disassemblers, but I also want to introduce anotherdisassembler tool which is famous in the reverse engineering world.

3.2.1 Proview disassembler

Proview or PVDasm is an admirable disassembler by the Reverse-Engineering-Community; it is stillunder development and bug fixing. You can find its disassmbler source engine and employ it to createyour own disassembler.

3.2.2 W32Dasm

W32DASM can disassemble both 16 and 32 bit executable file formats. In addition to its disassemblingability, you can employ it to analyze import, export and resource data directories data.

3.2.3 IDA Pro

All reverse-engineering experts know that IDA Pro can be used to investigate, not only x86instructions, but that of various kinds of CPU types like AVR, PIC, and etc. It can illustrate theassembly source of a portable executable file by using colored graphics and tables, and is very useful

12 of 40

Page 13: Inject your code to a Portable Executable file - CodeProject®

for any newbie in this area. Furthermore, it has the capability to trace an executable file inside theuser mode level in the same way as OllyDbg.

3.3 Some Useful Tools

A good PE tools developer is conversant with the tools which save his time, so I recommend to selectsome appropriate instruments to investigate the base information under a portable executable file.

3.3.1 LordPE

LordPE by y0da is still the first choice to retrieve PE file information with the possibility to modifythem.

3.3.2 PEiD

PE iDentifier is valuable to identify the type of compilers, packers, and cryptors of PE files. As of now, itcan detect more than 500 different signature types of PE files.

3.3.3 Resource Hacker

Resource Hacker can be employed to modify resource directory information; icon, menu, version info,string table, and etc.

3.3.4 WinHex

WinHex, it is clear what you can do with this tool.

13 of 40

Page 14: Inject your code to a Portable Executable file - CodeProject®

3.3.5 CFF Explorer

Eventually, CFF Explorer by Ntoskrnl is what you wish to have as a PE Utility tool in your dream; itsupports PE32/64, PE rebuild included Common Language Infrastructure (CLI) file, in other words, the.NET file, a resource modifier, and much more facilities which can not be found in others, just try anddiscover every unimaginable option by hand.

4 Add new section and Change OEP

We are ready to do the first step of making our project. So I have provided a library to add a newsection and rebuild the portable executable file. Before starting, I like you get familiar with the headersof a PE file, by using OllyDbg. You should first open a PE file, that pops up a menu, View->Executablefile, again get a popup menu Special->PE header. And you will observe a scene similar to Figure 3.Now, come to Main Menu View->Memory, try to distinguish the sections inside the Memory mapwindow.

Figure 3

00000000000000020000000400000006000000080000000A0000000C0000000E00000010000000120000001400000016000000180000001A0000001C0000001D0000001E

4D 5A 9000 0300 0000 0400 0000 FFFF 0000 B800 0000 0000 0000 4000 0000 00 00 00

ASCII "MZ" DW 0090 DW 0003 DW 0000 DW 0004 DW 0000 DW FFFF DW 0000 DW 00B8 DW 0000 DW 0000 DW 0000 DW 0040 DW 0000 DB 00 DB 00 DB 00

DOS EXE Signature DOS_PartPag = 90 (144.) DOS_PageCnt = 3 DOS_ReloCnt = 0 DOS_HdrSize = 4 DOS_MinMem = 0 DOS_MaxMem = FFFF (65535.) DOS_ReloSS = 0 DOS_ExeSP = B8 DOS_ChkSum = 0 DOS_ExeIP = 0 DOS_ReloCS = 0 DOS_TablOff = 40 DOS_Overlay = 0

14 of 40

Page 15: Inject your code to a Portable Executable file - CodeProject®

0000001F000000200000002100000022000000230000002400000025000000260000002700000028000000290000002A0000002B0000002C0000002D0000002E0000002F000000300000003100000032000000330000003400000035000000360000003700000038000000390000003A0000003B0000003C

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F0000000

DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DB 00 DD 000000F0 Offset to PE signature

I want to explain how we can plainly change the Offset of Entry Point (OEP) in our sample file,CALC.EXE of Windows XP. First, by using a PE Tool, and also using our PE Viewer, we find OEP,0x00012475, and Image Base, 0x01000000. This value of OEP is the Relative Virtual Address, so theImage Base value is used to convert it to the Virtual Address.

Virtual_Address = Image_Base + Relative_Virtual_Address

DWORD OEP_RVA = image_nt_headers->OptionalHeader.AddressOfEntryPoint ; // OEP_RVA = 0x00012475

DWORD OEP_VA = image_nt_headers->OptionalHeader.ImageBase + OEP_RVA ; // OEP_VA = 0x01000000 + 0x00012475 = 0x01012475

PE Maker - Step 1

Download source files - 54.7 Kb

CALC.EXE - test file

Download test PE file - 49.5 Kb

DynLoader(), in loader.cpp, is reserved for the data of the new section, in other words, the Loader.

DynLoader Step 1

__stdcall void DynLoader(){_asm{//----------------------------------

DWORD_TYPE(DYN_LOADER_START_MAGIC)//----------------------------------

MOV EAX,01012475h // << Original OEP

15 of 40

Page 16: Inject your code to a Portable Executable file - CodeProject®

JMP EAX//----------------------------------

DWORD_TYPE(DYN_LOADER_END_MAGIC)//----------------------------------

}}

Unfortunately, this source can only be applied for the sample test file. We should complete it by savingthe value of the original OEP in the new section, and use it to reach the real OEP. I have accomplishedit in Step 2 (Section 5).

4.1 Retrieve and Rebuild PE file

I have made a simple class library to recover PE information and to use it in a new PE file.

CPELibrary Class Step 1

//----------------------------------------------------------------

class CPELibrary {private: //-----------------------------------------

PCHAR pMem; DWORD dwFileSize; //-----------------------------------------

protected: //-----------------------------------------

PIMAGE_DOS_HEADER image_dos_header; PCHAR pDosStub; DWORD dwDosStubSize, dwDosStubOffset; PIMAGE_NT_HEADERS image_nt_headers; PIMAGE_SECTION_HEADER image_section_header[MAX_SECTION_NUM]; PCHAR image_section[MAX_SECTION_NUM]; //-----------------------------------------

protected: //-----------------------------------------

DWORD PEAlign(DWORD dwTarNum,DWORD dwAlignTo); void AlignmentSections(); //-----------------------------------------

DWORD Offset2RVA(DWORD dwRO); DWORD RVA2Offset(DWORD dwRVA); //-----------------------------------------

PIMAGE_SECTION_HEADER ImageRVA2Section(DWORD dwRVA); PIMAGE_SECTION_HEADER ImageOffset2Section(DWORD dwRO); //-----------------------------------------

DWORD ImageOffset2SectionNum(DWORD dwRVA); PIMAGE_SECTION_HEADER AddNewSection(char* szName,DWORD dwSize); //-----------------------------------------

public: //-----------------------------------------

CPELibrary(); ~CPELibrary(); //-----------------------------------------

void OpenFile(char* FileName); void SaveFile(char* FileName); //-----------------------------------------

};

16 of 40

Page 17: Inject your code to a Portable Executable file - CodeProject®

By Table 1, the usage of image_dos_header, pDosStub, image_nt_headers,image_section_header [MAX_SECTION_NUM], and image_section[MAX_SECTION_NUM] is clear. Weuse OpenFile() and SaveFile() to retrieve and rebuild a PE file. Furthermore, AddNewSection() isemployed to create the new section, the important step.

4.2 Create Data for new Section

In pecrypt.cpp, I have represented another class, CPECryptor, to comprise the data of the newsection. Nevertheless, the data of the new section is created by DynLoader() in loader.cpp, DynLoaderStep 1. We use the CPECryptor class to enter this data in to the new section, and also some otherstuff.

CPECryptor Class Step 1

//----------------------------------------------------------------

class CPECryptor: public CPELibrary{private: //----------------------------------------

PCHAR pNewSection; //----------------------------------------

DWORD GetFunctionVA(void* FuncName); void* ReturnToBytePtr(void* FuncName, DWORD findstr); //----------------------------------------

protected: //----------------------------------------

public: //----------------------------------------

void CryptFile(int(__cdecl *callback) (unsigned int, unsigned int)); //----------------------------------------

};//----------------------------------------------------------------

4.3 Some notes regarding creating a new PE file

Align the VirtualAddress and the VirtualSize of each section by SectionAlignment:

image_section_header[i]->VirtualAddress= PEAlign(image_section_header[i]->VirtualAddress, image_nt_headers->OptionalHeader.SectionAlignment);

image_section_header[i]->Misc.VirtualSize= PEAlign(image_section_header[i]->Misc.VirtualSize, image_nt_headers->OptionalHeader.SectionAlignment);

Align the PointerToRawData and the SizeOfRawData of each section by FileAlignment:

image_section_header[i]->PointerToRawData = PEAlign(image_section_header[i]->PointerToRawData, image_nt_headers->OptionalHeader.FileAlignment);

image_section_header[i]->SizeOfRawData = PEAlign(image_section_header[i]->SizeOfRawData, image_nt_headers->OptionalHeader.FileAlignment);

Correct the SizeofImage by the virtual size and the virtual address of the last section:

image_nt_headers->OptionalHeader.SizeOfImage = image_section_header[LastSection]->VirtualAddress + image_section_header[LastSection]->Misc.VirtualSize;

17 of 40

Page 18: Inject your code to a Portable Executable file - CodeProject®

Set the Bound Import Directory header to zero, as this directory is not very important to executea PE file:

image_nt_headers-> OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT]. VirtualAddress = 0;image_nt_headers-> OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;

4.4 Some notes regarding linking this VC Project

Set Linker->General->Enable Incremental Linking to No (/INCREMENTAL:NO).

You can comprehend the difference between incremental link and no-incremental link by lookingat the following picture:

To acquire the virtual address of DynLoader(), we obtain the virtual address of JMPpemaker.DynLoader in the incremental link, but by no-incremental link, the real virtual addressis gained by the following code:

DWORD dwVA= (DWORD) DynLoader;

This setting is more critical in the incremental link when you try to find the beginning and endingof the Loader, DynLoader(), by CPECryptor::ReturnToBytePtr():

void* CPECryptor::ReturnToBytePtr(void* FuncName, DWORD findstr){ void* tmpd; __asm { mov eax, FuncName jmp dfhjg: inc eaxdf: mov ebx, [eax] cmp ebx, findstr jnz hjg mov tmpd, eax } return tmpd;}

5 Store Important Data and Reach Original OEP

Right now, we save the Original OEP and also the Image Base in order to reach to the virtual addressof OEP. I have reserved a free space at the end of DynLoader() to store them, DynLoader Step 2.

PE Maker - Step 2

18 of 40

Page 19: Inject your code to a Portable Executable file - CodeProject®

Download source files - 58.3 Kb

DynLoader Step 2

__stdcall void DynLoader(){_asm{//----------------------------------

DWORD_TYPE(DYN_LOADER_START_MAGIC)//----------------------------------

Main_0: PUSHAD // get base ebp

CALL Main_1Main_1: POP EBP SUB EBP,OFFSET Main_1 MOV EAX,DWORD PTR [EBP+_RO_dwImageBase] ADD EAX,DWORD PTR [EBP+_RO_dwOrgEntryPoint] PUSH EAX RETN // >> JMP to Original OEP

//----------------------------------

DWORD_TYPE(DYN_LOADER_START_DATA1)//----------------------------------

_RO_dwImageBase: DWORD_TYPE(0xCCCCCCCC)_RO_dwOrgEntryPoint: DWORD_TYPE(0xCCCCCCCC)//----------------------------------

DWORD_TYPE(DYN_LOADER_END_MAGIC)//----------------------------------

}}

The new function, CPECryptor::CopyData1(), will implement the copy of the Image Base value andthe Offset of Entry Point value into 8 bytes of free space in the loader.

5.1 Restore the first Registers Context

It is important to recover the Original Context of the thread. We have not yet done it in the DynLoaderStep 2 source code. We can modify the source of DynLoader() to repossess the first Context.

__stdcall void DynLoader(){_asm{//----------------------------------

DWORD_TYPE(DYN_LOADER_START_MAGIC)//----------------------------------

Main_0: PUSHAD// Save the registers context in stack

CALL Main_1Main_1: POP EBP// Get Base EBP

SUB EBP,OFFSET Main_1 MOV EAX,DWORD PTR [EBP+_RO_dwImageBase] ADD EAX,DWORD PTR [EBP+_RO_dwOrgEntryPoint] MOV DWORD PTR [ESP+1Ch],EAX // pStack.Eax <- EAX

POPAD // Restore the first registers context from stack

19 of 40

Page 20: Inject your code to a Portable Executable file - CodeProject®

PUSH EAX XOR EAX, EAX RETN // >> JMP to Original OEP

//----------------------------------

DWORD_TYPE(DYN_LOADER_START_DATA1)//----------------------------------

_RO_dwImageBase: DWORD_TYPE(0xCCCCCCCC)_RO_dwOrgEntryPoint: DWORD_TYPE(0xCCCCCCCC)//----------------------------------

DWORD_TYPE(DYN_LOADER_END_MAGIC)//----------------------------------

}}

5.2 Restore the Original Stack

We can also recover the original stack by setting the value of the beginning stack + 0x34 to theOriginal OEP, but it is not very important. Nevertheless, in the following code, I have accomplished theloader code by a simple trick to reach OEP in addition to redecorating the stack. You can observe theimplementation by tracing using OllyDbg or SoftICE.

__stdcall void DynLoader(){_asm{//----------------------------------

DWORD_TYPE(DYN_LOADER_START_MAGIC)//----------------------------------

Main_0: PUSHAD // Save the registers context in stack

CALL Main_1Main_1: POP EBP SUB EBP,OFFSET Main_1 MOV EAX,DWORD PTR [EBP+_RO_dwImageBase] ADD EAX,DWORD PTR [EBP+_RO_dwOrgEntryPoint] MOV DWORD PTR [ESP+54h],EAX // pStack.Eip <- EAX

POPAD // Restore the first registers context from stack

CALL _OEP_Jump DWORD_TYPE(0xCCCCCCCC)_OEP_Jump: PUSH EBP MOV EBP,ESP MOV EAX,DWORD PTR [ESP+3Ch] // EAX <- pStack.Eip

MOV DWORD PTR [ESP+4h],EAX // _OEP_Jump RETURN pointer <- EAX

XOR EAX,EAX LEAVE RETN//----------------------------------

DWORD_TYPE(DYN_LOADER_START_DATA1)//----------------------------------

_RO_dwImageBase: DWORD_TYPE(0xCCCCCCCC)_RO_dwOrgEntryPoint: DWORD_TYPE(0xCCCCCCCC)//----------------------------------

DWORD_TYPE(DYN_LOADER_END_MAGIC)//----------------------------------

}}

20 of 40

Page 21: Inject your code to a Portable Executable file - CodeProject®

5.3 Approach OEP by Structured Exception Handling

An exception is generated when a program falls into a fault code execution and an error happens, so insuch a special condition, the program immediately jumps to a function called the exception handlerfrom exception handler list of the Thread Information Block.

The next example of a try-except statement in C++ clarifies the operation of structured exceptionhandling. Besides the assembly code of this code, it elucidates the structured exception handlerinstallation, the raise of an exception, and the exception handler function.

#include "stdafx.h"

#include "windows.h"

void RAISE_AN_EXCEPTION(){ _asm{ INT 3 INT 3 INT 3 INT 3}}

int _tmain(int argc, _TCHAR* argv[]){ __try { __try{ printf("1: Raise an Exception\n"); RAISE_AN_EXCEPTION(); } __finally { printf("2: In Finally\n"); } } __except( printf("3: In Filter\n"), EXCEPTION_EXECUTE_HANDLER ) { printf("4: In Exception Handler\n"); } return 0;}

; main()00401000: PUSH EBP00401001: MOV EBP,ESP00401003: PUSH -100401005: PUSH 00407160; __try {; the structured exception handler (SEH) installation 0040100A: PUSH _except_handler3 0040100F: MOV EAX,DWORD PTR FS:[0]00401015: PUSH EAX00401016: MOV DWORD PTR FS:[0],ESP0040101D: SUB ESP,800401020: PUSH EBX00401021: PUSH ESI00401022: PUSH EDI00401023: MOV DWORD PTR SS:[EBP-18],ESP; __try {00401026: XOR ESI,ESI00401028: MOV DWORD PTR SS:[EBP-4],ESI0040102B: MOV DWORD PTR SS:[EBP-4],100401032: PUSH OFFSET "1: Raise an Exception"00401037: CALL printf0040103C: ADD ESP,4; the raise a exception, INT 3 exception; RAISE_AN_EXCEPTION()0040103F: INT3 00401040: INT3

21 of 40

Page 22: Inject your code to a Portable Executable file - CodeProject®

00401041: INT300401042: INT3; } __finally {00401043: MOV DWORD PTR SS:[EBP-4],ESI00401046: CALL 0040104D0040104B: JMP 004010800040104D: PUSH OFFSET "2: In Finally"00401052: CALL printf00401057: ADD ESP,40040105A: RETN; }; }; __except( 0040105B: JMP 004010800040105D: PUSH OFFSET "3: In Filter"00401062: CALL printf00401067: ADD ESP,40040106A: MOV EAX,1 ; EXCEPTION_EXECUTE_HANDLER = 10040106F: RETN; , EXCEPTION_EXECUTE_HANDLER ); {; the exception handler funtion00401070: MOV ESP,DWORD PTR SS:[EBP-18]00401073: PUSH OFFSET "4: In Exception Handler"00401078: CALL printf0040107D: ADD ESP,4; }00401080: MOV DWORD PTR SS:[EBP-4],-10040108C: XOR EAX,EAX; restore previous SEH0040108E: MOV ECX,DWORD PTR SS:[EBP-10]00401091: MOV DWORD PTR FS:[0],ECX00401098: POP EDI00401099: POP ESI0040109A: POP EBX0040109B: MOV ESP,EBP0040109D: POP EBP0040109E: RETN

Make a Win32 console project, and link and run the preceding C++ code, to perceive the result:

1: Raise an Exception3: In Filter2: In Finally4: In Exception Handler_

This program runs the exception expression, printf("3: In Filter\n");, when an exceptionhappens, in this example the INT 3 exception. You can employ other kinds of exception too. InOllyDbg, Debugging options->Exceptions, you can see a short list of different types of exceptions.

5.3.1 Implement Exception Handler

22 of 40

Page 23: Inject your code to a Portable Executable file - CodeProject®

We desire to construct a structured exception handler in order to reach OEP. Now, I think you havedistinguished the SEH installation, the exception raise, and the exception expression filter, byforegoing the assembly code. To establish our exception handler approach, we need to comprise thefollowing codes:

SEH installation:

LEA EAX,[EBP+_except_handler1_OEP_Jump] PUSH EAX PUSH DWORD PTR FS:[0] MOV DWORD PTR FS:[0],ESP

An Exception Raise:

INT 3

Exception handler expression filter:

_except_handler1_OEP_Jump: PUSH EBP MOV EBP,ESP ... MOV EAX, EXCEPTION_CONTINUE_SEARCH // EXCEPTION_CONTINUE_SEARCH = 0 LEAVE RETN

So we yearn for making the ensuing C++ code in assembly language to inaugurate our engine toapproach the Offset of Entry Point by SEH.

__try // SEH installation

{ __asm { INT 3 // An Exception Raise

}}__except( ..., EXCEPTION_CONTINUE_SEARCH ){}// Exception handler expression filter

In assembly code...

; ----------------------------------------------------

; the structured exception handler (SEH) installation

; __try {

LEA EAX,[EBP+_except_handler1_OEP_Jump] PUSH EAX PUSH DWORD PTR FS:[0] MOV DWORD PTR FS:[0],ESP ; ----------------------------------------------------

; the raise a INT 3 exception

INT 3 INT 3 INT 3 INT 3 ; }

; __except( ...

; ----------------------------------------------------

; exception handler expression filter

_except_handler1_OEP_Jump:

23 of 40

Page 24: Inject your code to a Portable Executable file - CodeProject®

PUSH EBP MOV EBP,ESP ... MOV EAX, EXCEPTION_CONTINUE_SEARCH ; EXCEPTION_CONTINUE_SEARCH = 0

LEAVE RETN ; , EXCEPTION_CONTINUE_SEARCH ) { }

The exception value, __except(..., Value), determines how the exception is handled, it can havethree values, 1, 0, -1. To understand them, refer to the try-except statement description in theMSDN library. We set it to EXCEPTION_CONTINUE_SEARCH (0), not to run the exception handlerfunction, therefore by this value, the exception is not recognized, is simply ignored, and the threadcontinues its code-execution.

How the SEH installation is implemented

As you perceived from the illustrated code, the SEH installation is done by the FS segment register.Microsoft Windows 32 bit uses the FS segment register as a pointer to the data block of the mainthread. The first 0x1C bytes comprise the information of the Thread Information Block (TIB).Therefore, FS:[00h] refers to ExceptionList of the main thread, Table 3. In our code, we havepushed the pointer to _except_handler1_OEP_Jump in the stack and changed the value ofExceptionList, FS:[00h], to the beginning of the stack, ESP.

Thread Information Block (TIB)

typedef struct _NT_TIB32 { DWORD ExceptionList; DWORD StackBase; DWORD StackLimit; DWORD SubSystemTib; union { DWORD FiberData; DWORD Version; }; DWORD ArbitraryUserPointer; DWORD Self;} NT_TIB32, *PNT_TIB32;

Table 3 - FS segment register and Thread Information Block

DWORD PTR FS:[00h] ExceptionListDWORD PTR FS:[04h] StackBaseDWORD PTR FS:[08h] StackLimitDWORD PTR FS:[0Ch] SubSystemTibDWORD PTR FS:[10h] FiberData / VersionDWORD PTR FS:[14h]ArbitraryUserPointerDWORD PTR FS:[18h] Self

5.3.2 Attain OEP by adjusting the Thread Context

In this part, we effectuate our performance by accomplishing the OEP approach. We change theContext of the thread and ignore every simple exception handling, and let the thread continue theexecution, but in the original OEP!

When an exception happens, the context of the processor during the time of the exception is saved inthe stack. By EXCEPTION_POINTERS, we have access to the pointer of ContextRecord. TheContextRecord has the CONTEXT data structure, Table 4, this is the thread context during theexception time. When we ignore the exception by EXCEPTION_CONTINUE_SEARCH (0), the instructionpointer as well the context will be set to ContextRecord in order to return to the previous condition.Therefore, if we change the Eip of the Win32 Thread Context to the Original Offset of Entry Point, itwill come clearly into OEP.

24 of 40

Page 25: Inject your code to a Portable Executable file - CodeProject®

MOV EAX, ContextRecord MOV EDI, dwOEP ; EAX <- dwOEP

MOV DWORD PTR DS:[EAX+0B8h], EDI ; pContext.Eip <- EAX

Win32 Thread Context structure

#define MAXIMUM_SUPPORTED_EXTENSION 512

typedef struct _CONTEXT { //-----------------------------------------

DWORD ContextFlags; //-----------------------------------------

DWORD Dr0; DWORD Dr1; DWORD Dr2; DWORD Dr3; DWORD Dr6; DWORD Dr7; //-----------------------------------------

FLOATING_SAVE_AREA FloatSave; //-----------------------------------------

DWORD SegGs; DWORD SegFs; DWORD SegEs; DWORD SegDs; //-----------------------------------------

DWORD Edi; DWORD Esi; DWORD Ebx; DWORD Edx; DWORD Ecx; DWORD Eax; //-----------------------------------------

DWORD Ebp; DWORD Eip; DWORD SegCs; DWORD EFlags; DWORD Esp; DWORD SegSs; //-----------------------------------------

BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION]; //----------------------------------------

} CONTEXT, *LPCONTEXT;

Table 4 - CONTEXT

ContextFlags 0x00000000 ContextFlags

ContextDebug

Registers

0x00000004 Dr00x00000008 Dr10x0000000C Dr20x00000010 Dr30x00000014 Dr60x00000018 Dr7

ContextFloating

Point

0x0000001C

FloatSave

StatusWord0x00000020 StatusWord0x00000024 TagWord0x00000028 ErrorOffset

25 of 40

Page 26: Inject your code to a Portable Executable file - CodeProject®

0x0000002C ErrorSelector0x00000030 DataOffset0x00000034 DataSelector0x00000038

...0x00000087

RegisterArea[0x50]

0x00000088 Cr0NpxState

ContextSegments

0x0000008C SegGs0x00000090 SegFs0x00000094 SegEs0x00000098 SegDs

ContextInteger

0x0000009C Edi0x000000A0 Esi0x000000A4 Ebx0x000000A8 Edx0x000000AC Ecx0x000000B0 Eax

ContextControl

0x000000B4 Ebp0x000000B8 Eip0x000000BC SegCs0x000000C0 EFlags0x000000C4 Esp0x000000C8 SegSs

ContextExtendedRegisters

0x000000CC...

0x000002CBExtendedRegisters[0x200]

By the following code, we have accomplished the main purpose of coming to OEP by the structuredexception handler:

__stdcall void DynLoader(){_asm{//----------------------------------

DWORD_TYPE(DYN_LOADER_START_MAGIC)//----------------------------------

Main_0: PUSHAD // Save the registers context in stack

CALL Main_1Main_1: POP EBP SUB EBP,OFFSET Main_1 // Get Base EBP

MOV EAX,DWORD PTR [EBP+_RO_dwImageBase] ADD EAX,DWORD PTR [EBP+_RO_dwOrgEntryPoint] MOV DWORD PTR [ESP+10h],EAX // pStack.Ebx <- EAX

LEA EAX,[EBP+_except_handler1_OEP_Jump] MOV DWORD PTR [ESP+1Ch],EAX // pStack.Eax <- EAX

POPAD // Restore the first registers context from stack

//----------------------------------------------------

// the structured exception handler (SEH) installation

PUSH EAX XOR EAX, EAX PUSH DWORD PTR FS:[0] // NT_TIB32.ExceptionList

MOV DWORD PTR FS:[0],ESP // NT_TIB32.ExceptionList <-ESP

26 of 40

Page 27: Inject your code to a Portable Executable file - CodeProject®

//----------------------------------------------------

// the raise a INT 3 exception

DWORD_TYPE(0xCCCCCCCC) //--------------------------------------------------------

// -------- exception handler expression filter ----------

_except_handler1_OEP_Jump: PUSH EBP MOV EBP,ESP //------------------------------

MOV EAX,DWORD PTR SS:[EBP+010h] // PCONTEXT: pContext <- EAX

//==============================

PUSH EDI // restore original SEH

MOV EDI,DWORD PTR DS:[EAX+0C4h] // pContext.Esp

PUSH DWORD PTR DS:[EDI] POP DWORD PTR FS:[0] ADD DWORD PTR DS:[EAX+0C4h],8 // pContext.Esp

//------------------------------

// set the Eip to the OEP

MOV EDI,DWORD PTR DS:[EAX+0A4h] // EAX <- pContext.Ebx

MOV DWORD PTR DS:[EAX+0B8h],EDI // pContext.Eip <- EAX

//------------------------------

POP EDI //==============================

MOV EAX, EXCEPTION_CONTINUE_SEARCH LEAVE RETN//----------------------------------

DWORD_TYPE(DYN_LOADER_START_DATA1)//----------------------------------

_RO_dwImageBase: DWORD_TYPE(0xCCCCCCCC)_RO_dwOrgEntryPoint: DWORD_TYPE(0xCCCCCCCC)//----------------------------------

DWORD_TYPE(DYN_LOADER_END_MAGIC)//----------------------------------

}}

6 Build an Import Table and Reconstruct the Original Import Table

To use the Windows dynamic link library (DLL) in Windows application programming, there are twoways:

Using Windows libraries by additional dependencies:

27 of 40

Page 28: Inject your code to a Portable Executable file - CodeProject®

Using Windows dynamic link libraries in run-time:

// DLL function signature

typedef HGLOBAL (*importFunction_GlobalAlloc)(UINT, SIZE_T);...importFunction_GlobalAlloc __GlobalAlloc;

// Load DLL file

HINSTANCE hinstLib = LoadLibrary("Kernel32.dll");if (hinstLib == NULL){ // Error - unable to load DLL

}

// Get function pointer

__GlobalAlloc = (importFunction_GlobalAlloc)GetProcAddress(hinstLib, "GlobalAlloc");if (addNumbers == NULL) { // Error - unable to find DLL function

}

FreeLibrary(hinstLib);

When you make a Windows application project, the linker includes at least kernel32.dll in the basedependencies of your project. Without LoadLibrary() and GetProcAddress() of Kernel32.dll, wecan not load a DLL in run-time. The dependencies information is stored in the import table section. ByDependency Walker, it is not so difficult to observe the DLL module and the functions which areimported into a PE file.

28 of 40

Page 29: Inject your code to a Portable Executable file - CodeProject®

We attempt to establish our custom import table to conduct our project. Furthermore, we have to fixup the original import table at the end in order to run the real code of the program.

PE Maker - Step 3

Download source files - 65.4 Kb

6.1 Construct the Client Import Table

I strongly advise you to read the section 6.4 of the Microsoft Portable Executable and the CommonObject File Format Specification document. This section contains the principal information tocomprehend the import table performance.

The import table data is accessible by a second data directory of the optional header from PE headers,so you can access it by using the following code:

DWORD dwVirtualAddress = image_nt_headers-> OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;DWORD dwSize = image_nt_headers-> OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size;

The VirtualAddress refers to structures by IMAGE_IMPORT_DESCRIPTOR. This structure contains thepointer to the imported DLL name and the relative virtual address of the first thunk.

typedef struct _IMAGE_IMPORT_DESCRIPTOR { union { DWORD Characteristics; DWORD OriginalFirstThunk; }; DWORD TimeDateStamp; DWORD ForwarderChain; DWORD Name; // the imported DLL name

DWORD FirstThunk; // the relative virtual address of the first thunk

} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR;

When a program is running, the Windows task manager sets the thunks by the virtual address of thefunction. The virtual address is found by the name of the function. At first, the thunks hold the relativevirtual address of the function name, Table 5; during execution, they are fixed up by the virtualaddress of the functions, Table 6.

29 of 40

Page 30: Inject your code to a Portable Executable file - CodeProject®

Table 5 - The Import Table in file image

IMAGE_IMPORT_DESCRIPTOR[0]

OriginalFirstThunkTimeDateStampForwarderChainName_RVA ------>"kernel32.dll",0FirstThunk_RVA ------>proc_1_name_RVA------>0,0,"LoadLibraryA",0

proc_2_name_RVA------>0,0,"GetProcAddress",0proc_3_name_RVA------>0,0,"GetModuleHandleA",0...

IMAGE_IMPORT_DESCRIPTOR[1]...IMAGE_IMPORT_DESCRIPTOR[n]

Table 6 - The Import Table in virtual memory

IMAGE_IMPORT_DESCRIPTOR[0]

OriginalFirstThunkTimeDateStampForwarderChainName_RVA ------>"kernel32.dll",0FirstThunk_RVA ------>proc_1_VA

proc_2_VAproc_3_VA...

IMAGE_IMPORT_DESCRIPTOR[1]...IMAGE_IMPORT_DESCRIPTOR[n]

We want to make a simple import table to import LoadLibrary(), and GetProcAddress() fromKernel32.dll. We need these two essential API functions to cover other API functions in run-time. Thefollowing assembly code shows how easily we can reach our solution:

0101F000: 00000000 ; OriginalFirstThunk0101F004: 00000000 ; TimeDateStamp0101F008: 00000000 ; ForwarderChain0101F00C: 0001F034 ; Name; ImageBase + 0001F034 -> 0101F034 -> "Kernel32.dll",00101F010: 0001F028 ; FirstThunk; ImageBase + 0001F028 -> 0101F0280101F014: 000000000101F018: 000000000101F01C: 000000000101F020: 000000000101F024: 000000000101F028: 0001F041 ; ImageBase + 0001F041 -> 0101F041 -> 0,0,"LoadLibraryA",00101F02C: 0001F050 ; ImageBase + 0001F050 -> 0101F050 -> 0,0,"GetProcAddress",00101F030: 000000000101F034: 'K' 'e' 'r' 'n' 'e' 'l' '3' '2' '.' 'd' 'l' 'l' 000001F041: 00 00 'L' 'o' 'a' 'd' 'L' 'i' 'b' 'r' 'a' 'r' 'y' 'A' 000001F050: 00 00 'G' 'e' 't' 'P' 'r' 'o' 'c' 'A' 'd' 'd' 'r' 'e' 's' 's' 00

After running...

0101F000: 00000000 ; OriginalFirstThunk0101F004: 00000000 ; TimeDateStamp0101F008: 00000000 ; ForwarderChain0101F00C: 0001F034 ; Name; ImageBase + 0001F034 -> 0101F034 -> "Kernel32.dll",00101F010: 0001F028 ; FirstThunk; ImageBase + 0001F028 -> 0101F0280101F014: 000000000101F018: 000000000101F01C: 00000000

30 of 40

Page 31: Inject your code to a Portable Executable file - CodeProject®

0101F020: 000000000101F024: 000000000101F028: 7C801D77 ; -> Kernel32.LoadLibrary()0101F02C: 7C80AC28 ; -> Kernel32.GetProcAddress()0101F030: 000000000101F034: 'K' 'e' 'r' 'n' 'e' 'l' '3' '2' '.' 'd' 'l' 'l' 000001F041: 00 00 'L' 'o' 'a' 'd' 'L' 'i' 'b' 'r' 'a' 'r' 'y' 'A' 000001F050: 00 00 'G' 'e' 't' 'P' 'r' 'o' 'c' 'A' 'd' 'd' 'r' 'e' 's' 's' 00

I have prepared a class library to make every import table by using a client string table. The CITMakerclass library in itmaker.h, it will build an import table by sz_IT_EXE_strings and also the relativevirtual address of the import table.

static const char *sz_IT_EXE_strings[]={ "Kernel32.dll", "LoadLibraryA", "GetProcAddress", 0,, 0,};

We subsequently employ this class library to establish an import table to support DLLs and OCXs, sothis is a general library to present all possible import tables easily. The next step is clarified in thefollowing code.

CITMaker *ImportTableMaker = new CITMaker( IMPORT_TABLE_EXE );...pimage_section_header=AddNewSection( ".xxx", dwNewSectionSize );// build import table by the current virtual address

ImportTableMaker->Build( pimage_section_header->VirtualAddress ); memcpy( pNewSection, ImportTableMaker->pMem, ImportTableMaker->dwSize );...memcpy( image_section[image_nt_headers->FileHeader.NumberOfSections-1], pNewSection, dwNewSectionSize );...image_nt_headers->OptionalHeader. DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = pimage_section_header->VirtualAddress;image_nt_headers->OptionalHeader. DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = ImportTableMaker->dwSize;...delete ImportTableMaker;

The import table is copied at the beginning of the new section, and the relevant data directory isadjusted to the relative virtual address of the new section and the size of the new import table

6.2 Using other API functions in run-time

At this time, we can load other DLLs and find the process address of other functions by usingLoadLibrary() and GetProcAddress():

lea edi, @"Kernel32.dll"//-------------------push edimov eax,offset _p_LoadLibrarycall [ebp+eax] //LoadLibrary(lpLibFileName);//-------------------mov esi,eax // esi -> hModulelea edi, @"GetModuleHandleA"//-------------------push edi

31 of 40

Page 32: Inject your code to a Portable Executable file - CodeProject®

push esimov eax,offset _p_GetProcAddresscall [ebp+eax] //GetModuleHandle=GetProcAddress(hModule, lpProcName);//--------------------

I want to have a complete imported function table similar in performance done in a real EXE file. If youlook inside a PE file, you will discover that an API call is done by an indirection jump through thevirtual address of the API function:

JMP DWORD PTR [XXXXXXXX]

...0101F028: 7C801D77 ; Virtual Address of kernel32.LoadLibrary()...0101F120: JMP DWORD PTR [0101F028]...0101F230: CALL 0101F120 ; JMP to kernel32.LoadLibrary...

It makes it easy to expand the other part of our project by this performance, so we construct two datatables: first for API virtual addresses, and the second for the JMP [XXXXXXXX].

#define __jmp_api byte_type(0xFF) byte_type(0x25)__asm{...//----------------------------------------------------------------

_p_GetModuleHandle: dword_type(0xCCCCCCCC)_p_VirtualProtect: dword_type(0xCCCCCCCC)_p_GetModuleFileName: dword_type(0xCCCCCCCC)_p_CreateFile: dword_type(0xCCCCCCCC)_p_GlobalAlloc: dword_type(0xCCCCCCCC)//----------------------------------------------------------------

_jmp_GetModuleHandle: __jmp_api dword_type(0xCCCCCCCC)_jmp_VirtualProtect: __jmp_api dword_type(0xCCCCCCCC)_jmp_GetModuleFileName: __jmp_api dword_type(0xCCCCCCCC)_jmp_CreateFile: __jmp_api dword_type(0xCCCCCCCC)_jmp_GlobalAlloc: __jmp_api dword_type(0xCCCCCCCC)//----------------------------------------------------------------

...}

In the succeeding code, we has concluded our ambition to install a custom internal import table! (Wecan not call it import table.)

... lea edi,[ebp+_p_szKernel32] lea ebx,[ebp+_p_GetModuleHandle] lea ecx,[ebp+_jmp_GetModuleHandle] add ecx,02h_api_get_lib_address_loop: push ecx push edi mov eax,offset _p_LoadLibrary call [ebp+eax] //LoadLibrary(lpLibFileName); pop ecx mov esi,eax // esi -> hModule push edi call __strlen add esp,04h add edi,eax_api_get_proc_address_loop: push ecx push edi push esi mov eax,offset _p_GetProcAddress call [ebp+eax]//GetModuleHandle=GetProcAddress(hModule, lpProcName); pop ecx

32 of 40

Page 33: Inject your code to a Portable Executable file - CodeProject®

mov [ebx],eax mov [ecx],ebx // JMP DWORD PTR [XXXXXXXX] add ebx,04h add ecx,06h push edi call __strlen add esp,04h add edi,eax mov al,byte ptr [edi] test al,al jnz _api_get_proc_address_loop inc edi mov al,byte ptr [edi] test al,al jnz _api_get_lib_address_loop ...

6.3 Fix up the Original Import Table

In order to run the program again, we should fix up the thunks of the actual import table, otherwise wehave a corrupted target PE file. Our code must correct all of the thunks the same as Table 5 to Table 6.Once more, LoadLibrary() and GetProcAddress() aid us in our effort to reach our intention.

... mov ebx,[ebp+_p_dwImportVirtualAddress] test ebx,ebx jz _it_fixup_end mov esi,[ebp+_p_dwImageBase] add ebx,esi // dwImageBase + dwImportVirtualAddress_it_fixup_get_lib_address_loop: mov eax,[ebx+00Ch] // image_import_descriptor.Name test eax,eax jz _it_fixup_end mov ecx,[ebx+010h] // image_import_descriptor.FirstThunk add ecx,esi mov [ebp+_p_dwThunk],ecx // dwThunk mov ecx,[ebx] // image_import_descriptor.Characteristics test ecx,ecx jnz _it_fixup_table mov ecx,[ebx+010h]_it_fixup_table: add ecx,esi mov [ebp+_p_dwHintName],ecx // dwHintName add eax,esi // image_import_descriptor.Name + dwImageBase = ModuleName push eax // lpLibFileName mov eax,offset _p_LoadLibrary call [ebp+eax] // LoadLibrary(lpLibFileName);

test eax,eax jz _it_fixup_end mov edi,eax_it_fixup_get_proc_address_loop: mov ecx,[ebp+_p_dwHintName] // dwHintName mov edx,[ecx] // image_thunk_data.Ordinal test edx,edx jz _it_fixup_next_module test edx,080000000h // .IF( import by ordinal ) jz _it_fixup_by_name and edx,07FFFFFFFh // get ordinal jmp _it_fixup_get_addr_it_fixup_by_name: add edx,esi // image_thunk_data.Ordinal + dwImageBase = OrdinalName inc edx inc edx // OrdinalName.Name_it_fixup_get_addr: push edx //lpProcName push edi // hModule mov eax,offset _p_GetProcAddress call [ebp+eax] // GetProcAddress(hModule, lpProcName);

mov ecx,[ebp+_p_dwThunk] // dwThunk mov [ecx],eax // correction the thunk // dwThunk => next dwThunk

33 of 40

Page 34: Inject your code to a Portable Executable file - CodeProject®

add dword ptr [ebp+_p_dwThunk], 004h // dwHintName => next dwHintName add dword ptr [ebp+_p_dwHintName],004h jmp _it_fixup_get_proc_address_loop_it_fixup_next_module: add ebx,014h // sizeof(IMAGE_IMPORT_DESCRIPTOR) jmp _it_fixup_get_lib_address_loop_it_fixup_end: ...

7 Support DLL and OCX

Now, we intend to include the dynamic link library (DLL) and OLE-ActiveX Control in our PE builderproject. Supporting them is very easy if we pay attention to the two time arrival into the Offset ofEntry Point, the relocation table implementation, and the client import table.

PE Maker - Step 4

Download source files - 68.6 Kb

7.1 Twice OEP approach

The Offset of Entry Point of a DLL file or an OCX file is touched by the main program atleast twice:

Constructor:

When a DLL is loaded by LoadLibrary(), or an OCX is registered by using LoadLibrary() andGetProcAddress() through calling DllRegisterServer(), the first of the OEP arrival is done.

hinstDLL = LoadLibrary( "test1.dll" );

hinstOCX = LoadLibrary( "test1.ocx" );_DllRegisterServer = GetProcAddress( hinstOCX, "DllRegisterServer" );_DllRegisterServer(); // ocx register

Destructor:

When the main program frees the library usage by FreeLibrary(), the second OEP arrivalhappens.

FreeLibrary( hinstDLL );

FreeLibrary( hinstOCX );

To perform this, I have employed a trick, that causes in the second time again, the instruction pointer(EIP) traveling towards the original OEP by the structured exception handler.

_main_0: pushad // save the registers context in stack call _main_1_main_1: pop ebp sub ebp,offset _main_1 // get base ebp //---------------- support dll, ocx -----------------_support_dll_0: jmp _support_dll_1 // nop; nop; // << trick // in the second time OEP jmp _support_dll_2_support_dll_1: //---------------------------------------------------- ... //---------------- support dll, ocx 1 --------------- mov edi,[ebp+_p_dwImageBase] add edi,[edi+03Ch]// edi -> IMAGE_NT_HEADERS mov ax,word ptr [edi+016h]// edi -> image_nt_headers->FileHeader.Characteristics

34 of 40

Page 35: Inject your code to a Portable Executable file - CodeProject®

test ax,IMAGE_FILE_DLL jz _support_dll_2 mov ax, 9090h // << trick mov word ptr [ebp+_support_dll_0],ax_support_dll_2: //---------------------------------------------------- ... into OEP by SEH ...

I hope you have caught the trick in the preceding code, but this is not all of it, we have problem inImageBase, when the library has been loaded in different image bases by the main program. Weshould write some code to find the real image base and store it to use forward.

mov eax,[esp+24h] // the real imagebase mov ebx,[esp+30h] // oep cmp eax,ebx ja _no_dll_pe_file_0 cmp word ptr [eax],IMAGE_DOS_SIGNATURE jne _no_dll_pe_file_0 mov [ebp+_p_dwImageBase],eax_no_dll_pe_file_0:

This code finds the real image base by investigating the stack information. By using the real imagebase and the formal image base, we should correct all memory calls inside the image program!! Don'tbe afraid, it will be done simply by the relocating the table information.

7.2 Implement Relocation Table

To understand the relocation table better, you can take a look at the section 6.6 of Microsoft PortableExecutable and Common Object File Format Specification document. The relocation table containsmany packages to relocate the information related to the virtual address inside the virtual memoryimage. Each package comprise of a 8 bytes header to exhibit the base virtual address and the numberof data, demonstrated by the IMAGE_BASE_RELOCATION data structure.

typedef struct _IMAGE_BASE_RELOCATION { DWORD VirtualAddress; DWORD SizeOfBlock;} IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION;

Table 7 - The Relocation Table

Block[1]

VirtualAddressSizeOfBlock

type:4offset:12type:4offset:12type:4offset:12type:4offset:12type:4offset:12type:4offset:12

... ... ... ...type:4offset:12 00 00

Block[2]

VirtualAddressSizeOfBlock

type:4offset:12type:4offset:12type:4offset:12type:4offset:12type:4offset:12type:4offset:12

... ... ... ...type:4offset:12 00 00

... ...

Block[n]

VirtualAddressSizeOfBlock

type:4offset:12type:4offset:12type:4offset:12type:4offset:12type:4offset:12type:4offset:12

35 of 40

Page 36: Inject your code to a Portable Executable file - CodeProject®

... ... ... ...type:4offset:12 00 00

Table 7 illustrates the main idea of the relocation table. Furthermore, you can upload a DLL or an OCXfile in OllyDbg to observe the relocation table, the ".reloc" section through Memory map window. By theway, we find the position of the relocation table by using the following code in our project:

DWORD dwVirtualAddress = image_nt_headers-> OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]. VirtualAddress;DWORD dwSize = image_nt_headers-> OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;

By OllyDbg, we have the same as the following for the ".reloc" section, by using the Long Hex viewermode. In this example, the base virtual address is 0x1000 and the size of the block is 0x184.

008E1000 : 00001000 00000184 30163000 30403028008E1010 : 30683054 308C3080 30AC309C 30D830CC008E1020 : 30E030DC 30E830E4 30F030EC 310030F4008E1030 : 3120310D 315F3150 31A431A0 31C031A8008E1040 : 31D031CC 31F431EC 31FC31F8 32043200008E1050 : 320C3208 32143210 324C322C 32583254008E1060 : 3260325C 32683264 3270326C 32B03274

It relocates the data in the subsequent virtual addresses:

0x1000 + 0x0000 = 0x10000x1000 + 0x0016 = 0x10160x1000 + 0x0028 = 0x10280x1000 + 0x0040 = 0x10400x1000 + 0x0054 = 0x1054...

Each package performs the relocation by using consecutive 4 bytes form its internal information. Thefirst byte refers to the type of relocation and the next three bytes are the offset which must be usedwith the base virtual address and the image base to correct the image information.

type offset03 000000

What is the type

The type can be one of the following values:

IMAGE_REL_BASED_ABSOLUTE (0): no effect.IMAGE_REL_BASED_HIGH (1): relocate by the high 16 bytes of the base virtual address and theoffset.IMAGE_REL_BASED_LOW (2): relocate by the low 16 bytes of the base virtual address and theoffset.IMAGE_REL_BASED_HIGHLOW (3): relocate by the base virtual address and the offset.

What is done in the relocation?

By relocation, some values inside the virtual memory are corrected according to the current imagebase by the ".reloc" section packages.

delta_ImageBase = current_ImageBase - image_nt_headers->OptionalHeader.ImageBase

mem[ current_ImageBase + 0x1000 ] = mem[ current_ImageBase + 0x1000 ] + delta_ImageBase ;mem[ current_ImageBase + 0x1016 ] = mem[ current_ImageBase + 0x1016 ] + delta_ImageBase ;mem[ current_ImageBase + 0x1028 ] = mem[ current_ImageBase + 0x1028 ] + delta_ImageBase ;

36 of 40

Page 37: Inject your code to a Portable Executable file - CodeProject®

mem[ current_ImageBase + 0x1040 ] = mem[ current_ImageBase + 0x1040 ] + delta_ImageBase ;mem[ current_ImageBase + 0x1054 ] = mem[ current_ImageBase + 0x1054 ] + delta_ImageBase ;...

I have employed the following code from Morphine packer to implement the relocation.

..._reloc_fixup: mov eax,[ebp+_p_dwImageBase] mov edx,eax mov ebx,eax add ebx,[ebx+3Ch] // edi -> IMAGE_NT_HEADERS mov ebx,[ebx+034h]// edx ->image_nt_headers->OptionalHeader.ImageBase sub edx,ebx // edx -> reloc_correction // delta_ImageBase je _reloc_fixup_end mov ebx,[ebp+_p_dwRelocationVirtualAddress] test ebx,ebx jz _reloc_fixup_end add ebx,eax_reloc_fixup_block: mov eax,[ebx+004h] //ImageBaseRelocation.SizeOfBlock test eax,eax jz _reloc_fixup_end lea ecx,[eax-008h] shr ecx,001h lea edi,[ebx+008h]_reloc_fixup_do_entry: movzx eax,word ptr [edi]//Entry push edx mov edx,eax shr eax,00Ch //Type = Entry >> 12 mov esi,[ebp+_p_dwImageBase]//ImageBase and dx,00FFFh add esi,[ebx] add esi,edx pop edx_reloc_fixup_HIGH: // IMAGE_REL_BASED_HIGH dec eax jnz _reloc_fixup_LOW mov eax,edx shr eax,010h //HIWORD(Delta) jmp _reloc_fixup_LOW_fixup _reloc_fixup_LOW: // IMAGE_REL_BASED_LOW dec eax jnz _reloc_fixup_HIGHLOW movzx eax,dx //LOWORD(Delta)_reloc_fixup_LOW_fixup: add word ptr [esi],ax// mem[x] = mem[x] + delta_ImageBase jmp _reloc_fixup_next_entry_reloc_fixup_HIGHLOW: // IMAGE_REL_BASED_HIGHLOW dec eax jnz _reloc_fixup_next_entry add [esi],edx // mem[x] = mem[x] + delta_ImageBase_reloc_fixup_next_entry: inc edi inc edi //Entry++ loop _reloc_fixup_do_entry_reloc_fixup_next_base: add ebx,[ebx+004h] jmp _reloc_fixup_block_reloc_fixup_end: ...

7.3 Build a Special Import table

In order to support the OLE-ActiveX Control registration, we should present an appropriate importtable to our target OCX and DLL file.

Therefore, I have established an import table by the following string:

const char *sz_IT_OCX_strings[]=

37 of 40

Page 38: Inject your code to a Portable Executable file - CodeProject®

{ "Kernel32.dll", "LoadLibraryA", "GetProcAddress", "GetModuleHandleA", 0, "User32.dll", "GetKeyboardType", "WindowFromPoint", 0, "AdvApi32.dll", "RegQueryValueExA", "RegSetValueExA", "StartServiceA", 0, "Oleaut32.dll", "SysFreeString", "CreateErrorInfo", "SafeArrayPtrOfIndex", 0, "Gdi32.dll", "UnrealizeObject", 0, "Ole32.dll", "CreateStreamOnHGlobal", "IsEqualGUID", 0, "ComCtl32.dll", "ImageList_SetIconSize", 0, 0,};

Without these API functions, the library can not be loaded, and moreover the DllregisterServer()and DllUregisterServer() will not operate. In CPECryptor::CryptFile, I have distinguishedbetween EXE files and DLL files in the initialization of the new import table object during creation:

if(( image_nt_headers->FileHeader.Characteristics & IMAGE_FILE_DLL ) == IMAGE_FILE_DLL ){ ImportTableMaker = new CITMaker( IMPORT_TABLE_OCX );}else{ ImportTableMaker = new CITMaker( IMPORT_TABLE_EXE );}

8 Preserve the Thread Local Storage

By using Thread Local Storage (TLS), a program is able to execute a multithreaded process, thisperformance mostly is used by Borland linkers: Delphi and C++ Builder. When you pack a PE file, youshould take care to keep clean the TLS, otherwise, your packer will not support Borland Delphi andC++ Builder linked EXE files. To comprehend TLS, I refer you to section 6.7 of the Microsoft PortableExecutable and Common Object File Format Specification document, you can observe the TLS structureby IMAGE_TLS_DIRECTORY32 in winnt.h.

typedef struct _IMAGE_TLS_DIRECTORY32 { DWORD StartAddressOfRawData; DWORD EndAddressOfRawData; DWORD AddressOfIndex; DWORD AddressOfCallBacks; DWORD SizeOfZeroFill; DWORD Characteristics;} IMAGE_TLS_DIRECTORY32, * PIMAGE_TLS_DIRECTORY32;

To keep safe the TLS directory, I have copied it in a special place inside the loader:

..._tls_dwStartAddressOfRawData: dword_type(0xCCCCCCCC)_tls_dwEndAddressOfRawData: dword_type(0xCCCCCCCC)

38 of 40

Page 39: Inject your code to a Portable Executable file - CodeProject®

_tls_dwAddressOfIndex: dword_type(0xCCCCCCCC)_tls_dwAddressOfCallBacks: dword_type(0xCCCCCCCC)_tls_dwSizeOfZeroFill: dword_type(0xCCCCCCCC)_tls_dwCharacteristics: dword_type(0xCCCCCCCC)...

It is necessary to correct the TLS directory entry in the Optional Header:

if(image_nt_headers-> OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS]. VirtualAddress!=0){ memcpy(&pDataTable->image_tls_directory, image_tls_directory, sizeof(IMAGE_TLS_DIRECTORY32)); dwOffset=DWORD(pData1)-DWORD(pNewSection); dwOffset+=sizeof(t_DATA_1)-sizeof(IMAGE_TLS_DIRECTORY32); image_nt_headers-> OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS]. VirtualAddress=dwVirtualAddress + dwOffset;}

9 Inject your code

We are ready to place our code inside the new section. Our code is a "Hello World!" message byMessageBox() from user32.dll.

... push MB_OK | MB_ICONINFORMATION lea eax,[ebp+_p_szCaption] push eax lea eax,[ebp+_p_szText] push eax push NULL call _jmp_MessageBox // MessageBox(NULL, szText, szCaption, MB_OK | MB_ICONINFORMATION) ;

...

PE Maker - Step 5

Download source files - 71.7 Kb

10 Conclusion

By this article, you have perceived how easily we can inject code to a portable executable file. You cancomplete the code by using the source of other packers, create a packer in the same way as Yoda'sProtector, and make your packer undetectable by mixing up with Morphine source code. I hope thatyou have enjoyed this brief discussion of one part of the reverse engineering field. See you again inthe next discussion!

Search

Per page 25 Update

New Message First PrevNext

39 of 40

Page 40: Inject your code to a Portable Executable file - CodeProject®

11:07 30 Sep '11

4:15 20 Sep '11

8:57 11 Nov '10

10:26 26 Oct '10

21:20 26 Oct '10

6:07 27 Oct '10

5:43 28 Oct '10

12:08 28 Oct '10

10:15 23 Oct '10

8:58 1 Nov '10

4:28 30 Jul '10

9:31 23 Oct '10

1:27 26 May '10

5:30 13 May '10

5:58 13 May '10

17:15 19 Nov '10

9:03 31 Jan '10

2:20 2 Feb '10

3:27 19 Jan '10

4:00 16 Dec '09

1:53 11 Sep '09

12:31 4 Aug '09

6:31 29 Jul '09

4:40 15 Apr '09

1:32 6 Mar '09

Last Visit: 14:13 30 Dec '11 Last Update: 11:26 31 Dec '11 12 3 4 5 Next »

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Last Updated 27 Dec 2005 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2011

ANTIVIRUS - false positive kuso666

My vote of 4 yakazem

My vote of 5 Heaven2020

pemaker5 does not compile TelmoM

Re: pemaker5 does not compile panda1987

Re: pemaker5 does not compile TelmoM

Re: pemaker5 does not compile panda1987

Re: pemaker5 does not compile TelmoM

Few questions... tafdasfasf

Re: Few questions... tafdasfasf

How does AddNewSection work? adhesive

Re: How does AddNewSection work? tafdasfasf

anyone explain why? minkun

Injected EXE can't run John Kenedy S.Kom

Re: Injected EXE can't run John Kenedy S.Kom

Re: Injected EXE can't run Member 4626918

Maybe the wrong with Offset in Data viewer wk19830318

Re: Maybe the wrong with Offset in Data viewer wk19830318

well Nguyen Sy Bang

Excellent eg_Anubhava

great! newine

Great article JoeJiao

Problem related to virtual directory Nazneen.Insignia

nice article Li Shu

nice article! whitehat.c

40 of 40