吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 9138|回复: 44
收起左侧

[游戏安全] 【原创】CE HOOK实现pvz子弹分身教程

  [复制链接]
lyl610abc 发表于 2021-2-5 19:07
本帖最后由 lyl610abc 于 2021-9-8 09:47 编辑

前言

上期教程更侧重于学习,并没有什么实际的功能效果,于是为了学以致用,今天给大家带来CE HOOK实现pvz子弹分身教程

适合学习人群:比萌新强两丝丝足矣

上期教程链接:https://www.52pojie.cn/thread-1361473-1-1.html

效果图

先给大家看看效果

pvz1

事前准备

本人使用的工具:CE7.2汉化版(不用在意版本问题)

论坛有:https://down.52pojie.cn/Tools/Debuggers/Cheat%20Engine%20v7.2.exe

代码注入工具:https://www.52pojie.cn/thread-963707-1-1.html

PS:OD什么的不需要啦

本人使用的游戏:植物大战僵尸原版的汉化版(非年度版)     就是阳光基址是006A9EC0+768+5560的那个

附带一个下载地址:https://lanzoui.com/i9u7o3i

教程内容

思路分析

首先搞清楚我们想要实现的功能:让发射的一个子弹变成多个

很明显与子弹的产生有关,于是我们的目的转化为:找到产生子弹的CALL→HOOK这个CALL让它一次产生多个子弹

如何找到子弹产生的这个CALL?寻找相关数据来获得

我们先暂且不论子弹产生的内部细节,但有一点显而易见的便是子弹产生后一定会引起场上子弹数量的增加

function generateBullet()
    .......
        bulletNum++;        --子弹数量增加
    .......
    return ?
end

于是我们便以这个场上的子弹数量为突破口开启找CALL之路

寻找子弹产生CALL

首先我们要找到这个记录场上子弹数量的地址

image-20210205130914263

通过CE过滤子弹数量,当子弹数为1时搜1,为2时搜2.........最终可以得到记录当前场上子弹数量的地址

image-20210205131126067

然后右键 找出是什么改写了这个地址

image-20210205131302353

这里有2条记录,一条是子弹产生时引起数量增加,还有一条是命中僵尸后子弹消失引起的数量减少

这里的第一条便是我们子弹产生时让子弹数量增加对应的汇编指令

我们点击显示反汇编程序进去看看

image-20210205131650345

PlantsVsZombies.exe+1DFC9 - 01 47 10              - add [edi+10],eax { 子弹增加 }

找到这一里以后要干什么?向上一层找

为什么要向上一层找?

我们前面已经分析过子弹数量的增加只是子弹产生里的一个小步骤,可能是如下结构

function bulletNumAdd()                --子弹增加的函数
    bulletNum++;                        --我们看到的add [edi+10],eax就对应这里
    return ?
end
function generateBullet()
    .......
    bulletNumAdd()                        --调用子弹增加的函数
    .......                                
    return ?
end

这里我们想要调用产生子弹的CALL就要返回到调用CALL的同一层来查看具体的参数

于是我们可以在这里下个断点,让它断下

image-20210205141000067

接着F8单步步过,在ret的这里停下,先不要返回

image-20210205141125569

我们这是可以看一下右下角的堆栈窗口,PS:如果显示不同 可以在这个窗口这里 右键"堆栈跟踪"

image-20210205141206972

堆栈窗口浅谈

首先我们都知道CALL XXXX以后是要返回的,要返回到哪里的相关数据都存在堆栈里,所以我们可以通过这个堆栈地址返回到上一层 上上一层 上上上层......,而这些返回地址的上一句就是CALL XXXX调用我们这个子弹数量增加的CALL

我们可以通过这里顺腾摸瓜 子弹数量增加语句→子弹数量增加CALL→子弹产生CALL (实际的执行顺序是反过来的)

如果我们不通过这个堆栈窗口,而是一直F8单步步过的到ret再返回实际结果也是如此

