2025/09/05

Write-up Malops - RokRAT Loader

Question 1

What is the MD5 hash of the binary?

Calculating the MD5 hash for the binary.

For example with
md5sum sample in a Linux shell
Get-FileHash -Algorithm MD5 sample in Powershell

Solution

CF28EF5CEDA2AA7D7C149864723E5890


Question 2

What is the entry point address of the binary in hex?

See https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#optional-header-standard-fields-image-only for the documentation. As this is the same for PE32 and PE32+ format, the offset is 16 in the Optional Header and the size of 4 bytes. “The address of the entry point relative to the image base when the executable file is loaded into memory. For program images, this is the starting address.”. This in this case we have to add the image base to the entry point, to get the answer.

904724ab8fe2c5ba4b818bf8c2cc6ad9.png
Image of PE-bear with the loaded sample

Ghidra or PE Studio etc. could also be used to get the entry point address.

Solution

0x401000


Question 3

What XOR key is used to decrypt the embedded shellcode in hex?

0b9d9fb6b8418b02e7f10a3d468c5810.png
Ghidra -> Search Text -> Instruction Mnemonic, then for xor
According to Ghidra there is only one XOR that would be suitable.

Capa will also directly point at this instuction.

966912c757e1a052741bcf1efe44e908.png
Capa result

Having a look at the surrounding code, EAX will be interated and BL is the XOR key, as it is static.

Setting a breakpoint during dynamic analysis did the trick.

Solution

0x29


Question 4

What is the memory protection constant used when allocating memory for the payload in hex?

Probably most efficient way would be to set breakpoints at VirtualAlloc and VirtualAllocEx in x64dbg and watch the arguments.

Before that you can debug the PE without any access error, you have to fix the access violation occuring. As “000D8C00” is in ESI, which is the counter for the XOR operation. You can do this dynamically or maybe patch the PE (havenĀ“t tried this).

311613b5cb181a78eaeb6a911b811701.png
Patch ESI

This occurs when trying to write to 406000, because this address is not writeable.

383f741ce0b1a5e9b75e57c613ff93a9.png
Memory Map

Anyhow, I went a complete different way and basically copied the pseudocode from Ghidra, made a few modifications that it compiles and passed in all the arguments (potential hashes) to what I identified as the hashing function. During execution I just added a print statement to print the potential function that matches the hash.

You can find the code there: https://gist.github.com/01f-nobot/824f29479f14c47677b0e5749f3d8b65

This gave me a pretty neat output and directed to to the function where VirtualAlloc is called.

Spoiler

e7babdebbf7ee9d04110e8e499a7e343.png
Output of custom function

The following push statements provide the answer to the question - see https://learn.microsoft.com/de-de/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc for reference.

f61e8848fe9afbb82c6222863e245931.png
VirtualAlloc arguments

Solution

0x40

If you want to better understand the pseudocode from Ghidra, here is the gist link to what Claude 3.5 gave me back with properly named variables - pretty impressive.

https://gist.github.com/01f-nobot/6b167b4d406ccee02c2e506555be1a94


Question 5

What is the hash value used to find the VirtualAlloc function in hex?

This is already covered due to the solution for question 4 - see explanation and spoiler.

Solution

0xaa7adb76


Question 6

How many bits does the DLL name hash algorithm rotate right (ROR) by in hex?

If you have a look at the the Claude 3.5 pseudocode with the named variables in the API Hash function (https://gist.github.com/01f-nobot/6b167b4d406ccee02c2e506555be1a94), you can spot the ROR operation for the DLL name hash.

Solution

0xb


Question 7

What value is checked to verify a valid PE header in hex?

That question got me. Before making the call to the Hashing function the integrity of the decrypted payload is checked. In the function at 0x004011f9, there are 2 functions calls to other functions: 0x00401164 and 0x00401197.

74d0787187bee6231bb20605d0ede3f8.png
Pseudocode of 0x00401164

And 0x5ad4 rang a bell, because that is “MZ” and the magic bytes for PE files - see https://upload.wikimedia.org/wikipedia/commons/1/1b/Portable_Executable_32_bit_Structure_in_SVG_fixed.svg

But that not the expected answer, because “MZ” is actually in the DOS Header, the PE Header offset is at offset 0x3c of the DOS header. As you can see in the linked image above.

Another check is the one we are looking for:

1a5bcba33646a76c9be5ef9d1a416415.png
Payload integrity check

The offset 0x3c is the relative offset to the start of the PE header, which is 0x128 in this case.

The 0x3c is only directly visible in the Assembly:

bd4a33b905494f77afe95eeee3cfaa36.png
Pseudocode of additional PE integrity check

e9281eeaa9084e536057d4ad5fd28891.png
Comparison of EAX with the signature

Effectively we are checking for the signature of the PE header (which is "PE" as ASCII), which is in this case at offset 0x128.

edee69b0cb738fdb00b41d7051f040e4.png
PE bear to get the offset of the PE Header and the signature of the PE Header

Solution

0x4550


Question 8

What is the hexadecimal offset value used in the code to access the export directory in the PE file’s Optional Header data directory?

Having a look at the named variable code from Clause, we can deduct the value in line 24 ( https://gist.github.com/01f-nobot/6b167b4d406ccee02c2e506555be1a94#file-gistfile1-txt-L24). This is also visible in the PE structure from Wikipedia. The code uses the offset 0x3C and then the offset of the export table.

Solution

0x78


Question 9

How many API functions are resolved using hashing in the entire binary?

This can be answered by looking at the references to the API hashing function (FUN_00401041).

Solution

7

8c4a41ac92cce64487020ce97c77b667.png
References to API hashing function
661aff231003cf6eb520b3718137fa2a.png
References to API hashing function


Question 10

How many bytes of headers are skipped to reach the start of the decrypted data?

Having a look at the decryption function, we can see that uVar2 - which is a uint - is the length and that puVar3 is the actual start of the decryption. param1 is the base for these offsets and is actually the XOR key.

ae6571c05eb0d3fa37fd874af88fd460.png
Decryption function pseudocode

In other words, at param1 the first byte is the key of the XOR operation, followed by 4 bytes of length of the encrypted payload, followed by the encrypted payload.

Solution

5