文章主要内容是有参CALL如何分析参数,在写汇编时如何把参数写进去以及如何调用。
以喊话CALL为例,喊话CALL是用代码来调用,打印任意的话。
1.打开x86dbg,文件-附加-打开游戏

![点击并拖拽以移动]()
2.bp send(设置send函数的断点)回车,断点,再运行
![点击并拖拽以移动]()
3.在游戏中,点击“当前”,输入123456,再运行x86dbg

![点击并拖拽以移动]()
4.点击调用堆栈,找到断点,复制整个表格
![点击并拖拽以移动]()
5.新建分析文本,粘贴整个表格,只留下主线程,在第三层74开始分析

![点击并拖拽以移动]()
6.运行,然后断点禁用或删除
![点击并拖拽以移动]()
7.Ctrl+G返回到这里,确定

![点击并拖拽以移动]()
8.返回到是Nop,它的上一层就是调用的call,可以看到有三个参数rdx、r8d(r8的32位)、rcx(在64位类似fastcall,它的前四个参数分别是rcx、rdx、r8、r9)
![点击并拖拽以移动]()
喊话CALL是会带一个发送的文本,有文本参数,所以先找一下参数。
9.1 点击call的地方下断点,在游戏内-当前-发送文本
![点击并拖拽以移动]()
9.2来看一下参数,发现其他rax、rsi、r10、r11里有文本,但在r8、r9、rcx、rdx里没有

![点击并拖拽以移动]()
因此判断不是我们要找的CALL,是底层或上一层call,取消断点
9.3文本参数应该前四个参数里
![点击并拖拽以移动]()
9.4 Ctrl+G返回到这里,确定

![点击并拖拽以移动]()
9.5下个断点,走动一下(防止是其他call),再说一句话,回车
![点击并拖拽以移动]()
9.6断下来,发现r8符合要求
![点击并拖拽以移动]()
9.7把参数记下来,然后断点运行
![点击并拖拽以移动]()
9.8复制寄存器,只留通用寄存器
![点击并拖拽以移动]()
9.9把rcx、rdx、r8、r9参数复制下来,可以确定r8是字符串地址
10.找rdx参数
10.1 Ctrl+G返回到这里,确定
![点击并拖拽以移动]()
10.2测试rdx,在当前多喊几次话,发现寄存器没有值,所以认为rdx是写死的值-0
![点击并拖拽以移动]()
10.3再切换主队,发现rdx有变化,所以判定rdx是说话的方式
![点击并拖拽以移动]()
10.4当前模式是0,组队模式是2,团队模式是12
11.找r9参数
11.1测试r9,多喊几遍,r9没有变化,r9是写死的值-FFFFFFFF
![点击并拖拽以移动]()
12.找rcx参数
12.1复制rcx,重启游戏并重新打开x86dbg,文件-附加-打开游戏
![点击并拖拽以移动]()
12.2喊话-断点,发现rcx的值变了,所以需要找一下值

![点击并拖拽以移动]()
12.3返回调用,发现rcx来自与rbp+620,然后找一下620
![点击并拖拽以移动]()
使用x64dbg继续调也可以,使用ida看起来更方便
12.4把64位客户端在64ida里打开
![点击并拖拽以移动]()
12.5 CTRL+G跳转到返回的位置上,发现没有rcx赋值
![点击并拖拽以移动]()
13.因为很难找到rcx,所以找到另一个突破点
13.1在寄存器里发现rbx和rcx一样,就以rbx为突破点,找到了rbx对rcx的赋值
![点击并拖拽以移动]()
13.2怀疑没有通过src对rcx赋值,而是通过rbx对rcx赋值之后,通过跳转到参数传递,直接调用喊话CALL
![点击并拖拽以移动]()
13.3 若是上述情况,需要先找rbx的值
13.3.1发现是变量Var EB0给rbx赋值
![点击并拖拽以移动]()
13.3.2再寻找变量Var EB0,发现是rax赋值给变量Var EB0

![点击并拖拽以移动]()
13.3.3 rax值来源于上面的call,call的返回值是rax
![点击并拖拽以移动]()
13.4 Rcx=那个call的返回值
13.4.1进一层,Rax就是call的返回值+48,然后取值
![点击并拖拽以移动]()
13.4.2再进去一层,发现一个基址放在rax里
![点击并拖拽以移动]()
13.4.3 Rcx=[0x基址+0x48]
![点击并拖拽以移动]()
到此数据分析的四个参数已经都找到了