室友之前疯狂爱上了一款叫做《泰拉瑞亚》的游戏,画风挺复古,不过游戏性确实很不错,初中的时候,好基友也痴迷过这个游戏。

于是我也跟风在steam上买了..结果吃灰了。Orz,总不能浪费钱吧,所以就尝试分析下,写个修改内存的外挂,结果发现,利用CE每次搜索出来的人物属性基址都是不一样的,应该是动态分配内存的原因。在OD中查看发现,关键的内存地址不在任何的模块中,查看内存映射窗口中才可以找到对应内存。

谷歌后,无果。突然想起来,CE和OD都有搜索特征码的功能,其实就是搜索内存的HEX值,可以通过?占位达到模糊搜索的效果,多的不说了,不了解的可以自行搜索下特征码的意思…
利用特征码即可定位到相关地址,这个技术也是查杀、外挂中常用的吧?

简单的分析流程:

通过CE搜索血量,得到疑似人物属性基址的地址

内存

643FEE10 – 8B 45 A8 – mov eax,[ebp-58]
643FEE13 – 8B 15 7460A807 – mov edx,[07A86074] : [06C6FAD0]
643FEE19 – 3B 42 04 – cmp eax,[edx+04]

07A86074就是关键的地址(疑似人物属性基址),选取以上部分为特征码参考。

得到特征码(CE、OD中使用)        8B45D88B15????????3B4204
正则表达式(本次使用)               8B45D88B15(.........)3B4204

通过正则匹配到的返回值就是我们所需要的东西了,对了,由于Intel是小端存储,需要reverse一下Bytes~

接下来解决搜索部分,

在思考了一番后,只想到了一个蠢方法:

分次ReadProcessMemory读取全部内存,然后匹配hex值

至于代码方面,用什么语言都一样,因为只是调用win32API罢了,这里我选择用的是Aardio,挺方便的,用来写小工具再方便不过了!其实就是因为C++功底太烂了
整体逻辑很简单,循环使用ReadProcessMemory读取内存,然后正则匹配字符,然后得到人物基址,加上偏移后,得到人物血量,具体代码放出来,函数名都十分的直白,看看应该就知道了!可惜的是速度太慢了。

import process
import console;

prcs = process.find("Terraria.exe");


miSize = 409600;

//         0x64700000
addrBegin = 0x64700000;
addrEnd = 0x7FFFFFFF;

pattern = "8B45D88B15(........)3B42040F83"

Revese_code = function(Rev_code){
    tarr  = {};
	
    for (i=1;string.len(Rev_code);1){
        if (i%2==0){
        	table.insert(tarr,string.pack(Rev_code[i-1],Rev_code[i]))
        }
    }

    Addr_code = ""
    for (i=1;table.len(tarr);1){
        Addr_code = string.concat(Addr_code,tarr[i]);
    }

	return Addr_code; 
}


while ( addrBegin < addrEnd ){
    console.log(string.format("特征码:%s   开始地址:0x%08X   页长度:%d",pattern,addrBegin,miSize));
	if( pattern ){ 
		str = prcs.readString(addrBegin,miSize );  
		if( str ){ 
			for i,j,group1 in string.gfind(string.hex(str,""), pattern) { 
				if(group1){
					Addr_code = Revese_code(group1);
					console.log(string.format("发现特征码:0x%08X i:0x%08X  人物属性基址:%s ",(i/2)+addrBegin, (i/2) ,Addr_code));
					plot = prcs.readNumber(prcs.readNumber(eval("0x"+Addr_code))+0x8);
					if (500>=prcs.readNumber(plot+0x340)&&prcs.readNumber(plot+0x340)>0){
						console.log(string.format("当前人物血量 :%d",prcs.readNumber(plot+0x340)));
						console.pause()
					}
				}
			}
		
			}
		}
	addrBegin = addrBegin + miSize ;

}


console.pause();

请教一位老前辈,得知了KMP算法,现在暂时先不用吧Orz,光是以上简单的东西,都花了我一天的时间!

 

 

测试:

测试效果图

成功~





本文链接地址: 搜索内存特征码的实现

原创文章,转载请注明: 转载自Lz1y's Blog

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.