欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]Find CALL Tool(带源码)

[原创]Find CALL Tool(带源码)

Find CALL工具功能与Cheat Engine类似,只不过Cheat Engine是找数据,Find CALL工具是找功能调用函数。这两个工具都为外挂制作者和游戏安全人员带来福音?。Cheat Engine和Find CALL工具界面如图1所示:
                                   
                                             
                                   
                                           图1 Cheat Engine和CallTool界面
在分析游戏中,游戏界面中是没有对应功能按钮的,都是绘制的,这样无法下按钮消息断点,定位功能代码不容易,有了CallTool工具就可以快速定位到功能函数。
一、工具使用:
这里使用Find CALL工具快速找记事本的“替换”功能以说明其使用。
1).在PID栏填写记事本进程ID:
                                    
                                              图2 在PID栏填写记事本进程ID
2).点击“Call按钮”,弹出成功对话框:
                                    
                                                    图3 弹出成功对话框
3).点击记事本“编辑”->“替换”,在“查找内容”对话框输入“aaaaaa”后点击“查找下一个”按钮:
                                    
                                                   图4“查找下一个”按钮
4).现在此功能已经调用了1次,更新调用次数为1次,并点击Updata按钮:
                           
                                              图5  更新调用次数为1次
5).重复步骤4,更新界面选项为2次,点击Updata按钮后仍然提示剩余4个CALL:
                              
                                              图6  更新调用次数为2次
此时说明不能再缩小范围了。
6). 点击Read按钮,右上方的List控件会显示找到的CALL,ID编号、CALL的地址、CALL的目标地址、调用CALL的数量:
                                      
                                                 图7  点击Read按钮后的显示
7).点击Clear按钮,再点击Order按钮,提示再次执行要定位的功能以便CALL Tool工具能定位:
                              
                                                 图8  点击Clear、Order按钮后
8).重复执行步骤3,再点击“Read按钮”,左上方的List控件显示找到Call的调用顺序:
                                      
                                                图9  点击Read按钮后界面显示
                                                   
9). 点击Clear按钮,再点击Stack按钮,提示再次执行要定位的功能以便CALL Tool工具能定位:
                               
                                                图10  点击Clear、Stack按钮后
10). 重复执行步骤3,再点击“Read按钮”,下方的List控件显示找到Call的堆栈调用关系:
                                      
                                                图11  点击Read按钮后界面显示
11). 图11有4条堆栈调用,从右往左依次调用,第一条(ID为0)调用路径是0x1007511->0x10029e0->0x100372e->0x1001faf。可以看出第二条路径(ID位0001)的Target为 010029e0在第一条调用路径上; 第三条路径(ID位0002)的Target为 0100372e在第一条调用路径上; 第四条路径(ID位0003)的Target为 0100372e在第一条调用路径上。
所以第一条调用的0x1001faf地址是最底层的调用Call。使用OD附加并 go到对应地址0x1001faf,发现其下有MessageBoxW调用,F9运行,断点触发:
                                                                    
                                               图12  MessageBoxW地址处断下
跟踪到MessageBoxW,可以看到OD堆栈窗口出现找不到“aaaaaa”,正是记事本弹出的提示对话框:
                                       
                                       图13  找不到“aaaaaa”弹框提示
因为替换查找功能执行后,找不到,就弹出提示对话框了。这就说明了0x1001faf的地址是最底层的Call,其它3个Call就是真正功能的执行函数了。
上文说明了如何找记事本程序的功能函数,同样可利用CallTool工具在游戏中查找某功能。
二、代码分析:
CALL TOOL工具实现的核心思想是反汇编需分析的程序,寻找Call调用(机器码0xE8、0xFF15),替换成自己的shellcode函数,shellcode函数预先在堆中分配好。shellcode函数中实现记录函数调用次数、调用先后次序、函数之间的堆栈层次关系。以下给出记录函数调用次数的流程如图14:
                          
                                              图14  记录函数调用次数的流程图
以下给出记录函数调用次数的伪代码:

