IMG

 
IMG
IMG   IMG
  Welcome to GTAForums! Be sure to check out the Grand Theft Auto V Forum.

You are not registered! (If you are, click here to login) Registering is fast, free and easy and allows you to instantly reply to any topic on GTAForums.
Why wait? Click here to register your own unique username and become part of the ever-growing community!


( Log In | Register | Revalidate Validation E-mail )
Quick Log-In:
  IMG
       
>
Forum Rules GTA Modification Forums

Please post mod releases in the Mod Showroom

GTAGarage.com
free mod hosting from GTANet, simply login with your GTAForums account details

GTAModding.com
GTANet's modding wiki

GTA Modding Chatroom
provided by irc.gtanet.com (Don't have an IRC client? Click here)


Pages: (3) [1] 2 3   ( Go to first unread post ) Reply to this topicStart new topicStart Poll

 SA Memory handling

 some tricks using SA arrays
 
Seemann  
Posted: Wednesday, Dec 6 2006, 11:57
Quote Post


Ruhe
Group Icon
Group: Members
Joined: Sep 3, 2004

ru.gif

Member Award




I've decided to create a new topic to collect all examples how to handle GTASA memory via SCM.

If you don't understand what is written there, maybe it's not yours. I'll try to explain more things later by editing this post.

All codes are written in Sanny Builder v2.99. To get it working, you should download the latest version of SB.
http://www.gtaforums.com/index.php?showtopic=211077

All codes are tested in San Andreas v1.0 US. Memory addresses could be different in other versions. If something is not working, be sure you use the version I said.

1.
Now, we have three ways to handle the game memory.

1. Initial memory handling way was published in this topic
Stat opcodes provide limited memory access to locations near the stat pools. It allows to make things like changing the player's money, for example.

Advantages:
- the only opcode is using

Disadvantages
- memory range is very limited, many useful addresses are inaccesible.


2. Second way: using the Xieon's patch, that changes three opcodes in gta-sa.exe and provides extremely wide possibilities for game memory handling.
Download

Advantages:
- all game addresses are accessible
- possibility to protect a memory region with VirtualProtect to rewrite it

Disadvantages
- requires exe patching; may not work with different versions (but in fact, I did not see any messages that the patch is working incorrectly).


3. Third way: using the SA arrays to get an access to any addresses in range of 0..FFFFFFFF. Initially was posted there.

Advantages:
- all game addresses are accessible
- easy to use
- nothing especial required; scm-based solution

Disadvantages
- some of addresses still coudn't be rewritable (because of AccessViolation Error).


2.
For the last way, there are three routines to read/write values to the specified address:
(briefly, so far).

Memory Handling Routines (san andreas)

1 MemoryWrite: write new value with specified length into the memory
Params: 0@ = address; 2@ = new value; 3@ - value length (1, 2, 3, 4)

2 MemoryWrite_DWORD: write new DWord value into the memory
Params: 0@ = address; 1@ = new value;

3 MemoryRead: read DWord value from the memory
Params: 0@ = address; 1@ = returned value;

note that some address could be unreadable/unrewriteable!!!
to change such addresses try Xieon's MemPatch: ..\tools\Sa Memory Patch\


CODE

//--write specified number of bytes into memory

:MemoryWrite  
0085: 5@ = 0@
0@ /= 4
0@ *= 4           // memory address
0062: 5@ -= 0@    // offset (0, 1, 2, 3)  
:_GetInitValue      // if you specify mem offset in 5@, you're able to gosub here
gosub @MemoryRead // get initial value
3@ *= 8 // bytes -> bits
5@ *= 8
dec(3@)
for 6@ = 0 to 3@
  if
    08B6: test 2@ bit 6@
  then
    08BF: set 1@ bit 5@    // 1
  else
    08C5: clear 1@ bit 5@  // 0
  end
  inc(5@) // next memory bit
end    
008A: &0(0@,1i) = 1@  // write new value
return


//--write 32-bit value into memory-----------

:MemoryWrite32bit
0@ -= 0xA49960
0@ /= 4
008A: &0(0@,1i) = 1@  
return

//--read 32-bit value from memory-----------

:MemoryRead
0@ -= 0xA49960
0@ /= 4
008B: 1@ = &0(0@,1i)
return




3.
I wrote some examples using these routines. Most of examples were published at gtaf, some of them was out of there.

Now, they are:

-------------------------------------------------

EXAMPLE 1.
Make extremely long trains, 15+ carriages!

Original (in Russian)
Screenshot
-------------------------------------------------


CODE

:LONGTRAINS
thread 'TRAINS'
  for 0@ = -382229 to -382216
    wait 0
    &0(0@,1i) = #STREAKC        
  end
                                             
  // type0 changed!

  // load models
  #FREIGHT.Load
  #FREIFLAT.Load
  #STREAKC.Load

  while true
    if and
      Model.Available(#FREIGHT)
      Model.Available(#FREIFLAT)
      Model.Available(#STREAKC)  
    then
      Break
    end
    wait 0
  end
   
  // create train with new carriages
  06D8: 1@ = create_train_at 2278.1771 -1144.8823 27.5108 type 0 direction 1

  #FREIGHT.Destroy
  #FREIFLAT.Destroy
  #STREAKC.Destroy
 
end_thread



-------------------------------------------------

EXAMPLE 2.
New cheats in run-time

Original
-------------------------------------------------


CODE

:NEWCHEATS
// EXAMPLE 1: TEST 1 key press (space)
thread 'CHEATS'
0@ = -229908
while true
008B: 1@ = &0(0@,1i)      // get last keypresses
0085: 2@ = 1@        
div(1@, 0x 1 00)          // 1char: 0x100, 2chars: 0x10000: 3chars: 0x1000000
mul(1@, 0x 1 00)          // same
0062: 2@ -= 1@            // get needed number of chars (1)

if
  2@ == 0x20              // test if it's SPACE
then  
   03E5: text_box 'CHEAT1'// Cheat activated
   Break
end
wait 1000
end

// EXAMPLE 2: TEST 2 keys ('NO')
0@ = -229908
while true
008B: 1@ = &0(0@,1i)       // get last keypresses
0085: 2@ = 1@        
div(1@, 0x 1 00 00)        // 1char: 0x100, 2chars: 0x10000: 3chars: 0x1000000
mul(1@, 0x 1 00 00)        // same
0062: 2@ -= 1@             // get needed number of chars (2)
if
  2@ == 0x4e4f             // test if player typed NO
then  
  03E5: text_box 'CHEAT1'  // Cheat activated
  Break
end
wait 1000
end

// EXAMPLE 3: TEST 3 keys ('WOW')
0@ = -229908
while true
008B: 1@ = &0(0@,1i)       // get last keypresses
0085: 2@ = 1@        
div(1@, 0x 1 00 00 00)     // 1char: 0x100, 2chars: 0x10000: 3chars: 0x1000000
mul(1@, 0x 1 00 00 00)     // same
0062: 2@ -= 1@             // get needed number of chars  (3)
if
  2@ == 0x574f57           // test if player typed WOW
then
    03E5: text_box 'CHEAT1'// Cheat activated
  Break
end
wait 1000
end

// EXAMPLE 4: TEST 4 keys ('HACK')
0@ = -229908
while true
if
  &0(0@,1i) == 0x4841434B  // test if player typed HACK
then
  03E5: text_box 'CHEAT1'  // Cheat activated
  Break
end
wait 1000
end

// EXAMPLE 5: TEST 5 keys ('SANNY')
// test 5th char 's' from address +4b, then test 'anny' from the beginning;
//  addr      keys
// -229908: X X X X    |  -229908: A N N Y
// -229907: X X X O <- |  -229907: _ _ _ S                    
while true
0@ = -229907 // +32bits; next 4 bytes/chars in the last keypresses block
008B: 1@ = &0(0@,1i)
0085: 2@ = 1@        
div(1@, 0x100)
mul(1@, 0x100)
0062: 2@ -= 1@               // 5th char is the last in the second block:
if
  2@ == 0x53                 // test if S is the 5th pressed key
then                        
   0@ = -229908
   008B: 3@ = &0(0@,1i)
   if 3@ == 0x414E4E59       // test if player also typed ANNY after that
   then  
     03E5: text_box 'CHEAT1' // Cheat activated
     Break
   end    
end
wait 1000
end
   
// EXAMPLE 6: TEST 16 keys: '1234567812345678'
0@ = -57477
while true
if
  &0(0@,1v) == "8765432187654321" // test if last pressed key combo is "1234567812345678"
then
  03E5: text_box 'CHEAT1'    // Cheat activated
  Break
end
wait 1000
end
end_thread



-------------------------------------------------

EXAMPLE 3.
Changing of the local variables of any thread

Original (in Russian)
-------------------------------------------------


CODE

// ---------------------------------------------
//  This thread searches the one named TEST
//  and changes its local variable 10@
// ---------------------------------------------
:CHANGELOCALVAR
thread 'CLV'
{
  0@  =  thread address
  1@  =  temp
}
0@ = 0xA8B42C  
// FIND_THREAD_LOOP
while true
  gosub @MemoryRead
  // 1@ = first active thread
  if 1@ == 0
  then
    Break // no threads, search failed
  end
  0085: 0@ = 1@    // save the pointer
  // get thread name magic address
  div(1@, 8)
  dec(1@, 1 348 395)
  {
   IMPORTANT NOTE:
    thread names are stored in lowercase registry,
    so we've to compare it in lowercase as well.
    SB option 'Case Converting' has to be set to 'As is'!
  }
  if &0(1@,1s) == 'test'
  // check if this thread's name is "test"
  then    
    // well, we've found it, can do everything with it
    // 0@ contains that thread address

    // get address of 10@      
    inc(0@, 0x3c)     // thread locals pool
    inc(0@, 40)       // local var name * 4; i.e. set to 36 to change 9@
   
    // MEMORY WRITE DWORD
    1@ = 3333 // new value of thread('test').10@
    gosub @MemoryWrite32bit

    Break // end the LOOP
  else
    // no, that thread has another name
    // check the next one
    wait 0
  end
  // go to while_begin
end
// variable changed, end_thread  
end_thread

// ---------------------------------------------
//  This thread shows a number after 1 sec
//  after activated. The number is stored in 10@
// ---------------------------------------------
:TEST1
thread 'TEST'
10@ = 10000
wait 3000
054C: use_GXT_table 'POOL'
01E3: text_1number_styled 'NUM' 10@ 5000 ms 1  // ~1~
end_thread



optimized version of CLV thread (see above):

CODE

:CLV
03A4: name_thread 'CLV'
0006: 0@ = 67251

:CLV_LOOP
008B: 0@ = &0(0@,1i)
00D6: if
8039:   not  0@ == 0
004D: jump_if_false @CLV_END
0001: wait 0 ms
0085: 1@ = 0@
0016: 1@ /= 8
000E: 1@ -= 1348395
0016: 0@ /= 4
000E: 0@ -= 2696792
00D6: if
05AD:   &0(1@,1s) == 'test'
004D: jump_if_false @CLV_LOOP

// 25 is the local number + 15
// i.e. set to 24 to change 9@
000A: 0@ += 25

// 3333 is a new value of the local
0004: &0(0@,1i) = 3333

:CLV_END
004E: end_thread



-------------------------------------------------

EXAMPLE 4.
Remove the message "To stop Carl..." when the player
first time stealing a car

Original
-------------------------------------------------


CODE

:MSGREMOVE
 thread 'NOMSG'
 0@ = 0xC0BC15 //  ADDRESS
 2@ = 1        //  VALUE
 3@ = 1        //  LENGTH (Byte)
 gosub @MemoryWrite
end_thread



4.
You can grab a main.scm with all examples from here:
http://www.mysharefile.com/v/7409206/memhandling.rar.html

- Readme included
- source included


changes history:

06 dec 2006:
- added link to the Xieon's patch
- added optimized version of CLV thread (example #3)


This post has been edited by Seemann on Wednesday, Dec 6 2006, 15:37
Users WebsitePM
  Top
 

 
ceedj  
Posted: Wednesday, Dec 6 2006, 12:58
Quote Post


PEDS Creator
Group Icon
Group: Members
Joined: May 21, 2005

us.gif

Member Award




Excellent post Seemann!

I have applied the #2 method (Xieon's Patch) and have gotten it working using the SA loader by op9080 (a C++ hook, and the foundation for SA Studios). Here's the opcode setups:
CODE
//Xieon's Memory Patch

DEFINE_OPCODE(read_mem_addy, 0x00C3, "iii");
DEFINE_OPCODE(write_mem_addy, 0x00C4, "iii");
DEFINE_OPCODE(virtual_protect_change_at, 0x0181, "iii");


And here's his example from the Read Me that comes with the patch (moon gravity on jumps)
CODE
theScript << virtual_protect_change_at << 8796548 << 4 << 4;
theScript << write_mem_addy << 8796548 << 2 << 0.002;
theScript << virtual_protect_change_at << 8796548 << 4 << -1;


Two things:

1) On 0181, the last parameter is a float in the example. Though it works now, suppose I use an address that needs an integer? How would I solve this?

2) Maybe add a link to the patch in your first post.

My only gripe with the patch method is that you'd have to include it in any mods that use it (is he allowing this? It's not really clear in the Read Me file), and get your end user to patch it. Although nifty that an auto-find and backup were included in the patch. smile.gif

This post has been edited by ceedj on Wednesday, Dec 6 2006, 15:48
Users WebsitePM
  Top
 

 
Seemann  
Posted: Wednesday, Dec 6 2006, 13:52
Quote Post


Ruhe
Group Icon
Group: Members
Joined: Sep 3, 2004

ru.gif

Member Award




QUOTE (ceedj @ Dec 6 2006, 21:58)

1) On 0181, the last parameter is a float in the example. Though it
works now, suppose I use an address that needs an integer? How would I solve this?

sorry, but why do you speak about 0181? This one has all the parameters integer. Do you mean 00C3/00C4?

QUOTE (ceedj @ Dec 6 2006, 21:58)

My only gripe with the patch method is that you'd have to include it in any mods that use it (is he allowing this? It's not really clear in the Read Me file), and get your end user to patch it.


