Additional Info
|
Quote from: "maximillian"
Quote from: "ActionScript 1 OpCodes" No Operation (NOP) = 0x02, Quote from: "ActionScript 3 opcodes" final int OP_bkpt = 0x01;
Code: [Select]
Code: [Select]
Code: [Select]
Code: [Select]
Code: [Select]
|
Additional Info
|
I think nop is 02.
|
Additional Info
|
AHH.. thanks KongregateHack!
96 10 00 00 73 63 6f 72 65 00 06 00 00 00 00 00 00 00 00 To This -> 96 0c 00 00 73 63 6f 72 65 00 07 a3 07 64 00 1d 02 02 02 Nevermind it worked perfectly!! now i got a score changer for some random game! Time to program a cheat engine in C++ a very small one for my trainer which finds bytes in memory based on process like iexplore.exe etc.. and changes the score to a value you want |
Additional Info
|
If anyone else would like to dive into this more here are some helpful links I've compiled over time.
Adobe's SWF Specifications http://www.adobe.com/devnet/swf/ You can download the newest spec PDF which lists all the AVM0 bytecode information. SWF File Reference http://www.m2osw.com/swf_alexref.html This can sometimes be easier to read than the above PDF for SWF specific information. AVM2 ByteCode Insturctions (for AS3 games) http://www.anotherbigidea.com/javaswf/avm2/AVM2Instructions.html A good quick reference for AVM2. I wish something like this existed for AVM0. AVM2 is much easier to read, but the use of the constant pool limits what you can do. AVM0 is much more flexible when hacking. AVM2 Constant Pool Viewer http://bluecork.net/cheats/scripts/cpool.py This is a python script I wrote to view constant pool data in AVM2 SWF files. This can make it a lot easier when trying to manipulate bytecode in AS3 games. You can run this in Windows by downloading Cygwin, and installing Python. I messed up on first attempt at programing a zlib decompressor in python for SWF files, so you need to decompress the SWF files with something like SWFTools first until I have time to update it. AMV2 u30 Converter Web: http://bluecork.net/cheats/short.php Script: http://bluecork.net/cheats/scripts/short.py This is a script I wrote to convert u30 hex to an integer, and vice-versa. This is needed for the AMV2 pushshort (0x25) command. |
Additional Info
|
The only time I use wildcards is when the bytecode could potentially change, or you need to find multiple locations that are slighty different. This is usually because of references to the constant pool, but can also be because of if statement offsets, and different values for the same variable. In AVM0 the cpool is just strings, while in AVM2 (AS3) the cpool has been expanded to use strings, ints, uints, doubles, and other stuff not that important for hacking.
Here are some real world examples of what I am talking about. AVM0 Cpool example for the game Bunny Invasion II. You start out with 1000 money. Real code: Code: [Select] money = 1000; Peusdo code and Bytecode: (from Sothink) Code: [Select] //96 07 00 08 07 07 e8 03 00 00 We can break the push down into its segments. 96 = push 07 00 = Size (7 bytes) 08 = Constant Pool 8 (the next byte is the location in the cpool) 07 = Cpool location 07 = 4-byte Integer (the next four bytes are the value) e8 03 00 00 = 1000 If we look at the first seven objects in the cpool we see this. Code: [Select] //88 = Set Constant Pool Notice that money is located in the seventh spot, which coorelates to the '08 07' in the push statement. The reason why this is important is because if you wanted to replace money=1000 with money=100000 you would normally do this. 96 07 00 08 07 07 e8 03 00 00 -> 96 07 00 08 07 07 a0 86 01 00 However if the game was updated, and another variable was added above money=1000, then suddenly money is located in the eight spot in the constant pool instead of seventh. So you would have to change what you're looking for to '96 07 00 08 08 07 e8 03 00 00'. Since we already know that the '08 07' is a reference to the constant pool we can just make the 07 a wildcard, and search for '96 07 00 08 ?? 07 e8 03 00 00'. That way if the game ever gets updated this search will continue to work. The only time we would have to significantly change our search is if the author added enough variables to break the 255 size limit. Then the push would change from using the 08 Cpool 8 command to the 09 Cpool 16 command, which uses two bytes to reference the cpool location. In that case our new search would look like this '96 08 00 09 ?? ?? 07 e8 03 00 00'. This is much more important in AVM2 where every other byte can be a reference to the cpool. For example lets look at Hero's Arms. Let's change the code so that when we pick up a 3 gold coin it is worth much more. Real code: Code: [Select] if (param1 is Coin3) Peusdo code and Bytecode: (this is only for the line 'metaHero.AddGold(3);') Code: [Select] //60 81 02 So lets break this all down. 60 = Get a namespace from the cpool 81 02 = location of object in cpool 24 = Push byte onto stack 03 = 3 4f = Call a function with given namespace referenced in the cpool c9 05 = location of object in cpool 01 = Number of parameters on the stack to send to this function This all makes little sense unless we can read the cpool. Lucky for us Sothink will do that for us, which is why we can see the names of the objects in the peusdo code. Since we know which bytes are cpool locations we can replace those bytes with wildcards to come up with a search of '60 ?? ?? 24 03 4f ?? ?? 01'. Here is where we now run into a limitation with AVM2 hacking. The command '24' only pushes a single singed byte, which has a limited value of 127 (which would be 7F). So we can change the '24 03' to '24 7F', and any coin we pick up with the value of 3 will be worth 127. However the good stuff all costs 5000 gold, and even getting 127 for each coin would still take us too much grinding to get to 5000. So we now have to dip into the cpool to reference a value larger than 127. Instead of using the '24' command we should instead use the '2d' command which pushes a 4 byte int from the cpool. However we have to find out what all the values are in the cpool to know which one to use. Using the handy python script I pasted in an early post we can decode the cpool and see the values for all the ints. I will only paste in the first 16 to save space. Code: [Select] int index count = 804 Okay, so we want to make a coin worth 1800 instead of 3. To do this we would change the '24 03' to '2d 08'. In this case the 08 following the 2d is the location of the int in the cpool, so '2d 0b' would make the coins worth 1210. We can expand our search with another wildcard. Instead of searching for '24 03' we can search for '24 ??' to include all instances of where coins are being added, and not just when a value of 3 is added. This will let us find the bytecode for adding coin values of 10 and 20 as well. The downside of this is that we are now finding 65 results when we only want 3. The reason for this is because we are using so many wildcards that we are finding cases of code unrelated to coin adding. To get around this you can either stop using some wildcards, or expand your searching. The bytecode we are searching for is only a single line of code. If we expand it include the next line that plays a sound we can further refine our search. Code: [Select] Jukebox.instance.PlaySound(HA_SfxFactory.instance.ID_SFX_CASH); The commands 60 and 66 are just reference more cpool objects, and can be wildcarded as well. If we add '60 ?? ??' to the end of our search we get 37 results. Adding '66 ?? ??' gets us down to 8. Adding any more doesn't refine our search any so we can now try adding the code that comes before. Code: [Select] if (param1 is Coin3) This will probably be more sucessful at refining our search because there are less cpool references. This translates out to '60 ?? ?? b3 12 ?? ?? 00'. Adding that before our search reduces our results to three. The full search is now '60 ?? ?? b3 12 ?? ?? 00 60 ?? ?? 24 ?? 4f ?? ?? 01 60 ?? ??'. You can add all the results, and change the '24 ??' to '2d 08'. Now all 3, 10, and 20 valued coins will be worth 1800. It would be easier to just not use wildcards, but using them allows you to keep using the same search if the game gets updated. Instead of using wildcards to make crazy searches you can also use them for just minor tweaks. For example these are the bytecodes for adding 3, 10, and 20 coins. 60 AA 15 B3 12 1F 00 00 60 81 02 24 03 4F C9 05 01 60 A5 01 = 3 60 A7 15 B3 12 1F 00 00 60 81 02 24 0A 4F C9 05 01 60 A5 01 = 10 60 A3 15 B3 12 1F 00 00 60 81 02 24 14 4F C9 05 01 60 A5 01 = 20 You'll notice looking at all of these that there are only a couple bytes different. Just replace those instances where the byte is different with a wildcard to find all three at once. Another problem you may have noticed. Lets say that we don't want our coins to be worth 1800. We want our coins to be worth 5000, but there are no ints with a value of 5000. This is another limitation of AVM2 which is very difficult to get around. One thing you can do is change the value of one of the int objects in the cpool to 5000, and reference it. The problem with doing that is that whatever variable was referencing the value you changed to 5000 will now also be worth 5000, and that can have drastic negitive effects on the game. Every int is also unique, and can be referenced by multiple variables. For example a game has two variables: 'distance=2000' and 'money=2000'. You change the value of the 2000 int to 5000 to start off with more money. The unintended consequence is that distance will now also be set to 5000, and who knows what that will do to the game. Its best just to use an existing cpool object and deal with the fact that it may not be exactly what you want. If you can subtract bytes from somewhere else in the game you can also use pushshort (0x25) instead of pushbyte (0x24) and pushint (0x2D). Pushshort lets you push an unsigned 30 bit value instead of a signed 8 bit value. So where pushbyte was limited to 24 7F for a max value of 127, pushshort can do 25 FF FF FF FF 03 for a max value of 1073741823. The problem with pushshort is that its using Flash's special u30 variable length 30 bit integer. This makes it difficult to properly calculate what you need to use to get the right value without a good understanding of bit calculation. |
Additional Info
|
I wanted to make some comments on the things pkedpker has said now that I've actually had time to read them. He did a really good job opening this discussion up.
Quote from: "pkedpker" so i'm changing This is a case where the SWF spec PDF mentioned in an earlier post comes in very handy. You can break down the push into its parts to better figure out what it is doing and how to alter it. 96 = Push 10 00 = Length of 16 bytes 00 = String follows 73 63 6f 72 65 = 'score' 00 = End of string 06 = Double (the next eight bytes are the value) 00 00 00 00 00 00 00 00 = 0 What you did is change this from a double to a 4 byte integer by changing the 06 to a 07. It would have been easier to just add a new double value in there. Using your example of 6555555 the new bytecode would be this. 96 10 00 00 73 63 6f 72 65 00 06 e8 01 59 41 00 00 00 c0 There are more benefits to this than just making it easier to edit. By changing score from a double to an integer you could potentially break the game if it tries to add points to your score that include a decimal. The game will figure out its trying to add a double into an integer and stop working because of a data type mismatch. The reason why score is a double is probably just to raise the max value, and has nothing to do with decimals. You likely wouldn't run into a problem until the game tried to increase the score past the 4 byte limit of 4,294,967,295. Quote from: "pkedpker" //1d = _setVariable This has more to do with assembly and memory assignment. The 0x96 push command pushes (where it gets its name) the objects in its statement onto the stack. The 0x1d command will then assign whatever is on the stack. 0x96 -> push the string 'score' and the double '0' onto the stack 0x1d -> take the first object on the stack, and assign it as a variable for the second object on the stack http://en.wikipedia.org/wiki/Stack_(data_structure) Quote from: "SWF Spec" ActionSetVariable does the following: For example the push command can be used to push more than two objects onto the stack. You could do this. 96 14 00 07 01 00 00 00 07 02 00 00 00 07 03 00 00 00 07 04 00 00 00 That will push the four integers 1, 2, 3, and 4 onto the stack. It is then the responsibity of other commands to pop those values off the stack to do something with them. AVM2 does away with a push command, and each command will do a push, pop, or whatever on its own. The same command for score=0 as a double in AVM2 would be this. 5e 01 2f 01 68 01 5e = Find property 01 = Location of string in the constant pool (assuming 'score' is located at the first spot) 2f = Push double onto stack 01 = Location of double in the constant pool (assuming '0' is located at the first spot) 68 = Initalize propety 01 = Location of string in the constant pool (this is identical to the 5e 01 location) This is why being able to read the constant pool is so important in AVM2. They've reduced the size of the code to make a flash game take less space and memory, and made it harder to read and alter. For this reason I actually think its easier to use bytecode hacking to change the way the game works, and not to change what certain values are set to. You can easily change values with CE, and don't have to resort to bytecode hacking. The use of encrypted secure variables is causing normal CE hacks to no longer work though. In those cases it is possible to reprogram the game to bypass security checks so that your normal CE hacks start working again. |
Additional Info
|
I noticed that there are "public functions" and "protected functions." What's the difference? Is it not possible to change the code in protected functions?
Also, how do I code for an integer? Or more specifically (if it's any difference), how do I return an integer? Or better yet, is there a guide somewhere for pushing all types of numbers such as integers, double, and floats? |
Additional Info
|
Quote from: "pythag12" I noticed that there are "public functions" and "protected functions." What's the difference? Is it not possible to change the code in protected functions? This has to do with function "visibility" between objects, in object-oriented programming. Look there: http://www.javacoffeebreak.com/faq/faq0002.html It works almost the same way in all object-oriented languages. And you can modify the bytecode of these protected functions. Quote from: "pythag12" Also, how do I code for an integer? Or more specifically (if it's any difference), how do I return an integer?In AVM2, you can use the pushbyte opcode (24), which allows signed integers from 0 to 127, then the returnvalue opcode (48). 24 64 48 : pushbyte 100, return value If you need more than 127 and have enough room, you can do something like this, said you need to return 20.000: 24 64 24 64 c7 24 02 c7 48 (pushbyte 100, pushbyte 100, multiply_i, pushbyte 2, multiply_i, returnvalue) use this instructions reference: http://www.anotherbigidea.com/javaswf/a ... tions.html You can also use the constant pool and the pushint (2d) opcode. Locate in the code a pushint with the value you're looking for, and copy/paste it, or use ignored constant pool reader. There's also a pushshort instruction that uses weird 30 bits integers, that are encoded with a variable number of bytes to save place. Have a look at the U30 definition (begining at line 006) here: http://www.m2osw.com/abc_format.html Quote from: "pythag12" Or better yet, is there a guide somewhere for pushing all types of numbers such as integers, double, and floats? For doubles, in AVM2 I think you will need to use the constant pool and the pushdouble (2f) instruction, and in AVM0, there's a more flexible "_push" (96) statement that allows to push IEEE 754 floating point numbers without using the constant pool, like this: //96 09 00 06 e1 7a 94 3f 7b 14 ae 47 _push 0.02 "e1 7a 94 3f 7b 14 ae 47" means 0.02 you can use this link for converstions between decimal floating point and IEEE 754 representations: http://babbage.cs.qc.cuny.edu/IEEE-754/Decimal.html Links tells me 0.02 is 3F 94 7A E1 47 AE 14 7B in hex. Then I need to reverse the bytes by groups of four, because of the little endian byte order, which results in E1 7A 94 3F 7B 14 AE 47. Same stuff as the above _push statement, see ? There's also this convert_d (75) AVM2 instruction that may allow to push an int on the stack, then convert it to a double. Like 24 0e 75 (pushbyte 15, convert_d) should give you the floating point number 15.0 on the stack. I haven't tested this, however. AFAIK, there's no float data type, use double. Also a double is 64 bits data. So pushing a double on the stack will use 2 stack segments, where an integer uses only one stack segment. So if your function returns an integer, and you push a double before the return, this will mess the stack because the return instruction will only pop the first 32 bits of your 64 bits double, and the program will crash. So make sure to push doubles before calls that will actually need to pop a double from the stack, like before Math.round() or Math.ceil() calls, or wherever the original program uses doubles. About a guide, I think you can find howto's on this forum, but maybe it would be useful to make a summary post about that. Ignored (and other people I'm forgetting here, sorry) made some really good posts earlier on this thread. |
Additional Info
|
here's how to use pushshort (read easy guide at end of post for the quick method):
let's take one instruction from tookie as example: //25 d0 0f _as3_pushshort 2000 and a reminder on how do U30 integers work: Quote from: "http://www.m2osw.com/abc_format.html" U30 - This is a 30 bit integer value encoded with a variable number of bytes to save space. now let's see how it works with your instruction pushshort 2000, I will use this http://www.mathsisfun.com/binary-decima ... erter.html hex-dec-binary converter 25 is pushshort opcode, so d0 0f means 2000 Code: [Select] d0 0f Now, the U30 definition says: "Each bit in a byte contributes 7 bits to the value, with the hi bit tellingus whether to use the next byte, or if this is the last byte for the value." So I remove each first bit of my two 8-bit blocks: (1)1010000 (0)0001111 Then, I reverse them because of the little-endian byte order, and convert them back to decimal 0001111 1010000 = 2000 I find back the 2000 of pushshort 2000 instruction. Now, we don't want to replace this with an integer that will take more than 2 bytes to represent, as these U30 integers are variable length. So, let's see what is the biggest value I can push with pushshort and 2 encoding bytes for my U30. This will be: 1 everywhere, except the first bit of the second byte, because remember, the hi-bit only tells us "whether to use the next byte, or if this is the last byte for the value." So, the first bit of my second byte has to be 0, because it's the last byte for the value: 11111111 01111111 that translates to: FF 7F which is in decimal: 11111111 01111111 (FF 7F) 1111111 1111111 (removed first bits) 1111111 1111111 (inverted for little-endian byte order, yeah it looks same) 16383 (decimal) So maximum pushshort with only 2 bytes for the U30 integer is //25 ff 7f _as3_pushshort 16383 easy guide to pushshort instruction: Use a converter like this: http://www.mathsisfun.com/binary-decima ... erter.html I want to pushshort 32571:
Integer range reminders according to number of encoding U30 bytes. Knowing the value you want to push, this tells you how many bytes you will need to encode your integer. 1 byte: 0 -> 127 2 bytes: 128 -> 16.383 3 bytes: 16.384 -> 2.097.151 4 bytes: 2.097.152 -> 268.435.455 5 bytes: 268.435.456 -> 1.073.741.823 |
Additional Info
|
I finally got around to converting my cpool dumper python script into a generic u30 converter, and turned it into a PHP/Python web page that anyone can use. If you notice something wrong with it send me a message, as I don't follow this thread much.
http://bluecork.net/cheats/short.php This is useful if you want to do something like modifying the following code to divide your time by 2000 instead of 1000. You would just change the 25 e8 07 to 25 d0 0f. You'll note that normally the hex for 1000 and 2000 are e8 03 and d0 07 which is why a new converter is needed for these pushshort functions. Code: [Select] //46 99 06 00 |
Additional Info
|
[hr:1x22rnds][/hr:1x22rnds]Changing strings in a swf's constant pool[hr:1x22rnds][/hr:1x22rnds]
Maybe I should post this in the "introduction to bytecode hacking" thread. :O Click the numbers at the left for images. 1. I used this download link for the program. You need java to be able to open the .jar file. 2. In the program, open a swf file. I chose Colony (it needs to be downloaded to your computer). 3. Click "read tags" and "read doABC". 4. At the top, go to Edit > doABC > cpool_info. 5. Click "names" in the window that pops up 6. Click "string_info", choose your string to modify, type the new string in the textbox and click "replace". 7. Save the modified file. Perhaps a major problem here is that it's sort of difficult to find the desired string in the really long list. Maybe an option is not to find the old string and replace it, instead add a new one to the constant pool, but after it's added I'm not sure how to push that new string lol. Maybe someone could help here? |
Additional Info
|
I was looking for an AS3 disassembler and ended up stumbling up on this AVM2 Disassembler. I think it might be useful in association with AS3 bytecode hacking, but I haven't tested it yet (it's downloaded though (broken image removed)).
P.S: It's not only a disassembler. All the features are written on the very same page I provided. P.S.S: It can only disassemble AS3, which covers the void space that flasm doesn't cover (broken image removed) |
Additional Info
|
How do I look at the constant pool in Sothink?
|
Additional Info
|
In AS2, the constant pool is presented to you in the Bytecode. You'll know it when you see it because...the P-code has the words constant pool in it. And it's gigantic.
In AS3, SoThink isn't enough. |
Additional Info
|
What about AS3?
|