Thursday, January 16, 2014

Flash VM Instruction Reference/Overview

aka SWF game hack guide

I know what you're planning. . . You are trying to make an AoB hack out of some flash games. Don't let me know. I hate keeping secrets for others :)

Some knowledge on ActionScript and general programming required and assumed.


Analyzing the SWF:
AS2.0(AVM1) Manual(legacy): Flash virtual machine - Flasm - Sourceforge
Note: The site above also provides a FREE command-line (Non-GUI) assembler/disassembler of Flash ActionScript bytecode (not sure if it works on AS3.0 as well) DOES NOT RECOVER ACTIONSCRIPT SOURCE

Note: Unfortunately, there is very little documentation about AVM1 on the Internet. Therefore you might want to experiment the instructions yourself using a debugger swf. 
Debugger for Flasm developer: http://www.jurjans.lv/flash/flasm_debug.html


AS3.0(AVM2) Manual: [PDF] ActionScript Virtual Machine 2 Overview - Adobe
Sociodox - The Miner Adobe Flash/Air Debugger. . . OVERKILL!!

Unpacking SWF - http://blog.codestage.ru/2012/03/07/packed/ (read later)

Notes on using Sothink SWF Decompiler:
If you use Sothink SWF Decompiler,  this is how you switch to ActionScript bytecode view (with AVM instructions)

 (Click to enlarge image)

You should be presented with this view:
 (Click to enlarge image)

Note that it does NOT show the correspondence between source code and raw data!! You have to rely on your own knowledge on this. (Search function helps a lot navigating through code)
N.B. When you switch views, the decompiler always brings you to the first line of the code. . .

OMFG! I have ZERO knowledge on ActionScript!
Suggested reading:

Essential ActionScript 3.0 by Colin Moock
ActionScript 3.0 is a huge upgrade to Flash's programming language. The enhancements to ActionScript's performance, feature set, ease of use, cleanliness, and sophistication are considerable. Essential ActionScript 3.0 focuses on the core language and object-oriented programming, along with the Flash Player API. Essential ActionScript has become the #1 resource for the Flash and ActionScript development community, and the reason is the author, Colin Moock. Many people even refer to it simply as "The Colin Moock book."

And for good reason: No one is better at turning ActionScript inside out, learning its nuances and capabilities, and then explaining everything in such an accessible way. Colin Moock is not just a talented programmer and technologist; he's also a gifted teacher.

Essential ActionScript 3.0 is a radically overhauled update to Essential ActionScript 2.0. True to its roots, the book once again focuses on the core language and object-oriented programming, but also adds a deep look at the centerpiece of Flash Player's new API: display programming. Enjoy hundreds of brand new pages covering exciting new language features, such as the DOM-based event architecture, E4X, and namespaces--all brimming with real-world sample code.

The ActionScript 3.0 revolution is here, and Essential ActionScript 3.0's steady hand is waiting to guide you through it.

Adobe Developer Library is a co-publishing partnership between O'Reilly Media and Adobe Systems, Inc. and is designed to produce the number one information resources for developers who use Adobe technologies. Created in 2006, the Adobe Developer Library is the official source for comprehensive learning solutions to help developers create expressive and interactive web applications that can reach virtually anyone on any platform. With top-notch books and innovative online resources covering the latest in rich Internet application development, the Adobe Developer Library offers expert training and in-depth resources, straight from the source.

ActionScript 2.0 Language Reference (NOT an AVM manual!!)

I know some programming language just not ActionScript:
Here is the essential stuff you need to know. (For AS2.0)

gotoAndPlay function

gotoAndPlay([scene:String], frame:Object) : VoidSends the playhead to the specified frame in a scene and plays from that frame. If no scene is specified, the playhead goes to the specified frame in the current scene. You can use the scene parameter only on the root Timeline, not within Timelines for movie clips or other objects in the document. 
TL;DR: gotoAndPlay(n) jumps to frame #n

stop function

stop() : Void
Stops the SWF file that is currently playing. That means stopping the flash animation at the current frame. The most common use of this action is to control movie clips with buttons.

eval function

eval(expression:Object) : Object
eval(expression:String) : Object

Accesses variables, properties, objects, or movie clips by name. If expression is a variable or a property, the value of the variable or property is returned. If expression is an object or movie clip, a reference to the object or movie clip is returned. If the element named in expression cannot be found, undefined is returned.

getTimer function

getTimer() : Number
Returns the number of milliseconds that have elapsed since the SWF file started playing.
Some games use this function to catch cheaters who are getting high scores in short gameplay time. . .

