Zero2Auto: Ch03-Practical Analysis Challenge (Part-I)
What’s up dudes!! This post is a walktrough of challenge binary from Chapter 03: Practical Analysis from Zero2Automated: Advanced Malware Analysis course. This challenge is set to make you comfortable with malware reversing and triage by covering variety of topics like API hashing, Anti-Debugging, PEB manipulation, Process Injection, Thread Context Hijacking, Unpacking Methods, Cryptography Algorithms and so on.
Base payload main_bin.exe : Stage01
In this Part-I of this series we’ll walkthrough the base binary(stage01) ie. main_bin.exe
. So, let’s get started…
Inside ‘main()’
-
Following is the formatted pseudocode of
main()
based on IDA decompiler output: -
this binary starts off by decrypting the needed module and win32API function name strings using
sub_401030
(which performsROT13
on encrypted string againstabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890./=
), to dynamically load them usingLoadLibraryA
followed byGetProcAddress
-
functions dynamically loaded are
FindResourceA
,LoadResource
,SizeOfResource
,LockResource
,VirtualAlloc
fromkernel32dll
-
moving on, we see it finds(
FindReosurceA
), loads(LoadResource
), gets the size(SizeOfResource
), lastly locks(LockResource
) a resource from.rsrc
section withID = 101(0x65)
of typeRT_RCDATA(0xA)
with size0x1541C
-
then it calculates the size(based on
lpRsrcLock+0x8
ie.0x2200
) for the data after offsetlpRsrcLock+0x1C
from resource ie.0x1541C - 0x1C => 0x15400
, then allocates(VirtualAlloc
) that much space to fill it with the bufferlpRsrcLock+0x1C
usingsub_402DB0
-
moving on, we see the constant
256
a bunch of times along with loops containing enough arithmetic instruction, with a quick search it reveals that this isRC4
decryption routine, not going deep into algorithm itself:- it’s a 3 staged stream cipher algorithm consisting of
KSA(Key Scheduling Algorithm)
: which initializes a list of values from0
to256
which is then swapped with value based on calculation done with keyPRGA(Pseudo-Random Generation Algorithm)
: generates and outputs the keystream using the scrambled list we had, and generates as many bytes needed up to256
XOR
Operation: XORing each byte of ciphertext/plaintext with a byte of the keystream generated
-
in this case the key is the next
15
bytes fromlpRsrcLock+0xC
ie.6b6b64355964504d32345642586d69
when the decryption routine finishes we’re left with an executable in previously allocated memory, which is then passed as an only argument tosub_401000
Inside ‘sub_401000()’
This Function gonna perform PROCESS INJECTION using THREAD CONTEXT HIJACKING in order to inject/execute the payload supplied as argument:
-
Following is the modified/edited Pseudocode of
sub_401000()
based on IDA decompiler output: -
creates a child process of it’s own in suspended state using
CreateProcessA()
-
then, get the thread
Context
of thread inside suspended process usingGetThreadContext()
in order to manipulate it later -
allocate some memory in suspended process using
VirtualAllocEx
with base address0x400000(stg02_nt_headers->OptionalHeader.ImageBase)
-
the using loop, this will write the payload section-by-section to the allocated memory using
WriteProcessMemory()
-
after injecting the payload in target process, this set the thread context back using
SetThreadContext()
after modifying thelpContext->Eax
to0x4022F3
(ie. original entry point(main
) of the stage02) -
then resume the suspended thread using
ResumeThread()
, which will immediately resume execution of injected payload from earlier set entry point
TIP: to break on the executing/injected payload in target process
- attach the targeted process to
x32dbg
, then navigate toMemory Map
tab , thenFollow in Dump
the memory(payload address of0x400000
with size0x18000
), you’ll see an executable header(4D5A..
), form here go to the entry point offset thenmain
in this case its0x401EA0
thenFollow in Disassembler
, put a break point there- after resuming the thread from parent process, simply resume the debugger of child process and you’ll jump to your intended breakpoint
Automations for this binary
- String decryption performed by sub_401300
# decryptStr_401300.py
# Author: ME :D
# this decryption routine, kinda performs string decryption similar to ROT 13
# but on given set of chararcters ie. 'all_chars'
def decrypt(enc_str):
dec_str = ""
all_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890./="
if len(enc_str) > 0:
for i in range(len(enc_str)):
if enc_str[i] in all_chars:
index_of_chr = all_chars.index(enc_str[i])
if (index_of_chr + 13) < len(all_chars):
dec_str += all_chars[index_of_chr + 13]
else:
dec_str += all_chars[index_of_chr - len(all_chars) + 13]
return dec_str
if __name__ == "__main__":
enc_str = input("String to decrypt: ")
print("Decrypted Str: ", decrypt(enc_str))
- Extraction of stage02 from .rsrc section and its decryption:
# stage02_extraction.py
# Author: ME :D
import pefile
from arc4 import ARC4
def extract_rsrc(pe):
for resrc in pe.DIRECTORY_ENTRY_RESOURCE.entries:
for entry in resrc.directory.entries:
print("Resource Name:", entry.name) # name of resource if present
print("Resource ID(Parent):", entry.id) # resource id of parent resource
print("Reosurce ID:", entry.directory.entries[0].id) # resource id of this resource
# get the size of this resource
sizeOfRsrc = entry.directory.entries[0].data.struct.Size
print(f"Size of resource: {hex(sizeOfRsrc)}")
# get the offset of this resource
offsetToRsrc = entry.directory.entries[0].data.struct.OffsetToData
print(f"Offset to resource: {hex(offsetToRsrc)}")
# write the reosurce ot a variable to return
rsrc = pe.get_memory_mapped_image()[offsetToRsrc : offsetToRsrc + sizeOfRsrc]
return rsrc
def rc4_decrypt(key, data):
cipher = ARC4(key)
decrypted_data = cipher.decrypt(data)
return decrypted_data
def main():
pe = pefile.PE("main_bin.exe")
extracted_resource = extract_rsrc(pe) # store the extracted resource
# RC4 decryption follows with key being 15bytes from 0xC,
# and rest of data is to be decrypted
decrypted_resource = rc4_decrypt(extracted_resource[0xC:27], extracted_resource[0x1C:])
executable = decrypted_resource
# now write it to a new file
with open("decrypted_Stage02.bin", "wb") as f:
f.write(executable)
if "__main__" == __name__:
main()
Conclusion
Now that we know, how the decryption of stage-02 is taking place using RC4 algorithm, also the ‘key’ for decryption and how the payload is injected and resumed to execute it and how put a breakpoint to it. Now in the part-II we’ll focus on working of stage 02
See you there :)