Reverse-engineering and deobfuscation of Flash apps
by CyberShadow on Feb.12, 2010, under Code, Hax
I probably should have known better when I started down this path with “cracking” PopCap’s latest version of Bejeweled Blitz. 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. PopCap 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:
SWF
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
Actions
flash.swf.ActionHandler: interface to handle actions(?)
flash.swf.tools.Disassembler: ActionHandler -> PrintWriter
flash.swf.ActionEncoder: ActionHandler -> SwfEncoder
flash.swf.ActionDecoder: SwfDecoder -> ActionList
ABC
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
Nodes
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
Optimizer
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 which PopCap used 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
February 12th, 2010 on 11:54 pm
Hi,
does this mean you aren’t gonna make a cheat for the new popcap bejewelled blitz? I know a lil about computers but what you wrote above is another language to me sorry lol
thanks
lou
February 12th, 2010 on 11:56 pm
No, it means that I already have.
February 13th, 2010 on 5:04 am
awesome job man….. thanks for the hard work. just be responsible everyone.
February 13th, 2010 on 5:54 am
You are the best!!!!!!!!!!!!!!!!!!!!!!
February 13th, 2010 on 11:41 am
you are a genius mr cybershadow. thanks for all your time and effort. its all such fun teasing people. You’re a star.
February 13th, 2010 on 10:05 pm
excellent job fella u r one clever mofo
February 14th, 2010 on 1:58 pm
amazing work mate.. hats off.
February 15th, 2010 on 6:14 am
just wanted 2 say thanks for all the hard work that you do
thank you
February 17th, 2010 on 4:40 pm
Absolutley brilliant !!!! i just love pissing my old schoolies off getting a higher score .
xx
just wish i could get the same for my bank account
February 18th, 2010 on 2:10 am
Im guessing this tricking is working by the above replies. Can someone help me understand what im suppose to do here.. Im lost, thank you
February 18th, 2010 on 8:31 am
i love this cheat its the best thanks
February 19th, 2010 on 4:57 am
how do i delete my bejeweled blitz score?
February 19th, 2010 on 4:58 am
You can’t, you just need to wait until the weekly highscore roll-over.
February 19th, 2010 on 10:29 am
This is black magic
March 27th, 2010 on 3:03 pm
After disabling comments to this post for over a month, I decided to re-enable them. Please keep the discussion on topic – any comments and questions regarding Bejeweled Blitz do not belong here, and – especially comments like “Help me, the extension doesn’t work” – will be deleted.
March 27th, 2010 on 11:34 pm
Great post, and thanks for making the source available. I found it quite useful.
June 17th, 2010 on 4:58 pm
I’m not able to compile this for some reason? Using javac tools\*.java I’m getting 87 errors
July 12th, 2010 on 8:24 am
this is by far lots of work. and very much appreciated. thank you so much for your hard work. as much as it takes hard work and takes your time. on the plus side learning and recapping is the best to keep knowledge alive.. your skills will only get sharper.