Just a short blog entry to save this info for the history.

We investigated originally two different pieces of duqu payload. One contained resource 302 with a compressed .zdata section, the other contained the to-be-injected code without compression. The injector-loader is the same for the two versions, then how does it find if .zdata should be loaded?

Here is the trick from netp 301 resource:

.text:10001220 mov ecx, 5A4Dh
.text:10001225 cmp [eax], cx
.text:10001228 jnz loc_100012CD
.text:1000122E mov ecx, [eax+3Ch]
.text:10001231 add ecx, eax
.text:10001233 cmp dword ptr [ecx], 4550h
.text:10001239 jnz loc_100012CD

First it checks for “MZ” header, then it check “PE” signature.

.text:1000123F movzx edx, word ptr [ecx+6] ; number of sections in PE File (5)
.text:10001243 cmp dx, 3
.text:10001247 jbe loc_100012CD
.text:1000124D movzx esi, word ptr [ecx+14h] ; pointer to symbol table
.text:10001251 movzx edx, dx
.text:10001254 imul edx, 28h ; each section entry in section table- 40 byte
.text:10001257 add edx, ecx
.text:10001259 lea edi, [esi+edx-38h] ; the section before the last section (zdata) + offset
.text:1000125D test edi, edi
.text:1000125F jz short loc_100012CD
.text:10001261 cmp dword ptr [edi+1Ch], 0BC395587h ; zdata magic PE Header NumberOfRelocations is abused
.text:10001268 jnz short loc_100012CD
.text:1000126A cmp dword ptr [edi+8], 2Ch ; some check on physical size
.text:1000126E jb short loc_100012CD

As you can see, it calculates the exact place for the end of the section table then moves back to the entry before the last (this is .zdata info). Then it checks for a magic number 0xBC395587 which is stored in “NumberOfReloctions” value.

.text:10001270 mov esi, [edi+0Ch]
.text:10001273 add esi, eax
.text:10001275 cmp dword ptr [esi], 0D139120Eh
.text:1000127B jnz short loc_100012CD

Finally it checks the first 4 bytes of the .zdata section against 0xD139120e.


Leave a Reply