那么我们再来看一下PUSH指令 void CASM_TESTDlg::OnBtnMov() {
// TODO: Add your control notification handler code here mycall(0x111a,0x222b); //stdcall m_a=a; m_b=b;
UpdateData(false); }
在OD里查找到传参数这里,看到反汇编代码如下,压栈方式从右至左 [attachment=557]
本节课汇编还没有讲完,下节继续.因为我学过DELPHI班,对汇编代码懂一些,所以这节课学起来很轻松. 2.1.6、内联汇编编程实例 a、加法add b、减法sub
c、纯汇编调用函数CALL(参数的传递) d、堆栈平衡 汇编指令add
int myadd(int a,int b)//加法 {
// return a+b; _asm {
mov ebx,b add a,ebx }
return a; }
int mysub(int a,int b)//减法 {
//return a+b; _asm {
mov ebx,b // ebx=b; sub a,ebx // a=a-b; }
return a; }
_stdcall //带参数 push b push a
call myadd
本节课继续讲汇编,加法指令add,减法指令sub,代码已经在上面教案中例出.先演示了一下汇编的加法指令,又演示了减法指令.除此之外还需要带参数的汇编调用 _asm {
Push b Push a Call myadd }
Int myadd(int a,int b)//带参数被调用 { _asm {
Mov ebx,b Add a,ebx }
Return a; }
但是这样调用会出错,因为堆栈不平衡了,所以还要加上代码 _asm {
Push b Push a Call myadd Add esp,8 }
21
因为每PUSH一次ESP的值会减4,所以两次PUSH之后,需要将ESP加8 . 还有一点需要知道的是,调用CALL之后,返回值都是EAX里. 然后又测试了一下减法带参调用 2.2.1、吃金创药CALL
a、CE工具使用技巧 b、OD断点F2
c、分析CALL的参数 d、代码注入器测试CALL CE:查找访问此地址的代码 005d89b8:mov [edx+204],eax 005d8b27:mov ecx,[edi+204] 0057433c:mov edx,[eax+4a0]
void usegood(int a,b,c) //使用金创药 {
005d89b8:mov [edx+204],eax }
int usegood(int 0,int 1,int b) { }
push 0b // 金创药分类编号 push 1 push 0
call 573720
005DA6F4 |> \\8B90 08020000 MOV EDX,DWORD PTR DS:[EAX+208]
005DA6FA |. 52 PUSH EDX ; 红药ID号=b 005DA6FB |. 6A 01 PUSH 1
005DA6FD |. 6A 00 PUSH 0 ; F1-F8
005DA6FF |. E8 1C90F9FF CALL Client.00573720 ; 使用物品
为了讲解工具的使用,今天来找一下游戏的金创药,首先是将药放在快捷F2上,用CE搜索一下当前的数量,然后吃一下药我,再搜索一下当前的数量,很容易就找到这个值了.然后在该值上下访问指针查找,发现了几个地址005d89b8/005d8b27 然后打开我们的OD,附加到游戏进程,看一下005d89b8地址,然后下个断点,在游戏中再吃一下药,断在当前地址了,我们来到当前函数的头部下个断,然后再吃一次药被断下,返回上一层,再来到这一层CALL的头部,下断马上被断了,这个不对,取消断点. 0057433c再试一试这个地址,来到这个函数的头部,再向上返回,终于找到了吃药的CALL
[attachment=558]
直接在背包里吃药没断下来,而在快捷栏上吃就断下来了 在代码注入器中测试如下 Push 0b Push 1 Push 0
Call 00573720 //0B是药品ID
再试一下其它的药品ID,先放在快捷键上 Push 8 Push 1 Push 0
Call 00573720
2.2.2、编写自己的CALL测试代码
a、远程分配内存空间VirtualAllocEx b、向游戏进程注入自己代码
c、CreateRomuteThread远程调用《吃金创药》 参考:2.2.1 分析 原理:
1获得自己函数的代码的真正起始地址
2在游戏进程内 分配一块内存空间 以写入我们自己的代码 3用CreateRomuteThread调用我们写入的代码. 要注入的代码
GetWindowThreadProcessId//获取PID OpenProcess //打开进程句柄
Calladdr=VirtualAllocEx //在远程进程内分配地址 WriteProcessMemory //写入代码 和参数 CreateRemoteThread //启用远程CALL WaitForSingleObject //等远程线程返回 GetExitCodeThread //退出对象句柄 CloseHandle(hThread); //关闭对象句柄 VirtualFreeEx //释放远程空间 代码部分:
void usegoods() {
22
_asm {
push 0x16 // 金创药分类编号 push 1 push 0
mov eax,0x573720 call eax } }
HWND h;//定义窗口句柄变量
h=::FindWindow(NULL,\查找窗口句柄 LPDWORD Pid=&id;//进程ID
::GetWindowThreadProcessId(h,Pid); //取得指定窗口的进程ID 存放到变量id里边 DWORD id; //创建线程ID变量
HANDLE hp=OpenProcess(PROCESS_ALL_ACCESS,false,id);//获取访问进程权限 存放至hp //分配一块内存 以写入我们自己的代码
LPVOID callbase=VirtualAllocEx(hp,NULL,0x3000,MEM_COMMIT |MEM_RESERVE,PAGE_EXECUTE_READWRITE);//申请页面可读可写可执行 if (callbase==NULL) {AfxMessageBox(\申请空间失败\加入出错信息
if (!::WriteProcessMemory(hp,callbase,usegoods,0x3000,NULL)) {AfxMessageBox(\写入代码失败\写入代码,如果返回假则显示错误信息
DWORD tid;//要创建的线程ID变量
CreateRemoteThread(hp,NULL,0,(LPTHREAD_START_ROUTINE)callbase,0,0,&tid); //远程调用代码
这节课讲了注入代码基础知识,教案写的很详细,而且我又加上了一些注释,相信大家都能看懂,其中函数的参数可以查阅MSDN,而且前面的课程当中也大部分都讲过.在这些个函数的运用上,VC和DELPHI很相似,想起自己以前学过易语言,还用别人定义的模块,感觉真是没啥意思,还是要学专业一些的语言啊,或者当易语言的高手要自己写模块才行. 2.3.1、DLL动态链接库构建,与调用 a、建立MFC动态链接库dll
b、EXE程序中调用DLL函数 MFC DLL函数的创建
.def文件与 __declspec( dllexport ) 调用申明
__declspec( dllimport ) int myfun(int a, int b); AFX_MANAGE_STATE(AfxGetStaticModuleState()); #pragma comment(lib,”mydll.lib”)
__declspec( dllexport ) int add(int a,int b) 1、创建一个MFC DLL动态链接库 int myadd( int a,int b)
{ AFX_MANAGE_STATE(AfxGetStaticModuleState());//如果用类成员就要这句 return a+b; }
2、MFC EXE应用程序里边调用 DLL函数
a、 #pragma comment(lib,\包函库文件
b、__declspec( dllimport ) int myadd( int a,int b);//固定函数格式
上节课只是简单的介绍了一下写内存的方法,也就是代码注入,从本节课开始就要写DLL挂了,因为DLL在调用游戏时比较方便.新建一个MFC的DLL,选择标准的MFC,文件名myadd,在myadd.cpp里写代码: CMyaddApp theApp;
int myadd(int a,int b) {
return a+b; }
然后在myadd.def中写代码 EXPORTS
; Explicit exports can go here Myadd
再新建一个MFC的EXE文件test_myadd,然后选 工程>设置>连接,在对象库模块中添加”myadd.lib” 增加两个编辑框,关联两个变量m_la/m_lb,然后添加代码 __declspec( dllimport ) int myadd(int a,int b); void CTest_myaddDlg::OnButtonAdd() {
UpdateData(true);
m_lr=myadd(m_la,m_lb); UpdateData(false); }
在调试DLL的时候需要设置一下主EXE的位置 [attachment=559]
再试一下乘法和减法也没问题,OK了.
DLL的建立格式就是这样,要增加什么功能就自己添加好喽.
23
2.3.2、API与回调函数
a、键盘勾子回调函数keyProc b、安装函数SetupFun
c、注入DLL至游戏进程空间 HHOOK SetWindowsHookEx( //键盘钩子 int idHook, // WH_KEYBOARD HOOKPROC lpfn, // Gameproc HINSTANCE hMod, // DLL句柄 DWORD dwThreadId // 游戏主线程ID );
LRESULT CALLBACK Gameproc( //回调函数 int code, // hook code WPARAM wParam, // 按键代码 LPARAM lParam // 键盘消息信息 );
LRESULT CallNextHookEx( //调用下一个钩子,恢复正常钩子 HHOOK hhk, // handle to current hook
int nCode, // hook code passed to hook procedure WPARAM wParam, // value passed to hook procedure LPARAM lParam // value passed to hook procedure );
这节课又新建了一次DLL复习一下昨天的课程,又增加了两个函数的调用 CGameDllApp theApp;
LRESULT CALLBACK Gameproc( int code, // hook code
WPARAM wParam, //按键代码 =VK_F12 VK_HOME LPARAM lParam // 31位为0 则是被按下 )
{ AFX_MANAGE_STATE(AfxGetStaticModuleState());//用到全局函数需要加这个宏 //比如说按下VK_HOME 我们要做什么
if ((wParam==VK_HOME)&&((lParam&(1<<31))==0)) { AfxMessageBox(\按下Home键\检测是否已经被按过热键,并显示提示信息. return CallNextHookEx(0,code,wParam,lParam);//恢复下一个钩子 }
#define GameCaption \void SetHook()//安装勾子的函数
{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); //获取游戏主线程ID号
HWND gameh=FindWindow(NULL,GameCaption);//查找游戏窗口 if (gameh==0) { AfxMessageBox(\未找到游戏\出错处理
DWORD tid=::GetWindowThreadProcessId(gameh,NULL);//获取线程ID
::SetWindowsHookEx(WH_KEYBOARD,&Gameproc,::GetModuleHandle(\//安装线程勾子, GetModuleHandle是获取相应句柄 }
最后别忘了在GameDll.def中将SetHook函数导出.这样动态链接库的部分基本上就构建完了,再来写一下EXE部分.还是建立一个MFC,建立一个”安装游戏函数”的按钮,编写代码如下:
__declspec( dllimport ) void SetHook();//先声明 #pragma comment(lib,\加入DLL连接 void CGamewgDlg::OnBUTT*****etHook() //按钮命令 {
SetHook(); //调用 SetHook }
将EXE文件复制到DLL目录中进行测试,打开游戏,按一下键盘上的键,打开360发现已经附加上DLL文件了,再设置一下热键为HOME键,然后弹出了对话框.
[attachment=561]
2.3.3、DLL中构建窗口
a、DLL中插入窗口资源 b、在游戏内创建DLL窗口
c、DLL内CALL代码书写(以吃红药为例) CWGForm *gameform;//定义窗口类指针
if (gameform==NULL) { gameform=new CWGForm;//分配内存大小
gameform->Create(IDD_DLG_MAIN); //创建窗口实例} ::ExitInstance()
int CGameDllApp::ExitInstance() {
delete gameform;//释放相应内存空间 gameform=NULL;
return CWinApp::ExitInstance();//winApp基类函数
24
}
void usegoods() {
_asm {
push 0x16 // 物品背包数组下标 push 1 push 0
mov eax,0x573720 call eax } }
在DLL代码中插入一个窗口,然后添加几个复选框,在GameDll.cpp里加入头文件#include \再定义一个全局变量CWGForm *gameform,再在DLL代码中添加创建窗口代码
int CGameDllApp::ExitInstance()//退出时释放DLL,否则游戏会影响 {
delete gameform;//释放相应内存空间 gameform=NULL;
return CWinApp::ExitInstance();//winApp基类函数 }
CGameDllApp theApp;
LRESULT CALLBACK Gameproc( int code, // hook code
WPARAM wParam, //按键代码 =VK_F12 VK_HOME LPARAM lParam // 31位为0 则是被按下 )
{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); //比如说 按下VK_HOME 我们要做什么
if ((wParam==VK_HOME)&&((lParam&(1<<31))==0)) {
if (gameform==NULL) { gameform=new CWGForm;gameform->Create(IDD_DLG_MAIN);} gameform->ShowWindow(true);//显示窗口 }
return CallNextHookEx(0,code,wParam,lParam); }
#define GameCaption \//安装勾子的函数 void SetHook()
{ AFX_MANAGE_STATE(AfxGetStaticModuleState()); //获取游戏主线程ID号
HWND gameh=FindWindow(NULL,GameCaption); //FindWindow if (gameh==0) { AfxMessageBox(\未找到游戏\ //GetWindowThreadProcessID
DWORD tid=::GetWindowThreadProcessId(gameh,NULL); //安装线程勾子
::SetWindowsHookEx(WH_KEYBOARD,&Gameproc,::GetModuleHandle(\}
还要在头文件里加上代码
class CGameDllApp : public CwinApp//退出时的代码 {
public:
CGameDllApp();
int ExitInstance();//表示动态链接库退出的时候 DECLARE_MESSAGE_MAP() };
再测试一下吃红药
void CWGForm::OnBUTTONCAllTEST() {
_asm {
push 3 // 物品背包 数组下标 0开始(表示第一格) push 1 push 0
mov eax,0x573720 call eax } }
25