You can figure out the rest here. . .
ActionScript 2.0 Language Reference (Again, it's NOT an AVM manual!!)

Note: The following list may not be exhaustive!
AS2.0 Reference List:
Opcode Instruction Description
0x00 _end Action Record End
0x04 NextFrame instruction
0x05 PreviousFrame instruction
0x06 Play instruction
0x07 Stop instruction
0x08 ToggleQuality instruction
0x09 StopSounds instruction
0x0A Add instruction
0x0B _subtract Subtract instruction
0x0C _multiply Multiply instruction
0x0D _divide Divide instruction
0x0E Equals instruction
0x0F Less instruction
0x10 _and Logical And instruction
0x11 Logical Or instruction
0x12 _not Not instruction
0x13 StringEquals instruction
0x14 StringLength instruction
0x15 StringExtract instruction
0x17 _pop Pop instruction
0x18 _toInteger ToInteger instruction
0x1C _getVariable GetVariable instruction
0x1D _setVariable SetVariable instruction
0x20 SetTarget2 instruction
0x21 StringAdd instruction
0x22 GetProperty instruction
0x23 SetProperty instruction
0x24 CloneSprite instruction
0x25 RemoveSprite instruction
0x26 Trace instruction
0x27 StartDrag instruction
0x28 EndDrag instruction
0x29 StringLess instruction
0x2A Throw instruction
0x2B CastOp instruction
0x2C Implements instruction
0x30 _randomNumber RandomNumber instruction
0x31 MBStringLength instruction
0x32 CharToAscii instruction
0x33 AsciiToChar instruction
0x34 _getTime GetTime instruction
0x35 MBStringExtract instruction
0x36 MBCharToAscii instruction
0x37 MBAsciiToChar instruction
0x3A Delete instruction
0x3B Delete2 instruction
0x3C _var DefineLocal instruction
0x3D _callFunction CallFunction instruction
0x3E Return instruction
0x3F Modulo instruction
0x40 _new NewObject instruction
0x41 DefineLocal2 instruction
0x42 InitArray instruction
0x43 InitObject instruction
0x44 TypeOf instruction
0x45 TargetPath instruction
0x46 Enumerate instruction
0x47 _add2 Add2 instruction
0x48 _less2 Less2 instruction
0x49 Equals2 instruction
0x4A ToNumber instruction
0x4B ToString instruction
0x4C _dup PushDuplicate instruction
0x4D StackSwap instruction
0x4E _getMember GetMember instruction
0x4F _setMember SetMember instruction
0x50 _increment Increment instruction
0x51 Decrement instruction
0x52 _callMethod CallMethod instruction
0x53 NewMethod instruction
0x54 InstanceOf instruction
0x55 Enumerate2 instruction
0x60 Bitwise And instruction
0x61 Bitwise Or instruction
0x62 Bitwise Xor instruction
0x63 Bitwise Left Shift instruction
0x64 Signed Bitwise Right Shift instruction
0x65 Unsigned Bitwise Right Shift instruction
0x66 StrictEquals instruction
0x67 _greater Typed Greater Than instruction
0x68 String Greater Than instruction
0x69 Extends instruction
0x81 GotoFrame instruction
0x83 GetURL instruction
0x87 _storeRegister StoreRegister instruction
0x88 _constantPool ConstantPool instruction
0x8A WaitForFrame instruction
0x8B SetTarget instruction
0x8C GoToLabel instruction
0x8D WaitForFrame2 instruction
0x8E DefineFunction2 (block) instruction
0x94 With instruction
0x96 _push Push instruction
0x99 _jump Jump instruction (branch)
0x9A GetURL2 instruction
0x9B _defineFunction DefineFunction (block) instruction
0x9D _if If instruction (conditional branch)
0x9E Call instruction
0x9F GotoFrame2 instruction

AS2.0 Examples:

AS Code Instructions Hex RawData
getTimer(); _getTime 34
Data types and push:
Push Type (HEX) Number of bytes Data Type Example
00 len(string) + 1 stringpush 'Hello'
01 4 float push Y_PROPERTY
02 0 null push NULL
03 0 undefined push UNDEF
04 1 register push r:2
05 1 boolean push TRUE
06 8 double push 3.1415926
07 4 integer push 25
08 1 constant (0-255) push 'Hello'
09 2 constant (256-65534) push 'Hello'
Push boolean:
_push true96 02 00 05 01
_push false96 02 00 05 00

Data Type register
Flash virtual machine has 4 global registers which we refer as r:0, r:1, r:2, r:3.
Accessing global registers is faster than accessing variables.
Inside of function2 (Flash Player >=6.0.65), and only there, up to 255 local registers exist — from r:0 to r:254. Why not 256? In the function2 header, the number of local registers used in this function is stored in a byte.
These are referred as register0, register1, register2, . . . as well as _loc0, _loc1,  _loc2, _loc3, . . .

Note on referencing variables in assembler:
Most variable names are declared from start of the code block using _constantPool asan array.
Say, the first variable is var0, then it would be declared in _constantPool as its first element, or (think _constantPool[0])
Example:
_constantPool var0 var1 var2 var3
Here I have declared 4 variables. Say I want to perform operation with var2. Then it would be at index=2 (arrays start from index 0).
Push type here would be 08, since 0<=index<=255. Otherwise it would be 09.
Now for var2, index=2. Therefore we reference var2 as 08 02.

Data Type double
The way Flash store double value is a bit weird. .

According to IEEE standard, a decimal should be represent hexadecimally as follows:
0.1 = 0x3FB999999999999A
however Flash store it like this:
99 99 B9 3F 9A 99 99 99
So it is necessary to convert decimals from Flash format to IEEE format, or vice versa to carry out conversion easily.
Start with the flash hex representation:
9999B93F9A999999
1. Divide the representation to first 4 bytes and last 4 bytes
9999B93F 9A999999
2. Now read the first 4 bytes from right to left, also applying this to last 4 bytes
3FB99999 9999999A
3. Then we have the IEEE representation of that decimal!
3FB999999999999A

You can use this on-site tool to do the hex conversation for Flash double values:
Flash Hexcode      <--->      Double         Converter
IEEE754 Double precision 64-bit Converter (this is for hex<->decimal)

Syntax: _push data0 data1 data2 . . .
96 <No. of bytes to push (WORD)> <push type of data0> <bytes of data0> <push type of data1> <bytes of data1> <push type of data2> <bytes of data2> . . .
random(100000); _push 100000
_randomNumber
96 05 00 07 a0 86 01 00
30
pointsWorth = random(8) + 1; _push "pointsWorth" 8
_randomNumber
_push 1
_add2
_setVariable
96 07 00 08 08 07 08 00 00 00
30
96 05 00 07 01 00 00 00
47
1d
points = pointsWorth + "k"; _push "points" "pointsWorth"
_getVariable
_push "k"
_add2
_setVariable
96 04 00 08 09 08 08
1c
96 02 00 08 0a
47
1d
The constant_pool is a variable length structure composed of integers, doubles, strings, namespaces, namespace sets, and multinames. These constants are referenced from other parts of the executive code block.

Syntax: _constantPool data0 data1 data2 . . .
88 <No. of bytes to store (WORD)> <No. of constants to store> <push type of data0> <bytes of data0> <push type of data1> <bytes of data1> <push type of data2> <bytes of data2> . . .
Hint: Strings are null(0x00)-terminated. An ASCII table would be handy!

Online ASCII conversion tools:
TextToHex: http://www.swingnote.com/tools/texttohex.php
HexToText: http://www.string-functions.com/hex-string.aspx

_constantPool "glassBlueLit" "_parent" "bonusPath" "glass" "_root" "changeColour" "glassBlue" "bg" "pointsWorth" "points" "k" 88 5c 00 0b 00 67 6c 61 73 73 42 6c 75 65 4c 69 74 00 5f 70 61 72 65 6e 74 00 62 6f 6e 75 73 50 61 74 68 00 67 6c 61 73 73 00 5f 72 6f 6f 74 00 63 68 61 6e 67 65 43 6f 6c 6f 75 72 00 67 6c 61 73 73 42 6c 75 65 00 62 67 00 70 6f 69 6e 74 73 57 6f 72 74 68 00 70 6f 69 6e 74 73 00 6b 00
_parent.spawnNewBall = true; _push "_parent"
_getVariable
_push "spawnNewBall" true
_setMember
96 02 00 08 00
1c
96 04 00 08 01 05 01
4f
_push var0 var1
Stack:
. . . => . . ., var0, var1
_greater
Stack:
. . . => (var0 > var1) ? . . ., true : . . ., false
_not
Stack:
. . ., boolN => . . ., !(boolN)
_not
Comment: 2 not instructions following each other cancel each other out. . . one of the stupid things about AS2.0 compiler, or it's trying to evaluate !(var0 <= var1)
_if true goto #n
Stack:
. . ., boolN => . . .
If boolN == true then goto #n
otherwise continue executing the next instruction

n is an arbitrary int
Basically, if the "if" condition is not satisfied then the code within the if-statement is not executed (by jumping directly to the end of the statement)
_push var0 var1
_subtract
Stack:
. . ., var0, var1 => . . ., (var0 - var1)
_storeRegister 1
Stack:
. . ., varN => . . ., varN (stack unchanged after instruction??)

_loc1 := varN

Comment: 1 is stored as byte
_pop
. . ., varN => . . .
if (_loc1 <= 0){
        _loc1 = -_loc1;
}
_push register1 0
_greater
_not
_not
_if true goto #20
_push 0 register1
_subtract
_storeRegister 1
_pop
96 0b 00 04 01 06 00 00 00 00 00 00 00 00
67
12
12
9d 02 00 14 00
96 0b 00 06 00 00 00 00 00 00 00 00 04 01
0b
87 01 00 01
17
AS Code Instructions Hex RawData


AS3.0 Reference List:
Opcode Instruction Description
0x02 nop Do nothing. (But you'll find this most useful!!)
0x03 throw Throws an exception.
0x04 getsuper Gets a property from a base class.
0x05 setsuper Sets a property in a base class.
0x06 dxns Sets the default XML namespace.
0x07 dxnslate Sets the default XML namespace with a value determined at runtime.
0x08 kill Kills a local register.
0x09 label Do nothing. Used to indicate that this location is the target of a branch.
0x0c ifnlt Branch if the first value is not less than the second value.
0x0d ifnle Branch if the first value is not less than or equal to the second value.
0x0e ifngt Branch if the first value is not greater than the second value.
0x0f infge Branch if the first value is not greater than or equal to the second value.
0x10 jump Unconditional branch.
0x11 iftrue Branch if true.
0x12 iffalse Branch if false.
0x13 ifeq Branch if the first value is equal to the second value.
0x14 ifne Branch if the first value is not equal to the second value.
0x15 iflt Branch if the first value is less than the second value.
0x16 ifle Branch if the first value is less than or equal to the second value.
0x17 ifgt Branch if the first value is greater than the second value.
0x18 ifge Branch if the first value is greater than or equal to the second value.
0x19 ifstricteq Branch if the first value is equal to the second value.
0x1a ifstrictne Branch if the first value is not equal to the second value.
0x1b lookupswitch Jump to different locations based on an index.
0x1c pushwith Push a with scope onto the scope stack.
0x1d popscope Pop a scope off of the scope stack.
0x1e nextname Get the name of the next property when iterating over an object.
0x1f hasnext Determine if the given object has any more properties.
0x20 pushnull Push null.
0x21 pushundefined Push undefined.
0x23 nextvalue Get the value of the next property when iterating over an object.
0x24 pushbyte Push a byte value.
0x25 pushshort Push a short value.
0x26 pushtrue Push true.
0x27 pushfalse Push false.
0x28 pushnan Push NaN.
0x29 pop Pop the top value from the stack.
0x2a dup Duplicates the top value of the stack, and then pushes the duplicated value onto the stack.
0x2b swap Swap the top two operands on the stack.
0x2c pushstring Push a string value (from constant pool) onto the stack.
0x2d pushint Push an int value (from constant pool) onto the stack.
0x2e pushuint Push an unsigned int value (from constant pool) onto the stack.
0x2f pushdouble Push a double value (from constant pool) onto the stack.
0x30 pushscope Push an object onto the scope stack.
0x31 pushnamespace Push a namespace.
0x32 hasnext2 Determine if the given object has any more properties. (byRef)
0x40 newfunction Create a new function object.
0x41 call Call a closure.
0x42 construct Construct an instance.
0x43 callmethod Call a method identified by index in the object’s method table.
0x44 callstatic Call a method identified by index in the abcFile method table.
0x45 callsuper Call a method on a base class.
0x46 callproperty Call a property.
0x47 returnvoid Return from the currently executing method. This returns the value undefined.
0x48 returnvalue Return a value from a method.
0x49 constructsuper Construct an instance of the base class.
0x4a constructprop Construct a property.
0x4c callproplex Call a property.
0x4e callsupervoid Call a method on a base class, discarding the return value.
0x4f callpropvoid Call a property, discarding the return value.
0x55 newobject Create a new object.
0x56 newarray Create a new array.
0x57 newactivation Create a new activation object.
0x58 newclass Create a new class.
0x59 getdescendants Get descendants.
0x5a newcatch Create a new catch scope.
0x5d findpropstrict Find a property.
0x5e findproperty Search the scope stack for a property.
0x60 getlex Find and get a property.
0x61 setproperty Set a property.
0x62 getlocal Get a local register.
0x63 setlocal Set a local register.
0x64 getglobalscope Gets the global scope.
0x65 getscopeobject Get a scope object.
0x66 getproperty Get a property.
0x68 initproperty Initialize a property.
0x6a deleteproperty Delete a property.
0x6c getslot Get the value of a slot.
0x6d setslot Set the value of a slot.
0x6e getglobalslot Get the value of a slot on the global scope.
0x6f setglobalslot Set the value of a slot on the global scope.
0x70 convert_s Convert a value to a string.
0x71 esc_xelem Escape an xml element.
0x72 esc_xattr Escape an xml attribute.
0x73 convert_i Convert a value to an integer.
0x74 convert_u Convert a value to an unsigned integer.
0x75 convert_d Convert a value to a double.
0x76 convert_b Convert a value to a Boolean.
0x77 convert_o Convert a value to an Object.
0x78 checkfilter Check to make sure an object can have a filter operation performed on it.
0x80 coerce Coerce a value to a specified type.
0x82 coerce_a Coerce a value to the any type.
0x85 coerce_s Coerce a value to a string.
0x86 astype Return the same value, or null if not of the specified type.
0x87 astypelate Return the same value, or null if not of the specified type.
0x90 negate Negate a value.
0x91 increment Increment a value.
0x92 inclocal Increment a local register value.
0x93 decrement Decrement a value.
0x94 declocal Decrement a local register value.
0x95 typeof Get the type name of a value.
0x96 not Boolean negation.
0x97 bitnot Bitwise not.
0xa0 add Add two values.
0xa1 subtract Subtract one value from another.
0xa2 multiply Multiply two values.
0xa3 divide Divide two values.
0xa4 modulo Perform modulo division on two values.
0xa5 lshift Bitwise left shift.
0xa6 rshift Signed bitwise right shift.
0xa7 urshift Unsigned bitwise right shift.
0xa8 bitand Bitwise and.
0xa9 bitor Bitwise or.
0xaa bitxor Bitwise exclusive or.
0xab equals Compare two values.
0xac strictequals Compare two values strictly.
0xad lessthan Determine if one value is less than another.
0xae lessequals Determine if one value is less than or equal to another.
0xaf greaterequals Determine if one value is greater than or equal to another.
0xb1 instanceof Check the prototype chain of an object for the existence of a type.
0xb2 istype Check whether an Object is of a certain type.
0xb3 istypelate Check whether an Object is of a certain type.
0xb4 in Determine whether an object has a named property.
0xc0 increment_i Increment an integer value.
0xc1 decrement_i Decrement an integer value.
0xc2 inclocal_i Increment a local register value.
0xc3 declocal_i Decrement a local register value.
0xc4 negate_i Negate an integer value.
0xc5 add_i Add two integer values.
0xc6 subtract_i Subtract an integer value from another integer value.
0xc7 multiply_i Multiply two integer values.
0xd0 getlocal_0 Get the local register at index 0.
0xd1 getlocal_1 Get the local register at index 1.
0xd2 getlocal_2 Get the local register at index 2.
0xd3 getlocal_3 Get the local register at index 3.
0xd4 setlocal_0 Set the local register at index 0.
0xd5 setlocal_1 Set the local register at index 1.
0xd6 setlocal_2 Set the local register at index 2.
0xd7 setlocal_3 Set the local register at index 3.
0xef debug Debugging info.
0xf0 debugline Debugging line number info.
0xf1 debugfile Debugging line number info.

AS3.0 Typename:
HEX Value Type Name
01 undefined = "undefined"
02 null = "object"
03 Boolean = "Boolean"
04 Number | int | uint = "number"
05 String = "string"
06 Function = "function"
07 XML | XMLList = "xml"
08 Object = "object"

You've come to the end! So here's a little gift for your effort reading all this:
Common techniques for making flash game AoB cheats:
1. Changing jump/if conditions
2. Changing the value of constants
3. Nop out a call using 0x02 AND nop out arguments to push onto stack
4. Change type of arithmetic operation
5. Change variable reference index
6. Unrandomize results by NOPping out the randomNumber instruction

1 comment: