MGAMERZ' SUPER LONG AND TECHNICAL ASM MODDING TUTORIAL FOR MMBN3

PART 2: HOOKING IS DONE, SEE THE SECOND POST.

MMBN3 White (US) game - I'll leave it up to you to get one

No$GBA Debugging Version - For debugging. You'll be spending almost all of your time here. It's definitely not as user friendly as VBA but it has a lot more debugging power.

VisualBoy Advance - For cheat searching, since No$GBA doesn't seem to have one. I use 1.7 RR, but there's also a developer edition called SDL. You also need to use this if you want to import a gameshark snapshot into no$GBA as it does not work with any sort of saves you can get from GameFAQs

Thumb Instruction Set Reference - You'll use this a lot to figure out what each instruction does until you learn it

Google - seriously, you will have to google a lot cause sometimes the reference isn't very useful in its description of an instruction (e.g. it does not tell you what the condition register does)

Some understanding of C (or at least another programming language)

[MODDING THE HP CHANGE SPEED]

Code: Select all bl 0x080AB56 mov r1, 02007346h swi 6 ldr r0,0805A66Bh mov r2,3h mul r1,r2 add r0,r0,r1 ldrb r3, [r0,2h] ldrb r1, [r0,1h] ldrb r0, [r0,0h] ldrb r2,[r5,16h] pop r15

[Time to debug]

[Breakpoints]

Code: Select all Address - Will break when r15 = Address (when the game is about to execute code at this address) [Address]? - Will break when anything reads memory from this address [Address]! - Will break when anything writes to this memory address, only if new data is different from existing [Address]!! - Will break when anything writes to this memory address [Address]=Hex Value = Break when this memory address equals some value. This only works with bytes.

[GBA ASSEMBLY]

[Tracing and backtracing]

after

[Tracing the method that modified our HP display]

[BACKTRACING FOR OUR DISPLAYED HP MODIFIER]

[THE POWER OF 2]

!! !!

!! !!

[CHANGING THE VALUE FOR TESTING]

Get ready to hook up