yes, it's free to distribute, the only you'd have to do is to include Readme.txt with the patch.
Users WebsitePM
  Top
 

 
Bigun  
Posted: Wednesday, Dec 6 2006, 14:30
Quote Post


wandering about
Group Icon
Group: Members
Joined: Jul 10, 2004

ie.gif

XXXXX



Splendid post Seemann!
That's nice, modifying thread locals...we can pretty much kiss globals away. O_o Also good for savegame compabillity.
Users WebsitePM
  Top
 

 
ceedj  
Posted: Wednesday, Dec 6 2006, 15:37
Quote Post


PEDS Creator
Group Icon
Group: Members
Joined: May 21, 2005

us.gif

Member Award




I was in fact refering to 00C4. Whoops. smile.gif Anyway, sorry for the confusion. I edited my post with the correct data type for 0181.

This is what I get for replying to topics with little sleep. lol.gif
Users WebsitePM
  Top
 

 
Seemann  
Posted: Friday, Dec 8 2006, 16:07
Quote Post


Ruhe
Group Icon
Group: Members
Joined: Sep 3, 2004

ru.gif

Member Award




Main.scm Got Cracked!

Finally, I figured out a way to run an assembler code from a main.scm without any patches or whatever.
From now, we have no limits for the coding ever.

It's similar to the CyQ's method of an injection of the asm code to change opcode handlers.
I found two opcodes in SA that could make the same function.