bool CCallToolDlg::GetCallCountHook(PBYTE pModBaseAddr, PCHAR szExePath, HANDLE hProcess)
{
打开需分析的可执行文件…
设置文件读取游标为文件开始处…
读取文件内容到申请的内容…
    用反汇编引擎反汇编文件内容,寻找call xxx、call [xxx]调用,并记录下总共call数量;
	使用VirtualAllocEx(hProcess… 在进程内存中为每个call申请3个DWORD内存空间;
	if (申请成功)
	{
		…
		BYTE shellcode[] = 
		{
			0x60, 0x8D, 0x35, 0x24, 0x09, 0x3E, 0x00, 0x8B, 0x06, 0x40,					0x89, 0x06, 0x61, 0x68, 0x7E, 0x38, 0x00, 0x01, 0xE9, 0x30, 
			0x14, 0xC2, 0x00
		};
		while (循环读取代码段)
		{
			用反汇编引擎反汇编…
			寻找0xE8(call xxx)、0xFF 0x15(call [xxx])调用…
			获得Call xxxx中xxxx内容…					
把Call xxxx中xxxx内容由"相对地址"转换为"绝对地址"(在申请的内存中)…
加判断,防止把数据识别成代码, 
			RtlCopyMemory(CI.ShellCode, shellcode, 23);	//把shellcode copy到结构体
			*(PDWORD)(CI.ShellCode + 3) = pRemoteAddr + sizeof(DWORD) * 2; //赋值shellcode中的lea esi,dword ptr ds:[3E0924] 为目标进程dwCount位置
			*(PDWORD)(CI.ShellCode + 0x0e) = dwCodeAddr + 5; //赋值shellcode中的push 100387E 为原Call的地址下一条指令[Call(0xE8)指令占字节]
			*(PDWORD)(CI.ShellCode + 0x13) = dwTarget - (pRemoteAddr + sizeof(DWORD) * 4 + 0x12) - 5; //赋值shellcode中jmp 01001D73 计算跳转偏移(为原Call到shellcode的偏移)
		    WriteProcessMemory(hProcess, (LPVOID)pRemoteAddr, &CI, sizeof(CALL_INFO), &NumberOfBytes); //写入shellcode到申请的空间
			更改Call Target 为JMP ShellCode…
		}
	}
	关闭打开的文件…
}

该函数打开被分析进程读取其内存,寻址其中的call调用(0xE8 call xxx、0xFF 0x15 call [xxx])替换为自己构造的shellcode地址,shellcode中实现“调用次数”自增操作。Shellcode的内容是60 8D 35 24 09 3E 00 8B 06 40 89 06 61 68 7E 38 00 01 E9 30 14 C2 00,对应汇编代码为:
pushad
lea esi,dword ptr ds:[3E0924]
mov eax,dword ptr ds:[esi]
inc eax
mov dword ptr ds:[esi],eax
popad
push 100387E
jmp 01001D73

以上代码先用pushad保存8个常用寄存器环境(eax、ebx、ecx、edx、ebp、esp、esi、edi)。因为随后的代码将使用这些寄存器。然后用lea esi,dword ptr ds:[3E0924],esi赋值为3E0924,3E0924随后会替换为自申请的空间地址。mov eax,dword ptr ds:[esi]取esi 中的内容也就是取3E0924地址中的内容赋值给eax。inc eax自增1,实现计数器+1。mov dword ptr ds:[esi],eax把eax中的数据保存到esi所指向地址的内存中,也就是计数器保存到3E0924地址中的内存中。Popad还原前面保存的8个寄存器内容,恢复环境。push 100387E把100387E压入栈中,100387E在后续的代码中会替换为原始call地址下面一条指令的地址,跳到shellcode运行完毕后会跳回来继续执行,不影响程序原始逻辑。jmp 01001D73跳到01001D73地址去执行,01001D73后续会替换为call到的地址。
该函数也为每个call调用申请三个DWORD,把函数调用次数记录在此段空间的第三个DOWRD中,其前面两个DWORD分别保存调用顺序编号、栈调用层次。
更详细的请见代码。
注意代码编译前,先安装XTToolkitPro。

exe: CallTool.rar
源代码:
CallTool.part01.rar
CallTool.part02.rar
CallTool.part03.rar
CallTool.part04.rar
CallTool.part05.rar
CallTool.part06.rar
文档: 【原创】Find CALL Tool(带源码).doc

上传的附件 【原创】Find CALL Tool(带源码).doc
CallTool.rar
CallTool.part01.rar
CallTool.part02.rar
CallTool.part03.rar
CallTool.part04.rar
CallTool.part05.rar
CallTool.part06.rar
0.png
1.png
3.png
4.png
5.png
6.png
7.png
8.png
9.png
10.png
11.png
12.png
13.png
14.png
15.png
16.png
17.png
18.png

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功