Stuck? Need help? Ask questions on our forums.

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?w­c?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:

  1. define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
  2. define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory
  3. define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory
  4. define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory
  5. define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory
  6. define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table
  7. define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory
  8. define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data
  9. define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP
  10. define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory
  11. define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory
  12. define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers
  13. define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table
  14. define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors
  15. 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






 

Other Views

corner
Popular resources and forums for programmers on Programmersheaven.com
Assembly, Basic, C, C#, C++, Delphi, Java, JavaScript, Pascal, Perl, PHP, Python, Ruby, Visual Basic
© Copyright 2009 Programmersheaven.com - All rights reserved.
Reproduction in whole or in part, in any form or medium without express written permission is prohibited.
Violators of this policy may be subject to legal action. Please read our Terms Of Use and Privacy Statement for more information.
Publisher: Lars Hagelin. Read the latest words from the publisher here.
Be the first to sign up for Lars Hagelin’s In-depth Outsourcing Newsletter here.
bootstrapLabs Logo A BootstrapLabs project.