Lists and Pointers

Team CMP
This tutorial touches more deeply on movie/sound/image swaping. i briefly touched on this last tutorial i wrote, but its not necessary that you read that... this tutorial will cover it all.

ok, firstly you need to know about labels (which by now im sure you do). labels pretty much tell the ps2 which image, sound and/or movie to load (among other things). they are loaded a certain way because the MIPS code cant simply put in an exact address in one line of code... luckily, its really easy (both to understand, and to program/hack). it is recommended that you read the 'MIPS' tutorial (or at least make sure you know a little MIPS already) before you read this tutorial.
first lets go over how MIPS calls a specific address. as stated in the above paragraph, you cant give one line of code a single command to load an entire address to load from, it MUST be broken up into two lines of code. heres how it works.
first, it loads the first four digits of the address. the command to do this is 'lui' or 'load upper immediate'. when you give this command, you also give a four digit value just as though you were doing an 'ori' (inclusive-OR immediate) command. the only difference between 'lui' and 'ori' is that lui stores the four digit value in the first four digits of the value in a register instead of the last four digits of the value. after youve done this, you can load the last four digits with another command to finish off the address... you can also use the second command to load or store directly because you pass the offset value along with the rest of the command. and example of this would be:
lui v0, $0030
sb v1, $bb68(v0)
what these two lines of code do is:
the first line loads 0030 into the register v0. then second line would store the value thats in v1 at the address 002FBB68. why 002F instead of 0030??? think of it this way, it will store the given register at the address identified by the offset to the highest range. in other words, 002FBB68 is the highest address that ends in BB68 without going higher that 00300000. also remember that this is an example of using an offset to do a command. you can also load the other half of an address into the last half of the first register... like this:
lui v0, $0030
ori v0, v0, $bb68
this code, however, should store the address 0030BB68 in the register v0. why??? because its not asking to find an address, its simply adding a number. the first line loads 0030 into the first half of v0 (so it would be holding 00300000). and the second line ori's the value BB68 with 00300000. also pay attention to the register usage, i catch the result of dealing with v0 in v0... in other words you can compare whats already in a register, get a different value, and catch it in the same register.
so, you have two options, you can either load 0030 into the first half of the value in a register, and use an offset to directly store or load from an address... or you can load 002F in a register, then add your offset to the last half of the same register to get the same address. in fact, the first option is usually used because the value in the register doesnt change, thus you can do this:
lui v0, $0030
sb v1, $bb68(v0)
sb v1, $bb6c(v0)
which would store the value in register v1 at addresses 002FBB68 and 002FBB6C... the end result would be that you have stored the exact same value in two consecutive addresses.

ok, now for the fun stuff... the meat 'n 'tators of this tutorial. now that you know how addresses work in MIPS, lets get on to how to swap/redirect/tell MIPS what the heck to do with movies/images/sounds.
first, open up your PS2dis and load up your SR2 (Soul Reaver 2) slus file, invoke the analyzer and LETS START HACKIN'.
FIRST, go to this address: 0023b9f8. notice how there are a bunch (seven to be exact)of referrals to labels called 'demo1, 2, 3, etc.'??? this is called a list... its a series of labels (actually pointers because its an address that goes to another address where the actual label is located), but only the top pointer is referred to. the way these work is as follows:
the code that calls on the list keeps a value stored at some address... the value at this address is adjusted as needed, so when the code is ready to use the list, it loads the value from that address and counts down the list as many times as the value says. in this case in SR2, its for demos... so it plays the first demo, increments the value by one, if the value is not too large it stores it at a certain address, if it is too large it stores zero at that address and begins playing the demos in their correct order once again... if that value exceeds the number of demos, the game will freeze because it will try to load a demo that isnt there.
also, to make it easy for you guys, the address that holds the value for this list is the address directly above the list: 0023B9F4.
go to the top of the list and select the line (the address is 0023b9f8) and push F3. you should now be at address 0010eff8. now lets look at all of the code that is relevant in this process:

0010eff0 lw v1, $b9f4(s0)
0010eff4 lui v0, $0024
0010eff8 addiu v0, v0, $b9f8
0010f014 lw v0, $b9f4(s0)
0010f018 addiu v0, v0, $0001
0010f01c sltiu v1, v0, $0006
0010f020 bne v1, zero, $0010f02c
0010f024 sw v0, $b9f4(s0)
0010f028 sw zero, $b9f4(s0)

