Inject your code to a Portable Executable file
This article demonstrates five steps to inject your code in a portable executable (EXE, DLL, OCX,...) file without recompiling source code of target file.
Content
http://www.programmersheaven.com/articles/Ashkbiz/InjectPE/pemaker.gif
Contents
0 Preface
You might want to understand the ways a virus program injects its code into a portable executable file and corrupts it, or you are interested in implementing a packer or a protector to encrypt the data of your portable executable (PE) file. This article describes the techiques which are used by EXE injection tools or by some kind of viruses.
You can use the source code in this article to create your custom EXE builder. It could be used to make an EXE protector, or to create a virus. My purpose of writing this article has been to experiment with the first application, so I will not be responsible for any other usage of these methods.
1 Prerequisite
There are no specific mandatory prerequisites to follow the topics in this article. If you are familiar with a debugger and also the portable file format, I suggest you skip the sections 2 and 3, the whole of these sections have been written for people who don?t have any knowledge regarding the EXE file format and debuggers.
2 Portable Executable file format
The Portable Executable file format was defined to provide the best way for the Windows Operating System to execute code and also to store the essential data which is needed to run a program, for example constant data, variable data, import library links, and resource data. It consists of MS-DOS file information, Windows NT file information, Section Headers, and Section images,
Table 1.
2.1 The MS-DOS data
This format originates from the first days of the Windows operating system.
Windows NT 3.51 (I mean,
Win3.1,
Win95,
Win98 were not perfect
OSs). The MS-DOS data causes that your executable file has the performance inside MS-DOS and
the MS-DOS Stub program lets it display:
"This program can not be run in MS-DOS mode" or
"This program can be run only in Windows mode", or some things like these comments when you try to run a Windows EXE file inside
MS-DOS 6.0, where there is no footstep of Windows. Thus, this data is reserved for the code to indicate these comments in the
MS-DOS operating system. The most interesting part of the
MS-DOS data is
"MZ"! Can you believe, it refers to the name of "
Mark Zbikowski", one of the first Microsoft programmers?
For our purposes, only the offset of the PE signature in the
MS-DOS data is important, we can use it to find the position of the
Windows NT data. I recommend you take a look at
Table 1, then observe the structure of IMAGE_DOS_HEADER in the
<winnt.h> header in the
<Microsoft Visual Studio .net path>\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 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 program to 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
http://www.programmersheaven.com/articles/Ashkbiz/InjectPE/peviewer1.gif
http://www.programmersheaven.com/articles/Ashkbiz/InjectPE/peviewer2.gif
http://www.programmersheaven.com/articles/Ashkbiz/InjectPE/peviewer3.gif
This sample is useful for the whole of this article.
Table 1 - Portable Executable file format structure
MS-DOS information | IMAGE_DOS_ HEADER | DOS EXE Signature | 00000000 ASCII "MZ"00000002 DW 009000000004 DW 000300000006 DW 000000000008 DW 00040000000A 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_PartPag |
DOS_PageCnt |
DOS_ReloCnt |
DOS_HdrSize |
DOS_MinMem |
DOS_MaxMem |
DOS_ReloSS |
DOS_ExeSP |
DOS_ChkSum |
DOS_ExeIPP |
DOS_ReloCS |
DOS_TablOff |
DOS_Overlay |
?
Reserved words ? |
| Offset to PE signature |
MS-DOS Stub Program | 00000040 ? ._._!?\L_!This program canno00000060 t be run in DOS mode....$....... |
Windows NT information IMAGE_ NT_HEADERS
| Signature | PE signature (PE) | 000000F0 ASCII "PE" |
IMAGE_ FILE_HEADER | Machine | 000000F4 DW 014C000000F6 DW 0003000000F8 DD 3B7D8410000000FC DD 0000000000000100 DD 0000000000000104 DW 00E000000106 DW 010F |
NumberOfSections |
TimeDateStamp |
PointerToSymbolTable |
NumberOfSymbols |
SizeOfOptionalHeader |
Characteristics |
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 |
MajorLinkerVersion |
MinorLinkerVersion |
SizeOfCode |
SizeOfInitializedData |
SizeOfUninitializedData |
AddressOfEntryPoint |
BaseOfCode |
BaseOfData |
ImageBase |
SectionAlignment |
FileAlignment |
MajorOSVersion |
MinorOSVersion |
MajorImageVersion |
MinorImageVersion |
MajorSubsystemVersion |
MinorSubsystemVersion |
Reserved |
SizeOfImage |
SizeOfHeaders |
CheckSum |
Subsystem |
DLLCharacteristics |
SizeOfStackReserve |
SizeOfStackCommit |
SizeOfHeapReserve |
SizeOfHeapCommit |
LoaderFlags |
NumberOfRvaAndSizes |
IMAGE_ DATA_DIRECTORY[16] | Export Table |
| Import Table |
| Resource Table |
| Exception Table |
| Certificate File |
| Relocation Table |
| Debug Data |
| Architecture Data |
| Global Ptr |
| TLS Table |
| Load Config Table |
| Bound Import Table |
| Import Address Table |
| Delay Import Descriptor |
| COM+ Runtime Header |
| Reserved |
Sections information | 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 |
VirtualSize |
VirtualAddress |
SizeOfRawData |
PointerToRawData |
PointerToRelocations |
PointerToLineNumbers |
NumberOfRelocations |
NumberOfLineNumbers |
Characteristics |
? ? ? 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 ?o?wc?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? |
? ? ? 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 the location of the Windows NT information. Hence, if you assume that the pMem pointer relates the start point of the memory space for a selected portable executable file, you can retrieve the MS-DOS header and also the Windows NT headers by the following lines, which you also can see in the
PE viewer sample (
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 header information. I recommend inspecting the MSDN library regarding the
IMAGE_NT_HEADERS structure definition. It makes it possible to see what the image NT header maintains to execute a code inside the Windows NT OS. Now, you are familier with the Windows NT structure, it consists of the "PE" Signature, the
File Header, and the
Optional Header. Do not forget to take a look at their comments in the
MSDN Library and besides in
Table 1.
I consider, in most circumstances, the following cells of the
IMAGE_NT_HEADERS structure:
FileHeader->NumberOfSections
OptionalHeader->AddressOfEntryPoint
OptionalHeader->ImageBase
OptionalHeader->SectionAlignment
OptionalHeader->FileAlignment
OptionalHeader->SizeOfImage
OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]->VirtualAddress
OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]->Size
You can see clearly, the main purpose of these values, and their role when the internal virtual memory space allocated for an EXE file by the Windows task manager if you pay attention to their 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 to survey the Optional header through the Windows NT information, you will find that there are 16 directories at the end of the Optional Header, where you can find the consecutive directories, including their Relative Virtual Address and Size. I just mention here, the notes from
<winnt.h> to clarify these information:
- 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) is reserved for future use; I have not yet seen any usage of it even in PE64.
For instance, if you want to see the relative virtual address (RVA) and the size of the resource data, 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 understand 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 their applications. We will discuss the section's advantage next.
2.3 The Section Headers and Sections
We currently know how the portable executable files declare the location and the size of a section on a disk storage file and inside the virtual memory space allocated for the program with
IMAGE_NT_HEADERS ->
OptionalHeader -> SizeOfImage by the Windows task manager, as well the characteristics to demonstrate the type of the section. To understand better the Section header as my previous declaration, I suggest having a short read on the
IMAGE_SECTION_HEADER structure definition in the MSDN library. For an EXE packer developer, VirtualSize, VirtualAddress, SizeOfRawData, PointerToRawData, and Characteristics cells have significant rules. While developing an EXE packer, you should be clever enough to play with them. There are somethings to be noted while you modify them; you should take care to align the VirtualSize and VirtualAddress according to
OptionalHeader ->SectionAlignment, as well as SizeOfRawData and PointerToRawData in line with
OptionalHeader ->FileAlignment.
Otherwise, you will corrupt your target EXE file and it will never run. Regarding Characteristics, I pay attention mostly to establish 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 during running process; such as import table; besides, I need it to be able to modify itself by the loader with my 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 by its name. I will just forward you to section 6:
Microsoft Portable Executable and the Common Object 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 understand the section headers and also the sections, you can run the sample
PE viewer. By this PE viewer, you only can realize the application of the section headers in a file image, so to observe the main significance in the Virtual Memory, you should try to load a PE file by a debugger, and the next section represents the main idea of using the virtual address and ?size in the virtual memory by using a debugger. The last note is about
IMAGE_NT_HEADERS ->
FileHeader -> NumberOfSections, that provides a number of sections in a PE file, do not forget to adjust it whenever you remove or add some sections to a PE file, I am talking about section injection!
Next Page