This guide will show you how to write a basic ASM mod for Megaman Battle Network 3 White (US). The skills you will learn/use in this guide can apply to just about any other ASM modding you do, be it on GBA, x86, etc.These tutorials will show you how to:1. Make the HP display change faster, so you can more quickly know your true HP2. Change what chip Gutsman will use instead of Z-Punch - pick a random chip from a pool we makeTo follow this guide you'll need a lot of patience -(and can be very frustrating at times!) you are literally reverse engineering machine code. You will have to figure out what you are looking at using context clues, and information that you, as the human behind the wheel, know. This first intro post has tons of technical data that will be super useful later.Some things you will need:This guide will assume you know at least some programming concepts like loops and methods.For the first part of this guide, we will be modifying how fast the HP displayed in the top right of battle changes. This is a simple start to ASM modding.ASM stands for assembly, which is a human readable form of machine code. Machine code is the classic 0's and 1's that the processor reads and does different things with. Assembly looks like the following; and get used to it, you'll be seeing tons of it:You can tell what that does right? You can't? Join the club. It's up to you to figure out what stuff like that means, using only context clues. ASM modding means we are going to be changing some existing assembly code in the game as well as possibly writing totally new code. In this example we won't need to write new code, just modify existing code.Load up your MMBN3 game into both No$GBA and VBA. We will start with VBA, as we need to find something that will point us in the right direction. But first you will need to ask yourself some questions:1. How does the HP counter work?2. What changes the HP counter?With ASM modding you will have to ask questions like this in order to find memory addresses that are relevant to what you want to do. In this instance, we have some answers:1. The HP counter changes by 2 every frame to until it matches your current real HP.2. A difference in your actual HP and the displayed HP.From this we can already tell there are two actual HP values, the displayed one, and the actual one. Since this is the display, we don't really care about our actual HP, since many other things will be able to change your actual HP.To find this address we do a cheat search in VBA. Get into a battle, and note your current HP. In this example, mine is 780. Go to Cheats -> Ram Search. Your current HP and displayed HP must be stored in RAM somewhere or the game wouldn't know your current and displayed HP.You will see a window similar to this.Make sure you have reset your search, then enter your current HP into the specific value field. You will need to set it to 2 bytes, as your HP can go up higher than a single byte (255). When searching for other pieces of memory, it is important that you search for the correct datasize - you may need to guess on your searches. Using the cheat search is almost always going to be your entry into new code territory - you will find addresses for memory, and then you will figure out what sets those values. (For example, what controls your X and Y position on the field). Press search, and you will notice that the list now only has memory addresses that have the same value as your HP stored at them.Have Megaman get hit and lose HP. Wait for your counter to stop changing. Search for the new HP value (do not reset!) The list should become smaller. Depending on your HP, you may need to do this a few times. In my case, I had to do it only once to get two results.If we look at the number of changes to these pieces of memory, we can easily tell one of these is our actual HP value, and the other is the displayed HP value. The actual HP value won't change anywhere near as much as the counter (unless we take constant damage or have healing like geddon or grass on grass). The address for the current displayed HP is what we need - note this address down -as you will make mistakes that crash the game, requiring a reload, and if you lose the address you have to find it again. Document everything, it will help save you tons of time. For future reference, Megaman's HP is stored at 0x02037294 and his displayed memory is stored at 0x0203F888.By selecting your address and clicking 'add cheat' you can create a cheat that will constantly set the value at that address to something. This can be sometimes useful if you want to figure out what a specific address does. For example, you can make something have a constant HP, which is really useful when trying to analyze an AI as it performs.We can put VBA in the background as we won't need it again for now. Now we will go into No$GBA, get into a battle, and watch the memory address we found.no$GBA's debugger is definitely behind VBA in terms of user friendlyness, and it's easy to accidentally open modal dialogs. We will use nearly all parts of the UI (I don't use the mini game display, I use a popout one scaled up). Note that you cannot seem to make the window wider - it's very annoying, but you'll just have to deal with it.NOTE: The popout game window will continue to play UNTIL you bring the debugging window focus. If you click the mini game window, it will also start playing. You must minimize the game window, and then minimize the debugger (not vice versa) or the game won't pause.Click on the memory view area(press tab if you are in breakpoint list) to bring it in focus - you need to have the panel you want in focus or you can't perform keyboard shortcuts on it. Press Ctrl+G (goto) and paste in the memory address you found in VBA, and press enter. You will (physically) watch this value to make sure it is the correct one. Take some hits, watch it change constantly until your HP stops changing in game. You should be confident that this is what you are looking for. You can skip this step if you already validated it using VBA's memory viewer.At this point we know where our display is stored... but what writes those values to this spot in memory? Now we need. Breakpoints will pause the game when a certain condition is met (something is reading this memory, something is writing this memory, something is writing something NEW to this memory (vs the same data), the program counter has reached this address, etc). When the game pauses at this breakpoint, we will see where the code is that is writing to the memory, as well as some info about the current state of the registers. I'll refer to these as breaks, and the UI will show them as BRK in the disassembly. We want to know what is writing to this address, as whatever writes here is probably updating the display.We also only care about what writes NEW values to this address - some things constantly write a value to memory, but most times the only thing we care about is what's writing something different - a changed HP to display. I highly, highly suggest reading the documentation on breakpoints for no$GBA - you will spend tons of time slowly advancing the game frame-by-frame (or multiple times per frame) trying to sift out the junk you don't care about. You can find this in the help menu.For this guide, I'll post the basic breakpoint syntax you should know.For finding what is writing updated counter values to this address, we will be using the [Address]! option, so we put inas the breakpoint value. Your breakpoint panel should now look like this:Now when we take some damage, and the game should pause. If you load a battle it will also pause as your HP is set - just click the game window again to continue execution.Before we start tracing code though, you need to know a some stuff about the GBAs processor, because tracing will involve quite a bit of it.The GBA has an ARM7 processor, which can run instructions in two modes, ARM (more advanced) and THUMB(v1, more simple). All of our assembly work will be in THUMB mode. If you are working on another game you may need to work with ARM mode.When you pause the game sometimes all the instructions will look foreign, this means it is in ARM mode (the instructions will look much more complicated). Breakpoints being triggered in ARM mode that were set while the game was paused in THUMB mode can essentially crash the emulated GBA, so be prepared to restart the GBA (CTRL+R in the debugger) and use lots of save states (F7 in game window = load, F8 = save). Savestates will also let you rewind time, so abuse them as necessary.THUMB mode is activated when jumping to an address using the Branch and Exchange (bx) instruction that has the least significant bit set(value of 1). Essentially, this means if you branch to an address that is odd, it will subtract one, and start executing at that address in THUMB mode. The same goes for ARM mode, just use an even address instead.Processors (aka, a CPU) accesses and works with data directly using registers, and works indirectly with data by shuffling it to and from memory. This typically means RAM, but for the GBA it also includes the game (as it is "memory mapped" - you can directly read data just like RAM from it. You can also directly write to the address space for hardware, such as the sound chip). Here's a diagram showing a processor and memory.Memory on a processor is very expensive (in both money and usable space), which is why RAM exists - a much cheaper (and slower) solution.For all intents and purposes, you will be reading and writing memory into the 020XXXXX block and reading game from the 08XXXXXX block. You may also use the stack (03000000 block) through push and pop on the stack pointer register, and infrequently by directly allocating stack items and modifying items in the stack that are not on top.To process data in the processor data must be loaded from memory into the registers. Registers contain a single 32-bit value. These are denoted by rX where X is a number. In assembly, the GBA can access r0 through r15. There are some additional registers that exist but can't be read directly.Best practices show that:are considered "working" registers, and become dirty as time goes on. A cmp instruction will load r0 and r1 for comparisons, and then branch to another piece of code. You should not assume the current r0 and r1 are what you want when being passed into your function. You will need to leverage the stack to save the values of registers and restore them as needed. At the same time, r0-r4 are commonly used as parameter registers too, so careful management of these is a must.are considered "variable" registers, and are typically set when passing data into a routine. These can be thought of as method arguments for the most part. Most times they shouldn't change until the method they are used in is completed, but as usual, this is not always the case. For example, r5 typically points to memory of the "self" object for an instance. If there are 2 gutsmans on the field, when the AI next-move routine is run on each of them, r5 will point to their own memory space. It does not change for the entire next-move routine, which has many, many subroutines.In my short time with GBA assembly, I have never seen r9-r11 used for anything. However, Prof9 tells me that in the BN seriespoints to a table of global memory addresses. He didn't elaborate on what that meant though...If you have worked with a object oriented language like Java or Python, this may seem strange to you. C is not object oriented, so each function must have a defined reference to some piece of memory that a method will operate on (to make it seem object oriented). Object oriented languages do all this work for you behind the scenes.is the stack pointer.. You should pretty much always use sp instead since it is more descriptive and is in line with the C compiler's output.is the link pointer. It points to the next instruction that should be executed after the current subroutine is completed. You will use this extensively. When calling a branch and link instruction (bl), this will automatically be updated to point to the instruction directly following the branch statement. Many times r14 is simply moved onto r15 to tell the processor what to read next. Other times it is pushed onto the stack, and then popped off later onto r15. This first method is used more if there are no subroutines for the current block of code.is the program counter. You may also see this referred to as PC (not in assembly however). It points to the next instruction that will be executed. Sometimes you will modify this, but you rarely will write an address directly into it. Doing so without properly managing the stack will bust your game. The branch commands will modify this to tell the processor what to do next.is the conditional code register. I don't think you can directly read or write this, but some instructions will read and write to it. For example, you can compare two registers' values with cmp and cspr will be updated with the correct bits (carry out, greater than or zero etc).Note that most GBA games were written in C, or so I've read. As such some code will be optimized by the compiler, which makes it harder to read as a human. For example, instead of loading two values and then 2 pushes onto the stack, the stack pointer may be adjusted so it acts like it has two more items followed by storing 2 times to sp and sp + 0x4. This saves 1 instruction. Battle Network 3 seems to be a mix of them both, as I have found some bugs in the code (not trigger-able in normal gameplay) that would not have been generated by a compiler output.The stack is a last in - first out system. It's a simple concept, as shown below.The stack for the GBA is comprised of 32-bit numbers (a word). There are no bytes or halfwords on the stack. If you need to push those onto the stack, it will be pushed as a word.Management of the stack however, can be a real pain, especially if you are bolting on your own code that will modify the stack.The stack is used to temporarily store values for safe keeping, like where to return to after you are done executing a block of code (this is known as a frame pointer), or if you need to save the values currently in a register because a subroutine will modify them.Management of the stack is critical - if you modify the stack in your code and then return control to the vanilla game without removing your stack items (unless done intentionally) the game will likely attempt to jump to an unknown address and will crash. The same issue happens if you pop too many, or accidentally modify a stack item. It's practically guaranteed to crash, but it may not crash until enough pops are done to a point where a value is needed that is invalid. This makes figuring out the issue confusing.The stack is managed with the push and pop instructions, and occasionally storing/loading data from offsets of the current stack pointer. As you push and pop items, the stack pointer register will automatically update to point to the item on the top of the stack. In very rare instances the stack will be managed by code (e.g. allocating many items onto the stack). This code is typically very complicated and most times won't be worth your time to analyze.Got all that? No? You'll learn it as you trace execution of programs. It will take some time (and will vary depending on your computer science knowledge) for it to start making sense.Upon taking damage your game should pause and the debugging view will update. You should see something very similar to the following, at the same position.The breakpoint condition of something writing to this address has been reached. That means something has already written to memory, rather than is about to write - this is important to remember. The debugger can't tell if a read or write is about to occur, only that one already has.This is indicated in the disassembly panel with the little black box on the left - the box indicates that the instruction on that line is about to be executed. As such, the display value has already been stored to memory with the strh command (store register halfword) one line above.You need to use the Trace button in no$GBA to advance the processor through one instruction. You can also use the Run Next to advance the program counter, but skip going into subroutines (bl statements). This can save you a lot of time if used properly.How you choose to trace is up to you, but I'll show you my method. At this point I would write this address down that is storing the halfword and label it as something like "PlayerHPCounterUpdate" or something - if you delete a breakpoint, you have to trace again to find it sometimes, as you can't just 'disable' breakpoints, only delete them. Very annoying really. If you want to return to a breakpoint just double click it in the breakpoint list.We want to check to see if something else is writing to this address - maybe the counter is updated two or three times per frame? Click on the game window to continue execution - it may stop in 1 frame, so it will be very quick. I typically cycle a few frames to get a feeling of what's calling my breakpoint - every frame? Multiple times by frame? Only one time? This is useful information to know.Click on the strh instruction until the line turns red, and the right side has BRK on it. This a breakpoint that will be executed when r15 (the program counter) is equal to it - which means it will pause right before it executes that instruction. This is very useful because you can edit the registers in no$GBA by right clicking and selecting "Change Value". It lets you quickly test what happens if code uses different data.When you run the game again, it should now pause at this instruction. Note our old breakpoint only triggered on writing of new data - this may be hit every frame as we are not conditionally stopping on new data. This is where you may consider a conditional breakpoint (not in this tutorial, however).At this point you should whip out your THUMB instruction set book and look for strh. It will tell you what it does. Go ahead, I suggest you look it up yourself and come back here when you're done.... got it? Maybe? STRH is store halfword. Your HP Display value is 2 bytes, a halfword, and it is being stored to memory. The r0 is the register that is being stored, and the items in the brackets [ ] are where it is being stored. Double items in brackets means offset - so it is storing r0 to the address stored in r5, offset by 18h - 18h is another way of writing 0x18. Sometimes you will see #0x18, it's pretty much all the same.While not totally necessary, while learning (and debugging) I find it useful to manually calculate these values. After a while you will learn thatthe instruction executes, if you click on the instruction you can see in the bottom left corner of no$GBA what that instruction did, in the form of [ADDRESS]=Value.Looking at the above disassembly, directly above this strh is is a mov r0, 0h command. This loads register 0 with a value of 0. But... that can't be right? That means it would be storing a value of 0 to our HP display, which is not the case! And you'd be correct - if you set a breakpoint on that position, it won't be reached. The program counter is being updated and its jumping over this statement, and going right to the strh. This is done through a branch statement. I'll talk about those in a moment.Right now we are stuck. We don't know what got us here. The statements right above aren't executed, but we have no idea how far the branch that got us here is from here. But something earlier I said is important - r14 is the link register, the next instruction that will be run after the subroutine ends. This value is used in two different ways - moving r14 onto r15 (mov r14, r15), or popping r14 off the stack and placing it onto r14 (pop r15). Looking below our breakpoint, we can see a pop r15 (note that due to branching there can be multiple exit points from a function! Or branches from multiple code paths to a single pop r15!), so that would be a good place to trace.This one is close so we could simply press trace a few times until we reach it... except there is a bl statement right after this - executing a subroutine, which if we trace into can take a long time to get out of - and may not even be relevant (on the other hand, it could be short, or very relevant in context!)We can go about this a ways:1. Set a breakpoint after the bl statement and trace it until execution exits the routine2. Goto what's in r14. I typically just do CTRL+G and then type in r14, and it will go to the value in r14. When you do this, you may need to push the up arrow one time because the address is odd (THUMB mode).3. Just mash Run Next to skip branch and link commands (they will still run, but you won't trace into them). This option is useful if you don't see the exit point and don't have a good value for r144. Check the stack. It may be a few items deep. I only do this method if it's life and death for my trace.You can identify the start of a routine by finding a push r14 line - this pushes the updated link register onto the stack, and will be popped at the end of the routine.Going to the value of r14 takes us to the next instruction after a branch and link.So now we know where the call to the start of the function that edits our HP is. Put a breakpoint on it by clicking it until its red, and then run the game until it breaks there.Below is a list of some branch instructions - not all of them. Use your THUMB instruction set reference for more information, and make sure to google it too if you need more info. Note that due to size limitations of THUMB instructions, most of these cannot jump across the whole game. If your game is expanded, you will have to use bx to jump large distances as they cannot be represented in the 12 usable bits.Unconditional branch. Literally go to the listed address, and that's it.Branch and Link. This jumps to an address and will update r14 for you. This is used to call a subroutine.Branch if not equal. Require a previous instruction to set the condition register, like cmp or tst. tst is a logical AND, and if two registers are being tested against each other (tst r0, r0 for example), it is testing if any bits are set (non-zero)Branch if equal. The same as above, but the result must be zero.Branch if less than/less than or equal to. You can probably guess what this does. Code directly following this is for not less than/not less than or equal to.Branch if greater than/greater than or equal to. You can probably guess what this does. Code directly following this is for not greater than/not greater than or equal to.Branch and Exchange. This lets you jump far distances and change the operating mode of the processor between THUMB and ARM. You may have to use this for hooking if you expand your game. Loading an address and then calling this instruction take up much more space than normal instructions, so you must carefully plant your hooks. I talk about hooks in the next tutorial.Now that we are at the branch and link statement that goes into our HP update routine, we should make note of this address and trace into it. This will take us to the start of the routine.It may be wise to also identify where our HP Display memory is modified so we have an idea of where we are eventually going. I like to set a breakpoint on that as well so it's easier to spot. As a reminder this is at 0x0800FC7E with an instruction of strh r0[r5,18h]. r0 will be our display value, so we need to find out what's setting up the r0 right before that strh is called - note that if you just pick the first r0 you find while tracing, it may not be the right one as once the value is stored, the program no longer cares about the value in the register, since there's a copy in memory.We need to find something that sets r0 and the strh's it. Something that will speed this up greatly is that we know the value of how much HP changes per frame - 2. So somewhere our HP Display will likely be read (it may have been already, or put onto the stack), a value of 2 will be subtracted or added, and then it will be stored back to memory. Our strh target is a good distance away, so we'll do a quick skim for some instruction that directly puts a 2 in r0... however in this function, you won't find any. Somewhere else a 2 is being put into r0. We may consider backtracing at this point, figuring out what leads to our strh, rather than keeping track of every time r0 is loaded - as it is a dirty register, it gets around a lot.At this point, I suggest one of two things:1. Manually trace until you hit the strh and figure out what jumped you there2. Find a branch statement that lists that strh as the jump target.Tracing the entire method yields no results. We pop back out to where r14 told us to go earlier. We never hit the strh instruction. Mgamerz, what gives!?Before I answer, keep tracing a few more times past this bl statement.While writing this guide, I learned something - if you perform bl, r14 is updated. Between the instruction after this bl (where r14 points) and our strh, there are no more subroutines. As such, r14 never got updated again. So the one we went to earlier actually went to the previous subroutine! You're literally navigating a maze.... and as such, we have now learned something: Between this bl statement and our strh, r0 is never modified as there are no subroutines and we obviously don't see any r0's here except our strh. This can only mean that that subroutine loaded r0 somewhere near the end, and then exited, and the code continued and eventually used the existing r0 - so we now have to find r0 in this subroutine. I would suggest going to the end and working up - setting breakpoints every time you see something with r0 as a first parameter that is not a store. (e.g. mul r0, r1, add r0, r1, r1, mov r0, 2h etc).As a side note it is technically possible that r0 is set up before this subroutine, saved, and then popped, or never modified at all, but as it is the first register that is pretty unlikely.We will backtrace this function like the cyber police.Once you trace back into this function from our breakpoint at the bl statement (or you can just manually goto the listed address using CTRL+G), find the pop r15 that signifies the end. We will look for r0 up from here...and we find that r0 is loaded with r1 at 0x0801EE6. Set a breakpoint on this, and run the program until it is here. We want to see what is in r1 to verify what we are looking at (it should be our next displayed HP)We can see that r0 and r1 have a difference of 2. And r2 has a value of 2 in it! So we're getting really close now - somewhere it is subtracting, or adding a negative 2. We're almost there. Remember, the value we are editing is 2 - we want to make this bigger so more HP changes every frame. We now need to see what sets r1 now. You think this is getting pretty long? Welcome to reverse engineering assembly. It gets easier as you learn, and symbol files you make will make this wayyyy easier. But you have to learn the hard way first.Right above this mov is the reverse mov - put together and both registers will be equal with the value of r0 (r0 becomes r1, and now r1 becomes r0, which is already r1) and right above that we can see a branch greater than that jumps to this address, skipping the first mov. I guess our search continues for r1.... into a comparison, which right above is a subtraction! This is where our display HP appears to change!r1 is our current displayed HP, r2 is how much HP changes, subtract the two and store it into r1 for our new HP value - and right aboe this, we can see where r2 is set - from memory. So we need to figure out what sets this piece of memory we are loading from - it's time to break out a new write breakpoint. It is loading a byte (ldrb) from r5 offset 0x11 - read the value of r5 and add 0x11 and put that as your breakpoint for writing (you may consider any writing to see what is writing to this address - but we will just use on any NEW write).So our hopefully last breakpoint isnow. You will want to remove your other breakpoints as they won't be necessary anymore since we have found the value of 2, we just need to figure out what sets that value. Select them from the list and press delete - leave your new breakpoint.Playing through the rest of your battle will show you that this value is never changed. That's not surprising as your HP always changes by 2 (or 1 if you have less than the changeable amount as a delta). Think about where this value would be set. Game startup? Maybe. Jacking in? Another shot, as your HP can change in the overworld with subchips. I'd say though it's probably when a battle starts. Let's start a new battle and see what happens.We got a hit!But... uh... 2 isn't here? It's setting it to zero?Yep. The game is initializing the battle and is resetting all values. This isn't what we are looking for. We should see if it is written to again, so let's continue execution by clicking on the game window...We got another hit!THERE IT IS! THE VALUE OF 2 IS STORED TO OUR ADDRESS! THIS IS IT! Finally!Now we can FINALLY change this.So we now know where the value is set: 0x08010E22. Curiously this is not a piece of data on the game but program code instead. Now we can change it. For a simple mov instruction where we are changing a hardcoded numeral, it's possible to do this in memory view.Delete all your breakpoints as we no longer need them, and then press Tab to change to memory view. Perform a goto of the address of the mov instruction which I listed just above - this will take you to program machine code. In the above image I show how the small value listed to the right of the address show's the instruction as hex - the 20 here means mov r0 - the way instructions are done in binary is beyond the scope of this tutorial. You may also notice some instructions are larger than 2 bytes, which can cause issues when hooking.This 02 value here is changeable. Just write whatever you want over it in memory view and watch your HP change at different speeds. Alternatively you can right click the mov r0, 2h instruction and click Change Instruction and then write your own assembly in, like mov r0, 0Ah. Take some damage, and now your HP will change faster (or slower!)And that's how you do very basic ASM tracing. This one has tons of technical info. I did not anticipate it being this long either!Want to try your hand at some stuff? Try figuring out how gutsman knows when he can use Z-Punch by him checking his HP/2. (note - lsr by 1 is division by 2 - that's a hint). You can make your life much easier if you load a symbol file for debugging: http://forums.therockmanexezone.com/topic/10006322/1 Hooking is where we insert a branch statement that redirects code execution to our own code. How you write your hooks and where you place them must be done with care!Thanks MegaRockEXE for some work with the images!