I study an analysis paper about a trojan and there are the following assembly lines:

.text:004010D0 Get_PE_section_address proc near        
.text:004010D0 arg_0           = dword ptr  4
.text:004010D0                 mov     ecx, [esp+arg_0]
.text:004010D4                 mov     eax, [ecx+3Ch]
.text:004010D7                 movzx   edx, word ptr [eax+ecx+14h]
.text:004010DC                 add     eax, ecx
.text:004010DE                 movzx   ecx, word ptr [eax+6]
.text:004010E2                 push    ebx
.text:004010E3                 add     edx, eax
.text:004010E5                 push    esi
.text:004010E6                 lea     esi, [ecx+ecx*4]
.text:004010E9                 lea     eax, [edx+esi*8-38h]
.text:004010ED                 xor     edx, edx
.text:004010EF                 test    ecx, ecx
.text:004010F1                 jbe     short loc_401102

.text:004010F3 loc_4010F3:                            
.text:004010F3                 mov     bl, [eax+5]
.text:004010F6                 test    bl, bl
.text:004010F8                 jz      short loc_401104
.text:004010FA                 inc     edx
.text:004010FB                 sub     eax, 28h
.text:004010FE                 cmp     edx, ecx
.text:00401100                 jb      short loc_4010F3

.text:00401102 loc_401102:                             
.text:00401102                 xor     eax, eax

.text:00401104 loc_401104:                             
.text:00401104                 pop     esi
.text:00401105                 pop     ebx
.text:00401106                 retn

.text:00401106 Get_PE_section_address endp

As you can see, the owner of the paper renamed the function as Get_PE_section_address. I spent a lot of time to understand why he/she calls in that way because I could not understand why this piece of code retrieves the the PE section address.

So, my question would be if there is anyone who can tell me which lines tells us that this is something about PE section address.

PS: I tried to work with the offsets but with a low success rate. The only thing I can say is that ebx = pointer to the malicious executable and arg_0 = 0 After searching a while PE file format papers, i have found out that the second line

   mov     eax, [ecx+3Ch]

gives me the file address of the exe header.

best regards,

2 Answers 2


Calling this function Get_PE_section_address is rather misleading since it doesn't generically get "the address of a PE section", but rather is used to get the virtual address of the Section Table entry for the first section with a 0x00 as the 5th byte of its section name, iterating through sections backwards starting from the second-to-last section.

So for example, if the section names were:

  • sec10
  • sec20
  • sec30
  • sec40

where 0 is a null-byte, then this function would return the virtual address for the Section Table entry for sec30, since it's the first section that meets the null-byte requirement when iterating backwards through the sections, starting with the second-to-last section.

I've commented the disassembly for you:

.text:004010D0 Get_PE_section_address proc near        
.text:004010D0 arg_0           = dword ptr  4
.text:004010D0                 mov     ecx, [esp+arg_0]             ; ecx = arg_0 = beginning of PE file mapped into memory
.text:004010D4                 mov     eax, [ecx+3Ch]               ; eax = ((IMAGE_DOS_HEADER*)ecx)->e_lfanew
.text:004010D7                 movzx   edx, word ptr [eax+ecx+14h]  ; edx = ((IMAGE_NT_HEADERS*)(eax+ecx))->FileHeader.SizeOfOptionalHeader
.text:004010DC                 add     eax, ecx                     ; eax = (IMAGE_NT_HEADERS*)(eax+ecx)
.text:004010DE                 movzx   ecx, word ptr [eax+6]        ; ecx = ((IMAGE_NT_HEADERS*)eax)->FileHeader.NumberOfSections
.text:004010E2                 push    ebx                          ; save ebx on stack
.text:004010E3                 add     edx, eax                     ; edx = (pointer to PE header) + SizeOfOptionalHeader
.text:004010E5                 push    esi                          ; save esi on stack
.text:004010E6                 lea     esi, [ecx+ecx*4]             ; esi = NumberOfSections * 5
.text:004010E9                 lea     eax, [edx+esi*8-38h]         ; eax = (pointer to PE header) + SizeOfOptionalHeader + NumberOfSections * 0x28 - 0x38 =
                                                                    ;       &(((IMAGE_SECTION_HEADERS*)(edx + 0x18))[NumberOfSections - 2])
.text:004010ED                 xor     edx, edx                     ; edx = section counter = 0
.text:004010EF                 test    ecx, ecx                     ; if NumberOfSections <= 0
.text:004010F1                 jbe     short loc_401102             ; then goto loc_401102