所以我们知道了 这个堆栈窗口里的某个CALL 一定就是产生子弹的CALL(我们可以先记录下这些CALL的位置 在相应CALL位置 右键设置书签)

如何确定是哪个CALL?

看参数,产生子弹至少需要哪两个参数?,答案呼之欲出:坐标,子弹的X坐标和Y坐标,于是我们的这个函数至少有2个参数

如何确定一个CALL的参数?

看CALL里面的返回值 ret xx

拿堆栈里的一个返回地址来举例,我们双击它来跳转到那里

image-20210205143758137

PlantsVsZombies.exe+D62A - E8 31090100           - call PlantsVsZombies.exe+1DF60 { 子弹数量增加call }

如何确定这个call的参数呢?进到CALL里面去查看返回值

我们Ctrl+G或者右键转到地址

image-20210205144232518

这里想跳转的地址填CALL XXXX 里的XXXX 我们这里就是填PlantsVsZombies.exe+1DF60

跳转后我们就已经进入到了CALL的内部,在下面还能看到我们之前的子弹数量增加语句(验证了堆栈窗口的作用,存储返回地址的相关数据,注意我这里说的是相关数据,不一定就直接是返回地址,但我们(系统)能够用相关数据算出返回地址,这涉及到段寄存器的相关知识,这里不做重点)

image-20210205144619477

我们直接到函数的尾部查看返回值

image-20210205145051654

PlantsVsZombies.exe+1E001 - C3                    - ret 

我们可以看到这里没有返回值 直接就ret了

那是不是说明这个函数不需要参数,直接就可以调用了?并不是

我们先说一下

ret xxx和参数的关系

在汇编中 一个子程序(call)有几个参数(push)就需要几个RETURN(堆栈平衡) 因为push压入的是四字节 所以有几个push 也就需要几个

ret  push数量*4)        打个比方如果压入了5个参数 则ret 的返回数值为 ret 0x14        注意这里是十六进制 0x14=20=5×4

push 只是将参数传给call的手段之一,也可以通过mov 寄存器,xxx等给寄存器赋值的方法来传递参数

如果我们这里直接用代码注入器调用这个CALL,没有给它传递参数,那么游戏直接崩溃,PS:代码注入器是拿来给我们外部直接调用CALL的

image-20210205150223661

我们可以看一下CALL前面的代码:

PlantsVsZombies.exe+D620 - 56                    - push esi
PlantsVsZombies.exe+D621 - 57                    - push edi
PlantsVsZombies.exe+D622 - 8B F8                 - mov edi,eax
PlantsVsZombies.exe+D624 - 81 C7 C8000000        - add edi,000000C8 { 200 }
PlantsVsZombies.exe+D62A - E8 31090100           - call PlantsVsZombies.exe+1DF60 { 子弹数量增加call}

可以看到mov edi,eax 我们怀疑可以怀疑它将edi作为了参数,所以我们可以在call这里下个断点,然后将edi的值复制下来:

image-20210205150913051

这里的EDI为15A8D050

我们修改一下代码注入器里的内容,然后重新测试

image-20210205151307797

代码注入以后,我们发现游戏并没有崩溃,同时场上子弹数量增加了1,且屏幕左上角出现了一个子弹

image-20210205151734218

image-20210205151422962

这里主要是为了说明call的参数可能不只是push给的可能还与寄存器的值有关,这个CALL我们没有找到与坐标相关的数据,于是看下一个CALL(之前堆栈窗口里的第二个)

image-20210205161942619

用同样的方法,查看这个call的参数(跳转地址到CALL XXXX里的XXXX,然后到尾部看返回值)

image-20210205153419441

PlantsVsZombies.exe+D653 - C2 1400               - ret 0014 { 20 }

从这里的ret 0014我们可以得到push了20/4=5个参数

于是我们在回到这个CALL这里 下个断点 看看它参数的内容

image-20210205162110428

