This is the first part of a series of articles (at least I will write a second part and i hope to continue) where I will write about different ways that I use to unpack malware, and where I will share some tools and scripts that I use frequently for this purpose. I hope these articles and tools will be useful for you 🙂
The way to unpack a malware depends a lot on the malware family being analyzed. Sometimes it is impossible to do it in a generic way, and it takes a lot of patience and imagination. Each one has a way of working on this. But sometimes we can find common behaviours in malware that can help us to automatize the task of unpacking malware.
PE files in ReadWriteExecute Memory
I don’t know an exact percentage, maybe around 60-70% of the packed malware that I have analyzed, the packer unpacks malware PE modules into RWE memory.
(With WinDbg we can switch to a process with .process /i <process> and see the address space with !address).
Sometimes the packer will unpack the malware into the current process memory space. Other times it will inject PEs into another process memory space, or it will create a new process for doing hollow processes. Etc… But usually, it will create RWE memory and it will map the PE there.
Windbg Scripts for finding PEs in RWE
Based on this, i wrote some Windbg scripts for scanning running processes on the debuggee machine, searching for PEs in RWE memory. I have used these scripts to unpack most of the malware that I have analyzed, and they helped me a lot since time ago. I hope they are useful for you too.
dump_injected_pe_rwemem.wdbg : This script will scan processes’ memory of the debugee machine searching for PEs mapped into RWE memory. When it finds a PE, it pages-in the memory of the PE (because sometimes, some page of the memory area could be not mapped and it could fail to dump it) and dumps it to the directory specified in the first argument:
$$>a<dump_injected_pe_rwemem.wdbg <results directory>
Dumped files will have a name with this format:
<process>_<baseaddress>_<length>.pedmp (the process containing the PE, the baseaddress of the PE and the length).
dump_injected_pe_rwemem_fast.wdbg : This script works exactly like the previous one, but it won’t page-in the memory of the PE before dumping it. Most of times, it will dump the PE perfectly and it will be much faster. Anyway, I usually disable swapping in the debuggee machine, because doing that, we can be sure all the pages are in memory. It works exactly like the previous script and results’ name follow the same format.
$$>a<dump_injected_pe_rwemem_fast.wdbg <results directory>
find_injected_pe_rwemem.wdbg : This script searchs for PEs in the same way that previous scripts, but it only notifies about PEs that it found, it won’t dump them to disk. No need params:
dump_process_symbols_to_file.wdbg : This is a very simple script, but useful. It will write to a file all the symbols of a given process (API addresses for example, and any other symbol loaded by WinDbg). It will write to the file the addresses and the symbols.
$$>a<dump_process_symbols_to_file.wdbg <destination file path> <process>
Each line will contain an address and a symbol, like this:
If we dump a PE and we disassemble it with IDA or any other disassembler, variables usually could contain these addresses (for example if the malware has loaded APIs with GetProcAddress and it has kept the pointer into a variable, or the imports, etc…).
set_symbols_for_addresses.py : This IDA script scan dumped PE memory for variables containing addresses matching symbols that were kept with the dump_process_symbols_to_file.wdbg script (for example a variable containing a pointer to kernel32!CreateFileA will be renamed to kernel32_CreateFileA). It helps a lot to analyze the dumped PE.
To understand better how to use these scripts I recorded the following short video that shows three examples where I use these scripts to unpack and analyze malware: