本帖最后由 JuncoJet 于 2020-7-7 13:09 编辑
学习本章内容前请先掌握上一章节知识(不掌握问题也不是很大,直接拿程序走人)
红警2秒杀原理剖析干货级讲解和专用修改器实现
https://www.52pojie.cn/thread-937873-1-1.html
(出处: 吾爱破解论坛)
前言
不搞前言什么什么的了,直接开始本章内容。
正文
也许有部分人有分析过红警2,也许也有人看到下面这种代码,
在OD调试的时候,会有很多字符串的提示,看着对程序的分析很有帮助,跟进CALL里如下图
对,就直接RETN了,什么也没有。这个就是被阉割的调试输出,本章节将围绕开启调试功能进行深入展开。
我们以这个CALL为例,可以看到CALL的下面有ADD ESP,0x4之类的,并且CALL之前没有ECX EDX之类的操作,这个就是典型的__cdecl调用约定的特征。
啥是佩奇,不对,啥是__cdecl?__cdecl是一种常见于C语言和C++编写的程序里的调用约定,是种默认的调用约定。他的伪代码如下
[Asm] 纯文本查看 复制代码 fun:
retn
main:
push 参数3
push 参数2
push 参数1
call fun
add esp,4*3
retn
可以看到,这种调用约定调用者在调用完成后,必须负责恢复栈指针(ESP寄存器)。遵循谁调用谁清理原则,这种调用的优势是什么?
在Windows API中大多数采用__stdcall(后面会介绍),但是少数的也会采用__cdecl约定,例如wsprintf能够支持不固定个数的参数,栈允许的情况下能支持无限多个,这自然需要归功于__cdecl这种调用机制的功劳。除此外,其实还有__stdcall __fastcall __pascal __thiscall等调用约定。
__stdcall比较常见的调用约定,被大多数程序所支持,调用者无需自己清理栈,伪代码如下
[Asm] 纯文本查看 复制代码 fun:
retn 4*3
main:
push 参数3
push 参数2
push 参数1
call fun
retn
__fastcall在Windows中底层会采用此调用约定,因为顾名思义,因为使用ECX和EDX寄存器性能较其使用栈(内存寻址)更快,他的伪代码如下
[Asm] 纯文本查看 复制代码 fun:
retn 4
main:
push 参数3
mov edx,参数2
mov ecx,参数1
call fun
retn
__pascal这个是pascal语言所采用的调用方式,他的调用顺序是从左到右,而__stdcall是从右到左,其他方面并没有任何差别,他的伪代码如下
[Asm] 纯文本查看 复制代码 fun:
retn 4*3
main:
push 参数1
push 参数2
push 参数3
call fun
retn
delphi虽然使用pascal语法,但从本坛的很多逆向资料来看,调用方式接近于__fastcall,把参数会压入EAX和ECX寄存器。
__thiscall是C++ CLASS的调用方式,把*this会放进ECX寄存器,类似于__fastcall的__stdcall调用约定,较高性能的一种调用约定,他的伪代码如下
[Asm] 纯文本查看 复制代码 fun:
retn 4*2
main:
push 参数2
push 参数1
lea ecx,[this]
call fun
retn
那所有的调用约定原理都已经学习过了,我们接下来就做补丁吧,先按照上次课程所学的窗口消息(SetWindowsHookEx)的方式注入游戏。然后用今天我们所学的,__cdecl调用约定来重新实现个调试输出的补丁,并且会使用的上个章节提及但并没有演示的inline hook部分。
代码写完大概就是这个样子
[C] 纯文本查看 复制代码 void dbgOut(DWORD p){//因为C语言里默认的调用方式__cdecl,所以可以不用描述词
DWORD *d=(DWORD*)((DWORD)&p-4);//指针概念,p是进入的参数,&p是他的参数栈的地址,&p-4就是返回地址
if(!strstr(d[1],"Theme")){//过滤掉Theme消息,太多了
sprintf(&buf[0x200],d[1],d[2],d[3],d[4],d[5],d[6],d[7],d[8],d[9],d[10]);//sprintf也是__cdecl调用约定,所以我输入多少个参数和他这个API无关,始终能保持栈的平衡
sprintf(buf,"[Ra2DbgOut] %08X %s",d[0],&buf[0x200]);//加一个前缀,显得更酷炫,并且把返回地址显示出来
OutputDebugString(buf); //输出调试信息,能够在dbgView中进行查看
}
}
接下来我们来耍一下吧
上图可以看到初始化信息,人和电脑选择的国家
上图可以看到最终的比分,和下面这个图上是一样的
然后我们可以尝试建造,暂停等操作
调试信息中能看到触发事件,并且成功得到目标代码地址,然后一个调试器过去
接下来怎么做大家都懂的,
讲的比较粗,有问题可以在下面留言提问,我不一定会回答
|