# Practical Reverse Engineering Solutions – Page 35 (Part II)

my go at exercises 7 on page 35

This blog post presents my solution to exercise 7 on page 35 from the book Practical Reverse Engineering by Bruce Dang, Alexandre Gazet and Elias Bachaalany (ISBN: 1118787315). The book is my first contact with reverse engineering, so take my statements with a grain of salt. All code snippets are on GitHub. For an overview of my solutions consult this progress page.

## Problem Statement

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.

Here you can see the complete function. In the following I’m doing a walk-through of the code, based on the PE offset reference. After that

## Walk-Through

### ▶ First Function Parameter

The function does not have a function prologue. Instead it starts with copying the first function parameter to `EAX`:

```mov     eax, [esp+4]
```

From the hint, and the way the offset work out later on, I infer that this parameter is a pointer to a PE file. So `EAX` now points to the start of an executable, which is the IMAGE_DOS_HEADER.

### ▶ Offset to Start of PE Header

Lines 2 and 3 just save `EBX` and `ESI` on the stack, so the registers can be used locally. Line 4 adds 0x3C to `EAX` and stores the result in `ESI`:

```push    ebx
push    esi
mov     esi, [eax+3Ch]
```

`EAX` is a pointer to an `IMAGE_DOS_HEADER`, at offset `3C` we have the member `e_lfanew`, which gives the offset to the real PE header. So ESI = IMAGE_DOS_HEADER.e_lfanew.

### ▶ Position of PE Header

`add     esi, eax`

`ESI` holds the offset to the PE header. By adding the start of the PE file still in `EAX` we get the position of the PE header. The header is a struct called `IMAGE_NT_HEADER`, so ESI = PIMAGE_NT_HEADER.

### ▶ Size of the Optional Header

`movzx   eax, word ptr [esi+14h]`

The struct `IMAGE_NT_HEADER` starts with a 4 byte signature. Next follows – at offset 4 – the struct `IMAGE_FILE_HEADER`. At offset 0x10 in IMAGE_FILE_HEADER we have the word `SizeOfOptionalHeader`. So `EAX = [esi + 14h] = [esi + 4 + 10h] = IMAGE_FILE_HEADER.SizeOfOptionalHeader`.

### ▶ Return if there aren’t any Sections

```xor     ebx, ebx
cmp     [esi+6], bx
...
...
jbe     short loc_0_10BEB
```

Line 7 sets `EBX=0`. In line 8 we get the member of `IMAGE_NT_HEADER` at offset 6. Subtracting the 4 byte for `IMAGE_NT_HEADER.Signature` we land 2 bytes into the `IMAGE_FILE_HEADER`, which is the member `IMAGE_FILE_HEADER.NumberOfSections`. Apart from headers, a PE file consists of sections such as .text or .data. `IMAGE_FILE_HEADER.NumberOfSections` indicates how many sections there are. The above snippet will make a jump to `loc_0_10BEB` if the number of sections is zero (or less). As will be shown later, `loc_0_10BEB` returns `NULL`.

### ▶ Get Start of Section Table

```push    edi
lea     edi, [eax+esi+18h]
```

The `LEA` instruction is used as a fast way to add three values in one instruction. `ESI` is still a pointer to the `IMAGE_NT_HEADER`. At offset 0x18h in this struct we find the `IMAGE_OPTIONAL_HEADER`. The size of this header is in `EAX = IMAGE_FILE_HEADER.SizeOfOptionalHeader`. By adding the size of the optional header to the start of `IMAGE_OPTIONAL_HEADER` we jump over this header and end up at the start of the section table. The section table consists of `IMAGE_FILE_HEADER.NumberOfSections` sections of type `IMAGE_SECTION_HEADER`.

In summary: Lines 1-10 calculate the position of the first `IMAGE_SECTION_HEADER` (elements of the section table), and store the result in `EDI`.

### ▶ Call Another Subroutine

```loc_0_10BCE:
push    [esp+0Ch+8]
push    edi
call    ds:dword_0_169A4
```

The routine doesn’t use the `EBP`. It therefore has to retrieve its function parameters in relation to the `ESP`. The function already pushed 12 bytes on the stack, that’s why the second function parameter is now at `[esp+0Ch+8]`. The value is pushed on the stack, along with `EDI` which is the start of the section table. The call is therefore

```int r = some_function(image_section_header, arg2);
```

Without reversing this function too, it’s hard to tell what it does. It might for instance compare the name of the section header to `arg2`.

