TheAbsnt

Zero2Auto: Ch03-Practical Analysis Challenge (Part-I)

· THEABSNT

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 performs ROT13 on encrypted string against abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890./=), to dynamically load them using LoadLibraryA followed by GetProcAddress

  • functions dynamically loaded are FindResourceA, LoadResource, SizeOfResource, LockResource, VirtualAlloc from kernel32dll

  • moving on, we see it finds(FindReosurceA), loads(LoadResource), gets the size(SizeOfResource), lastly locks(LockResource) a resource from .rsrc section with ID = 101(0x65) of type RT_RCDATA(0xA) with size 0x1541C

  • then it calculates the size(based on lpRsrcLock+0x8 ie. 0x2200) for the data after offset lpRsrcLock+0x1C from resource ie. 0x1541C - 0x1C => 0x15400, then allocates(VirtualAlloc) that much space to fill it with the buffer lpRsrcLock+0x1C using sub_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 is RC4 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 from 0 to 256 which is then swapped with value based on calculation done with key
    • PRGA(Pseudo-Random Generation Algorithm): generates and outputs the keystream using the scrambled list we had, and generates as many bytes needed up to 256
    • 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 from lpRsrcLock+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 to sub_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 using GetThreadContext() in order to manipulate it later

  • allocate some memory in suspended process using VirtualAllocEx with base address 0x400000(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 the lpContext->Eax to 0x4022F3 (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 to Memory Map tab , then Follow in Dump the memory(payload address of 0x400000 with size 0x18000), you’ll see an executable header(4D5A..), form here go to the entry point offset then main in this case its 0x401EA0 then Follow 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 :)