植物大战僵尸,用QT注入代码,AT&T汇编语法

遇到了硬茬子,找了半天资料才找到,因为这个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的汇编,主要我是小白啥也看不懂,也没有相对应的问题,真的我哭死,不过慢慢试可算是试出来了

最后的功能小弹框,很简单:

 

posted @ 2024-03-08 15:37  淡定君  阅读(23)  评论(0编辑  收藏  举报