# Practical Reverse Engineering Exercise Solutions: Page 35 / Exercise 7

Contents

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 specification nearby.

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

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 `````` ``````sub_10BB2: 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 loc_10BCE: 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 loc_10BEB: xor eax, eax loc_10BED: pop edi pop esi pop ebx retn 8 loc_10BF3: mov eax, edi jmp short loc_10BED ``````

The PE file format and offsets have been described in detail here: http://www.sunshine2k.de/reversing/tuts/tut_pe.htm

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:

 ``````1 `````` ``````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:

 ``````1 `````` ``````sub_10BB2(PIMAGE_DOS_HEADER param1, param2); ``````

Below, the disassembly including the provisional decompilation is provided:

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 `````` `````` 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 loc_10BCE: 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 loc_10BEB: xor eax, eax // int* retVal = 0; loc_10BED: // clean up stack (stdcall convention) pop edi pop esi pop ebx retn 8 // function has two parameters, 2 x 4 bytes loc_10BF3: mov eax, edi // int* retVal = sectionTable; jmp short loc_10BED ``````

Finally, we arrive at the following decompiled function:

 `````` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 `````` ``````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 } ``````