over 1 year ago


SAMPLE MD5: 50d3cbd314e39b28bcd7938794e18c97

This sample is packed with a packer that drops a shellcode to decompress the

The packer uses a similar technique to “Process Hollowing”. In this case, after dropping the shellcode, the shellcode decodes the payload. Finally, the shellcode unmaps the packer and it maps the payload in the same memory address as the packer was.

The next image shows the different phases of unpacking process.

1.pngImage​ ​ 1:​ ​ Logic​ ​ summary​ ​ of​ ​ the​ ​ packer.

1. When the packer is in memory, after a process which I am going to describe later, it​ ​ drops​ ​ the​ ​ shellcode.
2. The shellcode drops encoded payload and decrypts it. After the decryption the payload​ ​ is​ ​ not​ ​ ready​ ​ yet​ ​ (red​ ​ color).
3.​ ​ The​ ​ shellcode​ ​ unmaps​ ​ the​ ​ packer.
4. The shellcode maps the decrypted payload at the same position as the packer was.
5.​ ​ The​ ​ shellcode​ ​ fixes​ ​ the​ ​ imports​ ​ addresses​ ​ which​ ​ will​ ​ be​ ​ used​ ​ by the​ ​ payload.
6.​ ​ Finally, ​ the​ ​ payload​ ​ is​ ​ executed.


I​ am​ going​ to​ explain​ in​ detail​ the​ 6 steps​ described​ above.

The​ first​ step​ (1)​ drops​ the​ shellcode​ using​ Windows​ messages.

2.pngImage​ 2:​​ ​ Main​ code of​ the​ packer.

The image 2 shows how the class named “needed” is registered. “needed” class has associated the subroutine “sub_4041A6” (The shellcode will be written by this subroutine).
After​ registering​ the​ class,​ the​ packer​ creates​ a ​ “needed”​ window.

The packer loops until it does not get more messages, at this moment the shellcode is​ ready​ to​ run​ (“image​ 2”,​ line​ 24).

“sub_4041A6” subroutine works as state machine. Depends on the received message, it jumps​ to​ one​ state​ or​ another.​ The​ next​ messages​ are​ the​ most​ important​ for​ the​ subroutine:

  • Message 0x111: This message manages the state machine, depends on lParam theprogram jumps to one state or another. The packer drops the shellcode after passing for all states.

Image 3 shows how the messages are managed by the window. If the message is different to 0x111 the program pass the message. In addition, if the message is 0x111 with value​ 0x579​ as​ lParam​ the​ window​ will​ start​ to​ drop​ the​ shellcode.

3.pngImage​ ​ 3:​ ​ Reading​ ​ 0x111​ ​ message.

  • Message 0x401: When this message is received, it will start to decode the shellcode. The wParam is the memory address to write from and the lParam is the address to​ write​ to.

4.pngImage​ ​ 4:​ ​ Message​ ​ 0x401​ ​ loop​ ​ which​ ​ is​ ​ responsible​ ​ for​ ​ decoding​ ​ the​ ​ shellcode.

The​ loop​ shown​ in​ the​ image​ 4,​ basically​ do​ the​ same​ as​ the​ next​ pseudo​ code.

dir_src​ = *wParam
dir_to_write​ = *wParam​ + 4
offset​ = lParam
for​ i in​ range(15):
    [dir_to_write]​ = [dir_src​ + i]
    dir_to_write​ = dirt_to_write​ + offset

This​ message​ is​ sent​ until​ the​ packer​ writes​ the​ shellcode.

When shellcode is executed, it decrypts itself at the beginning. After this decryption, the​ shellcode​ starts​ to​ work.

5.pngImage​ ​ 5:​ ​ Entry​ ​ point​ ​ of​ ​ the​ ​ shellcode​ ​ before​ ​ the​ ​ decryption.

6.pngImage​ ​ 6:​ ​ Piece​ ​ of​ ​ code​ ​ of​ ​ initial​ ​ decryption​ ​ just​ ​ before​ ​ calling​ ​ to​ ​ the​ ​ decrypted​ ​ shellcode.

7.pngImagen​ ​ 7:​ ​ Entry​ ​ point​ ​ of​ ​ the​ ​ shellcode​ ​ after​ ​ the​ ​ decryption.

The shellcode allocates memory with VirtualAlloc function and starts to drop binary data​ which​ looks​ to​ be​ compressed.

8.pngImage​ ​ 8:​ ​ Uncompress​ ​ process.

After​ uncompressing​ data,​ we​ can​ find​ the​ payload.

9.pngImage​ ​ 9:​ ​ uncompressed,​ ​ payload.

Now we are at the third (3) step, the shellcode will unmap the packer and will map the​ decrypted​ payload​ in​ the​ same​ address​ as​ the​ packer​ was​ (4).

10.pngImage​ ​ 10:​ ​ Unmap/map​ ​ code.

Finally, the shellcode fixes up the import addresses of the payload and it passes the control​ to​ the​ payload.

11.pngImage​ ​ 11:​ ​ Fixing​ ​ up​ ​ the​ ​ imports​ ​ of​ ​ the​ ​ payload.

12.pngImage​ ​ 12:​ ​ Jump​ ​ to​ ​ OEP.

The first command for starting the unpacking (in the subroutine associated with the "needed" registered class) is when the lParam is 0x38.

The firs state of the "needed" class is to get the system time. Once it has the current month (using GetSystemTime) it moves to lParam, the current month value (1 = January, 2 = February ... 11 = November, 12 = December) plus 0x27 and sends the message.


So, If it is not November It won't unpack =(

Author: @D00RT

← Fileless Code Injection in Word without macros (CVE-2017-11882) Easy way for analyzing the GootKit banking malware with radare2 →