PlantsVsZombies.exe+672A5 - 50                    - push eax         {子弹类型}
PlantsVsZombies.exe+672A6 - 8B 45 04              - mov eax,[ebp+04]        {植物基址}
PlantsVsZombies.exe+672A9 - 53                    - push ebx         {行数}
PlantsVsZombies.exe+672AA - 83 E9 01              - sub ecx,01 { 1 }
PlantsVsZombies.exe+672AD - 51                    - push ecx                         {未知,貌似不影响结果,可以直接填0}
PlantsVsZombies.exe+672AE - 56                    - push esi { y坐标 }
PlantsVsZombies.exe+672AF - 57                    - push edi { x坐标 }
PlantsVsZombies.exe+672B0 - E8 6B63FAFF           - call PlantsVsZombies.exe+D620 { 子弹产生call }

我们通过分析数值 可以得出ESI和EDI分别是子弹的Y坐标和X坐标,如何确定?

在PUSH 之前修改寄存器的值,修改后F8单步步过,确保被修改过的寄存器压入到堆栈中,然后返回游戏,可以发现子弹产生的位置发生了改变

image-20210205162211359

image-20210205154304453

由此我们可以认为这个CALL便是子弹产生的关键CALL,于是依葫芦画瓢,我们把填入相关的参数然后调用这个CALL

image-20210205160831700

image-20210205161010386

这里我们可以看到子弹成功产生了,所以这个CALL就是产生子弹的关键CALL

如何获得参数的值

在参数压入之前下断

image-20210205161153256

断下:

image-20210205161232219

push eax  则把eax 变成此时的push 0x0

mov eax,[ebp+04]则把eax变成赋值后的数值即mov eax,0x13587F08(记得要F8单步步过一步步下来哦)

push ebx则把ebx变成此时的push 0x3

....以此类推

我们只需要关注call之前push xxx和mov xxx的值即可,然后把相关数值给它即可

如何得知相关参数含义

然后我们可以修改相关数值,比如把push edi 的edi由0x69改成0x169 可以发现子弹的x坐标发生了改变来确定相关参数的含义

也可以观察不同位置豌豆引发中断时寄存器数值的不同来分析出各参数的含义

得出注入代码

于是我们就得出了上面要注入的代码,mov eax,xxxx后面的那个值要修改成你自己的EAX的值

push 0x0
mov eax,0x13587F08
push 0x3
mov ecx,0x513DD
push 0x000513DC
push 0x186
push 0x69
call 0040D620

对照

PlantsVsZombies.exe+672A5 - 50                    - push eax         {子弹类型}
PlantsVsZombies.exe+672A6 - 8B 45 04              - mov eax,[ebp+04]        {植物基址}
PlantsVsZombies.exe+672A9 - 53                    - push ebx         {行数}
PlantsVsZombies.exe+672AA - 83 E9 01              - sub ecx,01 { 1 }
PlantsVsZombies.exe+672AD - 51                    - push ecx                         {未知,貌似不影响结果,可以直接填0}
PlantsVsZombies.exe+672AE - 56                    - push esi { y坐标 }
PlantsVsZombies.exe+672AF - 57                    - push edi { x坐标 }
PlantsVsZombies.exe+672B0 - E8 6B63FAFF           - call PlantsVsZombies.exe+D620 { 子弹产生call }

到这一步我们就已经找到产生子弹的CALL了,但是我们会发现参数好多啊,我们想让子弹分身只需要修改子弹的行数和子弹的y坐标就可以了,其它的参数和原本一致就行,我们无需关心。那么能不能换个参数少点的CALL呢,自然可以,我们直接去到下一个CALL(之前堆栈窗口的第三个)

image-20210205164455977

