QQ登录

只需一步,快速开始

 找回密码
 定下契约(新注册)

QQ登录

只需一步,快速开始

查看: 1160|回复: 7
收起左侧

SA内存地址的运用和方法-----原版英文版

[复制链接]

翘楚 Outstanding

Rank: 6Rank: 6Rank: 6

UID
32
宝石
7 粒
金币
4871 枚
节操
-202 斤
灵石
4 块
精力
8906 ℃
发表于 2012-3-22 20:45:41 | 显示全部楼层 |阅读模式

你这样只看不注册,真的大丈夫?~

您需要 登录 才可以下载或查看,没有账号?定下契约(新注册)

x
本帖最后由 Sidlady 于 2012-3-22 21:10 编辑




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\
  • //--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


-------------------------------------------------
  • :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
-------------------------------------------------
  • :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)
-------------------------------------------------
  • // ---------------------------------------------
  • //  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):
  • :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
-------------------------------------------------
  • :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


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

传奇 Legend

谷歌翻译坑爹人肉版(不是人肉饭)

Rank: 16

UID
83
宝石
140 粒
金币
573 枚
节操
30 斤
灵石
0 块
精力
32 ℃
发表于 2012-3-22 20:57:34 来自手机 | 显示全部楼层
支持 Opcode库作者出的教程啊

翘楚 Outstanding

Rank: 6Rank: 6Rank: 6

UID
32
宝石
7 粒
金币
4871 枚
节操
-202 斤
灵石
4 块
精力
8906 ℃
 楼主| 发表于 2012-3-22 20:59:20 | 显示全部楼层
kwanz 发表于 2012-3-22 20:57
支持 Opcode库作者出的教程啊

看到图吗

世界工人

心之所向

Rank: 16

UID
1
宝石
30 粒
金币
3713 枚
节操
1271 斤
灵石
2 块
精力
12635 ℃

sex lady精力射线真の绅士

发表于 2012-3-22 21:04:34 | 显示全部楼层
图挂了。。。。。华丽丽的挂了

翘楚 Outstanding

Rank: 6Rank: 6Rank: 6

UID
32
宝石
7 粒
金币
4871 枚
节操
-202 斤
灵石
4 块
精力
8906 ℃
 楼主| 发表于 2012-3-22 21:05:54 | 显示全部楼层
kami 发表于 2012-3-22 21:04
图挂了。。。。。华丽丽的挂了

无语。。果断千脑= =

璞玉 Potential

Rank: 4

UID
34
宝石
6 粒
金币
486 枚
节操
-15 斤
灵石
0 块
精力
8 ℃
发表于 2012-4-23 12:08:49 来自手机 | 显示全部楼层
手動頂起 @kwanz
有空翻譯這篇文章嗎?
....

翘楚 Outstanding

Rank: 6Rank: 6Rank: 6

UID
411
宝石
21 粒
金币
2142 枚
节操
4 斤
灵石
0 块
精力
1589 ℃
发表于 2012-4-23 12:12:06 | 显示全部楼层
E文压力大

传奇 Legend

谷歌翻译坑爹人肉版(不是人肉饭)

Rank: 16

UID
83
宝石
140 粒
金币
573 枚
节操
30 斤
灵石
0 块
精力
32 ℃
发表于 2012-4-23 12:43:29 来自手机 | 显示全部楼层
razor 发表于 2012-4-23 12:08
手動頂起 @kwanz
有空翻譯這篇文章嗎?

手上还有一篇How to create a mission,然后我会译这一篇

点评

我“@”到你了嗎?(手機)  发表于 2012-4-23 13:07

本版积分规则

    切换繁體
    Archiver|手机版|小黑屋|

GMT+8, 2024-11-23 11:20 , Processed in 0.168256 second(s), 112 queries .

沪ICP备2021020632号-1

快速回复 返回顶部 返回列表