I probably should have known better when I started down this path with “cracking” a certain flash game. This has taken way more of my time than I had initially planned. On the other hand, now I know how to use Adobe Flash Builder, Adobe Flex SDK, XML schemas and JAXB and brushed up on my Java as well.
My previous versions of the cheat consisted of a Mozilla Firefox extension which redirected requests for the game SWF (and data.xml, a configuration file) to my server. The server (configured as a HTTP proxy) sent back an older version of the game SWF, which still had some debugging code left in which allowed you to edit the game board using hotkeys. The game developer has once changed the MD5 salt used to calculate validation checksums (after removing the debugging code), but I got away with it once by uncompressing (gzip) the SWF file, hex-editing the salt, and compressing it back. However, the latest build of the game was obfuscated, so no such tricks would pass this time.
In retrospect (as I wrote on the cheat page), I could have used simpler techniques such as memory editing and replay attacks, but all these could eventually be “patched up”. It would probably even have been simpler if I had written a bot (or just updated the old one) – there really isn’t much to do against screen-scraping bots, other than heuristics and changing the UI every once in a while. Still, I have written an ActionScript 3 deobfuscator.
I began my research with the Adobe Flex SDK. Considering that it includes a full open-source ActionScript/SWF compiler and utilities, I thought it would have some code which I could adapt to my needs. I was right, in fact there was actually an overlap/duplication of functionality in some classes. I have created the following “map” during my spelunking of the SDK source:
flash.swf.TagHandler: interface to handle SWF tags
flash.swf.TagDecoder: InputStream -> TagHandler
flash.swf.TagEncoder: TagHandler -> OutputStream/byte
flash.swf.MovieDecoder: TagHandler -> Movie
flash.swf.MovieEncoder: Movie -> TagHandler
flash.swf.tools.SwfxPrinter: TagHandler -> PrintWriter (Swfx)
flash.swf.tools.SwfxParser: XML (Swfx) -> TagHandler
flash.swf.ActionHandler: interface to handle actions(?)
flash.swf.tools.Disassembler: ActionHandler -> PrintWriter
flash.swf.ActionEncoder: ActionHandler -> SwfEncoder
flash.swf.ActionDecoder: SwfDecoder -> ActionList
macromedia.abc.Visitor: interface to handle ABC instructions
macromedia.abc.Decoder: BytecodeBuffer -> Visitor
macromedia.abc.Encoder: Visitor -> byte
macromedia.abc.DefaultVisitor: Visitor -> higher-level interface
Visitors (DefaultVisitor at least) still need reference to the original decoder
macromedia.abc.Printer.ABCVisitor: Visitor -> System.out
flash.swf.tools.AbcPrinter: byte -> PrintWriter
Used by flash.swf.tools.SwfxPrinter
macromedia.asc.parser.Evaluator: interface to handle macromedia.asc.parser.*Node
flash.swf.tools.SyntaxTreeDumper: Evaluator -> XML
flash.swf.tools.as3.PrettyPrinter: Evaluator -> PrintWriter
macromedia.asc.semantics.Emitter: interface for handling ABC instructions?
macromedia.asc.semantics.CodeGenerator: Evaluator -> Emitter
macromedia.asc.embedding.avmplus.ActionBlockEmitter: Emitter -> ByteList
adobe.abc.GlobalOptimizer: reads/writes .abc files, uses adobe.abc.Expr/Node/Edge/etc.
It looks like the adobe.abc namespace is only used for optimization of already-compiled code.
Unfortunately, I haven’t found any code capable of robust deserialization of ABC. (macromedia.abc.Encoder/Decoder come close to that, however they choke on some obfuscated code and produce broken output.) I haven’t written a deserializer, but instead I wrote a class (based on flash.swf.tools.AbcPrinter) that allows its subclasses to edit ABC structures “on the fly”.
The deobfuscator classes (the main class extending TagEncoder, to also edit SWF tags “on the fly”) performed two functions: correct identifier names in SymbolClass tags and ABC string constant pools, and rearrange code blocks to eliminate dead “junk” code inserted by the obfuscator.
The first function is fairly self-explanatory: it searched for strings starting with “_-” (the obfuscator’s prefix for all obfuscated names) or containing ActionScript keywords, and replacing them with strings which an ActionScript compiler would be more happy with. This step wasn’t actually necessary as the decompiled code wasn’t directly reusable anyway. It also allowed replacing strings based on a dictionary read from a text file, which allowed me to “rename” identifiers (similar to IDA).
The second feature is more interesting. The gist is that it splits each function into blocks (delimited at jumps and jump targets), constructs a flow graph, and then rewrites the code by traveling across the graph starting with the first node, and writing out the blocks in visited order. Practically, this is done by in-place patching relative jump offsets then writing the same bytecode in a different order (inserting labels and jumps where appropriate). Thus, the code doesn’t actually create in-memory copies of the bytecode. This approach has some side effects though, in that all unconditional jumps are rewritten to be strictly backwards, and this seems to break the AVM as it will spit out a cryptic error such as “VerifyError: Error #1068: package.class and package.class cannot be reconciled” (yes, the very same class). However, it makes decompilers much more happy with the new code, and that’s what mattered to me most.
The deobfuscator allowed me to study the game’s code much easier, however that wasn’t enough to accomplish my goal. It looks like the obfuscator used for this game also had a “string encryption” feature, and the MD5 salt used for validating sent and received data was encrypted using this feature (namely, a class which contained an encrypted version of the script and allowed decrypting it at runtime). Code generated by a decompiler was unusable, and the encryption algorithm (which I later recognized as the Tiny Encryption Algorithm) was too long to decipher from bytecode directly. I needed some way to execute that code without decompiling it. After initially planning to do some string replacement tricks and merging ABC code, I noticed that the respective class was in a separate DoABC tag (the deobfuscator must have written that block manually). Then, running the code was as simple as:
- extracting the contents of the DoABC tag to an .abc file (AbcExport)
- creating an ActionScript 3 application with the code:
var c:Class = getDefinitionByName("_-GF._-FA") as Class; var method:Function = c["_-NR"]; throw new Error(method(117, -75));
- injecting the .abc file from step 1 into the resulting SWF (AbcReplace)
and you get the magic string in a Flash Player exception box
You can find the source code for my deobfuscator and other utilities on GitHub. Please don’t ask for help in using the source code, you’re on your own.
Continued in: Announcing: RABCDAsm