PlantsVsZombies.exe+64BBF - 6A 00                 - push 00 { 0 }
PlantsVsZombies.exe+64BC1 - 51                    - push ecx                {行数}
PlantsVsZombies.exe+64BC2 - 6A 00                 - push 00 { 0 }
PlantsVsZombies.exe+64BC4 - 57                    - push edi                {植物基址}
PlantsVsZombies.exe+64BC5 - E8 36220000           - call PlantsVsZombies.exe+66E00 { call 植物动态基址 }

用同样的方法得出这个CALL的参数是4个 然后我们试着调用一下这个CALL

image-20210205165048428

image-20210205165039977

push 0x0
push 0x3
push 0x0
push 0x15B01A48
call 00466E00

对比

PlantsVsZombies.exe+64BBF - 6A 00                 - push 00 { 0 }
PlantsVsZombies.exe+64BC1 - 51                    - push ecx                {行数}
PlantsVsZombies.exe+64BC2 - 6A 00                 - push 00 { 0 }
PlantsVsZombies.exe+64BC4 - 57                    - push edi                {植物基址}
PlantsVsZombies.exe+64BC5 - E8 36220000           - call PlantsVsZombies.exe+66E00 { call 植物动态基址 }

我们这里只给了两个参数,还有两个参数固定为0 就成功调用了子弹的产生

说一下原理:子弹的产生是由具体的某一个植物产生的,子弹产生首先要获取植物的基址,通过植物基址可以获取到植物的X坐标和Y坐标 以及子弹类型等等参数,然后根据植物的X坐标和Y坐标生成对应的子弹的坐标

所以其实只需要传入一个植物的基址就可以完成,但这里它额外多加了一个行数的参数

CALL调用流程

从前面的分析 我们可以知道调用的关系是

植物产生子弹(植物基址,行数)→产生子弹(子弹类型,植物基址,行数,未知,X坐标,Y坐标)→子弹数量增加()→子弹数量++

我们这里就选择HOOK 最外层的这个CALL  植物产生子弹(植物基址,行数),当然也可以HOOK 后面的那个产生子弹(CALL),但要填的参数较多就是了,感兴趣可以当作业自己做一下~~~

修改参数测试CALL

前面我们用原本的参数填充了CALL,发现子弹可以正常产生没有问题,但是当我们想要让子弹换个行产生,我们修改一下行数的参数发现:子弹的显示位置还是在下面,但是阴影在上面

image-20210205171213451

怎么解决呢?前面的原理说过子弹的产生是由植物的X坐标和Y坐标计算而来的,我们这里之所以子弹的Y坐标没有改变自然是因为植物的Y位置还是原本的那个值,所以我们如果想要子弹的Y坐标改变就得改变植物的Y坐标,然后再恢复植物的Y坐标即可

那么植物的Y坐标的偏移是多少呢?可以从前面一个CALL来追溯(较麻烦不推荐)

PlantsVsZombies.exe+672A5 - 50                    - push eax         {子弹类型}
PlantsVsZombies.exe+672A6 - 8B 45 04              - mov eax,[ebp+04]        {植物基址}
PlantsVsZombies.exe+672A9 - 53                    - push ebx         {行数}
PlantsVsZombies.exe+672AA - 83 E9 01              - sub ecx,01 { 1 }
PlantsVsZombies.exe+672AD - 51                    - push ecx                         {未知,貌似不影响结果,可以直接填0}
PlantsVsZombies.exe+672AE - 56                    - push esi { y坐标 }
PlantsVsZombies.exe+672AF - 57                    - push edi { x坐标 }
PlantsVsZombies.exe+672B0 - E8 6B63FAFF           - call PlantsVsZombies.exe+D620 { 子弹产生call }

我们知道前面的这个CALL的 esi是植物的y坐标,于是我们可以追溯这个y坐标的来源

image-20210205173237108

PlantsVsZombies.exe+671DD - 8D 74 08 DF           - lea esi,[eax+ecx-21]

于是我们得到了子弹是eax+ecx-21得来的,很显然是通过计算得来的,我们这里去追溯eax和ecx就可以得到植物的偏移

