Demarest Posted September 30, 2005 Share Posted September 30, 2005 (edited) For those of you that do not remember this, here are page 1 and page 2 of the original topic from Google cache (damn pruning grumble grumble). In my quest to maximize SCM usefulness, I decided I wanted to master this technique too. It's something I've been discussing with CyQ. At the time, he was okay with me digging the topic up. I thought I'd make this public so we can all have fun, especially now that I've made it work in MB. The code I'm about to post is for MB 0.22 and as of right now, the MB you use HAS to support DMA. Note: this is only possible on VC for now and possibly always. You will need to turn scm.ini off in MB by going to the Compiler menu and selecting disable custom IDs. Below is a stripped SCM. I'm sharing the code in this manner becuase since DMA is required and these slots are in use by original code. So this means no compatibility at this time. I've already tried moving the block--I originally tried starting with 0?? and so on and backing the addresses off the same 8 bytes, but the game crashed. Hopefully we will be able to move the block. If so, I will do what I can to incoporate it into savegame compatibility. Don't get your hopes up as I've already been told this isn't possible. I'm just stubborn and have been learning lately that there's no reason to accept no for an answer Anyways, go into your MB folder and open up scm.ini. BACK IT UP FIRST! Add the lines 0124=2,write_mem_address %1d% value %2d%0125=2,read_mem_address %1d% into %2d% and save. These changes won't be usable in MB until the next time you launch it. And now the stripped SCM: DEFINE VERSION VICE 0.220002: jump ��Label008620DEFINE MEMORY 97:Label0086200002: jump ��Label008644DEFINE OBJECTS 1DEFINE OBJECT (no name) \\ This is an unused object. You can put anything here.:Label0086440002: jump ��Label008658DEFINE MISSIONS 0;-------------MAIN---------------:Label008658016A: fade 0? () 0? ms01F0: set_max_wanted_level_to 6?0111: set_wasted_busted_check_to 0? (disabled)00C0: set_current_time 12? 0?0007: [email protected] = -444! \\ floating-point values0007: [email protected] = -486! \\ floating-point values0007: [email protected] = 10! \\ floating-point values04E4: unknown_refresh_game_renderer_at [email protected] [email protected]: set_camera [email protected] [email protected] [email protected]: $MYPLAYER_CHAR = create_player #NULL at [email protected] [email protected] [email protected]: $MYPLAYER_ACTOR = create_emulated_actor_from_player $MYPLAYER_CHAR0001: wait 0? ms01B6: set_weather 0?0352: set_actor $MYPLAYER_ACTOR skin_to "PLAYER"038B: load_requested_models0353: refresh_actor $MYPLAYER_ACTOR016A: fade 1? (back) 1000& ms04BB: select_interiour 0? \\ select render area01B4: set_player $MYPLAYER_CHAR frozen_state 1? (unfrozen)01B7: release_weather004F: create_thread ��LabelMEMHACKING:LabelMAIN30001: wait 5000& ms0002: jump ��LabelMAIN3:LabelMEMHACKING0004: 8?? = -1995422835&&0004: 12?? = 1342335705&&0004: 16?? = -1023575064&&0004: 20?? = 1949868543&&0004: 24?? = 495648893&&0004: 28?? = 8221756&&0004: 32?? = -1070589815&&0004: 36?? = 10011777&&0004: 40?? = 1599930368&&0004: 44?? = 79846238&&0004: 48?? = 272862464&&0004: 52?? = 23779721&&0004: 56?? = -44898224&&0004: 60?? = 950140866&&0004: 64?? = -1962902156&&0004: 68?? = 1949868800&&0004: 72?? = 1133314173&&0004: 76?? = 1792641296&&0004: 80?? = 2045267969&&0004: 84?? = 822067963&&0004: 88?? = -1731952192&&0004: 92?? = 1560281088&&0004: 96?? = -1034199457&&0004: 100?? = 4&&03FD: set_player -5035& handling_responsiveness 8524424&&0124: write_mem_address 6850752&& value 8524465&&:LabelMEMHACKINGTRAP0001: wait 5000& ms0002: jump ��LabelMEMHACKINGTRAP Edited September 30, 2005 by Demarest Link to comment Share on other sites More sharing options...
Y_Less Posted September 30, 2005 Share Posted September 30, 2005 As both Dem and I were working on this at the same time, talking as we did it, I have a few pieces of code to demonstrate it (nothing exciting, just some bits to mess up your radar). Add these as threads (note: they both use the same labels, im lazy, so one at once): :Labelmemhack 03A4: name thread "RADAR" 0007: [email protected] = -0.01! \\ floating-point values 0125: read_mem_address 6880572&& value [email protected] :labelmemloop 0001: wait 100? ms 0125: read_mem_address 6880572&& value $radar 005f: $radar += [email protected] \\ floating-point values (never used in VC or GTA 3) 0124: write_mem_address 6880572&& value $radar 00D6: if 0? 0032: 0! >= $radar \\ floating-point values 004D: jump if false ££labelmemloop2 0007: [email protected] = 0.01! \\ floating-point values :labelmemloop2 00D6: if 0? 0036: $radar >= [email protected] \\ floating-point values (never used in VC or GTA 3) 004D: jump if false ££labelmemloop3 0007: [email protected] = -0.01! \\ floating-point values :labelmemloop3 0002: jump ££labelmemloop :Labelmemhack 03A4: name thread "RADAR" 0007: [email protected] = 0.01! \\ floating-point values 0124: write_mem_address 6880572&& value 1000! 0125: read_mem_address 6880552&& value [email protected] :labelmemloop 0001: wait 10? ms 0125: read_mem_address 6880552&& value $radar 0125: read_mem_address 6880564&& value $radar2 005f: $radar += [email protected] \\ floating-point values (never used in VC or GTA 3) 0013: [email protected] *= 200! \\ floating-point values (never used in VC or GTA 3) 005f: $radar2 += [email protected] \\ floating-point values (never used in VC or GTA 3) 0017: [email protected] /= 200! \\ floating-point values (never used in VC or GTA 3) 0124: write_mem_address 6880552&& value $radar 0124: write_mem_address 6880564&& value $radar2 0011: $radar *= 100! \\ floating-point values 008C: [email protected] = float_to_integer $radar 0015: $radar /= 100! \\ floating-point values 01E4: text 1number lowpriority "HJ_IS" [email protected] 2000& ms 1? 00D6: if 0? 8032: 1! >= $radar \\ floating-point values 004D: jump if false ££labelmemloop2 0007: [email protected] = -0.01! \\ floating-point values :labelmemloop2 00D6: if 0? 8036: $radar >= [email protected] \\ floating-point values (never used in VC or GTA 3) 004D: jump if false ££labelmemloop3 0007: [email protected] = 0.01! \\ floating-point values :labelmemloop3 0002: jump ££labelmemloop Link to comment Share on other sites More sharing options...
random_download Posted September 30, 2005 Share Posted September 30, 2005 @0 = 8524416&&@0 += ££[email protected] += <bytesfromlabel>0124: write_mem_address @0 value <code> Would doing that be an easier way to do self-modifying code? Currently I think you store the modifing bit in global vars, then gosub to those, which is a little confusing Link to comment Share on other sites More sharing options...
Y_Less Posted September 30, 2005 Share Posted September 30, 2005 (edited) Yes that would, but self modifying code was sort of developed (by me anyway - apparently CyQ thought of it long ago, but meh, he never released it) before we looked into this. Edit: also note that Mission Builder likes to screw with certain DMA variables (the ones defined at the bottom of vicescm.ini). Dems way around was to rename $player_char (which is ALWAYS (even when custom ids are disabled on DECOMILE) COMPILED to 8??) to $myplayer_char. My way, which I much prefer, but its up to you, is to comment out all the global vars at the end of vicescm.ini (just put a semi-colon ( at the start of every line under "[variables]" (without the double quotes)). Edited September 30, 2005 by Y_Less Link to comment Share on other sites More sharing options...
Demarest Posted September 30, 2005 Author Share Posted September 30, 2005 you store the modifing bit in global vars, then gosub to those, which is a little confusing Nah. MB doesn't allow DMA to anything that's not divisible by 4 and certainly not to anything outside the defined memory. The gosub initially jumps to this command 0084: 61973?? = 96?? ...which MB won't touch. If however you store valued in globals that set the bytes to where it looks like that, MB won't know, the game will execute, and everybody lives happily ever after. Link to comment Share on other sites More sharing options...
Un3462 Posted October 6, 2005 Share Posted October 6, 2005 ok. so. you want to move this around. it's possible, if you can find a block of 24 free variables. you could even split the two opcode handlers apart quite easily, requiring two separate blocks of only 11 and 13 free variables. (someone with x86 asm knowledge and a bit of time, could even optimize it for less variables, and variables which aren't in a single block.) the key in moving them around is keeping the relative addressing and the hooking correct. relative addressing occurs in three places: e8 7b-fd-c2-ff call CollectParameterse8 52-fd-c2-ff call CollectParameterse8 79-fb-c2-ff call StoreParameters so if you want to move all the code 4 bytes higher, you simply need to subtract 4 from those values (they're negative, and you'd want them to point back 4 bytes further). the first one for example (e8 is the call opcode, nearly equivalent to gosub in gta): 7b-fd-c2-ff -> ffc2fd7b -> in wincalc subtract 4 -> ffc2fd77 -> 77-fd-c2-ff, and you're done. when you're done adjusting the addresses, you put all the bytes together again in groups of 4, and convert them to ints, like i did in my original post. then set those in the correct variables. then you change the following: set_player_handling_responsiveness -5035, 8524424; set opcode handler for 0124 at $00000000write_mem 6850752, 8524465; set opcode handler for 0125 at second byte of $0000000a ..by editing those two addresses (second param for each) accordingly. in this example, you'd simply add 4 to both. Link to comment Share on other sites More sharing options...
Y_Less Posted October 6, 2005 Share Posted October 6, 2005 Ahh, I had thought the problem was due to relative addressings (can't you use absolutes for those though?). Link to comment Share on other sites More sharing options...
Un3462 Posted October 6, 2005 Share Posted October 6, 2005 i don't think so, actually (x86 opcodes are confusing). you might be able to do "mov eax, absaddress / call eax". but relative is how gta does calls to near functions, so i just used that. small correction to the above: if you split the opcode handlers apart, you need 14 vars for read_mem. Link to comment Share on other sites More sharing options...
Y_Less Posted October 6, 2005 Share Posted October 6, 2005 (edited) Fair enought then. People interested in this may be interesed in THIS (Im sure CyQ already has something like it, but useful for others. Just enter your HEX string in the top box (with spaces between each byte) and it will generate a load of 32 bit integers for use in your code. I tested it on the start of the code CyQ wrote and it worked fine. One known bug though is that sometimes it adds an extra 0 to the bottom of the list, I know why this is but I can't get rid of it (as you may have entered 00 00 at the end which may end up on a separate needed string, so I cant just not display if the string equals 0 (but thats my problem not yours). Edit: I also displays 8 numbers a line (assuming 1 space between) in IE, but it displays 9 in FF until you fill the box and the scroll bar appears, filling the box slightly, and then it displays 8 correctly, for one of the first times ever I made my code run better on IE than FF (although if I did it right on FF, it would be wrong on IE AND FF if you had too many, so this is actually better, but anyway). Edit 2: I THINK I've solved the random extra 0's problem (I set a variable to tell the code that actual numbers have been processed, not just empty spaces (the error occured when you had trailing spaces after a 4 byte boundary, so there should have been data, but wasn't, therefore no data = 0)). But be careful, if you see it again, please tell me (this way WILL display 0 if the last bits entered are 00s, so should technically have a 0 to enter the data. Edited October 6, 2005 by Y_Less Link to comment Share on other sites More sharing options...
Demarest Posted October 6, 2005 Author Share Posted October 6, 2005 CyQ! I was just about to prod you for this since it had been a bit. Thank you. And now a second can of worms. From what I've seen, I'm assuming that your method HAS to write 4 bytes at a time. And I would also assume that your code was made to do exactly that. Fair enough. Keep in mind that the rest of this post is based on those assumptions being true... I would like a way to be able to write a byte at a time as some memory addresses contain one byte switches/values. I've actually tried a read_mem $var, $var -= 1, write_mem $var and it crashed. I'm assuming that the other 3 bytes I'm involving while trying to change the 1 are the ones crashing either because I'm trying to write to read-onlys or that the data in them move that quickly. Most likely I'm wrong and I'm just implimenting it wrong since mem-hacking is new to me. If this is the case, indulge me if you will for the sake of education/discussion. I've noticed that quite a few on/off options in the pause menu have one byte switches assigned to them. When you consider an opcode such as 02A3 toggle_widescreen $int, I would assume the opcode handler code for it is something along the lines of "write_mem address value" where address is the memory address tied to the widescreen option being on and off. If all of the above is true, I'm assuming we could "borrow" that opcode for single byte writing by use of write_mem (address of 02A3's target address) (one byte address we'd like to write to), toggle_widescreen (0-255), write_mem (address of 02A3's target address) (original value), eh? I apologize if this is ambiguous in any way. Of course if you know of an easier way to write to a single byte at a time, please share. Or if you're certain that the continuous nature of my failed attempt above is in fact my own misapplication, feel free to say so. Link to comment Share on other sites More sharing options...
KennyJ Posted October 7, 2005 Share Posted October 7, 2005 fantastic Link to comment Share on other sites More sharing options...
Un3462 Posted October 7, 2005 Share Posted October 7, 2005 the write-only values are called that because the game will mostly ignore them if you change them, not because it would crash or anything. gta is not multithreaded, so things changing inbetween your opcodes shouldn't be a problem either. so, in theory, your approach should work (as long as the value doesn't over- or underflow). i can sort of see what you're trying to do with the toggle thing, but that really isn't necessary. and indeed, it's possible (likely even, imo) that there's something else you're not quite doing right. it might help to post full code, or some info on the memory value you're trying to manipulate. Link to comment Share on other sites More sharing options...
Y_Less Posted December 29, 2005 Share Posted December 29, 2005 Right, this comes from my masses of work recently (I REALLY should be revising for exams but aren't), I have made this darkpact compatible (I just shifted it over a load of variables only used in mission 0 (this overwrites references to things like pickups but they still work): 0004: 8288?? = -1995422835&&0004: 8292?? = 1342335705&&0004: 8296?? = -1025694744&&0004: 8300?? = 1949868543&&0004: 8304?? = 495648893&&0004: 8308?? = 8221756&&0004: 8312?? = -1070589815&&0004: 8316?? = 10011777&&0004: 8320?? = 1599930368&&0004: 8324?? = 79846238&&0004: 8328?? = 272862464&&0004: 8332?? = 23779721&&0004: 8336?? = -587536304&&0004: 8340?? = 950140866&&0004: 8344?? = -1962902156&&0004: 8348?? = 1949868800&&0004: 8352?? = 1133314173&&0004: 8356?? = 1792641296&&0004: 8360?? = 568872961&&0004: 8364?? = 822067931&&0004: 8368?? = -1731952192&&0004: 8372?? = 1560281088&&0004: 8376?? = -1034199457&&0004: 8380?? = 4&& 03FD: set_player -5035& handling_responsiveness 8532704&&0124: write_mem_address 6850752&& value 8532745&& Thats it, just use that instead of the original. Link to comment Share on other sites More sharing options...
Demarest Posted December 29, 2005 Author Share Posted December 29, 2005 Thank you, sir. I personally wouldn't have reused pickups for good measure, but that's what I get for not getting off my own lazy ass, eh? Link to comment Share on other sites More sharing options...
Y_Less Posted January 3, 2006 Share Posted January 3, 2006 Err, I've been looking through the disassembly of my copy of the 1.1 EXE and unless I'm very much mistaken (i.e. the EXE I have is not 1.1) the pointers for both 0124 and 0125 are at the same point, so there is no problem using this in VC. Link to comment Share on other sites More sharing options...
chaosislife Posted June 19, 2006 Share Posted June 19, 2006 a quick note; the 'page 1' and 'page 2' links are inactive,Perhaps google pruned them as well? Link to comment Share on other sites More sharing options...
Y_Less Posted June 19, 2006 Share Posted June 19, 2006 Hmm, I'll have to see if I have my local copies still and host them somewhere. Link to comment Share on other sites More sharing options...
random_download Posted July 3, 2006 Share Posted July 3, 2006 Is there something that stops you writing to addresses in the opcode jump tables in San Andreas? Writing to one through the scm caused the game to crash, even if the value was the same as the original. Link to comment Share on other sites More sharing options...
Y_Less Posted July 3, 2006 Share Posted July 3, 2006 I don't know, I was experimenting with it before, using some OpCode in the 500s (IIRC) that fell on a boundary in SA but I could never get it to even write the address (and now I don't have a decompiled version of the EXE). Link to comment Share on other sites More sharing options...
random_download Posted July 3, 2006 Share Posted July 3, 2006 I was going for the address 0x466D68 (opcode 0046) by writing -5DBD. Did your game crash when you tried or just didn't write the address? I can't find any reason why it does, the handling_responsiveness opcode does almost exactly the same thing as in VC, as does the CollectParameters function. I have no idea why it doesn't work :s Link to comment Share on other sites More sharing options...
Y_Less Posted September 8, 2006 Share Posted September 8, 2006 Bump. This is an old post from elsewhere but I never finished it and having only just seen randoms post I thought I'd post here in the hope someone better saw it: The offset for OpCode 03FD in SA is: param1*134h+B73458h+74h Based on the code at 489731h (handler for the opcode) but it doesn't seem to work although SA has 'unk_B73458' (unknown type) as opposed to 'word_7DBCB0' so it could be unsigned. The problem is, even when I set the command to set_player 1, which should produce an address of B73600h and set the value to 2, it still appears as 0 in memory. However some positive values seem to correctly modify the correct memory addresses, which leads me to believe the formula is correct, but others don't, and no negative numbers I've tried do. Also, based on that formula, I found OpCode 05DF which is unused and on a correct boundary (using -23414 in the OpCode) and 05E0 which is unused to redirect the read_mem OpCode but when I use -23414, the game crashes. Finally (this is just extra as I've not got this far yet without the game crashing) could someone check my modified ASM for SA style OpCodes please (note the jump at the end goes to what appears to be a common OpCode end for 1500 range OpCodes), I've never done ASM before: Based on CyQs VC write_mem code and existing SA OpCodes:6a 02 push 2; num pars8B CE mov ecx, esi; get ptr to threadstructE8 0f-a7-a1-ff call CollectParmeters; (-6183153)a1 78-3c-a4-00 mov eax, ds:ScriptParams; get address8b 1d 7c-3c-a4-00 mov ebx, ds:ScriptParams+4; get value89 18 mov [eax], ebx; write memE9 0d-91-a4-ff jmp 0x492AA4; end OpCoderead_mem:6a 01 push 1; num pars8B CE mov ecx, esi; get ptr to threadstructE8 f4-a6-a1-ff call CollectParmeters; (-6183180)a1 78-3c-a4-00 mov eax, ds:ScriptParams; get address8b 00 mov eax, [eax]; read mema3 78-3c-a4-00 mov ds:ScriptParams, eax; store value8B CE mov ecx, esi; get ptr to threadstruct6a 01 push 1; num pars50 push eaxE8 ce-a9-a1-ff call StoreParmeters; (-6182450)E9 36-91-a4-ff jmp 0x492AA4; end OpCode Any help would be much appreciated. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now