前言
这次的帖子拖得有点久,都怪万恶的双十一。大家见谅,我手恢复好的第一时间就想到了继续分享。
本篇来找一下CS1.6人物的基址和实现人物无敌。
接下来基本的自瞄,透视,这些功能应该都会讲到。当然最终还是会易语言整合一波,请大家多多支持。
欢迎文明转载,请注明出处 丸子de爸爸
本文所有技术资料仅供研究,不鼓励任何盗版商用行为
请大家支持正版,支持正版!支持正版!!!
PS:如果对很多概念不懂或者看不明白,建议去看一下之前的系列,学习是一个长期功课,别急于一时。
工具
本次基础概念
内存,一切皆内存,我们操作的全部都是内存。
所有地址相关的概念,都可以理解为坐标,用来给我们做标记的而已。
如果实在搞不明白,你想想指南针为啥指向北边,为啥叫南北,只是定义,只是公认
PS:上面这一段是重复了,但是我觉得还是有必要多重复一下,看多了,大家就印象深刻一点。
实现步骤
CS游戏调试前准备
游戏的版本(其实这个不重要,都是类似的逻辑)
首先选择“游戏选项”,把游戏调成窗口模式,然后分辨率自己调到舒服的大小
之后可以新建游戏,设置一下红框内容,为了调试方便。
无限金钱实现
CE查找金钱基址
开始游戏,我这仓库地图,建议选择匪徒。(到时候CT会自己跑进来,不用去找他)
在CE中附加CS1.6,然后先搜索金钱数,16000
回到游戏,买一颗雷,然后搜索新的金钱数量。
只有两个数据,根据颜色发现,一个是基址,一个是动态地址。
右键,将第一个基址的值改为10000
回到游戏,发现数值已经改变,但是这时还不能确定,因为有两个地址
此时我们要做的,就是在游戏里面再购买一个道具
如果地址是正确的,那么两个地址都会变成新的值,而且是从10000开始减少
同理,如果此时金钱还是从15700减少,说明第二个才是正确的金钱地址
购买了一个闪光弹,结果金钱增加到了15500,说明我们之前推断是正确的
第一个基址只是用来做界面显示的,第二个动态地址,才是真正的金钱地址
验证一下,将第二个地址改为10000,然后再回到游戏买一个道具试试
果然如我们推测的那样,金钱也变化了
CE查找扣除金钱关键逻辑
我们需要实现的功能是,购买物品不花钱,而购买物品是需要扣除金钱的
所以我们需要监控“是什么改写了这个地址”
回到游戏,再随便买一个东西,会发现有一条修改记录
选中这一条,双击
详细信息就是这一条记录产生时的一些信息记录,我们分析一下:
红色的就是当前行,也就是扣除金钱的执行
我们能得到什么信息呢?结合汇编,mov [esi+1CC],ecx
就是给esi+1CC这个内存地址赋值ecx寄存器里面的值,ECX的值为251C,转换为十进制正好是金钱数。
所以我们可以得到esi+1CC里面存放的值,就是金钱
这样我们就可以完全翻译这一波汇编,从上到下解读:
- 将金钱放入ecx中
- 金钱增加一个值,仍然放在ecx中,增加可以为负可以为正,这里理解就是改变金钱。
- 将改变后的金钱(不管是增加还是减少)放到金钱内存地址中
- 将改变后的金钱放到eax中
AA脚本编写
回到之前的列表中,选择“显示反汇编”,跳到汇编界面,在工具中选中自动汇编
自动汇编中按红框中数字顺序先后选择
脚本中就会自动出现模板,将originalcode中的代码中的ecx改为0x3E80。之后选择分配到当前CT表。
之所以改ecx,上面已经分析了很多了,ecx是动态的金钱,扣除或增加了之后,再赋值到金钱内存中。
这里直接改为0x3E80(十进制16000),就等于,不管加钱还是减钱,都直接变为16000。
然后回到CE界面,你的脚本已经在下面的列表中了,红框位置选择激活。再回到游戏,可以乱买了,是不是不扣钱了。
金钟罩铁布衫实现
CE查找生命基址
开一个新的搜索,先搜索100。然后折磨自己,用雷炸也行,跳楼也行。掉个血搜一次,掉个血搜一次。
最终可以得到7-8个这样的结果,而且会发现,不管怎么搜,都筛选不出来。
这时候就可以用点特殊的方法了。
之前金钱的详细信息中,金钱的内存信息是esi+1CC,一个偏移值。我们通过图,可以知道esi是05414008,金钱是通过这个值来偏移的。在之前的分享中,我有介绍过对象的概念,也就是相同的数据,会存放在相近的内存位置。所以我们可以大胆猜测,真正的生命值位置,也在05414008附近。
PS:这个0541是我本地的,你们的不一定一样,是动态的。但是都可以根据金钱旁边的位置找。
回到CE看一看,离金钱最近的地址果然有一个054145BC。(你们那的地址应该不一样)
双击这个地址,把他添加到下面的列表中,也可以修改描述。
选择最靠近金钱那个地址,右键“是什么访问了这个地址”
这里选择访问的原因,是因为CS游戏中,你掉血死亡都是即时的,也就是说,他一直有个线程在循环访问生命值,如果为0,就是死亡了。
当然你要搜改写也行,这样就每一次掉血,会改写一次,你就会先找到改生命值的位置。然后需要往上推导,当然如果运气好的话,直接就可以把扣血改为0。(这里我就是先尝试的改写,但是逻辑不太一样,当然最终还是可以找到正确的位置,但是太曲折,你们也可以锻炼一下自己)
PS:下图的金钱动态地址,是我打错名字了,很后面才发现,懒得改了,大家注意看数值哈。金钱我是没添加到下面列表的,下面列表的全是生命相关。
发现只有一个访问,就是一个对比的命令,我们同样双击,查看详细信息
这里的esi仍然是05414008,生命值也是由esi+5B4得来,所以我们可以大概得知esi对应的地址就是玩家信息的首地址。然后这里在使用eax和生命值比较,eax=0x64=100,意思暂时猜不到啥意思,用生命比较生命,暂时不知道啥意思,不如我们就动一下。
在CE中,将生命的值改为90,发现立刻又变回了100,这样一来,eax的意思就更加明确了,上面的eax应该是准确的生命值,用ESI+5B4和eax比较,如果不一致,则以eax为准。
可以简单理解为,cmp作为比较指令,肯定要有一个标准嘛,比如说和0比,和1比,这里就是和eax比。为啥是和eax比,因为我们修改了ESI+5B4的值,如果是以他为准,生命值直接就会变成90,但是变回了100,说明以eax为准。
那接下来我们就需要分析eax是从哪里赋值的,在之前查看访问列表中选择“查看反汇编”,进入汇编界面
可以发现cmp上面一行就是一个方法(如果不懂汇编,先去看下我之前其他的教程),这个方法里面对eax赋值的可能性很大。所以在上面方法处按下F5打断点,并按F7进入方法。
一路按F8步进,同时观察eax的值,最终发现,在一句指令执行完之后,eax的赋值变为了生命值。
发现这里的赋值是ebp-0C,而ebp这个寄存器一般是作为通用的,不作为数据存储使用,所以大概率代表这个方法是一个公共的方法,而不是专门的方法,往上看,会发现有几个fldce,fistp,fldcw,这种的汇编指令。具体啥意思大家都不用去了解,简单理解就是对浮点型数据的操作,也就是带小数点的数进行操作的,但是他也是通过进栈出栈的方式进行操作。
所以在方法前面,一定会有对需要操作的数进行的赋值,也就是用相同的fld等语句,将数字放到栈里,由公共方法统一读取操作。所以我们跳出这个方法,往方法前面查看一下。
方法前面两句:
esi是人物对象的动态地址
- edi赋值为esi+04的值
- 将edi+160的值压到浮点数计算的栈里
感觉应该就是这里了,也就是ESI+04存放的内存地址,[ESI+04]里面的地址再偏移160,得到的地址,才是真实的生命内存地址。
选择内存窗口,ctrl+G,输入对象基址+4,我的是05414008+4你们的看之前金钱那的ESI。
确定之后,记录左下角红框里的值,逆向记录内存中的值06EC1BFC,为啥逆向记录我之前教程有说。
刚才我们拿到了ESI+4中的内存地址,接下来还需要把这个地址偏移160。
在CE中选择手动添加地址,输入刚才查到的值06EC1BFC+160。点确定,发现是乱七八糟的值。
是不是忘记了,这个是浮点数,将类型改为float之后,数值变为了100。
将刚才添加的地址的值给改为90,然后发现CE中,所有的生命记录都是90了,而且游戏中的血量也变为了90。
说明我们这才算是找到了真正的生命值地址。
玩家对象动态指针构造
右键在生命值真实地址上,选择“什么访问了这个地址”,发现有一个mov eax,[edi+160],按之前的方法,查看一下详细信息,发现ebx中的值就是对象的基址。就在这里做指针把。选择mov那一条,显示反汇编。
PS:不选择其他的fld是因为,fld是放到float栈里,公用的概率很大,mov公用的概率小一些。如果公用,就可能导致对象基址一直会变,因为玩家数量很多,他循环调用,就会导致无敌失效,会一人无敌一小会。
还是按照之前的方法,创建AA脚本。
具体啥意思不多解释了,就是自己构建了一个动态指针,详细解释在植物大战僵尸第一篇。
[ENABLE]
alloc(newmem,128)
registersymbol(pointer)
alloc(pointer,4)
label(returnhere)
label(originalcode)
label(exit)
newmem:
originalcode:
mov [pointer],ebx
mov eax,[edi+00000160]
exit:
jmp returnhere
"mp.dll"+65101:
jmp newmem
nop
returnhere:
[DISABLE]
dealloc(newmem)
dealloc(pointer)
unregistersymbol(pointer)
"mp.dll"+9AF86:
mov edi,[esi+04]
fld dword ptr [edi+00000160]
//Alt: db 8B 7E 04 D9 87 60 01 00 00
创建完成后,打开脚本,我们就可以添加生命值基址了,按照刚才那样添加偏移。
金钱基址pointer+1CC就行
CE查找扣除生命逻辑
对刚才添加的生命基址右键,“找出是什么改写了地址”,然后选择指针改写的地址。这里改写的原因,是找到扣除生命值的地方,直接把赋值修改,和前面不同的原因是,访问里面东西太多了,不好定位。
回到游戏,自残一下,发现多出了一条记录。
AA脚本编写
选择这条记录,显示反汇编,之后直接在选中位置创建AA脚本
启动脚本后,再去自残试试,发现已经不掉血了。但是这又会出现一个问题,如果是通过这种公共的方法赋值,那多个敌人或者队友,都会无敌,这是我们不希望的,添加个敌人试试。
[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
alloc(newmem,128)
label(returnhere)
label(originalcode)
label(exit)
newmem:
originalcode:
//fstp dword ptr [eax+00000160] 这是原来的代码,直接注释让他不生效
mov [eax+160],0x42C80000 //把生命值改为100,后面这一串是100的浮点数值显示
exit:
jmp returnhere
"mp.dll"+66F05:
jmp newmem
nop
returnhere:
[DISABLE]
//code from here till the end of the code will be used to disable the cheat
dealloc(newmem)
"mp.dll"+66F05:
fstp dword ptr [eax+00000160]
//Alt: db D9 98 60 01 00 00
果不其然,我和电脑互相打得满地鲜血,结果神仙打架,都伤不了对方分毫。于是我们看一下刚才生命基址的改写内容的列表,双击,查看一下详细信息。
在ESI位置,果然还是看到了熟悉的东西,这不就是玩家对象的基址么,那如果我们拿之前我们有默认存储的pointer和这里的ESI进行对比,是不是就可以区分开了呢?
PS:这里我是有尝试,敌人在打我和我打他,都会触发这个方法,但是ESI不同
修改上面的脚本内容
[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
alloc(newmem,128)
label(returnhere)
label(originalcode)
label(exit)
newmem:
fstp dword ptr [eax+00000160] //正常扣血逻辑
cmp [pointer],ESI //比较对象基址和当前玩家基址
jne exit //如果不是玩家的话,就不无敌。是玩家,就把血量改回来。
mov [eax+00000160],0x42C80000 //把生命值改为100,后面这一串是100的浮点数值显示
originalcode:
exit:
jmp returnhere
"mp.dll"+66F05:
jmp newmem
nop
returnhere:
[DISABLE]
//code from here till the end of the code will be used to disable the cheat
dealloc(newmem)
"mp.dll"+66F05:
fstp dword ptr [eax+00000160]
//Alt: db D9 98 60 01 00 00
完事,添加一群一群的电脑,杀戮,大刀向敌人头上砍就行了。
结尾
CS的修改比起植物大战僵尸就要稍微复杂一些,不过还是那些套路,先找到内存中正确的存放地址,然后通过地址找到逻辑,分析逻辑,构造指针,然后完成脚本。建议看不懂的兄弟们结合之前的文章知识一起观看,有啥问题欢迎提出来一起讨论,但是请描述清楚和带有基本的尊重哦,多谢各位的支持。