### ▶ Check Return Value

```test    eax, eax
pop     ecx
pop     ecx
jz      short loc_0_10BF3
```

The unknown subroutine returns a double word. Line 17 an 20 check if the return value is zero. If this is the case, the subroutine jumps to `loc_0_10BF3`. I’ll talk about this section later. For now, assume that the return value was not zero, which might indicate that the “search” in `dword_0_169A4` was not successful.

The two `pop` instructions in lines 18 and 19 simply clean up the stack – `dword_0_169A4` is obviously using the `CDECL` calling convention.

### ▶ Iterate

```movzx   eax, word ptr [esi+6]
add     edi, 28h
inc     ebx
cmp     ebx, eax
jb      short loc_0_10BCE
```

Line 21, as in line 8, retrieves the number of sections `IMAGE_FILE_HEADER.NumberOfSections`. Line 23 increments `EBX`, which is still 0 from the instruction in line 7, by one. `EBX` is the loop counter. Line 24 and 25 are the test of a loop. Line 22 points `EDI` to the next image section header. So these lines form a loop:

```for (int i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
{
// (...)

// line 22: add edi, 28h (28h = sizeof(IMAGE_SECTION_HEADER))
img_section_header += sizeof(IMAGE_SECTION_HEADER);
}
```

### ▶ Return Value

If the jump in line 20 is never taken, i.e., the loops runs out without `dword_0_169A4` ever reporting sucess, then the snippet continues with:

```loc_0_10BEB:
xor     eax, eax

loc_0_10BED:
pop     edi
pop     esi
pop     ebx
retn    8
```

Line 28 sets the return value to `NULL`. The `pop` instructions in lines 31 to 33 restore the registers. Finally, line 34 restores the stack (STDCALL-convention) and returns.

If, on the other hand, at some point `dword_0_169A4` returns a non zero value, then the routine jumps to:

```loc_0_10BF3:
mov     eax, edi
jmp     short loc_0_10BED
```

This just sets the return value of our subroutine to the current section table entry. The jump to `loc_0_10BED` will then cleanup the stack and return.

## C++ Disassembly

This is the routine in C++:

```#include <Windows.h>

IMAGE_SECTION_HEADER* get_section(char* pe_file, char* criterion)
{
// line 1: mov eax, [esp+4]
IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*)pe_file;

// lines 2-4: mov esi, [eax+3Ch]
unsigned int pe_header_offset = dos_header->e_lfanew;

// line 5: add esi, eax
IMAGE_NT_HEADERS* nt_header = (IMAGE_NT_HEADERS*)(pe_file + pe_header_offset);

// line 6: movzx eax, word ptr [esi+14h]
unsigned short size_of_optional_header = nt_header->FileHeader.SizeOfOptionalHeader;

// line 10: lea, [eax+esi+18h]
IMAGE_OPTIONAL_HEADER* optional_header = &nt_header->OptionalHeader; // esi + 18h
IMAGE_SECTION_HEADER* img_section_header =
(IMAGE_SECTION_HEADER*)(optional_header + size_of_optional_header);

// for loop in lines 7,8, 11 and 21, 23, 24, 25
for (int i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
{
// lines 14-16: call ds:dword_0_169A4
int ret = check_section(img_section_header, criterion);

// lines 17-20:
if (!ret)
{
// lines 17-19, 30-34: mov eax, edi
return img_section_header;
}

// line 22: add edi, 28h (28h = sizeof(IMAGE_SECTION_HEADER))
img_section_header += sizeof(IMAGE_SECTION_HEADER);
}
// lines 27-34: xor eax, eax
return NULL;
}```

## Summary

The function iterates over all image section headers of a PE file. It returns the first such section header for which an unknown function `ds:dword_0_169A4` returns zero, if no such section exists, the function returns `NULL`.

The second parameter of our function is passed to `ds:dword_0_169A4` and might be the criterion applied to the search of the section header. The unknown function might for instance compare the name in the image section headers to the second argument of our function.

## Archived Comments

Note: I removed the Disqus integration in an effort to cut down on bloat. The following comments were retrieved with the export functionality of Disqus. If you have comments, please reach out to me by Twitter or email.

Mar 22, 2016 21:05:38 UTC

Hello Johannes Bader,
first: great blog! Found it yesterday and I already like it alot. Thanks for it.
Currently I'm also reading practical reverse engineering. Keep going :-) .
Greetings from Germany,
Claudio Grau