-
十月 10
有两个API函数,ReadProcessMemory和WriteProcessMemory,这两个函数我想做外挂的朋友一定是再熟悉不过了。ReadProcessMemory是读取其他进程的指定地址的内存数据,而WriteProcessMemory是写入数据到一个进程的内存空间指定的地址。我不知道微软给的这两个函数的初衷是什么,不过我觉得他们除了做外挂好像也没什么其他用处了(玩笑)。
这里我们不讨论怎么做外挂,也不讨论如何教你去找进程数据的基地址和偏移地址,仅对大家经常问的一个问题来做个解答。
首先说说基地址,基地址其实是个静态地址,他在程序中是固定不变的,所谓的偏移地址其实就指的是动态地址了。玩过游戏修改器的朋友都有这个体会,我们利用游戏修改器来修改游戏某个数据的时候,会发现同一个数据,每次修改的地址都不一样,即使在一台机器是一样的,换一个机器又不一样了,为什么会有这个现象,那就说明了这个数据所在的内存位置是动态的,每次都不一样。
比如说某个游戏的金钱(其实是红色警戒2的),他的基地址是$00A35DB4,偏移地址是$24c,有些朋友就用ReadProcessMemory来读取这个金钱值:
ReadProcessMemory(pHandle, Pointer($00A35DB4+$24c), Pointer(@money),sizeof(money),tmpNum);
但是执行这个函数以后,发现读取的并不是我们想要的数值,这是为什么呢?Pointer($00A35DB4+$24c)基地址+偏移地址,应该没错啊?其实这里恰恰是错误的。
我们刚才已经说了,偏移地址表示的就是动态地址的偏移量,Pointer($00A35DB4+$24c),这么写,明明就是个静态地址,静态地址+静态偏移量=静态地址,所以,肯定读取的数值是错误的。
那我们该怎么正确读取$00A35DB4基地址上偏移$24c的数据呢?这里应该这样写:
...... pAddr:= $00A35DB4; //基地址 ReadProcessMemory(pHandle, Pointer(pAddr), Pointer(@money),sizeof(money),tmpNum); //记得格式 offerAddr:= money+$24c;//先读取$00A35DB4位置的地址,然后把该地址+偏移24C才是真正的地址 ReadProcessMemory(pHandle, Pointer(offerAddr), Pointer(@money),sizeof(money),tmpNum); //记得格式 label1.caption:=inttostr(money); ......
看到了吧,应该先读取$00A35DB4基地址处的地址数据,这样就是动态地址了,然后把读取到的这个地址+$24c才是真正的地址,因为读取$00A35DB4处的地址是每次都不一样的,这才真正的表示了$00A35DB4基地址上偏移$24c的数据。
至于修改,那有了上面这个思路就简单多了:
...... pAddr:= $00A35DB4; //基地址 ReadProcessMemory(pHandle, Pointer(pAddr), Pointer(@money),sizeof(money),tmpNum); //记得格式 offerAddr:= money+$24c;//先读取$00A35DB4位置的地址,然后把该地址+偏移24C才是真正的地址 writeProcessMemory(pHandle, Pointer(offerAddr), pointer(@writenumber),4,writenum);//注意这里修改的地址是offerAddr ......
注意上面的代码,由于是动态地址,所以必须先用ReadProcessMemory读取后才能修改,如果直接修改$00A35DB4+$24c是错误的。
看到这里大家应该明白怎么做了,这里的例子是一级偏移,如果有二级偏移,三级偏移甚至是多级偏移等,就要老老实实的用ReadProcessMemory分级读取了。
说到writeProcessMemory,有时候我们修改并不成功,这是什么原因呢?因为Windows里进程一般都是默认对内存空间进行只读保护,除了自身其他进程是无权修改的,我们必须先对其取得修改权限才行。取权限也很简单,两个函数就可以搞定:
var mbi_thunk:TMemoryBasicInformation; begin VirtualQueryEx(pHandle,Pointer(offerAddr),mbi_thunk, sizeof(TMemoryBasicInformation));//首先查询指定地址 VirtualProtectEx(pHandle,Pointer(offerAddr),4,PAGE_EXECUTE_READWRITE,mbi_thunk.Protect);//对指定地址给予读写权限PAGE_EXECUTE_READWRITE ...... writeProcessMemory//使用writeProcessMemory来修改数据 VirtualProtectEx(pHandle,Pointer(offerAddr), 4, mbi_thunk.Protect,dwOldProtect);//修改完毕记得重新加上只读保护
对于VirtualQueryEx和VirtualProtectEx两个函数,感兴趣的可以查询MSDN,这里就不过多解释了。通过本文,你应该可以了解基地址和偏移地址的关系了吧?

- 评论(0)
发表评论 TrackBack
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。