|
本帖最后由 kwanz 于 2012-4-25 21:07 编辑
原帖地址 http://www.gtaforums.com/index.php?showtopic=262280
SA内存控制
原帖作者/ Seemann @GTAF 翻译/ kwanz @虚拟世界
未经许可 谢绝转载
译注 本帖的一楼包含了Seemann大人及其他论坛高手在SB开发早期对内存操作技术的讨论,有一些例子和结果已经过时了。有个别不准确的说法已在后续回复中补充修正,译文中不再指出。所有的示例代码仅供研究学习原理使用。新版的SB+CLEO已经实现了opcode级别的WriteMemory和ReadMemory操作。具体请参考
EN - CLEO Script Tutorial
CH - CLEO编程教程(未完成)的地板(4#)
---------------------------------
我决定开一帖来集中讲解用SCM操作SA内存的所有例子。
如果你看不懂,也许不是你的错。我稍后会编辑帖子解释更清楚一点。
所有的代码是用SB2.99编写的。要成功运行,你需要下载最新版本的SB
http://www.gtaforums.com/index.php?showtopic=211077
译者注:或者下载【下载】SB汉化版+最小启动包 有汉化版SB
下载地址:http://game.55660.net/thread-138-1-1.html
所有代码在SA1.0美版总测试通过,不同版本的内存地址可能不同。如果什么东西用不了,请确认你的程序版本正确。
一
现在,我们有三种方法操作游戏内存。
1. 这个帖子讨论了操作内存的最初的方法。
Stat相关opcode提供了统计数据池附近有限的地址的内存访问。它允许一些简单的操作,比如更改玩家的金钱。
优点
- 只需要用到opcode
缺点
- 可访问地址非常有限,很多有用的地址不能访问
2. 方法二:用Xieon的补丁修改gta-sa.exe的3个opcode,提供了极大量的操作内存的方式。点此下载
优点
- 所有地址都可访问
- 可以保护带有VirtualProtect的内存区域,实现重写
缺点
- 需要破解exe;可能不兼容其他版本(不过 我还没有见过这个补丁不能正常工作的例子)
3. 方法三:用SA的数组访问0到FFFFFFFF之间的任何地址,此法首发在这一帖。
优点
- 可以访问所有地址
- 容易使用
- 无特殊要求,纯scm实现
缺点
- 某些地址仍然不可写(会发生非法访问错误)
二
对法三,可以调用三个函数访问特定地址,简单地讲,包括
1 MemoryWrite: 写入特定长度的新值
参数 0@=地址 2@=新值 3@=长度(1,2,3,4)
2 MemoeryWrite_DWORD:写入新的双字节数值
参数 0@=地址 1@=新值
3 MemeoryRead: 从内存读取双字节数值
参数 0@=地址 1@=返回值
注意仍有部分地址是不可读/写的!!!
要破解这些地址,尝试用Xieon's的内存补丁: ..\tools\Sa Memory Path\
- //--写特定数值
- :MemoryWrite
- 0085: 5@ = 0@
- 0@ /= 4
- 0@ *= 4 // 地址
- 0062: 5@ -= 0@ // 偏移 (0, 1, 2, 3)
- :_GetInitValue // 如果你已经把偏移赋给5@, 就可以跳到这里
- gosub @MemoryRead // 取初值
- 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@ // 写入新值
- return
- //--写32位数值-----------
- :MemoryWrite32bit
- 0@ -= 0xA49960
- 0@ /= 4
- 008A: &0(0@,1i) = 1@
- return
- //--读32位数值-----------
- :MemoryRead
- 0@ -= 0xA49960
- 0@ /= 4
- 008B: 1@ = &0(0@,1i)
- return
复制代码
三
我写了几个用这些函数的例子。多数的例子都发在GTAF上,有的发在别的地方
---------------------------------
例1
用CLEO做超长火车,15+节车厢!
原文链接(俄文)
效果截图
---------------------------------
- :LONGTRAINS
- thread 'TRAINS'
- for 0@ = -382229 to -382216
- wait 0
- &0(0@,1i) = #STREAKC
- end
-
- // 修改type0
- // 加载模型
- #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
-
- // 生成带有新车厢的火车
- 06D8: 1@ = create_train_at 2278.1771 -1144.8823 27.5108 type 0 direction 1
- #FREIGHT.Destroy
- #FREIFLAT.Destroy
- #STREAKC.Destroy
-
- end_thread
复制代码
---------------------------------
例2
运行时作弊码的新实现方法
原文链接
---------------------------------
- :NEWCHEATS
- // 例1:测试1个键(空格)
- thread 'CHEATS'
- 0@ = -229908
- while true
- 008B: 1@ = &0(0@,1i) // 获得最后按键
- 0085: 2@ = 1@
- div(1@, 0x 1 00) // 1个字符: 0x100, 2个字符: 0x10000: 3个字符: 0x1000000
- mul(1@, 0x 1 00) // 同上
- 0062: 2@ -= 1@ // 获得指定数目的按键记录 (1)
- if
- 2@ == 0x20 // 检测是否空格
- then
- 03E5: text_box 'CHEAT1'// 显示作弊启用字样
- Break
- end
- wait 1000
- end
- // 例2:测试2个键的序列 (NO)
- 0@ = -229908
- while true
- 008B: 1@ = &0(0@,1i) // 获得最后按键
- 0085: 2@ = 1@
- div(1@, 0x 1 00 00) // 1个字符: 0x100, 2个字符: 0x10000: 3个字符: 0x1000000
- mul(1@, 0x 1 00 00) // 同上
- 0062: 2@ -= 1@ // 获得指定数目的按键记录 (2)
- if
- 2@ == 0x4e4f // NO
- then
- 03E5: text_box 'CHEAT1' // 显示作弊启用字样
- Break
- end
- wait 1000
- end
- // 例3:测试3个键的序列('WOW')
- 0@ = -229908
- while true
- 008B: 1@ = &0(0@,1i) // 获得最后按键
- 0085: 2@ = 1@
- div(1@, 0x 1 00 00 00) // 1个字符: 0x100, 2个字符: 0x10000: 3个字符: 0x1000000
- mul(1@, 0x 1 00 00 00) // 同上
- 0062: 2@ -= 1@ // 获得指定数目的按键记录 (3)
- if
- 2@ == 0x574f57 // WOW
- then
- 03E5: text_box 'CHEAT1'// 显示作弊启用字样
- Break
- end
- wait 1000
- end
- // 例4:测试4个键的序列 ('HACK')
- 0@ = -229908
- while true
- if
- &0(0@,1i) == 0x4841434B // HACK
- then
- 03E5: text_box 'CHEAT1' // 显示作弊启用字样
- Break
- end
- wait 1000
- end
- // 例5:测试5个键的序列 ('SANNY')
- // 首先在偏移+4位的地址上检测第5键是否为s,然后再测试anny
- // 地址 按键
- // -229908: X X X X | -229908: A N N Y
- // -229907: X X X O <- | -229907: _ _ _ S
- while true
- 0@ = -229907 // 偏移+32位; 也就是最后按键记录地址偏移+4字节/字符处
- 008B: 1@ = &0(0@,1i)
- 0085: 2@ = 1@
- div(1@, 0x100)
- mul(1@, 0x100)
- 0062: 2@ -= 1@ // 第5个字符是第二个按键块的末字母
- if
- 2@ == 0x53 // 检测第5键是否为s
- then
- 0@ = -229908
- 008B: 3@ = &0(0@,1i)
- if 3@ == 0x414E4E59 // 检测后续按键是否为anny
- then
- 03E5: text_box 'CHEAT1' // 作弊启用
- Break
- end
- end
- wait 1000
- end
-
- // 例6:测试16个键的序列: '1234567812345678'
- 0@ = -57477
- while true
- if
- &0(0@,1v) == "8765432187654321" // "1234567812345678"
- then
- 03E5: text_box 'CHEAT1' // 作弊启用
- Break
- end
- wait 1000
- end
- end_thread
复制代码
---------------------------------
例3
修改任意线程的局部变量数值
原文链接(俄文)
---------------------------------
- // ---------------------------------------------
- // 此线程搜索名为'TEST'的线程
- // 并修改它的局部变量10@
- // ---------------------------------------------
- :CHANGELOCALVAR
- thread 'CLV'
- {
- 0@ = thread address
- 1@ = temp
- }
- 0@ = 0xA8B42C
- // 查找线程循环
- while true
- gosub @MemoryRead
- // 1@ = 第一个活动线程
- if 1@ == 0
- then
- Break // 没有找到活动线程,搜索失败
- end
- 0085: 0@ = 1@ // 保存指针
- // 获得线程名称的指针
- div(1@, 8)
- dec(1@, 1 348 395)
- {
- 重要提示:
- 线程名称是以小写形式保存的,
- 所以我们要用小写进行比较.
- 注意SB选项'Case Converting'(大小写转换)必须设为'As is'(保持原值)!
- }
- if &0(1@,1s) == 'test'
- // 测试线程名称是否"test"
- then
- // 找到了,我们可以为所欲为
- // 0@ 包含线程地址
- // 获得10@的地址
- inc(0@, 0x3c) // 线程局部存储池
- inc(0@, 40) // 局部变量号 * 4; 比如说要修改9@,就设为36
-
- // 写入双字节数值
- 1@ = 3333 // 新值
- gosub @MemoryWrite32bit
- Break // 结束循环
- else
- // 否,线程名称不符
- // 检查下一个
- wait 0
- end
- // 跳转到while循环的开始处
- end
- // 变量值已修改,结束线程
- end_thread
- // ---------------------------------------------
- // 这个线程在被激活1秒后
- // 显示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
复制代码
以下是一个改进版的CLV线程
- :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 为局部变量号+15
- // 比如,要修改9@就设为24
- 000A: 0@ += 25
- // 3333为新值
- 0004: &0(0@,1i) = 3333
- :CLV_END
- 004E: end_thread
复制代码
---------------------------------
例4
去除CJ第一次抢车时"To stop Carl..."的提示
原文链接
---------------------------------
- :MSGREMOVE
- thread 'NOMSG'
- 0@ = 0xC0BC15 // 地址
- 2@ = 1 // 数值
- 3@ = 1 // 长度 (字节)
- gosub @MemoryWrite
- end_thread
复制代码
四
你可以点这个下载带有全部示例的main.scm
http://www.mysharefile.com/v/7409206/memhandling.rar.html
已包含自述文件和源代码
更新历史
2006.12.06
- 添加了Xieon的补丁的链接
- 添加了改进版的CLV线程(例3)
---------------------------------
---------------------------------
main.scm已破解!
我终于找到不用任何补丁从main.scm运行汇编代码的方法了。
从此以后编程无极限。
这种方法类似CyQ的注入汇编代码修改opcode句柄的方法
我找到SA中有两个opcode可以实现这个效果
它们是0572和0A3D
方法是这样的
1. SA中有92个作弊码,有些是没有用的,有些大家都知道,很常用
2. Opcode里也有很常见的,比如0572给所有出租车加氮气,0A3D让女支女给你钱(无所谓,我都用0572)
但不是所有人都知道这些opcode的原理和作弊十分类似。它们会开启92个标志位之一,游戏会认为你作弊(但不会影响作弊计数,只是和调用作弊效果一样)
3. 0A3D与作弊标志90相关,0572-标志位91
4. 在标志位上,所有的作弊调用函数地址都以简单的双字节形式存储,可以用数组法在运行时改变
5. 也就是说,这个opcode做到的是用一个新数值修改main.scm的91号作弊标志(所有的地址我们都已熟知)。然后我们启用作弊,游戏就会跳转到我们设定的地址,换句话说,它跳进了main.scm,也就达到了汇编修改运行代码的效果。
在SB中使用hex...end结构,我们可以执行任意代码。
我个人asm用的不好,所以这里给的例子没什么意思(给玩家+1000刀),但这只是个开始。
随便一个会用asm的人可以写出带VirtualProtect的函数,然后我们甚至不需要Xieon的补丁就可以操作被保护的地址(比如,重力相关的地址)
- // ----------------------------------
- // Asm代码注入器
- // ----------------------------------
- // 设置新的句柄地址
- 0@ = -429863
- &0(0@,1i) = 0xA49960
- &0(0@,1i) += @__AsmInjection
- // 运行Asm注入
- 0572: 1
- // 还原句柄
- &0(0@,1i) = 0
- return
- :__AsmInjection
- hex
- // 这里写上asm代码
- // 我的例子是加钱
- B8 E8030000 // mov eax, 1000
- 01 05 50CEB700 // add [0xB7CE50], eax
- C3 // return
- end
复制代码
这段程序对0xB7CE50(金钱)加1000。有点没意思,不过很好用!
注意:程序在1.0美版中测试通过。如果你用的是v1.01,请自行测试。
额,下面是另一个例子
http://sannybuilder.com/files/cheater.rar
这个程序允许你按下动作键启用所有作弊
---------------------------------
---------------------------------
我已经实现了从main.scm运行VirtualProtect函数的方法,现在已经没有必要使用Xieon的补丁了。我们用scm可以达到相同的效果。在1.0美版,欧版,德版中可用
下面是向带VP保护的地址写入定长数值(1,2,4字节)的完整代码
- :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
复制代码
这个线程只执行一次,然后停止。跟你写其他线程一样,把它摆到你的程序里。
当你用004F创建线程的时候,要传4个参数
- create_thread @MemoryProofWrite address (DWORD) size (Byte: 1,2,4) value (DWORD) VirtualProtect (BOOL)
复制代码
若你要写入无VP保护的地址,只需要使用
- create_thread @MemoryProofWrite address XXXX size XXXX value XXXX VirtualProtect 0
复制代码
或者略去VirtualProtect参数
Hello, World!
例1 修改重力(用补丁的例子)带VP
- create_thread @MemoryProofWrite address XXXX size XXXX value XXXX VirtualProtect 0
复制代码
编译版scm和源代码
例2 去除首次抢车消息提示 不带VP
- create_thread @MemoryProofWrite address 0xC0BC15 size 1 value 1
复制代码
---------------------------------
---------------------------------
引用 (DexX @ Mar 3 2007, 13:16)
你是说我们可以往游戏内存的任意位置写入任意数据么?
内存地址任意,但数值长度必须为1,2,4字节
可以包含类似这样的asm代码
- 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
复制代码
我可以实现写入任何长度的BlockWrite函数,需要不?
---------------------------------
---------------------------------
引用 (PLPynton @ Mar 3 2007, 19:12)
在反编带有十六进制数据的脚本时会不会出现丢失数据的情况?
从v.298, IIRC以后就不会了
SB控制台可以接受如何输入命令,你可以打开IGNORE_UKNNOWN选项来反编任何受保护或损坏的scm。请参考帮助文件和控制台输出。
---------------------------------
---------------------------------
引用
SB返回
"Thread not found. Base: 194426. Probably Script.img is broken"
我成功反编过带十六进制的文件啊
顺便说,没有一种确保正确反编所有文件的方法。反编的时候标签(_____vpsv, _____mwss)也会消失。所以对其他人最有效的方法就是祈祷作者在他的mod里包含了源文件吧。
引用
我在用
create_thread @MemoryProofWrite address 0x00863984 size 4 value 0.002 VirtualProtect 1
的时候出状况了
神马状况?无法通过编译还是游戏出错?这个我搞过,用的好好的啊(顺便说一句,gravity=2.0的效果太喜感了)
(译注:修改重力只接受整型数值)
---------------------------------
---------------------------------
引用 (PLPynton @ Mar 3 2007, 21:45)
其实我们反编以后差不多就得到源文件了吧?
反编译器不需要代码中的特殊标记(nop等等)来检测是否存在内嵌十六进制代码。编译器只是把源代码和插入代码的偏移并在一起,并在结尾记录长度。这样也节省了空间。
所以,反编译器只是检测一下长度,然后直接插入纯文本,没有字节码了(本来就是源码。。)。很简单的。
不过想像一下,比如说,我有两个自定义线程,我准备把其中一个的源码插入main.scm。但是它使用了另一个线程的自定义变量和标签。结果是:得到的源码使用原有的名字,但反编以后县城名都变掉了,结果就会和源代码不兼容。
我觉得想要避免这个挺困难的,大家觉得呢
我觉得目前只有在用hex...end结构的时候需要用到这样的代码。我可以让编译器存储所有十六进制嵌入的偏移和长度,然后反编译器解析它们,从而解决兼容问题。
引用 (PLPynton @ Mar 3 2007, 20:32)
开头的if语句漏掉了
单行if无须用到00D6。我在节省main.scm的空间
你那gravity.rar好用吧。。。
---------------------------------
---------------------------------
引用 (SteaVor @ Mar 4 2007, 00:41)
现在从内存读取数值的最佳方法是什么?
我会为读取数据写类似的代码,不过我还是不确定传递目标指针的最佳方式
理论上结果大概是这样的:
- create_thread @MemoryProofRead address XXX size XXX variable_offset 20
复制代码
代码将数值存入变量$5
不过我还是可能用别的方法
引用 (PLPynton @ Mar 4 2007, 01:00)
我觉得我们对内嵌代码的讨论好像没有什么结果,无视我。。
不不不,这主意很好。我会首先对十六进制代码实现它,然后再看看它对纯文本源码的效果如何。
多谢各位的反馈。
---------------------------------
---------------------------------
好了,结果是这样
- { -----------------------------------------------------------------
- 内存访问线程
- 要向内存地址写入定长数值,使用
- create_thread @MemoryProofWrite address X:DWord size X:BYTE value X:DWORD VirtualProtect X:BOOL
- 要从内存地址读取定长数值,使用
- create_thread @MemoryProofRead address X:DWord size X:BYTE VirtualProtect X:BOOL
- The read value will be stored to the variable $MEMORY_PROOF_READ
- 可用的size值为 1-字节 2-字 4-双字
- VirtualProtect参数为可选
- ----------------------------------------------------------------- }
- :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
- { ---------内存访问线程结束----------------------------- }
复制代码
线程写得有点复杂了,实际情况下你可能需要更简短的,随意修改。
示例:减少重力5秒,然后恢复
- 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
复制代码
---------------------------------
---------------------------------
以下是多版本的内存访问线程
你可以传递两个地址,一个用于v1,一个用于v1.01。程序检测运行游戏的版本,并且能正确处理
参数:
- 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)
复制代码- { -----------------------------------------------------------------
- 内存访问线程
- 多版本 :: 支持 GTA SA v1 and v1.01
- 要向内存地址写入定长数值,使用
- create_thread @MemoryProofMultiWrite v1地址 X:DWord v1.01地址 X:DWord size X:BYTE value X:DWORD VirtualProtect X:BOOL
- 示例:
- create_thread @MemoryProofMultiWrite address_V1 0xC0BC15 address_V2 0xC0E295 size 1 value 1
-
- 要从内存地址读取定长数值,使用
- create_thread @MemoryProofMultiRead v1地址 X:DWord v1.01地址 X:DWord size X:BYTE VirtualProtect X:BOOL
-
- 结果存入 $MEMORY_PROOF_READ
-
- 示例:
- create_thread @MemoryProofMultiRead address_V1 0x863984 address_V2 0 size 4 VirtualProtect 1
- 可用的size值为 1-字节 2-字 4-双字
- VirtualProtect参数为可选
- ----------------------------------------------------------------- }
- :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
复制代码 |
评分
-
查看全部评分
|