Sunday, 30 July 2017

Practical Reverse Engineering Exercise Solutions: Page 35 / Exercise 7

Exercise 7 on page 35:

Sample H. The function sub_10BB6 has a loop searching for something. 
First recover the function prototype and then infer the types based on the 
context. Hint: You should probably have a copy of the PE specifi cation 

Due to alignment issues, our routine is located at 10BB2 and has the following disassembly:


mov     eax, [esp+4]  
push    ebx
push    esi
mov     esi, [eax+3Ch]
add     esi, eax
movzx   eax, word ptr [esi+14h]
xor     ebx, ebx
cmp     [esi+6], bx
push    edi
lea     edi, [eax+esi+18h]
jbe     short loc_10BEB

push    [esp+0Ch+arg_4]
push    edi
call    ds:dword_169A4
test    eax, eax
pop     ecx
pop     ecx
jz      short loc_10BF3
movzx   eax, word ptr [esi+6]
add     edi, 28h
inc     ebx
cmp     ebx, eax
jb      short loc_10BCE

xor     eax, eax

pop     edi
pop     esi
pop     ebx
retn    8

                mov     eax, edi
                jmp     short loc_10BED

The PE file format and offsets have been described in detail here:

Other useful sites are:

Firstly, we notice that the program contains the statement retn 8, which means it takes two arguments that are passed on the stack. Thus, its abstract prototype looks as follows:

sub_10BB2(param1, param2);

The first parameter seems to be a pointer that fetches a value from the offset 0x3C. Looking at the PE file format specification, we see the offset at 0x3C of the DOS header structure contains a pointer to the PE header structure. Therefore, we assume that param1 points to a DOS header file structure.

We refine the function prototype to:

sub_10BB2(PIMAGE_DOS_HEADER param1, param2);

Below, the disassembly including the provisional decompilation is provided: 

 mov     eax, [esp+4]   // function has first argument at esp+4, which means it is located on the stack
 push    ebx    
 push    esi
 mov     esi, [eax+3Ch] // long offsetpeheader = PIMAGE_DOS_HEADER->lfanew;
 add     esi, eax   // PIMAGE_NT_HEADERS pNtHeaders = (dosheaderptr + offsetpeheader); // calculate the effective address of the PE header beginning
 movzx   eax, word ptr [esi+14h] // word sizeOptHeader = pNtHeaders->FileHeader.SizeOfOptionalHeader;
 xor     ebx, ebx // int countSections = 0;
 cmp     [esi+6], bx   // word numSections = pNtHeaders->FileHeader.NumberOfSections
 push    edi      // save edi for later
 lea     edi, [eax+esi+18h]  // int* sectionTable = pNtHeaders->OptionalHeader + sizeOptHeader; AND! the end address is immediately the beginning of the new
    data structure, i.e. the first section! SectionTable is located at offset(OptionalHeader) + SizeOfOptionalHeader
 jbe     short loc_10BEB   // when we have no sections (countSections == numSections) , go to exit routine

 push    dword ptr [esp+14h] 
 push    edi
 call    ds:dword_169A4 // dword_169A4(sectionTable, param2)
 test    eax, eax // check if returned 0 
 pop     ecx // pop value from stack to ecx 
 pop     ecx // pop value from stack to ecx
 jz      short loc_10BF3 // if eax == 0 , jump 
 movzx   eax, word ptr [esi+6] // reload number of Header
 add     edi, 28h // sectionTable += 0x28; // one section table has a size of 0x28 bytes (40 bytes) 
 inc     ebx // countSections += 1;
 cmp     ebx, eax // if countSections < numSections goto loc_10BCE:
 jb      short loc_10BCE  

 xor     eax, eax // int* retVal = 0;

// clean up stack (stdcall convention)                    
 pop     edi
 pop     esi
 pop     ebx
 retn    8    // function has two parameters, 2 x 4 bytes

                mov     eax, edi // int* retVal = sectionTable;
                jmp     short loc_10BED

Finally, we arrive at the following decompiled function:

sub_10BB2(PIMAGE_DOS_HEADER dosHeaderPtr, param2) {
long offsetpeheader = PIMAGE_DOS_HEADER->lfanew;
PIMAGE_NT_HEADERS ntHeadersPtr = (dosHeaderPtr + offsetpeheader); // calculate the effective address of the PE header beginning

word sizeOptHeader = ntHeadersPtr->FileHeader.SizeOfOptionalHeader;

int countSections = 0;

word numSections = ntHeadersPtr->FileHeader.NumberOfSections;

int* sectionTablePtr = ntHeadersPtr->OptionalHeader + sizeOptHeader;

while (countSections < numSections) {
int retVal = dword_169A4(sectionTablePtr, param2); // call unknown function
if (retVal == 0) {
return sectionTablePtr;

sectionTablePtr += 0x28; // get the next sectionTable
countSections += 1; // set the number of processed sections

return 0; // we have not found the target section


No comments:

Post a Comment