Okay, we can dump heap buffers. What’s next?
What about a sandbox-like, IOC generator & payload dumper? In its most basic version we will run a sample and our handlers will spit out all the file names of files being opened by the analyzed program. They will also dump file buffers read to and written from. And for a good measure, we will try to convert some of the file creation flags/arguments passed to the APIs so we can get a more readable log.
To dump a list of files being opened by APIs I will focus on handling CreateFileA, and CreateFileW APIs. I chose these APIs for a couple of reasons:
- They are very commonly used and are easy to test
- CreateFileA & CreateFileW exist inside kernel32.dll
- CreateFileA & CreateFileW exist inside kernelbase.dll
- you may hook them all, and you may also want to choose either of them; of course, too many hooks is not good, hence there are challenges introduced by this duplication
To test handlers (copy provided at the end of this post) just run this:
frida-trace -i RtlFreeHeap -i RtlAllocateHeap -i KERNEL32.DLL!CreateFileA -i KERNEL32.DLL!CreateFileW -i KERNEL32.DLL!WriteFile -i KERNEL32.DLL!ReadFile -f <exe> > log
Same as with buffers, we will store file handles in a table at the time file is created / opened. We will then lookup these handles at the time of file reading and writing so we can log actual file names in our logs, as opposed to just file handles. In my old sandbox I used a code inject that was relying on NtQueryObject executed in a context of a target process at the time Read/Write APIs were executed, but then again – I had to inject my code into that process, hook APIs before the malicious implant took over. Pretty complicated.
Anyway… since we can map file handles to file names we can now output the content of buffers/arguments to appropriate files (one file will store list of files/objects and the other one – actual file buffers). And for the fun of it, we will file buffers in hex + will include PID and TID, and of course a file name in our log:
The list of objects (and file handle to file name mapping) created using CreateFile APIs will be stored inside objects_list.txt file:
You may notice that some of them are 0xFFFFFFFF — these failed to open. It’s an interesting result – you will not only see existing files being accessed, but also these that don’t. Let me reiterate — these are calls to CreateFile API to access _some_ files or directories that may not be present on the system. Pretty much like Procmon, but a bit easier to read and far easier to mod the output to our needs. Such log’s value in security research cannot be overstated — it can help finding references to non-existing files, phantom libraries, anti-debugging strings e.g. device names, etc..
Finally, our attribute/flags resolution code works as well:
The screenshot below shows how this works in practice – the dwDesiredAccess’s value of 0x80000000 is translated to ‘GENERIC_READ’:
Now, before we get too excited about our ‘building our own sandbox’ experience… let me mention that there are caveats. One of them is that Frida doesn’t work all the time. For the benefit of this article, I tried to run my handlers over pafish.exe executable and… it just got stuck:
I wanted to test pafish, because it refers to a number of devices associated with guest OS devices that help to detect a virtualization:
– so I thought I can output all these referenced device names and show how cool the handlers can be. Then the main pafish.exe process got stuck and that’s about it. So, you have been warned.
You can download my testhandlers from here.