thats the relevant addresses and their commands. heres exactly whats happening (from top address down). first, it loads the value from 0023b9f4 into register v1 (this is the offset, it tells the game how many addresses to count down from the top of the list).
the second line loads 0024 into the first four (usually called the 'upper half', hence the 'load upper immediate' name) digits of register v0.
thirdly, we have the line that calls the actually demo.
now, the fourth line in the above code isnt in order... notice the address, i skipped a few lines of code from the slus file because they were not relevant to what i am talking about... anyway back to the code.
the fourth line reloads the current demo offset value (because the register is used in the lines that i skipped between the 3rd and 4th lines).
the fifth line adds one to the demo offset.
the sixth line is very important (from here on is what determines if the game crashes in the normal game). the sixth line uses a 'sltiu' ('store if less than immediate unsigned', forget about the unsigned part... all you need to know is that slt/slti means that it sets the register to 1 if the given register is less than the comparison value) command to determine if the new demo offset is greater than the number of demos. the 'immediate' part makes it so that you can give a $XXXX value (where X is any hex value), and test it with the value in a register. heres exactly whats happening:
if the new demo offset (because we added one to it the line before) which is held in register v0 is less than 6 (or $0006) then set the value in register v1 to 1, otherwise set v1 to zero... the 1 (or 0 if the offset was equal to or greater than 6) in register v1 is used for testing, which is exactly why this technique is used.
ok, now we are at line seven. line seven is a 'bne' or 'branch if not equal'... we test v1 with zero because the last line of code ensures that if the new demo offset is greater than the number of demos, v1 will be set to zero and if its less than or equal to the number of demos, it sets v1 to 1. now, we 'branch if v1 is NOT equal to zero'. this means that if the offset is not greater than the number of demos, we WILL branch.
line eight lies in line sevens 'dely slot'. because of the way MIPS works, the line after a jump or branch is executed as well, and the program/game will actually jump AFTER the next line has been executed. so the eighth line is ALWAYS executed. what it does is it stores the value held in v1 to the address that holds the demo offset. so if the game branches at the seventh line, it still stores v1 at the address so it can be called on and used later.
line nine (the final line in the above code) stores zero at the demo offset address. it may seem weird that the game would store v1 at the address, then go and store zero at the exact same place... but remember that the eighth line ONLY matters when the game branches, otherwise it will be written over by zero so that the game can call on the offset again starting from zero, and start playing the demos over again.

there are a few things you can do to manipulate the order of demo play.
one, you can edit the code at address 0010f018. you can NOP it out, make it add 2, 3, 4, etc... whatever. this edits how many the offset is incremented by thus altering the normal 'add one' routine.
TWO, we can go straight to the address where the offset is stored an make it constantly write it as something different. in other words: 0023b9f4 00000002 is a code in and of itself. what this would do is ensure that that offset is ALWAYS loaded to count down that many times through the list to load the desired demo to be played... tho if this is set too high, the game will crash when it tries to load the demo.
3, we can go straight to the list and tell the different pointers to call on different videos. not only can this be used to resort the normal order of demos played, you can also switch them out with other videos in the game at which time when the pointer is called, it will play the game video instead of the demo... all thats required to do this is the other videos address.
four, you can make the seventh line NEVER branch by making its command 'bne zero, zero' (i didnt put number of addresses to jump on the end of the command cuz it can be ANYTHING... itll NEVER jump). doing this will make it always reset the offset to zero, thus the game will always play the first demo.
five, you can mix a couple of the options. for instance, you can switch demo pointer 2's label with another videos label, AND set the offset address to always hold 1. this will ensure that the game always steps one down from the top of the list, and calls the MODed video everytime (or combine options 3 and 4, this will achieve the same goal).

this can be done with ANY list wether it be for images, videos or sounds (you can even do this with actual game play animations in some games, BO2 is an example of that kind of game). all it requires is that you examine the code and find out how it works... which is the very essance of hacking itself =)
now you should be ready to find those lists and RRRIIIIIIPP 'em to shreds with your sup3r 133t h/\xor ski11z... what're you waitin' for??? get to hackin.