.text:004010F3 loc_4010F3:                            
.text:004010F3                 mov     bl, [eax+5]                  ; bl = ((IMAGE_SECTION_HEADERS*)eax)->Name[5]
.text:004010F6                 test    bl, bl                       ; if ((IMAGE_SECTION_HEADERS*)eax)->Name[5] == 0
.text:004010F8                 jz      short loc_401104             ; then goto loc_401104
.text:004010FA                 inc     edx                          ; edx = (section counter)++
.text:004010FB                 sub     eax, 28h                     ; ((IMAGE_SECTION_HEADERS*)eax)-- 
.text:004010FE                 cmp     edx, ecx                     ; if section counter < NumberOfSections
.text:00401100                 jb      short loc_4010F3             ; then goto loc_4010F3

.text:00401102 loc_401102:                             
.text:00401102                 xor     eax, eax                     ; eax = 0

.text:00401104 loc_401104:                             
.text:00401104                 pop     esi                          ; restore esi
.text:00401105                 pop     ebx                          ; restore ebx
.text:00401106                 retn                                 ; return eax = IMAGE_SECTION_HEADERS* with a 0x00 at Name[5]

.text:00401106 Get_PE_section_address endp

Note that there's a bug in the assembly code: it iterates backwards through NumberOfSections Section Table entries, but since it starts with the second-to-last section, it may end up reading past the beginning of the first section's section table entry.

So, my question would be if there is anyone who can tell me which lines tells us that this is something about PE section address.

Typically you would know the input argument to the function (in this case, the beginning of the PE module in memory), which would help you step through the assembly code. But even if you were given this code with little-to-no context (as we were here) a good hint that it's handling PE sections is the following line:

.text:004010DE                 movzx   ecx, word ptr [eax+6]        ; ecx = ((IMAGE_NT_HEADERS*)eax)->FileHeader.NumberOfSections

Whenever you see movzx ..., word ptr [...+6], it strongly suggests that the number of sections is being read, since there aren't other common word-sized values beginning 6 bytes into a structure.

  • hello, thx for the great comments. I was reading "PORTABLE EXECUTABLE FILE FORMAT – A REVERSE ENGINEER VIEW" to understand the PE File format concept better. For that reason, it takes a while for my comment. But I have one question. So, your commented line: &(((IMAGE_SECTION_HEADERS*)(edx + 0x18))[NumberOfSections - 1]) . So, the edx=SizeOfOptionalHeaders, the 0x18 = 24 bytes(since Signature is 4 bytes & FileHeader is 20 bytes) and now, when we add size of optional header we would point to beginning of the section table,right?If yes,then why you have written [NumberOfSections -1]?best regards Commented Dec 14, 2014 at 21:33
  • NumberOfSections * 0x28 - 0x38 = NumberOfSections * 0x28 - 0x28 - 0x28 + 0x18 = sizeof(IMAGE_SECTION_HEADER) * (NumberOfSections - 2) + 0x18, so it should have been ... [NumberOfSections - 2] in my original comments above (which would correspond with my original "second-to-last" description) -- I've replaced the [NumberOfSections - 1] with [NumberOfSections - 2] in my answer above. Commented Dec 14, 2014 at 21:58
  • another question: why is 0x38 = 0x28-0x28+0x18 ? Commented Dec 15, 2014 at 0:36
  • It doesn't. See my comment above: - 0x38 = - 0x28 - 0x28 + 0x18. Commented Dec 15, 2014 at 3:43
  • 1
    aaah, ok. Thx. I ve forgotten the "-" sign. Ok, now is everything clear. Commented Dec 15, 2014 at 15:13

looks like some homemade untested code for retrieving section address retrieves address of second section if the section name[5] is null terminator \x0

MOV     ECX, DWORD PTR SS:[ESP+4]          ; ecx = 1000000 base of image
MOV     EAX, DWORD PTR DS:[ECX+3C]         ; eax = 0xe8 ptrtopeheader
MOVZX   EDX, WORD PTR DS:[EAX+ECX+14]      ; edx = e0 = sizeofoptional header
ADD     EAX, ECX                           ; eax = peheader
MOVZX   ECX, WORD PTR DS:[EAX+6]           ; ecx - no of sections
ADD     EDX, EAX                           ; edx = 10001c8 ?
LEA     ESI, DWORD PTR DS:[ECX+ECX*4]      ; esi = 14 ?
LEA     EAX, DWORD PTR DS:[EDX+ESI*8-38]   ; ? esi * 8 - 38 + edx ; 1000230
JBE     SHORT 01063F5E                     ; jmp ot if no sections
MOV     BL, BYTE PTR DS:[EAX+5]            ; checks for 0 in section name ?
TEST    BL, BL                             ; some kind of homemade crap
JE      SHORT 01063F6C                     ; jmps out of proc with address of second section if section name was sya .rsrc
INC     EDX                                ; loop checking section 1
SUB     EAX, 28                            ;  size of section header
CMP     EDX, ECX                           ; counting no of sections
JB      SHORT 01063F05                     ; <loop>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.