출출 : //www.codeproject.com/KB/system/inject2exe.aspx 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 o 2.1 The MS-DOS data o 2.2 The Windows NT data o 2.3 The Section Headers and Sections 3. Debugger, Disassembler and some Useful Tools o 3.1 Debuggers 3.1.1 SoftICE 3.1.2 OllyDbg 3.1.3 Which parts are important in a debugger interface? o 3.2 Disassembler 3.2.1 Proview disassembler 3.2.2 W32Dasm 3.2.3 IDA Pro
79
Embed
pds11.egloos.compds11.egloos.com/.../Inject_your_code_to_a_Portable_Ex… · Web view->FileAlignment. Otherwise, you will corrupt your target EXE file and it will never run. Regarding
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
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
o 2.1 The MS-DOS data o 2.2 The Windows NT data o 2.3 The Section Headers and Sections
3. Debugger, Disassembler and some Useful Tools o 3.1 Debuggers
3.1.1 SoftICE 3.1.2 OllyDbg 3.1.3 Which parts are important in a debugger
interface? o 3.2 Disassembler
3.2.1 Proview disassembler 3.2.2 W32Dasm 3.2.3 IDA Pro
o 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
o 4.1 Retrieve and Rebuild PE file o 4.2 Create Data for new Section o 4.3 Some notes regarding creating a new PE file o 4.4 Some notes regarding linking this VC Project
5. Store Important Data and Reach Original OEP o 5.1 Restore the first Registers Context o 5.2 Restore the Original Stack o 5.3 Approach OEP by Structured Exception Handling
5.3.1 Implement Exception Handler 5.3.2 Attain OEP by adjusting the Thread Context
6. Build an Import Table and Reconstruct the Original Import Table o 6.1 Construct the Client Import Table o 6.2 Using other API functions in run-time o 6.3 Fix up the Original Import Table
7. Support DLL and OCX o 7.1 Twice OEP approach o 7.2 Implement Relocation Table o 7.3 Build a Special Import table
8. Preserve the Thread Local Storage 9. Inject your code 10. Conclusion
0 PrefaceIt might be, you demand to comprehend the ways a virus program injects its procedure in to the interior of a portable executable file and corrupts it, or you are interested in implementing a packer or a protector for your specific intention to encrypt the data of your portable executable (PE) file. This article is committed to represent a brief intuition to realize the performance which is accomplished by EXE 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 to make an EXE protector in the right way, or with a wrong intention, to pullulate a virus. However, my purpose of writing this article has been to gaze on the first application, so I will not be responsible for the immoral usage of these methods.
1 PrerequisiteThere are no specific mandatory prerequisites to follow the topics in this article. If you are familiar with debugger and also the portable file format, I suggest you to drop the sections 2 and 3, the whole of these sections have been made for people who don�t have any knowledge regarding the EXE file format and also debuggers.
2 Portable Executable file formatThe 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
These data let you remember the first days of developing the Windows Operating System, the days. We were 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 calls a function 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?
To me, only the offset of the PE signature in the MS-DOS data is important, so I can use it to find the position of the Windows NT data. I just recommend you to 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!
Collapsetypedef 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
This sample is useful for the whole of this article.
Table 1 - Portable Executable file format structure
DOS_PartPagDOS_PageCntDOS_ReloCntDOS_HdrSizeDOS_MinMemDOS_MaxMemDOS_ReloSSDOS_ExeSPDOS_ChkSumDOS_ExeIPPDOS_ReloCSDOS_TablOffDOS_Overlay�Reserved words�Offset to PE signature
MS-DOS Stub ProgramCollapse
00000040
�
.�.�!�\L�!This program canno00000060 t be run in DOS mode....$.......
Windows NT information
IMAGE_NT_HEADERS
Signature PE signature (PE) Collapse000000F0 ASCII "PE"
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 perceive in the PE viewer sample (pelib.cpp, PEStructure::OpenFileName()):
It seems to be very simple, the retrieval of the headers information. I recommend inspecting the MSDN library regarding the IMAGE_NT_HEADERS structure definition. It makes comprehensible to grasp what the image NT header maintains to execute a code inside the Windows NT OS. Now, you are conversant with the Windows NT structure, it consists of the "PE" Signature, the File Header, and the Optional Header. 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 the IMAGE_NT_HEADERS structure:
You can observe clearly, the main purpose of these values, and their role when the internal virtual memory space allocated for an EXE file by the Windows OS is fully allocated, 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:
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 their applications. 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 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 gape 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 comprehend 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-><CODE>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!
3 Debugger, Disassembler and some Useful ToolsIn this part, you will become familiar with the necessary and essential equipments to develop your PE tools.
3.1 Debuggers
The first essential prerequisite, to become a PE tools developer, is to have enough experience with bug tracer tools. Furthermore, you should know most of the assembly instructions. To me, the Intel documents are the best references. You can obtain them from the Intel site for IA-32, and on top of that 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 at high school, is the best debugger in the world. It implements process tracing by using kernel mode method 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 the Windows debugging API to trace a PE file and also attaches itself to an active process. These API functions have been provided by Microsoft teams, inside the Windows Kernel32 library, to trace a specific process, by using Microsoft tools, or perhaps, to make your own debugger! Some of those API functions 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 NuMega Technologies in Nashua, NH, in order to develop some equipments to trace and test the reliability of Microsoft Windows software programs. Now, it is a part of Compuware Corporation and its product has participated to accelerate the reliability in Windows software, and additionally in Windows driver developments. Currently, everyone knows the Compuware DriverStudio which is used to establish an environment for implementing the elaboration of a kernel driver or a system file by aiding the Windows Driver Development Kit (DDK). It bypasses the involvement of DDK to implement a portable executable file of kernel level for a Windows system software developer. For us, only one instrument of DriverStudio is important, SoftICE, this debugger can be used to trace every portable executable file, a PE file for user mode level or a PE file for kernel mode level.
It was about 4 years ago, that I first saw this debugger by chance. For me, it was the best choice, I was not 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 a debugger that can be used to trace all kinds of portable executable files except a Common Language Infrastructure (CLI) file format in user mode level, by using the Windows debugging API. Oleh Yuschuk, the author, is one of worthiest software developers I have seen in my life. He is a Ukrainian who now lives in Germany. I should mention here that his debugger is the best choice for hacker and cracker parties around the world! It is a freeware! You can try it from OllyDbg Homepage.
Figure 2 - OllyDbg CPU Window
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 parts you should pay attention more. Regarding using debuggers, I refer you to their instructions in help documents. However, I want to explain shortly the important parts of a debugger; of course, I am talking about low-level debuggers, or in other words, machine-language debuggers of the x86 CPU families.
All of low-level debuggers consist of the following subdivisions:
5. 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
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 another disassembler 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 still under development and bug fixing. You can find its disassmbler source engine and employ it to create your own disassembler.
3.2.2 W32Dasm
W32DASM can disassemble both 16 and 32 bit executable file formats. In addition to its disassembling ability, 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 x86 instructions, but that of various kinds of CPU types like AVR, PIC, and etc. It can illustrate the assembly source of a portable executable file by using colored graphics and tables, and is very useful for any newbie in this area. Furthermore, it has the capability to trace an executable file inside the user 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 select some 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 modify them.
3.3.2 PEiD
PE iDentifier is valuable to identify the type of compilers, packers, and cryptors of PE files. As of now, it can 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.
3.3.5 CFF Explorer
Eventually, CFF Explorer by Ntoskrnl is what you wish to have as a PE Utility tool in your dream; it supports 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 and discover 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 new section and rebuild the portable executable file. Before starting, I like you get familiar with the headers of a PE file, by using OllyDbg. You should first open a PE file, that pops up a menu, View->Executable file, 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 map window.
Collapse 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 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
00000038000000390000003A0000003B0000003C
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 the Image Base value is used to convert it to the Virtual Address.
Unfortunately, this source can only be applied for the sample test file. We should complete it by saving the value of the original OEP in the new section, and use it to reach the real OEP. I have accomplished it 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.
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. We use OpenFile() and SaveFile() to retrieve and rebuild a PE file. Furthermore, AddNewSection() is employed 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 new section. Nevertheless, the data of the new section is
created by DynLoader() in loader.cpp, DynLoader Step 1. We use the CPECryptor class to enter this data in to the new section, and also some other stuff.
Set Linker->General->Enable Incremental Linking to No (/INCREMENTAL:NO).
You can comprehend the difference between incremental link and no-incremental link by looking at the following picture:
To acquire the virtual address of DynLoader(), we obtain the virtual address of JMP pemaker.DynLoader in the incremental link, but by no-incremental link, the real virtual address is gained by the following code:
Collapse
DWORD dwVA= (DWORD) DynLoader;
This setting is more critical in the incremental link when you try to find the beginning and ending of the Loader, DynLoader(), by CPECryptor::ReturnToBytePtr():
5 Store Important Data and Reach Original OEPRight now, we save the Original OEP and also the Image Base in order to reach to the virtual address of OEP. I have reserved a free space at the end of DynLoader() to store them, DynLoader Step 2.
The new function, CPECryptor::CopyData1(), will implement the copy of the Image Base value and the 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 DynLoader Step 2 source code. We can modify the source of DynLoader() to repossess the first Context.
We can also recover the original stack by setting the value of the beginning stack + 0x34 to the Original OEP, but it is not very important. Nevertheless, in the following code, I have accomplished the loader code by a simple trick to reach OEP in addition to redecorating the stack. You can observe the implementation by tracing using OllyDbg or SoftICE.
An exception is generated when a program falls into a fault code execution and an error happens, so in such a special condition, the program immediately jumps to a function called the exception handler from exception handler list of the Thread Information Block.
The next example of a try - except statement in C++ clarifies the operation of structured exception handling. Besides the assembly code of this code, it elucidates the structured exception handler installation, the raise of an exception, and the exception handler function.
Collapse#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;}Collapse
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 exception happens, in this example the INT 3 exception. You can employ other kinds of exception too. In OllyDbg, Debugging options->Exceptions, you can see a short list of different types of exceptions.
5.3.1 Implement Exception Handler
We desire to construct a structured exception handler in order to reach OEP. Now, I think you have distinguished the SEH installation, the exception raise, and the exception expression filter, by foregoing the assembly code. To establish our exception handler approach, we need to comprise the following codes:
The exception value, __except(..., Value), determines how the exception is handled, it can have three values, 1, 0, -1. To understand them, refer to the try - except statement description in the MSDN library. We set it to EXCEPTION_CONTINUE_SEARCH (0), not to run the exception handler function, therefore by this value, the exception is not recognized, is simply ignored, and the thread continues 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 main thread. 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 have pushed the pointer to _except_handler1_OEP_Jump in the stack and changed the value of ExceptionList, FS:[00h], to the beginning of the stack, ESP.
Table 3 - FS segment register and Thread Information Block
DWORD PTR FS:[00h] ExceptionList
DWORD PTR FS:[04h] StackBase
DWORD PTR FS:[08h] StackLimit
DWORD PTR FS:[0Ch] SubSystemTib
DWORD PTR FS:[10h]
FiberData / Version
DWORD PTR FS:[14h]
ArbitraryUserPointer
DWORD 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 the Context of the thread and ignore every simple exception handling, and let the thread continue the execution, but in the original OEP!
When an exception happens, the context of the processor during the time of the exception is saved in the stack. By EXCEPTION_POINTERS, we have access to the pointer of ContextRecord. The ContextRecord has the CONTEXT data structure, Table 4, this is the thread context during the exception time. When we ignore the exception by EXCEPTION_CONTINUE_SEARCH (0), the instruction pointer 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, it will come clearly into OEP.
6 Build an Import Table and Reconstruct the Original Import TableTo use the Windows dynamic link library (DLL) in Windows application programming, there are two ways:
Using Windows libraries by additional dependencies:
__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 base dependencies of your project. Without LoadLibrary() and GetProcAddress() of Kernel32.dll, we can not load a DLL in run-time. The dependencies information is stored in the import table section. By Dependency Walker, it is not so difficult to observe the DLL module and the functions which are imported into a PE file.
We attempt to establish our custom import table to conduct our project. Furthermore, we have to fix up 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 Common Object File Format Specification document. This section contains the principal information to comprehend 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:
The VirtualAddress refers to structures by IMAGE_IMPORT_DESCRIPTOR. This structure contains the pointer to the imported DLL name and the relative virtual address of the first thunk.
Collapsetypedef 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
When a program is running, the Windows task manager sets the thunks by the virtual address of the function. The virtual address is found by the name of the function. At first, the thunks hold the relative virtual address
of the function name, Table 5; during execution, they are fixed up by the virtual address of the functions, Table 6.
We want to make a simple import table to import LoadLibrary(), and GetProcAddress() from Kernel32.dll. We need these two essential API functions to cover other API functions in run-time. The following assembly code shows how easily we can reach our solution:
I have prepared a class library to make every import table by using a client string table. The CITMaker class library in itmaker.h, it will build an import table by sz_IT_EXE_strings and also the relative virtual address of the import table.
We subsequently employ this class library to establish an import table to support DLLs and OCXs, so this is a general library to present all possible import tables easily. The next step is clarified in the following code.
CollapseCITMaker *ImportTableMaker = new CITMaker( IMPORT_TABLE_EXE );...pimage_section_header=AddNewSection( ".xxx", dwNewSectionSize );
// build import table by the current virtual address
The import table is copied at the beginning of the new section, and the relevant data directory is adjusted 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 using LoadLibrary() and GetProcAddress():
Collapselea edi, @"Kernel32.dll"//-------------------push edimov eax,offset _p_LoadLibrarycall [ebp+eax] //LoadLibrary(lpLibFileName);//-------------------mov esi,eax // esi -> hModulelea edi, @"GetModuleHandleA"//-------------------push edipush 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 you look inside a PE file, you will discover that an API call is done by an indirection jump through the virtual address of the API function:
JMP DWORD PTR [XXXXXXXX]
Collapse...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 data tables: first for API virtual addresses, and the second for the JMP [XXXXXXXX].
In the succeeding code, we has concluded our ambition to install a custom internal import table! (We can not call it import table.)
Collapse
... 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 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 we have 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.
7 Support DLL and OCXNow, we intend to include the dynamic link library (DLL) and OLE-ActiveX Control in our PE builder project. Supporting them is very easy if we pay attention to the two time arrival into the Offset of Entry 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() and GetProcAddress() through calling DllRegisterServer(), the first of the OEP arrival is done.
When the main program frees the library usage by FreeLibrary(), the second OEP arrival happens.
Collapse
FreeLibrary( hinstDLL );
Collapse
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.
Collapse_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 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 in ImageBase, when the library has been loaded in
different image bases by the main program. We should write some code to find the real image base and store it to use forward.
Collapse 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 image base and the formal image base, we should correct all memory calls inside the image program!! Don't be 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 Portable Executable and Common Object File Format Specification document. The relocation table contains many packages to relocate the information related to the virtual address inside the virtual memory image. Each package comprise of a 8 bytes header to exhibit the base virtual address and the number of data, demonstrated by the IMAGE_BASE_RELOCATION data structure.
Table 7 illustrates the main idea of the relocation table. Furthermore, you can upload a DLL or an OCX file in OllyDbg to observe the relocation table, the ".reloc" section through Memory map window. By the way, we find the position of the relocation table by using the following code in our project:
By OllyDbg, we have the same as the following for the ".reloc" section, by using the Long Hex viewer mode. In this example, the base virtual address is 0x1000 and the size of the block is 0x184.
Each package performs the relocation by using consecutive 4 bytes form its internal information. The first byte refers to the type of relocation and the next three bytes are the offset which must be used with the base virtual address and the image base to correct the image information.
type offset
03 00
00
00
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 the offset. IMAGE_REL_BASED_LOW (2): relocate by the low 16 bytes of the
base virtual address and the offset. 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 image base by the ".reloc" section packages.
Without these API functions, the library can not be loaded, and moreover the DllregisterServer() and DllUregisterServer() will not operate. In CPECryptor::CryptFile, I have distinguished between EXE files and DLL files in the initialization of the new import table object during creation:
Collapseif(( 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 StorageBy using Thread Local Storage (TLS), a program is able to execute a multithreaded process, this performance mostly is used by Borland linkers: Delphi and C++ Builder. When you pack a PE file, you should take care to keep clean the TLS, otherwise, your packer will not support Borland Delphi and C++ Builder linked EXE files. To comprehend TLS, I refer you to section 6.7 of the Microsoft Portable Executable and Common Object File Format Specification document, you can observe the TLS structure by IMAGE_TLS_DIRECTORY32 in winnt.h.
10 ConclusionBy this article, you have perceived how easily we can inject code to a portable executable file. You can complete the code by using the source of other packers, create a packer in the same way as Yoda's Protector, and make your packer undetectable by mixing up with Morphine source code. I hope that you have enjoyed this brief discussion of one part of the reverse engineering field. See you again in the next discussion!
LicenseThis article, along with any associated source code and files, is licensed under The GNU General Public License (GPL)
About the AuthorAshkbiz Danehkar
Member
Occupation: OtherLocation: United Kingdom
Other popular Hardware & System articles:
/wEPDwUKMT/wEWCAKSu96
Start Your Windows Programs From An NT Service
Make your MFC, VB and other Windows programs behave like NT services.
Serial library for C++
A high-performance, complete and compact serial library for C++
Driver Development Part 1: Introduction to Drivers
This article will go into the basics of creating a simple driver.
API hooking revealed
The article demonstrates how to build a user mode Win32 API spying system
Eliminating Explorer's delay when deleting an in-use file
How to track down and patch an annoyance in Windows Explorer's code.