|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Downloads
Contents
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 dataThese 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 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;
PE Viewer
This sample is useful for the whole of this article. Table 1 - Portable Executable file format structure
2.2 The Windows NT dataAs mentioned in the preceding section, IMAGE_DOS_HEADER image_dos_header;
IMAGE_NT_HEADERS image_nt_headers;
PCHAR pMem;
…
memcpy(&image_dos_header, pMem,
sizeof(IMAGE_DOS_HEADER));
memcpy(&image_nt_headers,
pMem+image_dos_header.e_lfanew,
sizeof(IMAGE_NT_HEADERS));
It seems to be very simple, the retrieval of the headers information. I recommend inspecting the MSDN library regarding the One the whole, I consider merely, on the most circumstances, the following cells of the 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 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 #define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory
#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table
#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP
#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers
#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor
The last one (15) was reserved for use in future; I have not yet seen any purpose to use it even in PE64. For instance, if you desire to perceive 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 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 SectionsWe 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 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
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 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 DebuggersThe 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!
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: 3.1.1 SoftICEIt 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. Figure 1 - SoftICE Window
3.1.2 OllyDbgIt 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 Window3.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:
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 DisassemblerWe 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 disassemblerProview 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 W32DasmW32DASM 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 ProAll 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 ToolsA 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 LordPELordPE by y0da is still the first choice to retrieve PE file information with the possibility to modify them.
3.3.2 PEiDPE 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 HackerResource Hacker can be employed to modify resource directory information; icon, menu, version info, string table, and etc.
3.3.4 WinHexWinHex, it is clear what you can do with this tool.
3.3.5 CFF ExplorerEventually, 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 OEPWe 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. Figure 3
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,
DWORD OEP_RVA = image_nt_headers->OptionalHeader.AddressOfEntryPoint ;
// OEP_RVA = 0x00012475
DWORD OEP_VA = image_nt_headers->OptionalHeader.ImageBase + OEP_RVA ;
// OEP_VA = 0x01000000 + 0x00012475 = 0x01012475
PE Maker - Step 1CALC.EXE - test file
DynLoader Step 1__stdcall void DynLoader()
{
_asm
{
//----------------------------------
DWORD_TYPE(DYN_LOADER_START_MAGIC)
//----------------------------------
MOV EAX,01012475h // << Original OEP
JMP EAX
//----------------------------------
DWORD_TYPE(DYN_LOADER_END_MAGIC)
//----------------------------------
}
}
Unfortunately, this source can only be applied for the sample test file. We should complete it by 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 fileI have made a simple class library to recover PE information and to use it in a new PE file. CPELibrary Class Step 1//----------------------------------------------------------------
class CPELibrary
{
private:
//-----------------------------------------
PCHAR pMem;
DWORD dwFileSize;
//-----------------------------------------
protected:
//-----------------------------------------
PIMAGE_DOS_HEADER image_dos_header;
PCHAR pDosStub;
DWORD dwDosStubSize, dwDosStubOffset;
PIMAGE_NT_HEADERS image_nt_headers;
PIMAGE_SECTION_HEADER image_section_header[MAX_SECTION_NUM];
PCHAR image_section[MAX_SECTION_NUM];
//-----------------------------------------
protected:
//-----------------------------------------
DWORD PEAlign(DWORD dwTarNum,DWORD dwAlignTo);
void AlignmentSections();
//-----------------------------------------
DWORD Offset2RVA(DWORD dwRO);
DWORD RVA2Offset(DWORD dwRVA);
//-----------------------------------------
PIMAGE_SECTION_HEADER ImageRVA2Section(DWORD dwRVA);
PIMAGE_SECTION_HEADER ImageOffset2Section(DWORD dwRO);
//-----------------------------------------
DWORD ImageOffset2SectionNum(DWORD dwRVA);
PIMAGE_SECTION_HEADER AddNewSection(char* szName,DWORD dwSize);
//-----------------------------------------
public:
//-----------------------------------------
CPELibrary();
~CPELibrary();
//-----------------------------------------
void OpenFile(char* FileName);
void SaveFile(char* FileName);
//-----------------------------------------
};
By Table 1, the usage of 4.2 Create Data for new SectionIn pecrypt.cpp, I have represented another class, CPECryptor Class Step 1//----------------------------------------------------------------
class CPECryptor: public CPELibrary
{
private:
//----------------------------------------
PCHAR pNewSection;
//----------------------------------------
DWORD GetFunctionVA(void* FuncName);
void* ReturnToBytePtr(void* FuncName, DWORD findstr);
//----------------------------------------
protected:
//----------------------------------------
public:
//----------------------------------------
void CryptFile(int(__cdecl *callback) (unsigned int, unsigned int));
//----------------------------------------
};
//----------------------------------------------------------------
4.3 Some notes regarding creating a new PE file
4.4 Some notes regarding linking this VC Project
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 PE Maker - Step 2DynLoader Step 2__stdcall void DynLoader()
{
_asm
{
//----------------------------------
DWORD_TYPE(DYN_LOADER_START_MAGIC)
//----------------------------------
Main_0:
PUSHAD
// get base ebp
CALL Main_1
Main_1:
POP EBP
SUB EBP,OFFSET Main_1
MOV EAX,DWORD PTR [EBP+_RO_dwImageBase]
ADD EAX,DWORD PTR [EBP+_RO_dwOrgEntryPoint]
PUSH EAX
RETN // >> JMP to Original OEP
//----------------------------------
DWORD_TYPE(DYN_LOADER_START_DATA1)
//----------------------------------
_RO_dwImageBase: DWORD_TYPE(0xCCCCCCCC)
_RO_dwOrgEntryPoint: DWORD_TYPE(0xCCCCCCCC)
//----------------------------------
DWORD_TYPE(DYN_LOADER_END_MAGIC)
//----------------------------------
}
}
The new function, 5.1 Restore the first Registers ContextIt 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 __stdcall void DynLoader()
{
_asm
{
//----------------------------------
DWORD_TYPE(DYN_LOADER_START_MAGIC)
//----------------------------------
Main_0:
PUSHAD// Save the registers context in stack
CALL Main_1
Main_1:
POP EBP// Get Base EBP
SUB EBP,OFFSET Main_1
MOV EAX,DWORD PTR [EBP+_RO_dwImageBase]
ADD EAX,DWORD PTR [EBP+_RO_dwOrgEntryPoint]
MOV DWORD PTR [ESP+1Ch],EAX // pStack.Eax <- EAX
POPAD // Restore the first registers context from stack
PUSH EAX
XOR EAX, EAX
RETN // >> JMP to Original OEP
//----------------------------------
DWORD_TYPE(DYN_LOADER_START_DATA1)
//----------------------------------
_RO_dwImageBase: DWORD_TYPE(0xCCCCCCCC)
_RO_dwOrgEntryPoint: DWORD_TYPE(0xCCCCCCCC)
//----------------------------------
DWORD_TYPE(DYN_LOADER_END_MAGIC)
//----------------------------------
}
}
5.2 Restore the Original StackWe can also recover the original stack by setting the value of the beginning stack + __stdcall void DynLoader()
{
_asm
{
//----------------------------------
DWORD_TYPE(DYN_LOADER_START_MAGIC)
//----------------------------------
Main_0:
PUSHAD // Save the registers context in stack
CALL Main_1
Main_1:
POP EBP
SUB EBP,OFFSET Main_1
MOV EAX,DWORD PTR [EBP+_RO_dwImageBase]
ADD EAX,DWORD PTR [EBP+_RO_dwOrgEntryPoint]
MOV DWORD PTR [ESP+54h],EAX // pStack.Eip <- EAX
POPAD // Restore the first registers context from stack
CALL _OEP_Jump
DWORD_TYPE(0xCCCCCCCC)
_OEP_Jump:
PUSH EBP
MOV EBP,ESP
MOV EAX,DWORD PTR [ESP+3Ch] // EAX <- pStack.Eip
MOV DWORD PTR [ESP+4h],EAX // _OEP_Jump RETURN pointer <- EAX
XOR EAX,EAX
LEAVE
RETN
//----------------------------------
DWORD_TYPE(DYN_LOADER_START_DATA1)
//----------------------------------
_RO_dwImageBase: DWORD_TYPE(0xCCCCCCCC)
_RO_dwOrgEntryPoint: DWORD_TYPE(0xCCCCCCCC)
//----------------------------------
DWORD_TYPE(DYN_LOADER_END_MAGIC)
//----------------------------------
}
}
5.3 Approach OEP by Structured Exception HandlingAn 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 #include "stdafx.h"
#include "windows.h"
void RAISE_AN_EXCEPTION()
{
_asm
{
INT 3
INT 3
INT 3
INT 3
}
}
int _tmain(int argc, _TCHAR* argv[])
{
__try
{
__try{
printf("1: Raise an Exception\n");
RAISE_AN_EXCEPTION();
}
__finally
{
printf("2: In Finally\n");
}
}
__except( printf("3: In Filter\n"), EXCEPTION_EXECUTE_HANDLER )
{
printf("4: In Exception Handler\n");
}
return 0;
}; main()
00401000: PUSH EBP
00401001: MOV EBP,ESP
00401003: PUSH -1
00401005: PUSH 00407160
; __try {
; the structured exception handler (SEH) installation
0040100A: PUSH _except_handler3
0040100F: MOV EAX,DWORD PTR FS:[0]
00401015: PUSH EAX
00401016: MOV DWORD PTR FS:[0],ESP
0040101D: SUB ESP,8
00401020: PUSH EBX
00401021: PUSH ESI
00401022: PUSH EDI
00401023: MOV DWORD PTR SS:[EBP-18],ESP
; __try {
00401026: XOR ESI,ESI
00401028: MOV DWORD PTR SS:[EBP-4],ESI
0040102B: MOV DWORD PTR SS:[EBP-4],1
00401032: PUSH OFFSET "1: Raise an Exception"
00401037: CALL printf
0040103C: ADD ESP,4
; the raise a exception, INT 3 exception
; RAISE_AN_EXCEPTION()
0040103F: INT3
00401040: INT3
00401041: INT3
00401042: INT3
; } __finally {
00401043: MOV DWORD PTR SS:[EBP-4],ESI
00401046: CALL 0040104D
0040104B: JMP 00401080
0040104D: PUSH OFFSET "2: In Finally"
00401052: CALL printf
00401057: ADD ESP,4
0040105A: RETN
; }
; }
; __except(
0040105B: JMP 00401080
0040105D: PUSH OFFSET "3: In Filter"
00401062: CALL printf
00401067: ADD ESP,4
0040106A: MOV EAX,1 ; EXCEPTION_EXECUTE_HANDLER = 1
0040106F: RETN
; , EXCEPTION_EXECUTE_HANDLER )
; {
; the exception handler funtion
00401070: MOV ESP,DWORD PTR SS:[EBP-18]
00401073: PUSH OFFSET "4: In Exception Handler"
00401078: CALL printf
0040107D: ADD ESP,4
; }
00401080: MOV DWORD PTR SS:[EBP-4],-1
0040108C: XOR EAX,EAX
; restore previous SEH
0040108E: MOV ECX,DWORD PTR SS:[EBP-10]
00401091: MOV DWORD PTR FS:[0],ECX
00401098: POP EDI
00401099: POP ESI
0040109A: POP EBX
0040109B: MOV ESP,EBP
0040109D: POP EBP
0040109E: RETN
Make a Win32 console project, and link and run the preceding C++ code, to perceive the result:
This program runs the exception expression,
5.3.1 Implement Exception HandlerWe 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:
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 // SEH installation
{
__asm
{
INT 3 // An Exception Raise
}
}
__except( ..., EXCEPTION_CONTINUE_SEARCH ){}
// Exception handler expression filter
In assembly code... ; ----------------------------------------------------
; the structured exception handler (SEH) installation
; __try {
LEA EAX,[EBP+_except_handler1_OEP_Jump]
PUSH EAX
PUSH DWORD PTR FS:[0]
MOV DWORD PTR FS:[0],ESP
; ----------------------------------------------------
; the raise a INT 3 exception
INT 3
INT 3
INT 3
INT 3
; }
; __except( ...
; ----------------------------------------------------
; exception handler expression filter
_except_handler1_OEP_Jump:
PUSH EBP
MOV EBP,ESP
...
MOV EAX, EXCEPTION_CONTINUE_SEARCH ; EXCEPTION_CONTINUE_SEARCH = 0
LEAVE
RETN
; , EXCEPTION_CONTINUE_SEARCH ) { }
The exception value, How the SEH installation is implementedAs 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, Thread Information Block (TIB)typedef struct _NT_TIB32 {
DWORD ExceptionList;
DWORD StackBase;
DWORD StackLimit;
DWORD SubSystemTib;
union {
DWORD FiberData;
DWORD Version;
};
DWORD ArbitraryUserPointer;
DWORD Self;
} NT_TIB32, *PNT_TIB32;
Table 3 - FS segment register and Thread Information Block
5.3.2 Attain OEP by adjusting the Thread ContextIn 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 MOV EAX, ContextRecord
MOV EDI, dwOEP ; EAX <- dwOEP
MOV DWORD PTR DS:[EAX+0B8h], EDI ; pContext.Eip <- EAX
Win32 Thread Context structure#define MAXIMUM_SUPPORTED_EXTENSION 512
typedef struct _CONTEXT {
//-----------------------------------------
DWORD ContextFlags;
//-----------------------------------------
DWORD Dr0;
DWORD Dr1;
DWORD Dr2;
DWORD Dr3;
DWORD Dr6;
DWORD Dr7;
//-----------------------------------------
FLOATING_SAVE_AREA FloatSave;
//-----------------------------------------
DWORD SegGs;
DWORD SegFs;
DWORD SegEs;
DWORD SegDs;
//-----------------------------------------
DWORD Edi;
DWORD Esi;
DWORD Ebx;
DWORD Edx;
DWORD Ecx;
DWORD Eax;
//-----------------------------------------
DWORD Ebp;
DWORD Eip;
DWORD SegCs;
DWORD EFlags;
DWORD Esp;
DWORD SegSs;
//-----------------------------------------
BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
//----------------------------------------
} CONTEXT,
*LPCONTEXT;
Table 4 - CONTEXT
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||