Seraph 内存搜索

一般情况下,为了应付游戏的动态内存地址,我们用基址的方式来读取内存,不过前提是可以知道基址。有的游戏,基址是很难分析到的,而且很多游戏加了隐藏和变换,搞的分析起来特别复杂。这个时候,借助Seraph,我们可以用另一种方式——搜索内存。

虽然找不出基址,但是我们可以很轻松的找到一些我们想要的数据的直接地址。比如我们在一次游戏的运行里,可以用CE找到血的地址是&H900010, 血最大值的地址是&H900014,MP地址&H900020,最大MP&H900024。

虽然下一次游戏运行时,这些地址都会变,但是我们知道,这些地址互相间的相对地址偏移是不变的。也就是说最大血地址=血地址+4,MP地址=血地址+&H10
这样我们就可以搜索了。举个例子,我们知道我们的血/最大血/MP/最大MP分别是8000/8000/12000/12000。那么在脚本里,告诉Seraph的内存搜索引擎,我们要搜索一个地址,它的值是8000,这个地址+4的值也是8000,这个地址+&H10和+&H14的值是12000。这样的地址,一般在游戏里只有一个。
怎么搜索呢?
 
ClearSearchMemoryTable()
AddSearchMemoryItem(&H900010, 2, 8000)
AddSearchMemoryItem(&H900014, 2, 8000)
AddSearchMemoryItem(&H900020, 2, 12000)
AddSearchMemoryItem(&H900024, 2, 12000)
if SearchMemory(&H000000, Address) then
Print("找到地址:"&Address)
end if


注意,以上代码里,我们调用AddSearchMemoryItem函数来设置一些我们要搜索的条件。
第一个参数是每个值的地址。不用担心这个地址在下一次游戏运行时不正确,Seraph搜索只关心所有添加的搜索项之间的“相对地址”。
第二个参数是指定类型,2代表四字节整型。我们同样可以添加双字节,浮点数,以及字符串等不同类型。详见帮助手册。
第三个参数就是这个搜索项的值。你必须填入这个数据的当前值,如果填错了,就搜不到了。(关于怎么在脚本里指定当前的用于搜索的值,我们之后讲)
注意,第一行的ClearSearchMemoryTable()是用于清除上一次添加的搜索项。重新开始一次搜索前我们都要调一上这个函数。
添加完了这4个搜索项以后,我们用SearchMemory开始搜索。第一个参数表示搜索的开始值,我们一般都可以用&H000000。第二个参数值用于返回搜索到的结果。
搜到的结果就是第一个搜索项的地址,也就是当前血的地址。我们可以保存这个地址,用ReadMemory随时去读数据。

那么,整体的流程应该是:
1. 在参数设置里,我们添加一些参数,用于填入搜索的数据。告诉用户在脚本开始前,先设置这些数据。比如,填入自己的血,MP,并在红蓝满的时候开始脚本。
2. 在脚本一开始,用GetConfigNumber等函数取出设置的值,用以上代码搜索内存,把得到的数据保存下来
3. 在脚本运行中,用保存下的地址,加上各种我们已经知道的偏移量,随时读取各项数据的值。

小技巧:

怎样添加搜索项才可以最方便准确的搜索到我想要的那个唯一的内存地址?
当然是与角色越相关越好的。比如角色的各项属性值。使用更多的搜索项可以有效的防止搜索的不准确(即搜到不止一个地址),但是也会带来每次启动脚本时的麻烦,因为我们启动时都要设置一下搜索值。建议用一些不经常变的值,比如,等级,攻击值等,只有升了级才会变。而血值是经常变的。
同时,根据我们的经验,角色名字是很好的一个搜索项。如果我们可以分析到角色名字的地址,加在搜索项里(字串型),一般就可以很准确的搜索到结果。
一般的游戏角色名是UTF8形式的。我们可能要先将角色名用GBToUTF8函数转换成UTF8编码的字串,再用AddSearchMemoryItem添加。

如果有时候我们添加的数项不够,或者我们在调试自己脚本的时候,会搜索到不同的内存地址,我们想让脚本全部输出,怎么办?
复制内容到剪贴板
代码:
AddSearchMemoryItem(...)
AddSearchMemoryItem(...)
...
Address=0
while SearchMemory(Address+1, Address)
  Print("找到地址:"&Address)
wend
原理就是从0开始,每搜索到一个地址,先输出,然后从这个地址+1继续往下搜,一直到搜不到为止。