Recently we took a look at a new flash player exploit used by the Angler exploit kit. The sample was obfuscated using the well known 'packing' technique: the dropped swf file embeds a second stage swf in the form of an encrypted blob that will be decrypted at runtime and then executed using the loader.loadbytes ActionScript API.
In order to extract the exploit code, we need to remove those multiple obfuscation layers. We could reverse engineer the ActionScript code to try and decrypt the second stage, or we could simply load the swf file in a flash player instance and let it unpack the sample for us...
Let's see how we could do the latter in REVEN:
The idea behind dynamic unpacking is that in order to be executed, sooner or later the final stage code has to be decrypted and stored in memory. This is perfect as REVEN provides a dead simple way to retreive memory chunks from an execution trace.
Once a trace of the swf file execution is generated, we extract a memory snapshot at the end of the trace and browse it – looking for swf content. According to the SWF File Format Specification, the uncompressed SWF file header contains an 'FWS' string followed by a version byte and the file size in a double-word integer. This is enough to find and dump all all swf files in the memory dump.
Enough theory, let's code some REVEN script.
The first step is to choose an execution point at wich the memory will contain the final stage code. We might search for the last allocations done by the flash player binary but we will keep it simple and select the last instruction of the trace.
import reven # Connect to reven rvn = reven.reven_connection("localhost", 13371) # Get the last execution point of the trace run = "Execution run" sequence = rvn.run_get_sequence_count(run) -1 point = reven.execution_point(run, sequence, 0) # Get the base address of the (Windows) data segment ds = 0x23 address = reven.logical_address(ds, 0)
Then, we look for the 'FWS' string in the wall segment and for each matching address, we retreive the swf size from the header and dump the chunk to disk.
matches = rvn.memory_search_buffer(point, address, address + 0xffffffff, "FWS") for match in matches: # 0 4 8 # +---------------------+-------+ # | Signature | Version | Size | # +---------------------+-------+ try: size = rvn.memory_get_dword(point, match+4) swf = rvn.memory_get_buffer(point, match, size) except: # Memory accesses may throw exception if requested chunk isn't mapped continue filename = str(match.offset)+'.swf' f = open(filename, 'w') f.write(swf) f.close()
And we are done, with this tiny script we can easily extract all swf files from memory – avoiding boring manual unpacking. Of course malware authors have found contermeasures and for example, some malicious swf file may create hundreds of fake swf headers in memory, but this is another story.
The goal of this short post was to show how REVEN compares to other debuggers in the case of the well known task of object memory extraction. We hope we have demonstrated how easy it is to script REVEN throught its python API.
Of course this is not the only way to extract packed flash objects. A much more accurate method is to directly intercept calls to the action script API – see the Timo Hirvonen sulo pin tool for example.