另一个办法就比较简单,遍历植物的基址,我们可以通过遍历基址比对来分析植物的数据结构,这里碍于篇幅问题就不具体展开了

植物的数据结构分析教程不少,疑惑的可以去看看,这里也不做重点,直接给出植物的y坐标偏移是0c

于是我们修改一下注入代码

image-20210205174420758

image-20210205174358141

注入以后发现子弹能够在我们指定的位置产生了

贴上注入代码:

pushad                                                //将所有的32位通用寄存器压入堆栈
pushfd                                                //将32位标志寄存器EFLAGS压入堆栈
mov eax,0x15B01A48                        //植物基址
mov ebx,0x64                                //要修改的植物y坐标
mov ecx,[eax+c]                                //保存修改前的植物y坐标,修改完要还原
mov [eax+c],ebx                                //修改植物的y坐标
mov edx,0x98000                                //此处的0x98000为任意一处可读写空地址
mov [edx],ecx                                //将到时候要还原的y坐标保存到空地址中
push 0x00                                        //固定值0
push 0x00                                        //行数 从0开始 0是第一行 4是最后一行
push 0x00                                        //固定值0
push eax                                        //植物基址
call 00466E00                                
mov eax,0x15B01A48                        //植物基址
mov ebx,0x98000                                //之前保存y坐标的地址
mov ebx,[ebx]                                //取出y坐标
mov [eax+c],ebx                                //还原y坐标
popfd                                                //将32位标志寄存器EFLAGS取出堆栈
popad                                                //将所有的32位通用寄存器取出堆栈

为什么要额外用空地址来保存修改前的y坐标? CALL执行后寄存器和堆栈的数据可能会发生变化

这里的空地址地址是哪来的?

CE直接搜索数组 十六进制然后填一堆零 即可得到空地址 搜索选项下面的可写记得勾上

image-20210205175242635

这里因为00098000已经被我修改过了,所以没在搜索结果里

HOOK 子弹产生

前面我们已经实现了在任意行发射子弹,接下来我们就是寻找要HOOK的点并HOOK

要在哪里HOOK呢,首先HOOK的点肯定是要在子弹发射的时候,并且能够获得植物基址

这里我选择了在我们CALL返回的位置HOOK

先贴修改前的代码:

image-20210205182526261

PlantsVsZombies.exe+64BCA - 5F                    - pop edi
PlantsVsZombies.exe+64BCB - 5E                    - pop esi
PlantsVsZombies.exe+64BCC - 5B                    - pop ebx
PlantsVsZombies.exe+64BCD - 8B E5                 - mov esp,ebp
PlantsVsZombies.exe+64BCF - 5D                    - pop ebp
PlantsVsZombies.exe+64BD0 - C3                    - ret 

修改后的代码:

image-20210205182622098

PlantsVsZombies.exe+64BCA - E9 31B45900           - jmp 00A00000
PlantsVsZombies.exe+64BCF - 5D                    - pop ebp
PlantsVsZombies.exe+64BD0 - C3                    - ret 

HOOK的代码:

[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat

alloc(newmem,2048)
alloc(oriaddr,32)                //申请地址 用来存储原本植物基址
alloc(oriy,16)                        //申请地址 用来存储原本植物的y坐标
alloc(orirow,16)                //申请地址 用来存储用本植物的行数
alloc(inity,16)                        //申请地址 用来存储初始的植物y坐标,每次增加0x64=100=一行的间隔
alloc(initrow,16)                //申请地址 用来存储初始的值与行数,每次增加1
label(loopcode)                        //要循环的代码段
label(returnhere)
label(originalcode)
label(exit)
label(endcode)          //退出循环后要复原的代码

newmem: //this is allocated memory, you have read,write,execute access
//place your code here
pushad
pushfd
mov [oriaddr],edi     //保存植物基址
mov [inity],0x0       //要改变的植物y坐标
mov [initrow],0x0       //要改变的植物行数
mov ecx,[edi+c]       //暂存植物y坐标,植物基址+c偏移为植物y坐标
mov [oriy],ecx        //保存植物y坐标到申请的空间
mov ecx,[edi+1c]      //暂存植物行数,植物基址+1c偏移为植物行数
mov [orirow],ecx        //保存植物行数到申请的空间
jmp loopcode

originalcode:
pop edi
pop esi
pop ebx
mov esp,ebp

exit:
jmp returnhere
loopcode:
cmp [initrow],0x5       //比较是否到了最后一行,如果是则跳出循环
je  endcode
mov edi,[oriaddr]
add [inity],0x64
add [initrow],0x1
mov ebx,[inity]         //要改变的植物y坐标
mov [edi+c],ebx       //改变植物的y坐标
mov ebx,[initrow]       //要改变的植物行数
mov [edi+1c],ebx         //改变植物行数
mov ebx,[initrow]
sub ebx,0x1
cmp ebx,[orirow]         //比较是否和原来的行相同,不重复发射
je loopcode              //相同则跳过,不重复发射
push 0x00
push ebx
push 0x00
push edi
call 00466E00
mov ecx,[inity]
cmp [inity],0x1f4    //这里的1f4=500 即比较是否到了最后一行
jb loopcode          //如果小于,则继续循环
jmp  endcode

endcode:
mov eax,[oriaddr]
mov ebx,[oriy]
mov [eax+c],ebx       //还原植物的y坐标
mov ebx,[orirow]
mov [eax+1c],ebx      //还原植物的行数
popfd
popad
pop edi
pop esi
pop ebx
mov esp,ebp
jmp 00464BCF
"PlantsVsZombies.exe"+64BCA:
jmp newmem
returnhere:

[DISABLE]
//code from here till the end of the code will be used to disable the cheat
//申请的空间记得撤销
dealloc(newmem)                
dealloc(oriaddr)
dealloc(oriy)
dealloc(inity)
"PlantsVsZombies.exe"+64BCA:
pop edi
pop esi
pop ebx
mov esp,ebp
//Alt: db 5F 5E 5B 8B E5

CT代码里已经写好了注释,主体思想就是从第一行开始到第五行,依次调用前面我们的CALL来产生子弹,期间加入了变量的保存和读取以及重复子弹的判断

总结(注意事项)

找CALL最重要的就是思路,根据相关变量来确定CALL,本教程的相关变量是场上的子弹数量

找CALL过滤CALL的时候可以看参数来过滤,因此分析目标CALL的结构至关重要

找CALL看CALL的参数时可以通过CALL里的ret返回值来判断PUSH的参数,RET和PUSH是对应的

CALL的参数传值不只局限于PUSH(堆栈传值),也有可能通过寄存器来传值

分析CALL参数含义时可以通过修改CALL在 PUSH前寄存器的值来验证 也可以通过不同的植物产生子弹的调用比较不同参数来判断

测试CALL的时候一定要注意堆栈平衡,该给的参数一定不能少,不然很容易造成游戏崩溃

HOOK的时候一定要注意保存现场,确保HOOK后寄存器和堆栈中的值没有受到影响,以此保证程序的正常运转

作业

HOOK前面找到的参数较多 较为里面那一层的CALL来实现相同的功能

找一找植物的基址,分析出其数据结构

个人感言

这个教程肝了我一天(是我比较菜的原因),后面那部分HOOK子弹产生的讲解比较少,主要都是代码的实现,思路在前面就已经铺开了,可能不是很好理解,本人能力水平也不是很高,望大家高抬贵手,多多担待,如果这个教程对你有用的话,希望能给我点点赞,你们的支持是对我最大的鼓励

最后附上CT表,(CT表里包含了上次教程的作业答案----通过HOOK实现秒杀所有僵尸 包括僵尸BOSS)
CT表截图
ct



PlantsVsZombies.zip

1.79 KB, 下载次数: 38, 下载积分: 吾爱币 -1 CB

CT表

免费评分

参与人数 24威望 +1 吾爱币 +50 热心值 +24 收起 理由
574illyasviel + 1 + 1 热心回复!
djnz + 1 + 1 热心回复!
zhuzhuxia111 + 1 + 1 我很赞同!
忆魂丶天雷 + 1 + 1 大佬666666
迷失的阿坑坑 + 1 + 1 谢谢@Thanks!
Hmily + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Minesa + 1 + 1 用心讨论,共获提升!
yycmd + 1 + 1 我很赞同!
白如雪 + 1 + 1 感谢您的宝贵建议,我们会努力争取做得更好!
finalcrasher + 1 + 1 鼓励转贴优秀软件安全工具和文档!
_小白 + 1 + 1 我很赞同!
迎风三尺郎 + 1 + 1 用心讨论,共获提升!
howsk + 2 + 1 思路清晰可辨
qaz003 + 1 + 1 谢谢分享,留着过年慢慢看。。
小朋友呢 + 2 + 1 我很赞同!
kelvar + 1 + 1 谢谢@Thanks!
Ebichu + 1 + 1 我很赞同!
某中二绅士 + 3 + 1 用心讨论,共获提升!
涛之雨 + 4 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
fanvalen + 1 + 1 我很赞同!
寒枫雨雪 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
我叫蛋dan + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
维多利加 + 1 + 1 热心回复!
国际豆哥 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| lyl610abc 发表于 2021-2-5 19:08
本帖最后由 lyl610abc 于 2021-2-10 14:15 编辑
 楼主| lyl610abc 发表于 2021-2-6 17:01
遛你玩528 发表于 2021-2-6 16:41
楼主你好,看了你的教程 还是不明白pushfd到底能起到什么作用。
还有最后还原植物的Y坐标+行数为什么用eax ...

pushad: 将所有的32位通用寄存器压入堆栈
pushfd:然后将32位标志寄存器EFLAGS压入堆栈
这两个是拿来保存寄存器状态的,因为我们自己进行修改的过程需要用到寄存器,会改变寄存器的值,如果修改完寄存器的值以后没有恢复会造成游戏崩溃
最后还原植物坐标不一定要用eax来还原,只是随便拿个通用寄存器过来暂时作为赋值的媒介,你也可以把这里的eax改成edx,ebx换成ecx 没有问题的。
 楼主| lyl610abc 发表于 2021-2-6 18:20
遛你玩528 发表于 2021-2-6 17:33
Pushad 我懂,就是把所有寄存器全部push一遍
那pushfd具体操作了什么呢?具体什么情况下需要用到pushfd

pushfd是保存标志位,比如cmp eax,0x0 然后je xxxx 这个je判断的其实就是标志位,cmp eax,0x0比较结果是给标志位的,如果你HOOK的代码里有用到cmp之类会改变标志位的指令的话就需要用到pushfd
璐璐诺 发表于 2021-2-5 19:12
大。。大佬 先前排再慢慢学习。。。。。
国际豆哥 发表于 2021-2-5 19:30
看见按这个大佬更新我上上就过来了很快啊
asd5478 发表于 2021-2-5 20:45
大佬牛逼啊,看的头晕
吾爱蛋蛋 发表于 2021-2-5 21:28
谢谢大佬教程
天空の幻像 发表于 2021-2-5 21:45
太厉害了,研究的真细致
侃遍天下无二人 发表于 2021-2-5 21:51
有点意思,感觉略微能看懂一点,我一直想有所进步,不要再是只会替换代码实现无敌的水平了
moliy 发表于 2021-2-5 22:07
贼爱看,还看不懂
 楼主| lyl610abc 发表于 2021-2-5 22:10
moliy 发表于 2021-2-5 22:07
贼爱看,还看不懂

哪里看不懂可以提出来,共同探讨,一起进步
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-26 07:20

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表