CD3=58.2cd25 cd4 cd3=32 CD8...

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 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:
Registers viewer.
o d t s z a p c
Disassembler or Code viewer.
MOV EBP,ESP
010119EA PUSH 01011D60
010119EF MOV EAX,DWORD PTR FS:[0]
MOV DWORD PTR FS:[0],ESP
010119FD ADD ESP,-68
01011A00 PUSH EBX
01011A01 PUSH ESI
01011A02 PUSH EDI
01011A03 MOV DWORD PTR SS:[EBP-18],ESP
01011A06 MOV DWORD PTR SS:[EBP-4],0
Memory watcher.
0 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................0 01 00 00 00 20 00 00 00-0A 00 00 00 0A 00 00 00 ................0 20 00 00 00 00 00 00 00-53 63 69 43 61 6C 63 00 ........SciCalc.0 00 00 00 00 00 00 00 00-62 61 63 6B 67 72 6F 75 ........backgrou0 6E 64 00 00 00 00 00 00-2E 00 00 00 00 00 00 00 nd..............
Stack viewer.
FFC4 4F 6D 81 7C 38 07 91 7C-FF FF FF FF 00 90 FD 7F Om |8 ‘| . FFD4 ED A6 54 80 C8 FF 07 00-E8 B4 F5 81 FF FF FF FF T . FFE4 F3 99 83 7C 58 6D 81 7C-00 00 00 00 00 00 00 00 Xm |........FFF4 00 00 00 00 E0 19 01 01-00 00 00 00 00 00 00 00 .... ....
Command line, command buttons, or shortcut keys to follow the debugging process.
Set Break Point
You can compare
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 som you should discover them by yourself.
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.
is an admirable
it is still under development and bug fixing. You can find its disassmbler source engine and employ it to create your own disassembler.
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.
All reverse-engineering experts know that
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.
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.
is still the first choice to retrieve PE file information with the possibility to modify them.
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.
can be employed to modify resource d icon, menu, version info, string table, and etc.
, it is clear what you can do with this tool.
Eventually, by is what you wish to have as a PE Utilit it supports PE32/64, PE rebuild included
file, in other words, the , a resource modifier, and much more facilities which can not be found in others, just try and discover every unimaginable option by hand.
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 . 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 . Now, come to Main Menu View-&Memory, try to distinguish the sections inside the Memory map window.
ASCII &FONT color=green&"MZ"&/FONT&
DD &FONT color=red&&/FONT&
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
Offset to PE signature
I want to explain how we can plainly change the Offset of Entry Point (OEP) in our , CALC.EXE of Windows XP. First, by using a PE Tool, and also using our PE Viewer, we find OEP, 0x, and Image Base, 0x. This value of OEP is the Relative Virtual Address, so the Image Base value is used to convert it to the Virtual Address.
Virtual_Address = Image_Base + Relative_Virtual_AddressDWORD OEP_RVA = image_nt_headers-&OptionalHeader.AddressOfEntryP
DWORD OEP_VA = image_nt_headers-&OptionalHeader.ImageBase + OEP_RVA ;
DynLoader(), in loader.cpp, is reserved for the data of the new section, in other words, the Loader.
__stdcall void DynLoader()
DWORD_TYPE(DYN_LOADER_START_MAGIC)
DWORD_TYPE(DYN_LOADER_END_MAGIC)
Unfortunately, this source can only be applied for the . 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).
I have made a simple class library to recover PE information and to use it in a new PE file.
class CPELibrary
protected:
PIMAGE_DOS_HEADER
image_dos_
dwDosStubSize, dwDosStubO
PIMAGE_NT_HEADERS
PIMAGE_SECTION_HEADER
image_section_header[MAX_SECTION_NUM];
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);
CPELibrary();
~CPELibrary();
void OpenFile(char* FileName);
void SaveFile(char* FileName);
By , 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.
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, . We use the CPECryptor class to enter this data in to the new section, and also some other stuff.
class CPECryptor: public CPELibrary
PCHAR pNewS
DWORD GetFunctionVA(void* FuncName);
void* ReturnToBytePtr(void* FuncName, DWORD findstr);
protected:
void CryptFile(int(__cdecl *callback) (unsigned int, unsigned int));
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.VirtualS
Set the Bound Import Directory header to zero, as this directory is not very important to execute a 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;
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:DWORD dwVA= (DWORD) DynL
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():void* CPECryptor::ReturnToBytePtr(void* FuncName, DWORD findstr)
mov eax, FuncName
mov ebx, [eax]
cmp ebx, findstr
mov tmpd, eax
Right 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, .
__stdcall void DynLoader()
DWORD_TYPE(DYN_LOADER_START_MAGIC)
CALL Main_1
SUB EBP,OFFSET Main_1
MOV EAX,DWORD PTR [EBP+_RO_dwImageBase]
ADD EAX,DWORD PTR [EBP+_RO_dwOrgEntryPoint]
DWORD_TYPE(DYN_LOADER_START_DATA1)
_RO_dwImageBase:
DWORD_TYPE(0xCCCCCCCC)
_RO_dwOrgEntryPoint:
DWORD_TYPE(0xCCCCCCCC)&/FONT&
DWORD_TYPE(DYN_LOADER_END_MAGIC)
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.
It is important to recover the Original Context of the thread. We have not yet done it in the
source code. We can modify the source of DynLoader() to repossess the first Context.__stdcall void DynLoader()
DWORD_TYPE(DYN_LOADER_START_MAGIC)
&FONT color=red&PUSHAD
CALL Main_1
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
&FONT color=red&POPAD
DWORD_TYPE(DYN_LOADER_START_DATA1)
_RO_dwImageBase:
DWORD_TYPE(0xCCCCCCCC)
_RO_dwOrgEntryPoint:
DWORD_TYPE(0xCCCCCCCC)
DWORD_TYPE(DYN_LOADER_END_MAGIC)
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
or SoftICE.__stdcall void DynLoader()
DWORD_TYPE(DYN_LOADER_START_MAGIC)
CALL Main_1
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
CALL _OEP_Jump
DWORD_TYPE(0xCCCCCCCC)
_OEP_Jump:
MOV EBP,ESP
MOV EAX,DWORD PTR [ESP+3Ch]
MOV DWORD PTR [ESP+4h],EAX
XOR EAX,EAX
DWORD_TYPE(DYN_LOADER_START_DATA1)
_RO_dwImageBase:
DWORD_TYPE(0xCCCCCCCC)
_RO_dwOrgEntryPoint:
DWORD_TYPE(0xCCCCCCCC)
DWORD_TYPE(DYN_LOADER_END_MAGIC)
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 .
The next example of a
in C++ clarifies the operation of . Besides the assembly code of this code, it elucidates the structured exception handler installation, the raise of an exception, and the exception handler function.#include "stdafx.h"
#include "windows.h"
void RAISE_AN_EXCEPTION()
int _tmain(int argc, _TCHAR* argv[])
printf("1: Raise an Exception\n");
RAISE_AN_EXCEPTION();
printf("2: In Finally\n");
__except( printf("3: In Filter\n"), EXCEPTION_EXECUTE_HANDLER )
printf("4: In Exception Handler\n");
}&FONT color=black&; main()&/FONT&&FONT color=gray&
: PUSH EBP
: MOV EBP,ESP
&FONT color=black&; __try {&/FONT&
&FONT color=green&; the structured exception handler (SEH) installation &/FONT&&FONT color=blue&
0040100A: PUSH _except_handler3
0040100F: MOV EAX,DWORD PTR FS:[0]
: PUSH EAX
: MOV DWORD PTR FS:[0],ESP&/FONT&
0040101D: SUB ESP,8
: PUSH EBX
: PUSH ESI
: PUSH EDI
: MOV DWORD PTR SS:[EBP-18],ESP
&FONT color=black&;
__try {&/FONT&
: XOR ESI,ESI
: MOV DWORD PTR SS:[EBP-4],ESI
0040102B: MOV DWORD PTR SS:[EBP-4],1
: PUSH OFFSET &FONT color=brown&"1: Raise an Exception"&/FONT&
: CALL printf
0040103C: ADD ESP,4
&FONT color=green&; the raise a exception, INT 3 exception&/FONT&
; RAISE_AN_EXCEPTION()&FONT color=blue&
0040103F: INT3
: INT3&/FONT&
&FONT color=black&;
} __finally {&/FONT&
: MOV DWORD PTR SS:[EBP-4],ESI
: CALL 0040104D
0040104B: JMP
0040104D: PUSH OFFSET &FONT color=brown&"2: In Finally"&/FONT&
: CALL printf
: ADD ESP,4
0040105A: RETN
&FONT color=black&;
&FONT color=black&; }&/FONT&
&FONT color=black&; __except( &/FONT&
0040105B: JMP
0040105D: PUSH OFFSET &FONT color=brown&"3: In Filter"&/FONT&
: CALL printf
: ADD ESP,4
0040106A: MOV EAX,1 ; EXCEPTION_EXECUTE_HANDLER = 1
0040106F: RETN
&FONT color=black&;
, EXCEPTION_EXECUTE_HANDLER )&/FONT&
&FONT color=black&; {&/FONT&
&FONT color=green&; the exception handler funtion&/FONT&&FONT color=blue&
: MOV ESP,DWORD PTR SS:[EBP-18]
: PUSH OFFSET &FONT color=brown&"4: In Exception Handler"&/FONT&
: CALL printf
0040107D: ADD ESP,4&/FONT&
&FONT color=black&; }&/FONT&
: MOV DWORD PTR SS:[EBP-4],-1
0040108C: XOR EAX,EAX
&FONT color=green&; restore previous SEH&/FONT&&FONT color=blue&
0040108E: MOV ECX,DWORD PTR SS:[EBP-10]
: MOV DWORD PTR FS:[0],ECX&/FONT&
0040109A: POP EBX
0040109B: MOV ESP,EBP
0040109D: POP EBP
0040109E: RETN&/FONT&
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 , Debugging options-&Exceptions, you can see a short list of different types of exceptions.
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:
SEH installation: &FONT color=gray&
LEA EAX,[EBP+_except_handler1_OEP_Jump]
PUSH DWORD PTR FS:[0]
MOV DWORD PTR FS:[0],ESP&/FONT&
An Exception Raise: &FONT color=gray&
INT 3&/FONT&
Exception handler expression filter: &FONT color=gray&_except_handler1_OEP_Jump:
MOV EBP,ESP
MOV EAX, EXCEPTION_CONTINUE_SEARCH
RETN&/FONT&
So we yearn for making the ensuing C++ code in assembly language to inaugurate our engine to approach the Offset of Entry Point by SEH.__try {
__except( ..., EXCEPTION_CONTINUE_SEARCH ){}
In assembly code...&FONT color=gray&
&FONT color=green&
&FONT color=black&
LEA EAX,[EBP+_except_handler1_OEP_Jump]
PUSH DWORD PTR FS:[0]
MOV DWORD PTR FS:[0],ESP
&FONT color=green&
&FONT color=black&
&FONT color=green&
_except_handler1_OEP_Jump:
MOV EBP,ESP
MOV EAX, EXCEPTION_CONTINUE_SEARCH
&FONT color=black&
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
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 . Therefore, FS:[00h] refers to ExceptionList of the main thread, . 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.
typedef struct _NT_TIB32 {
DWORD ExceptionL
DWORD StackB
DWORD StackL
DWORD SubSystemT
DWORD FiberD
DWORD ArbitraryUserP
} NT_TIB32, *PNT_TIB32;
DWORD PTR FS:[00h]
ExceptionList
DWORD PTR FS:[04h]
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]
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 , we have access to the pointer of ContextRecord. The ContextRecord has the
data structure,, 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
to the Original Offset of Entry Point, it will come clearly into OEP. MOV EAX, ContextRecord
MOV EDI, dwOEP
MOV DWORD PTR DS:[EAX+0B8h], EDI
#define MAXIMUM_SUPPORTED_EXTENSION
typedef struct _CONTEXT {
DWORD ContextF
FLOATING_SAVE_AREA FloatS
ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
} CONTEXT,
*LPCONTEXT;
Context Flags
ContextFlags
Context Debug Registers
0x0000000C
Context Floating Point
0x0000001C
StatusWord
StatusWord
ErrorOffset
0x0000002C
ErrorSelector
DataOffset
DataSelector
RegisterArea [0x50]
Cr0NpxState
Context Segments
0x0000008C
Context Integer
0x0000009C
0x000000AC
Context Control
0x000000BC
Context Extended Registers
0x000000CC...0x000002CB
ExtendedRegisters[0x200]
By the following code, we have accomplished the main purpose of coming to OEP by the structured exception handler:__stdcall void DynLoader()
DWORD_TYPE(DYN_LOADER_START_MAGIC)
CALL Main_1
SUB EBP,OFFSET Main_1
MOV EAX,DWORD PTR [EBP+_RO_dwImageBase]
ADD EAX,DWORD PTR [EBP+_RO_dwOrgEntryPoint]
MOV DWORD PTR [ESP+10h],EAX
LEA EAX,[EBP+_except_handler1_OEP_Jump]
MOV DWORD PTR [ESP+1Ch],EAX
PUSH DWORD PTR FS:[0]
MOV DWORD PTR FS:[0],ESP
DWORD_TYPE(0xCCCCCCCC)
_except_handler1_OEP_Jump:
MOV EBP,ESP
MOV EAX,DWORD PTR SS:[EBP+010h]
MOV EDI,DWORD PTR DS:[EAX+0C4h]
PUSH DWORD PTR DS:[EDI]
POP DWORD PTR FS:[0]
ADD DWORD PTR DS:[EAX+0C4h],8
MOV EDI,DWORD PTR DS:[EAX+0A4h]
MOV DWORD PTR DS:[EAX+0B8h],EDI
MOV EAX, EXCEPTION_CONTINUE_SEARCH
DWORD_TYPE(DYN_LOADER_START_DATA1)
_RO_dwImageBase:
DWORD_TYPE(0xCCCCCCCC)
_RO_dwOrgEntryPoint:
DWORD_TYPE(0xCCCCCCCC)
DWORD_TYPE(DYN_LOADER_END_MAGIC)
To use the Windows
in Windows application programming, there are two ways:
Using Windows libraries by additional dependencies:
Using Windows dynamic link libraries in run-time: typedef HGLOBAL (*importFunction_GlobalAlloc)(UINT, SIZE_T);
importFunction_GlobalAlloc __GlobalA
HINSTANCE hinstLib = LoadLibrary("Kernel32.dll");
if (hinstLib == NULL)
__GlobalAlloc =
(importFunction_GlobalAlloc)GetProcAddress(hinstLib,
"GlobalAlloc");
if (addNumbers == NULL)
FreeLibrary(hinstLib);
When you make a Windows application project, the linker includes at least kernel32.dll in the base dependencies of your project. Without
of Kernel32.dll, we can not load a DLL in run-time. The dependencies information is stored in the import table section. By , 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.
I strongly advise you to read the section 6.4 of the
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:DWORD dwVirtualAddress = image_nt_headers-&
OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualA
DWORD dwSize = image_nt_headers-&
OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].S
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.typedef struct _IMAGE_IMPORT_DESCRIPTOR {
OriginalFirstT
ForwarderC
&FONT color=red&Name&/FONT&;
&FONT color=red&FirstThunk&/FONT&;
} IMAGE_IMPORT_DESCRIPTOR, *PIMAGE_IMPORT_DESCRIPTOR;
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, ; during execution, they are fixed up by the virtual address of the functions, .
IMAGE_IMPORT_
DESCRIPTOR[0]
OriginalFirstThunk
TimeDateStamp
ForwarderChain
"kernel32.dll",0
FirstThunk_RVA
proc_1_name_RVA
0,0,"LoadLibraryA",0
proc_2_name_RVA
0,0,"GetProcAddress",0
proc_3_name_RVA
0,0,"GetModuleHandleA",0
IMAGE_IMPORT_
DESCRIPTOR[1]
IMAGE_IMPORT_
DESCRIPTOR[n]
IMAGE_IMPORT_DESCRIPTOR[0]
OriginalFirstThunk
TimeDateStamp
ForwarderChain
"kernel32.dll",0
FirstThunk_RVA
IMAGE_IMPORT_DESCRIPTOR[1]
IMAGE_IMPORT_DESCRIPTOR[n]
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:&FONT color=gray&:
&FONT color=blue&&/FONT& ; OriginalFirstThunk
: &FONT color=blue&&/FONT& ; TimeDateStamp
: &FONT color=blue&&/FONT& ; ForwarderChain
0101F00C: &FONT color=blue&&/FONT& ; N
ImageBase +
-& "Kernel32.dll",0
: &FONT color=blue&&/FONT& ; FirstT ImageBase +
: &FONT color=blue&&/FONT&
: &FONT color=blue&&/FONT&
0101F01C: &FONT color=blue&&/FONT&
: &FONT color=blue&&/FONT&
: &FONT color=blue&&/FONT&
: &FONT color=blue&&/FONT& ; ImageBase +
-& 0,0,"LoadLibraryA",0
0101F02C: &FONT color=blue&&/FONT& ; ImageBase +
-& 0,0,"GetProcAddress",0
: &FONT color=blue&&/FONT&
: &FONT color=brown&'K' 'e' 'r' 'n' 'e' 'l' '3' '2' '.' 'd' 'l' 'l' &/FONT&&FONT color=blue&00&/FONT&
: &FONT color=blue&00 00&/FONT& &FONT color=brown&'L' 'o' 'a' 'd' 'L' 'i' 'b' 'r' 'a' 'r' 'y' 'A'&/FONT&
&FONT color=blue&00&/FONT&
: &FONT color=blue&00 00&/FONT& &FONT color=brown&'G' 'e' 't' 'P' 'r' 'o' 'c' 'A' 'd' 'd' 'r' 'e' 's' 's'
&/FONT& &FONT color=blue&00&/FONT&&/FONT&
After running...&FONT color=gray&:
&FONT color=blue&&/FONT& ; OriginalFirstThunk
: &FONT color=blue&&/FONT& ; TimeDateStamp
: &FONT color=blue&&/FONT& ; ForwarderChain
0101F00C: &FONT color=blue&&/FONT& ; N
ImageBase +
-& "Kernel32.dll",0
: &FONT color=blue&&/FONT& ; FirstT ImageBase +
: &FONT color=blue&&/FONT&
: &FONT color=blue&&/FONT&
0101F01C: &FONT color=blue&&/FONT&
: &FONT color=blue&&/FONT&
: &FONT color=blue&&/FONT&
: &FONT color=red&7C801D77&/FONT& ; -& Kernel32.LoadLibrary()
0101F02C: &FONT color=red&7C80AC28&/FONT& ; -& Kernel32.GetProcAddress()
: &FONT color=blue&&/FONT&
: &FONT color=brown&'K' 'e' 'r' 'n' 'e' 'l' '3' '2' '.' 'd' 'l' 'l' &/FONT&
&FONT color=blue&00&/FONT&
: &FONT color=blue&00 00&/FONT& &FONT color=brown&'L' 'o' 'a' 'd' 'L' 'i' 'b' 'r' 'a' 'r' 'y' 'A'
&/FONT& &FONT color=blue&00&/FONT&
: &FONT color=blue&00 00&/FONT& &FONT color=brown&'G' 'e' 't' 'P' 'r' 'o' 'c' 'A' 'd' 'd' 'r' 'e' 's' 's'
&/FONT& &FONT color=blue&00&/FONT&&/FONT&
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.static const char *sz_IT_EXE_strings[]=
"Kernel32.dll",
"LoadLibraryA",
"GetProcAddress",
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.CITMaker *&FONT color=red&ImportTableMaker&/FONT& = new CITMaker( IMPORT_TABLE_EXE );
pimage_section_header=AddNewSection( ".xxx", dwNewSectionSize );
&FONT color=red&ImportTableMaker&/FONT&-&&FONT color=green&Build&/FONT&
( &FONT color=blue&pimage_section_header-&VirtualAddress&/FONT& );
memcpy( pNewSection, &FONT color=red&ImportTableMaker&/FONT&-&&FONT color=green&pMem&/FONT&,
&FONT color=red&ImportTableMaker&/FONT&-&&FONT color=green&dwSize&/FONT& );
memcpy( image_section[image_nt_headers-&FileHeader.NumberOfSections-1],
pNewSection,
dwNewSectionSize );
image_nt_headers-&OptionalHeader.
DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
= &FONT color=blue&pimage_section_header-&VirtualAddress&/FONT&;
image_nt_headers-&OptionalHeader.
DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
= &FONT color=red&ImportTableMaker&/FONT&-&&FONT color=green&dwSize&/FONT&;
delete &FONT color=red&ImportTableMaker&/FONT&;
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
At this time, we can load other DLLs and find the process address of other functions by using
and :&FONT color=gray&lea edi, &FONT color=red&@&/FONT&&FONT color=brown&"Kernel32.dll"&/FONT&
//-------------------
&FONT color=blue&push edi
mov eax,offset _p_LoadLibrary
call [ebp+eax] //LoadLibrary(lpLibFileName);&/FONT&
//-------------------
mov esi,eax
// esi -& hModule
lea edi, &FONT color=red&@&/FONT&&FONT color=brown&"GetModuleHandleA"&/FONT&
//-------------------
&FONT color=blue&push edi
mov eax,offset _p_GetProcAddress
call [ebp+eax] //GetModuleHandle=GetProcAddress(hModule, lpProcName);&/FONT&
//--------------------&/FONT&
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]&FONT color=gray&...
: &FONT color=red&7C801D77&/FONT& Virtual Address of kernel32.LoadLibrary()
: JMP DWORD PTR [&FONT color=red&&/FONT&]
: CALL &FONT color=red&&/FONT& ;
JMP to kernel32.LoadLibrary
...&/FONT&
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].#define __jmp_api
byte_type(0xFF) byte_type(0x25)
_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:
dword_type(0xCCCCCCCC)
_jmp_VirtualProtect:
dword_type(0xCCCCCCCC)
_jmp_GetModuleFileName:
dword_type(0xCCCCCCCC)
_jmp_CreateFile:
dword_type(0xCCCCCCCC)
_jmp_GlobalAlloc:
dword_type(0xCCCCCCCC)
In the succeeding code, we has concluded our ambition to install a custom internal import table! (We can not call it import table.)&FONT color=gray&
lea edi,[ebp+_p_szKernel32]
lea ebx,[ebp+_p_GetModuleHandle]
lea ecx,[ebp+_jmp_GetModuleHandle]
add ecx,02h
_api_get_lib_address_loop:
&FONT color=blue&push edi
mov eax,offset _p_LoadLibrary
call [ebp+eax]
//LoadLibrary(lpLibFileName);&/FONT&
mov esi,eax
// esi -& hModule
call __strlen
add esp,04h
add edi,eax
_api_get_proc_address_loop:
&FONT color=blue&push edi
mov eax,offset _p_GetProcAddress
call [ebp+eax]//GetModuleHandle=GetProcAddress(hModule, lpProcName);&/FONT&
&FONT color=green&mov [ebx],eax
mov [ecx],ebx // JMP DWORD PTR [XXXXXXXX] &/FONT&
add ebx,04h
add ecx,06h
call __strlen
add esp,04h
add edi,eax
mov al,byte ptr [edi]
test al,al
jnz _api_get_proc_address_loop
mov al,byte ptr [edi]
test al,al
jnz _api_get_lib_address_loop
...&/FONT&
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
to . Once more,
aid us in our effort to reach our intention.&FONT color=gray&
mov ebx,[ebp+&FONT color=red&_p_dwImportVirtualAddress&/FONT&]
test ebx,ebx
jz _it_fixup_end
mov esi,[ebp+&FONT color=red&_p_dwImageBase&/FONT&]
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+&FONT color=red&_p_dwThunk&/FONT&],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+&FONT color=red&_p_dwHintName&/FONT&],ecx // dwHintName
add eax,esi
// image_import_descriptor.Name + dwImageBase = ModuleName
&FONT color=blue&push eax
// lpLibFileName
mov eax,offset _p_LoadLibrary
call [ebp+eax]
// LoadLibrary(lpLibFileName);&/FONT&
test eax,eax
jz _it_fixup_end
mov edi,eax
_it_fixup_get_proc_address_loop:
mov ecx,[ebp+&FONT color=red&_p_dwHintName&/FONT&] // dwHintName
mov edx,[ecx]
// image_thunk_data.Ordinal
test edx,edx
jz _it_fixup_next_module
test edx,h
// .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
// OrdinalName.Name
_it_fixup_get_addr:
&FONT color=blue&push edx //lpProcName
// hModule
mov eax,offset _p_GetProcAddress
call [ebp+eax] // GetProcAddress(hModule, lpProcName);&/FONT&
&FONT color=green&mov ecx,[ebp+&FONT color=red&_p_dwThunk&/FONT&] // dwThunk
mov [ecx],eax
// correction the thunk&/FONT&
// dwThunk =& next dwThunk
add dword ptr [ebp+&FONT color=red&_p_dwThunk&/FONT&], &FONT color=blue&004h&/FONT&
// dwHintName =& next dwHintName
add dword ptr [ebp+&FONT color=red&_p_dwHintName&/FONT&],&FONT color=blue&004h&/FONT&
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:
...&/FONT&
Now, we intend to include the
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.
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 , or an OCX is registered by using
through calling , the first of the OEP arrival is done.hinstDLL = LoadLibrary( "test1.dll" );hinstOCX = LoadLibrary( "test1.ocx" );
_DllRegisterServer = GetProcAddress( hinstOCX, "DllRegisterServer" );
_DllRegisterServer();
Destructor:
When the main program frees the library usage by , the second OEP arrival happens.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.&FONT color=gray&&FONT color=black&_main_0:
// save the registers context in stack
call _main_1
sub ebp,offset _main_1 // get base ebp
//---------------- support dll, ocx
-----------------
_support_dll_0:&/FONT&
jmp _support_dll_1 // &FONT color=red& // && trick&/FONT& // in the second time OEP
&FONT color=black&jmp _support_dll_2&/FONT&
_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,&FONT color=green&IMAGE_FILE_DLL&/FONT&
jz _support_dll_2
mov ax, &FONT color=red&9090h // && trick&/FONT&
mov word ptr [ebp+_support_dll_0],ax&/FONT&
&FONT color=black&_support_dll_2:
//----------------------------------------------------
into OEP by SEH ...&/FONT&
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.
&FONT color=gray&mov eax,&FONT color=green&[esp+24h]&/FONT& // the real imagebase
mov ebx,&FONT color=green&[esp+30h]&/FONT& // 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:&/FONT&
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.
To understand the relocation table better, you can take a look at the section 6.6 of
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.typedef struct _IMAGE_BASE_RELOCATION {
} IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION;
VirtualAddress
SizeOfBlock
VirtualAddress
SizeOfBlock
VirtualAddress
SizeOfBlock
illustrates the main idea of the relocation table. Furthermore, you can upload a DLL or an OCX file in
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:DWORD dwVirtualAddress = image_nt_headers-&
OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].
DWORD dwSize = image_nt_headers-&
OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].S
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.008E1000 : 403028
008E1010 : 8C9C
008E1020 : 30E030DC
008E1030 : 3120310D
008E1040 : 31D031CC
008E1050 : 320C10
008E1060 : 3260325C
It relocates the data in the subsequent virtual addresses:0x1000 + 0x0000 = 0x1000
0x1000 + 0x0016 = 0x1016
0x1000 + 0x0028 = 0x1028
0x1000 + 0x0040 = 0x1040
0x1000 + 0x0054 = 0x1054
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.
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.
delta_ImageBase = current_ImageBase - image_nt_headers-&OptionalHeader.ImageBasemem[ current_ImageBase + 0x1000 ] =
mem[ current_ImageBase + 0x1000 ] + delta_ImageB
mem[ current_ImageBase + 0x1016 ] =
mem[ current_ImageBase + 0x1016 ] + delta_ImageB
mem[ current_ImageBase + 0x1028 ] =
mem[ current_ImageBase + 0x1028 ] + delta_ImageB
mem[ current_ImageBase + 0x1040 ] =
mem[ current_ImageBase + 0x1040 ] + delta_ImageB
mem[ current_ImageBase + 0x1054 ] =
mem[ current_ImageBase + 0x1054 ] + delta_ImageB
I have employed the following code from Morphine packer to implement the relocation.
&FONT color=gray&...
_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
&FONT color=red&sub edx,ebx // edx -& reloc_correction // delta_ImageBase&/FONT&
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
mov edx,eax
shr eax,00Ch
//Type = Entry && 12
mov esi,[ebp+_p_dwImageBase]//ImageBase
and dx,00FFFh
add esi,[ebx]
add esi,edx
_reloc_fixup_HIGH:
// IMAGE_REL_BASED_HIGH
jnz _reloc_fixup_LOW
mov eax,edx
shr eax,010h
//HIWORD(Delta)
jmp _reloc_fixup_LOW_fixup
_reloc_fixup_LOW:
// IMAGE_REL_BASED_LOW
jnz _reloc_fixup_HIGHLOW
movzx eax,dx
//LOWORD(Delta)
_reloc_fixup_LOW_fixup:
&FONT color=red&add word ptr [esi],ax// mem[x] = mem[x] + delta_ImageBase&/FONT&
jmp _reloc_fixup_next_entry
_reloc_fixup_HIGHLOW:
// IMAGE_REL_BASED_HIGHLOW
jnz _reloc_fixup_next_entry
&FONT color=red&add [esi],edx
// mem[x] = mem[x] + delta_ImageBase&/FONT&
_reloc_fixup_next_entry:
loop _reloc_fixup_do_entry
_reloc_fixup_next_base:
add ebx,[ebx+004h]
jmp _reloc_fixup_block
_reloc_fixup_end:
...&/FONT&
In order to support the
registration, we should present an appropriate import table to our target OCX and DLL file.
Therefore, I have established an import table by the following string:const char *sz_IT_OCX_strings[]=
"Kernel32.dll",
"LoadLibraryA",
"GetProcAddress",
"GetModuleHandleA",
"User32.dll",
"GetKeyboardType",
"WindowFromPoint",
"AdvApi32.dll",
"RegQueryValueExA",
"RegSetValueExA",
"StartServiceA",
"Oleaut32.dll",
"SysFreeString",
"CreateErrorInfo",
"SafeArrayPtrOfIndex",
"Gdi32.dll",
"UnrealizeObject",
"Ole32.dll",
"CreateStreamOnHGlobal",
"IsEqualGUID",
"ComCtl32.dll",
"ImageList_SetIconSize",
Without these API functions, the library can not be loaded, and moreover the
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:if(( image_nt_headers-&FileHeader.Characteristics
& IMAGE_FILE_DLL ) == IMAGE_FILE_DLL )
ImportTableMaker = new CITMaker( IMPORT_TABLE_OCX );
ImportTableMaker = new CITMaker( IMPORT_TABLE_EXE );
By using Thread Local Storage (TLS), a program is able to execute a multithreaded process, this performance mostly is used by
and . 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
document, you can observe the TLS structure by IMAGE_TLS_DIRECTORY32 in winnt.h.typedef struct _IMAGE_TLS_DIRECTORY32 {
StartAddressOfRawD
EndAddressOfRawD
AddressOfI
AddressOfCallB
SizeOfZeroF
} IMAGE_TLS_DIRECTORY32, * PIMAGE_TLS_DIRECTORY32;
To keep safe the TLS directory, I have copied it in a special place inside the loader:&FONT color=gray&...
_tls_dwStartAddressOfRawData:
dword_type(0xCCCCCCCC)
_tls_dwEndAddressOfRawData:
dword_type(0xCCCCCCCC)
_tls_dwAddressOfIndex:
dword_type(0xCCCCCCCC)
_tls_dwAddressOfCallBacks:
dword_type(0xCCCCCCCC)
_tls_dwSizeOfZeroFill:
dword_type(0xCCCCCCCC)
_tls_dwCharacteristics:
dword_type(0xCCCCCCCC)
...&/FONT&
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 + dwO
We are ready to place our code inside the new section. Our code is a "Hello World!" message by
from user32.dll.&FONT color=gray&...
push MB_OK | MB_ICONINFORMATION
lea eax,[ebp+_p_szCaption]
lea eax,[ebp+_p_szText]
call _jmp_MessageBox
...&/FONT&
By 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 , and make your packer undetectable by mixing up with
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!
This article, along with any associated source code and files, is licensed under
No Biography provided
Comments and Discussions
General &&
Suggestion &&
Question &&
Admin && 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
Article Copyright 2005 by A. DanehkarEverything else
Copyright & ,

我要回帖

更多关于 cd25 cd4 cd3 的文章

 

随机推荐