如何在x86程序集中编写自修改代码

我正在寻找一个JIT编译器的爱好虚拟机我最近一直在工作。我知道有一点汇编(我主要是一个C程序员,我可以阅读大多数程序集参考我不明白的操作码,并写一些简单的程序)。但我很难理解几个例子的自我修改代码我在网上找到。

这是一个这样的例子:http://asm.sourceforge.net/articles/smc.html

所提供的示例程序在运行时做了四个不同的修改,其中没有一个被清楚地解释。 Linux内核中断使用了好几次,没有解释或详细说明。 (作者在调用中断之前将数据移入了多个寄存器,我假设他正在传递参数,但是这些参数根本没有解释,让读者猜测。

我正在寻找的是自修改程序代码中最简单,最直接的例子。我可以看看,并使用来了解如何自我修改代码在x86程序集中必须写,以及它是如何工作的。有没有任何资源,你可以指点我,或任何例子,你可以给,以充分证明这一点?

我使用NASM作为我的汇编。

编辑:我也在Linux上运行这个代码。

最佳答案
哇,这竟然是比我预想的更痛苦。 100%的痛苦是linux保护程序不被覆盖和/或执行数据。

两个解决方案如下所示。很多谷歌搜索被涉及,所以有点简单放一些指令字节并执行它们是我的,mprotect和页面大小排列从谷歌搜索,我不得不学习这个例子的东西。

自修改代码是直接的,如果你采取程序或至少只是两个简单的函数,编译然后反汇编,你会得到这些指令的操作码。或者使用nasm来编译汇编程序块等。从这里我确定了将立即数加载到eax然后返回的操作码。

理想情况下,你只需把这些字节在一些ram,并执行那个ram。要得到linux,你必须改变保护,这意味着你必须发送一个指针在一个mmap页面上对齐。所以分配多于你需要的,在分配中找到在页边界上的对齐地址,并从该地址mprotect,并使用该内存来放置你的操作码,然后执行。

第二个例子使用一个编译成程序的现有函数,再次因为保护机制,你不能简单地指向它和改变字节,你必须从写保护它。因此,您必须备份到具有该地址的前一个页面边界调用mprotect和足够的字节来覆盖要修改的代码。然后,您可以以任何想要的方式更改该函数的字节/操作码(只要不会溢出到要继续使用的任何函数中)并执行它。在这种情况下,你可以看到fun()工作,然后我改变它只是返回一个值,再次调用它,现在它已被修改。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>

unsigned char *testfun;

unsigned int fun ( unsigned int a )
{
    return(a+13);
}

unsigned int fun2 ( void )
{
    return(13);
}

int main ( void )
{
    unsigned int ra;
    unsigned int pagesize;
    unsigned char *ptr;
    unsigned int offset;

    pagesize=getpagesize();
    testfun=malloc(1023+pagesize+1);
    if(testfun==NULL) return(1);
    //need to align the address on a page boundary
    printf("%p\n",testfun);
    testfun = (unsigned char *)(((long)testfun + pagesize-1) & ~(pagesize-1));
    printf("%p\n",testfun);

    if(mprotect(testfun, 1024, PROT_READ|PROT_EXEC|PROT_WRITE))
    {
        printf("mprotect failed\n");
        return(1);
    }

    //400687: b8 0d 00 00 00          mov    $0xd,%eax
    //40068d: c3                      retq

    testfun[ 0]=0xb8;
    testfun[ 1]=0x0d;
    testfun[ 2]=0x00;
    testfun[ 3]=0x00;
    testfun[ 4]=0x00;
    testfun[ 5]=0xc3;

    ra=((unsigned int (*)())testfun)();
    printf("0x%02X\n",ra);


    testfun[ 0]=0xb8;
    testfun[ 1]=0x20;
    testfun[ 2]=0x00;
    testfun[ 3]=0x00;
    testfun[ 4]=0x00;
    testfun[ 5]=0xc3;

    ra=((unsigned int (*)())testfun)();
    printf("0x%02X\n",ra);


    printf("%p\n",fun);
    offset=(unsigned int)(((long)fun)&(pagesize-1));
    ptr=(unsigned char *)((long)fun&(~(pagesize-1)));


    printf("%p 0x%X\n",ptr,offset);

    if(mprotect(ptr, pagesize, PROT_READ|PROT_EXEC|PROT_WRITE))
    {
        printf("mprotect failed\n");
        return(1);
    }

    //for(ra=0;ra&lt;20;ra++) printf("0x%02X,",ptr[offset+ra]); printf("\n");

    ra=4;
    ra=fun(ra);
    printf("0x%02X\n",ra);

    ptr[offset+0]=0xb8;
    ptr[offset+1]=0x22;
    ptr[offset+2]=0x00;
    ptr[offset+3]=0x00;
    ptr[offset+4]=0x00;
    ptr[offset+5]=0xc3;

    ra=4;
    ra=fun(ra);
    printf("0x%02X\n",ra);

    return(0);
}

转载注明原文:如何在x86程序集中编写自修改代码 - 代码日志