遇到了硬茬子,找了半天资料才找到,因为这个QT是mingw编译的,好像编译器是gcc吧,我也不太懂,但是查了半天知道他的语法是AT&T,而我在学汇编的时候学的是8086,好像叫intel语法。所以开头就碰壁到崩溃。。但是又不想放弃换MFC框架 。。也不想用QT5.0+的版本。因为毕竟以后还是高版本好用吗。。不能碰到个岔子,就降低要求了是吧。。所以查了好几天才解决了问题。AT&T语法教程太少了 ,基本上都是零零碎碎的一些回答,和一些其他的文章。
而且我遇到的问题并不能完全复制,因为我这个QT的编译器是mingw 64位的,但是碰上的这个植物大战僵尸是32位的。。所以遇到了很多困难。。在64位的编译器上写32位的代码还要考虑到兼容问题。实在令我头大,又不想放弃。因为一旦放弃意味着我要去学习MFC了。而且。我不可能以后做辅助碰到32位的用32位编译器,注入64位的用64位编译器吧。。那是不可能的,既然他们64位可以兼容32位的,那他一定就可以找到解决办法所以查了半天以自己的理解,才搞定了这几行简单的代码。虽然说就几行代码,但是我查了很多天才组织出这几行代码。
// 这是在MFC也就是,视频老师教的是这样写的,因为我学的也是intel语法所以,会汇编的都可以看的懂这些代码。我就不讲解我的思路了 __declspec(naked) void putPlant(){ __asm { pushad mov ebx , [006A9EC0] mov ebx ,[ebx+768] push -1 push 2 mov eax,2 push 6 push ebx call 40D120 popad ret } }
而以下是AT&T语法,也是我找半天,才捣鼓出来的。
// 这些代码需要逐行分析 __declspec(naked) void putPlant() { // 还是那个原因因为用的是64位编译器,所以pushad不可以用了。只能手动堆栈平衡 __asm volatile("push %rbx"); // -> pushad __asm volatile("push %rax"); // 语法不同,没有需要讲解的 __asm volatile("mov (0x6A9EC0),%ebx"); // -> mov ebx , [006A9EC0] // 尤其是这段代码。因为此编译器是mingw64位的所以编译器的寄存器是rbx,但是呢,我要注入软件的这个软件是32位的所以他的寄存器最大的就是ebx。 // 我当时试过这么写的 mov 0x768(%ebx) ,%ebx 但是编译后的代码确是 // mov ebx, dword ptr ss:[bp+di+0x768] 和 add byte ptr ds:[eax], al // 他们甚至不在同一个内存单元里。此时我的代码绝对会崩溃。在网上查了半天也没有解决的方法。 // 最后我试了试如下代码。竟然可以了。。 // 其实按照逻辑来说的话 我真的不懂他是怎么回事。因为在8086里 他可能是这样的 mov al ,[ ax + 768 ]; // 应该就是ax的低八位给了al 所以这里就是 rbx的低八位给了%ebx // 因为需要注入的软件是32位的所以他不可能超字节,所以不需要担心。 __asm volatile("mov 0x768(%rbx) ,%ebx"); // -> mov ebx ,[ebx+768] // START:以下没有什么可以需要讲解的。百度上都可以查得到。 __asm volatile("push $-1"); // -> push -1 __asm volatile("push $2"); // -> push 2 __asm volatile("mov $2 ,%eax"); // -> mov eax,2 __asm volatile("push $6"); // -> push 6 // END // 这块也一样,push %ebx不好使,构建后直接报错,但是push %rbx就可以。不知道为啥可能是兼容后自动就变成ebx了把。 // 这里报错会出现 Error: operand type mismatch for `push' ,网上查了原因是:重定位文件是32位,机器是64位,不兼容出现的问题 __asm volatile("push %rbx"); // -> push ebx // 这块出现的问题就很大了,我先开始写的是 call $0x40D120 不行他会报:Error: unsupported syntax for `call',查都没地方查去 // 因为我需要 0x40D120是个立即数,根据上边的写法call $0x40D120就应该是立即数但是不行 // 然后我去查了半天发现查出来的语法是这样的 call *0x40D120 这时候编译器总算是没有报错了。但是我运行的时候竟然报错了。调试后发现注入后的代码: // call *0x40D120 变成了 call dword ptr ds:[0x0040D120] 所以我程序直接崩溃了。。那么反向思考。所以我最终的代码就变成了如下: __asm volatile("mov $0x40D120 ,%ebx"); // -> call 40D120 __asm volatile("call *%rbx"); // 堆栈平衡 __asm volatile("pop %rax"); // -> popad __asm volatile("pop %rbx"); // 这代码也很重要,是返回函数的。所有老师基本都有讲 __asm volatile("ret"); }
正确注入的代码图:
错误注入的代码图:
完整的代码如下
#include "widget.h" #include "ui_widget.h" #include <windows.h> #include <QMessageBox> Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); } Widget::~Widget() { delete ui; } /* * 这中间穿插这上一节的代码,重复的就不添加了 */ __declspec(naked) void putPlant() { __asm volatile("push %rbx"); // -> pushad __asm volatile("push %rax"); __asm volatile("mov (0x6A9EC0),%ebx"); // -> mov ebx , [006A9EC0] __asm volatile("mov 0x768(%rbx) ,%ebx"); // -> mov ebx ,[ebx+768] __asm volatile("push $-1"); // -> push -1 __asm volatile("push $2"); // -> push 2 __asm volatile("mov $2 ,%eax"); // -> mov eax,2 __asm volatile("push $6"); // -> push 6 __asm volatile("push %rbx"); // -> push ebx __asm volatile("mov $0x40D120 ,%ebx"); // -> call 40D120 __asm volatile("call *%rbx"); __asm volatile("pop %rax"); // -> popad __asm volatile("pop %rbx"); __asm volatile("ret"); } // 秒杀的点击事件 void Widget::on_injectButton_clicked() { // 获取进程ID DWORD pid = findGameProcessByWndTitle("植物大战僵尸汉化版"); // 获取进程句柄 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid); // 在目标进程中申请虚拟内存 PVOID ThreadFunAdd = VirtualAllocEx(hProcess,NULL,4096,MEM_COMMIT,PAGE_EXECUTE_READWRITE); // 往指定内存中写入代码 WriteProcessMemory(hProcess,ThreadFunAdd,LPCVOID(putPlant),4096,NULL); // 执行目标进程中的指定代码 CreateRemoteThread(hProcess,NULL,NULL,(LPTHREAD_START_ROUTINE)ThreadFunAdd,NULL,NULL,NULL); // 关闭句柄 CloseHandle(hProcess); }
后边的点击事件不是我遇到的困难,这些照着API去看就好了,和老师教的没啥区别。
主要是AT&T的汇编,主要我是小白啥也看不懂,也没有相对应的问题,真的我哭死,不过慢慢试可算是试出来了
最后的功能小弹框,很简单:
标签:__,汇编,QT,mov,volatile,push,AT&T,ebx,asm From: https://www.cnblogs.com/dandingjun/p/18061130