They are: 0572 and 0A3D.

So, how it works.

1. In San Andreas we have 92 cheats. Some of them are null, some are well-known and often used.
2. These opcodes are well known too. 0572 gives to all taxis the nitro, 0A3D makes the prostitutes pay you (it doen't matter, I use 0572).
But not anybody knows that this opcodes works as the cheats like. They enables one of the 92 flags and game begins to think that you use a cheat (but without affecting cheats history, only implying what the cheat does).
3. 0A3D referring to the cheat #90, 0572 - cheat #91
4. All the cheats routines addresses are stored as simple Dword values and COULD be changed in run-time via array's method.
5. So, what this code does: it changes 91st cheat routine address with a value INSIDE main.scm (all adresses are well-known). Then we run this cheat and game goes to the address we set, in other words it goes inside main.scm and begins work with the code as with an assembler.

Using hex..end struct in Sanny Builder it's possible to execute ANY code you want.

Personally I'm not good ASM'er, so my example is a kind of useless (I just give 1000 buxes to the player), but it's only the beginning.
Somebody who knows asm well could implement VirtualProtect routine and then we even do not need to patch the game with the Xieon's patch to work with the addresses that have to be protected (a gravity one, for example).

The code:
CODE

// ----------------------------------
//      Asm code injector
// ----------------------------------
// set new handler address
0@ = -429863
&0(0@,1i) = 0xA49960
&0(0@,1i) += @__AsmInjection
// Run Asm Injection
0572: 1
// restore handler
&0(0@,1i) = 0
return

:__AsmInjection
hex
// here goes ASM code!


//My example: Add $1000 to the player money
B8 E8030000     // mov eax, 1000
01 05 50CEB700  // add [0xB7CE50], eax
C3              // return

end


This code adds 1000 to the value stored at 0xB7CE50 (player.money). Bit useless, but works!


Pay attention: that was tested in San Andreas v1.0 US. If you have v1.01 please test if it works.


well, well... There's another example:
http://sannybuilder.com/files/cheater.rar

This mod allows to enable all cheats by pressing Action Key.


This post has been edited by Seemann on Saturday, Dec 9 2006, 05:42
Users WebsitePM
  Top
 

 
Seemann  
Posted: Saturday, Mar 3 2007, 02:42
Quote Post


Ruhe
Group Icon
Group: Members
Joined: Sep 3, 2004

ru.gif

Member Award




I could run the VirtualProtect procedure from the main.scm, and now there's no need for the Xieon's patch: we can do the same through the SCM. Worked on US, EUR, GER 1.0

That's the full code how to write the value with the specified length (1,2,4 bytes) to the specified address protected with VP.

CODE
:MemoryProofWrite
3@ == 1
jf @_____novp
4@ = -429863
&0(4@,1i) =  0xA49960
&0(4@,1i) += @_____vpsv
0052: gap 0 virtual_protect_at_address 0@ size 1@ newprotect 4 gap 0 0
0572: 1
gosub @MemoryWrite
0052: gap 0 virtual_protect_at_address 0@ size 1@ newprotect -1 gap 0 0
0572: 1
&0(4@,1i) = 0
end_thread

:_____novp
gosub @MemoryWrite
end_thread

:MemoryWrite
3@ = -429864
&0(3@,1i) =  0xA49960
&0(3@,1i) += @_____mwss
0052: gap 0 target_address 0@ size 1@ value 2@ gap 0 0
0A3D: 1
&0(3@,1i) = 0
return

:_____vpsv
hex
68 F4 3C A4 00 83 3D 84 3C A4 00 FF
75 08 FF 35 F4 3C A4 00 EB 06 FF 35
84 3C A4 00 FF 35 80 3C A4 00 FF 35
7C 3C A4 00 FF 15 2C 80 85 00 C3
end

:_____mwss
hex
8B 15 7C 3C A4 00 8B 05 84 3C A4 00
83 3D 80 3C A4 00 01 75 03 88 02 C3
83 3D 80 3C A4 00 02 75 04 66 89 02
C3 89 02 C3
end


It is a thread that executed once and stopped. Place it to your scripts as you did with other threads.
When you create it with 004F, pass four parameters to it:

CODE
create_thread @MemoryProofWrite address (DWORD) size (Byte: 1,2,4) value (DWORD) VirtualProtect (BOOL)


then the local variables of the thread will be initialized with these values. The variables as parameters are allowed.


If you only need to write values (without the VirtualProtect) use
CODE
create_thread @MemoryProofWrite address XXXX size XXXX value XXXX VirtualProtect 0

or without VirtualProtect parameter ever





Hello, world!

Example1. Changing the gravity (the patch example) /with VirtualProtect


CODE
create_thread @MemoryProofWrite address 0x00863984 size 4 value 0.002 VirtualProtect 1


Compiled SCM and source


Example2. Remove annoying message about entering car (from the first post) /without VirtualProtect

CODE
create_thread @MemoryProofWrite address 0xC0BC15 size 1 value 1


This post has been edited by Seemann on Sunday, Mar 4 2007, 04:01
Users WebsitePM
  Top
 

 
DexX  
Posted: Saturday, Mar 3 2007, 05:16
Quote Post


Black Hat
Group Icon
Group: Retired Staff
Joined: May 16, 2002

Member Award




Seemann, i just want to be sure i understand you correctly, since i'm not a mission coder;
Are you saying we can write anywhere in the game's memory, and write any size data?

i've been using a modified vorbis dll (by delfi) to load .asi files, which alter the game's memory as i wish @ runtime. could we use this code you posted, along with the "mission pack" method of installing scm mods? if so that would really be sweet..
PM
  Top
 

 
Seemann  
Posted: Saturday, Mar 3 2007, 07:07
Quote Post


Ruhe
Group Icon
Group: Members
Joined: Sep 3, 2004

ru.gif

Member Award




QUOTE (DexX @ Mar 3 2007, 13:16)
Are you saying we can write anywhere in the game's memory, and write any size data?

The memory address could be any, but the value size could only be 1, 2 or 4 bytes.

The asm code there contains something like:

CODE
cmp size, 1
ja @2
mov byte ptr [address], value
ret

:2
cmp size, 2
ja @4
mov word ptr [address], value
ret

:4
mov dword ptr [address], value
ret



I could implement the BlockWrite routine for writing the data with any size, need that?
Users WebsitePM
  Top
 

 
PLPynton  
Posted: Saturday, Mar 3 2007, 11:12
Quote Post


Player Hater
Group Icon
Group: Members
Joined: Jul 9, 2005

pl.gif

XXXXX



that is just great. what is missing is a possibility to decompile a game script whenever hex data input is there. or in fact make a way so code written in such a form will could be decompiled and compiled without loosing its functionality.
as most of the coders will like to use your work here it will be a big minus if their MOD can not be decompiled back.

This post has been edited by PLPynton on Saturday, Mar 3 2007, 11:16
PM
  Top
 

 
Seemann  
Posted: Saturday, Mar 3 2007, 12:04
Quote Post


Ruhe
Group Icon
Group: Members
Joined: Sep 3, 2004

ru.gif

Member Award




QUOTE (PLPynton @ Mar 3 2007, 19:12)
what is missing is a possibility to decompile a game script whenever hex data input is there.

No, such possibility is there since v2.98, IIRC.
The Sanny Builder console could receive the commands from the input line and you can turn on the option IGNORE_UNKNOWN which allows to decompile almost any protected/broken scm. Read the help files and the console texts

Users WebsitePM
  Top
 

 
PLPynton  
Posted: Saturday, Mar 3 2007, 12:32
Quote Post


Player Hater
Group Icon
Group: Members
Joined: Jul 9, 2005

pl.gif

XXXXX



i mean that in other way:
it is great what you just did!

and the SB returns me
"Thread not found. Base: 194426. Probably Script.img is broken"

edit: i inserted the thread just before mission 0 (added if line that was missing at the beginning), i issued with
create_thread @MemoryProofWrite address 0x00863984 size 4 value 0.002 VirtualProtect 1
from mission 0 code
is there anything i could forget to switch?

This post has been edited by PLPynton on Saturday, Mar 3 2007, 12:41
PM
  Top
 

 
Seemann  
Posted: Saturday, Mar 3 2007, 12:55
Quote Post


Ruhe
Group Icon
Group: Members
Joined: Sep 3, 2004

ru.gif

Member Award




QUOTE
and the SB returns me
"Thread not found. Base: 194426. Probably Script.img is broken"

I'm successed to decompile the files with the hex insertions.
BTW, there's no way for exact decompiling. The labels (_____vpsv, _____mwss) will disappear as well when you decompile . So, the way for other people is that the author has to include his source with the mod.

QUOTE
i issued with create_thread @MemoryProofWrite address 0x00863984 size 4 value 0.002 VirtualProtect 1

cant understand the kind of issue: code doesnt compile or the game crashes? I just do the same and all works fine to me (heh, it's too funny play with gravity=2.0)
Users WebsitePM
  Top
 

 
PLPynton  
Posted: Saturday, Mar 3 2007, 13:45
Quote Post


Player Hater
Group Icon
Group: Members
Joined: Jul 9, 2005

pl.gif

XXXXX



well, i still can not decompile it but as you say we have to include source ok, not a problem i guess.

i do not want to mess up too much: there is a way to place any kind of informations within script after jump command and that information is ignored by the game, while that kind of information can be interpreted by decompiler after it was created by compiler. additional marking of START, END and TXTCODE (3 nops) will be also required for code that is extraordinary when compiling. nop1 for start of code, nop2 for end code and nop3 somewhere in script after jump (to avoid main part consumption). well but that is just an idea and i understand how unnecesary it might be. ignore that please.

ignore that, i have had an issue because my game crashed after i quit and dis not want to start again. did because i messed to much in memory.

edit: he i can imagine what happens with 2.0, deadly gravity hehe

EDIT2: listen, do not ignore that idea with txt code included in main.scm. what if you do that: i can write a mod then mark my code as "SPECIAL" and it decompiles it after all EXACTLY AS SOURCE- with custom labels, globals, and descriptions. you just place text code after jump when our special nop is there (within main.scm code). then decompile using this text and putting it between our 2 special nops. (even using one nop with several parameters). i think people can like have SOURCE after decompiling right? if the game accepts it of course.

This post has been edited by PLPynton on Saturday, Mar 3 2007, 14:17
PM
  Top
 

 
Seemann  
Posted: Saturday, Mar 3 2007, 15:51
Quote Post


Ruhe
Group Icon
Group: Members
Joined: Sep 3, 2004

ru.gif

Member Award




QUOTE (PLPynton @ Mar 3 2007, 21:45)
i think people can like have SOURCE after decompiling right?

The decompiler don't even need for the special marks (nops or whatever) in the code to detect if there's an in-built source code. The compiler just adds the source and the offsets where the text has to be insterted and its length at very end of the file. That also save the space.
So, the decompiler checks that and inserts this plain text instead of the byte code (it wont even decompile it as there's a source ready-to-go, yes, just skip?).
Very easy.

But lets imagine: for example, I have two custom threads. I decide to include one of them as source in main.scm. But it uses custom variables and labels from another one. What happen: when the decompiler put the source, it still use such names, but those thread will have another names after the decompiling. So, that source will be uncompilable.
And to avoid that is too hard, I think. Ideas?

I think the using of such sources for now only necessary for the hex..end construct. I could make the compiler store all the hex insertions offsets and its length to allow then the decompiler parse them and it should solve the problem with the undecompilable sources.


QUOTE (PLPynton @ Mar 3 2007, 20:32)
added if line that was missing at the beginning

For the single ifs there's no need for 00D6. I just save some space in the main.scm

Is the compiled scm from the gravity.rar working for you?

This post has been edited by Seemann on Saturday, Mar 3 2007, 16:20
Users WebsitePM
  Top
 

 
SteaVor  
Posted: Saturday, Mar 3 2007, 16:41
Quote Post


GTA:LC Contributor
Group Icon
Group: Members
Joined: Dec 17, 2005

gr.gif

XXXXX



Excellent work, Seemann, this is really useful and does work flawlessly for me - it even works with my German v1.0 exe! That's so great!
What's the best way to read a value from memory now?
Users WebsitePM
  Top
 

 
PLPynton  
Posted: Saturday, Mar 3 2007, 17:00
Quote Post


Player Hater
Group Icon
Group: Members
Joined: Jul 9, 2005

pl.gif

XXXXX



yes it can be decompiled but that does not proof why it can not on full game script. i see that it does not lead in any good direction, our further discussion about built in source. just forget it.

besides from me too: great work, EU 1.0 NoCD works

This post has been edited by PLPynton on Saturday, Mar 3 2007, 17:04
PM
  Top
 

 
Seemann  
Posted: Sunday, Mar 4 2007, 04:03
Quote Post


Ruhe
Group Icon
Group: Members
Joined: Sep 3, 2004

ru.gif

Member Award




QUOTE (SteaVor @ Mar 4 2007, 00:41)
What's the best way to read a value from memory now?

I will write similar code for reading the data, but still don't know the best way how to pass the variable pointer where the read value will be stored

In theory it should be something like:
CODE
create_thread @MemoryProofRead address XXX size XXX variable_offset 20

And the code stores the value to variable $5.

But most likely I will use another way.


QUOTE (PLPynton @ Mar 4 2007, 01:00)
i see that it does not lead in any good direction, our further discussion about built in source. just forget it.

No, that’s good idea. I will implement it for the hex firstly, and when we'll see how that works - for the text sources.


Thanks for your feedbacks, guys.
Users WebsitePM
  Top
 

 
Seemann  
Posted: Sunday, Mar 4 2007, 05:57
Quote Post


Ruhe
Group Icon
Group: Members
Joined: Sep 3, 2004

ru.gif

Member Award




Well, that's it:

CODE
{ -----------------------------------------------------------------
  Memory Access Thread

  to write a value with the specified length to the memory address  use
  create_thread @MemoryProofWrite address X:DWord size X:BYTE value X:DWORD VirtualProtect X:BOOL
 
  to read a value with the specified length by the memory address  use
  create_thread @MemoryProofRead address X:DWord size X:BYTE VirtualProtect X:BOOL
  The read value will be stored to the variable $MEMORY_PROOF_READ

  The possible Size values: 1 (byte), 2 (word), 4 (dword)
  The VirtualProtect parameter is optional
----------------------------------------------------------------- }

:MemoryProofWrite
4@ = @MemoryWrite
3@ == 1
jf @_____novp

:_____mpvp
5@ = -429863
&0(5@,1i) =  0xA49960
&0(5@,1i) += @_____vpsv
0052: gap 0 virtual_protect_at_address 0@ size 1@ newprotect 4 gap 0 0
0572: run_VPSV 1
gosub 4@
0052: gap 0 virtual_protect_at_address 0@ size 1@ newprotect -1 gap 0 0
0572: run_VPSV 1
&0(5@,1i) = 0
end_thread

:MemoryProofRead
4@ = @MemoryRead
2@ == 0
jf @_____mpvp

:_____novp
gosub 4@
end_thread

:MemoryWrite
4@ = -429864
&0(4@,1i) =  0xA49960
&0(4@,1i) += @_____mwss
0052: gap 0 target_address 0@ size 1@ value 2@ gap 0 0
0A3D: run_MWSS 1
&0(4@,1i) = 0
return

:MemoryRead
4@ = -429864
&0(4@,1i) =  0xA49960
&0(4@,1i) += @_____mrmm
02EC: run_MRMM 1 read_address 0@ size 1@
hex
3D0A008D0100000000 {store_to} 02 $MEMORY_PROOF_READ
end
&0(4@,1i) = 0
return

:_____vpsv
hex
68 F4 3C A4 00 83 3D 84 3C A4 00 FF
75 08 FF 35 F4 3C A4 00 EB 06 FF 35
84 3C A4 00 FF 35 80 3C A4 00 FF 35
7C 3C A4 00 FF 15 2C 80 85 00 C3
end

:_____mwss
hex
8B 15 7C 3C A4 00 8B 05 84 3C A4 00
8B 0D 80 3C A4 00 83 F9 01 75 03 88
02 C3 83 F9 02 75 04 66 89 02 C3 89
02 C3
end

:_____mrmm
hex
31 C0 BA 78 3C A4 00 89 02 8B 0D 80
3C A4 00 8B 05 7C 3C A4 00 83 F9 01
75 05 8A 00 88 02 C3 83 F9 02 75 07
66 8B 00 66 89 02 C3 8B 00 89 02 C3              
end

{ ---------end of memory access thread----------------------------- }


That thread is the more complex way of getting memory access. For some cases you may need for something shorter. Feel free to modify it.



Example: decrease a gravity for 5 sec, then restore to normal

CODE

create_thread @MemoryProofRead  address 0x863984 size 4 VirtualProtect 1
wait 0
create_thread @MemoryProofWrite address 0x863984 size 4 value 0.002 VirtualProtect 1
wait 5000
create_thread @MemoryProofWrite address 0x863984 size 4 value $MEMORY_PROOF_READ VirtualProtect 1



edit: optimized mrmm

This post has been edited by Seemann on Sunday, Mar 4 2007, 08:09
Users WebsitePM
  Top
 

 
Seemann  
Posted: Sunday, Mar 4 2007, 12:51
Quote Post


Ruhe
Group Icon
Group: Members
Joined: Sep 3, 2004

ru.gif

Member Award




That's the multiversion of the memory access thread.

You could pass two addresses: one for v1, second for v1.01. The code detects what version is running now and works with that correctly.

Parameters:
CODE
  create_thread @MemoryProofMultiWrite/Read address for v1.0 (X:DWord) address for v1.01 (X:DWord) size (X:BYTE) value (X:DWORD) VirtualProtect (X:BOOL)



CODE
{ -----------------------------------------------------------------
  Memory Access Thread
  MultiVersion :: supports GTA SA v1 and v1.01

  to write a value with the specified length to the memory address  use
  create_thread @MemoryProofMultiWrite address for version1 X:DWord address for version1.01 X:DWord size X:BYTE value X:DWORD VirtualProtect X:BOOL

  Example:
  create_thread @MemoryProofMultiWrite address_V1 0xC0BC15 address_V2 0xC0E295 size 1 value 1
 
  to read a value with the specified length by the memory address  use
  create_thread @MemoryProofMultiRead address for version1 X:DWord address for version1.01 X:DWord size X:BYTE VirtualProtect X:BOOL
 
  The read value will be stored to the variable $MEMORY_PROOF_READ
 
  Example:
  create_thread @MemoryProofMultiRead address_V1 0x863984 address_V2 0 size 4 VirtualProtect 1

  The possible Size values: 1 (byte), 2 (word), 4 (dword)
  The VirtualProtect parameter is optional
----------------------------------------------------------------- }

:MemoryProofMultiWrite
gosub @_____gsvo01
7@ = @MemoryWrite
4@ == 1
jf @_____novp

:_____mpvp
0085: 8@ = 10@(9@,2i)
008A: &0(8@,1i) = 14@(9@,2i)
005E: &0(8@,1i) += 16@(9@,2i)
0052: gap 0 virtual_protect_at_address 0@(9@,2i) size 2@ newprotect 4 gap 0 0
0572: run_VPSV 1
gosub 7@
0052: gap 0 virtual_protect_at_address 0@(9@,2i) size 2@ newprotect -1 gap 0 0
0572: run_VPSV 1
&0(8@,1i) = 0
end_thread

:MemoryProofMultiRead
gosub @_____gsvo01
7@ = @MemoryRead
3@ == 0
jf @_____mpvp

:_____novp
gosub 7@
end_thread

:MemoryWrite
0085: 7@ = 12@(9@,2i)
008A: &0(7@,1i) = 14@(9@,2i)
005E: &0(7@,1i) += 18@(9@,2i)
0052: gap 0 target_address 0@(9@,2i) size 2@ value 3@ gap 0 0
0A3D: run_MWSS 1
&0(7@,1i) = 0
return

:MemoryRead
0085: 7@ = 12@(9@,2i)
008A: &0(7@,1i) = 14@(9@,2i)
005E: &0(7@,1i) += 20@(9@,2i)
02EC: run_MRMM 1 read_address 0@(9@,2i) size 2@
hex
3D0A008D0100000000 {store_to} 02 $MEMORY_PROOF_READ
end
&0(7@,1i) = 0
return

:_____gsvo01
8@ = -429566
&0(8@,1i) == 4611680
jf @_____gsvo012 // 1.0
//    9@  = 0
   10@ = -429863
   12@ = -429864
   14@ = 0xA49960
   16@ = @_____vpsv
   18@ = @_____mwss
   20@ = @_____mrmm
return
:_____gsvo012    // 1.01
   9@  = 1
   11@ = -431117
   13@ = -431118
   15@ = 0xA4BFE0
   17@ = @_____vpsv2
   19@ = @_____mwss2
   21@ = @_____mrmm2    
return

:_____vpsv2
hex
68 74 63 A4 00 83 3D 04 63 A4 00 FF
75 08 FF 35 74 63 A4 00 EB 06 FF 35
04 63 A4 00 FF 35 FC 62 A4 00 FF 35
F8 62 A4 00 FF 15 2C 90 85 00 C3
end

:_____vpsv
hex
68 F4 3C A4 00 83 3D 84 3C A4 00 FF
75 08 FF 35 F4 3C A4 00 EB 06 FF 35
84 3C A4 00 FF 35 80 3C A4 00 FF 35
7C 3C A4 00 FF 15 2C 80 85 00 C3
end

:_____mwss2
hex
8B 15 FC 62 A4 00 8B 05 04 63 A4 00
8B 0D 63 00 A4 00 EB 12
end

:_____mwss
hex
8B 15 7C 3C A4 00 8B 05 84 3C A4 00
8B 0D 80 3C A4 00 83 F9 01 75 03 88
02 C3 83 F9 02 75 04 66 89 02 C3 89
02 C3
end

:_____mrmm2
hex
31 C0 BA F8 62 A4 00 89 02 8B 0D 00
63 A4 00 8B 05 FC 62 A4 00 EB 15
end

:_____mrmm
hex
31 C0 BA 78 3C A4 00 89 02 8B 0D 80
3C A4 00 8B 05 7C 3C A4 00 83 F9 01
75 05 8A 00 88 02 C3 83 F9 02 75 07
66 8B 00 66 89 02 C3 8B 00 89 02 C3              
end

{ ---------end of memory access thread----------------------------- }




Example: how to remove the message showed when Carl first time stealing a car in the both versions

CODE
create_thread @MemoryProofMultiWrite address_V1 0xC0BC15 address_V2 0xC0E295 size 1 value 1


This post has been edited by Seemann on Sunday, Mar 4 2007, 12:58
Users WebsitePM
  Top
 

 

0 User(s) are reading this topic (0 Guests and 0 Anonymous Users)

0 Members:

Pages: (3) [1] 2 3 

Topic Options Reply to this topicStart new topicStart Poll
Search topic for posted by (exact match)



 
IMG IMG