使用C with assembly在运行时分配和创建新函数

前端之家收集整理的这篇文章主要介绍了使用C with assembly在运行时分配和创建新函数前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我一直在研究一个(C)项目,它需要完全动态分配的函数,这意味着malloc / new和mprotect,然后手动修改缓冲区到汇编代码.因此我完全想知道,我的这个“缓冲区”需要什么,因为它是任何其他_cdecl函数的复制品.例如:
int ImAcDeclFunc(int a,int b)
{
     return a + b;
}

如果我想从字面上创建这个函数的副本,但是完全动态,那需要什么(并记住它是带内联汇编的C)?对于初学者,我想我必须做这样的事情(或类似的解决方案):

// My main....
byte * ImAcDeclFunc = new byte[memory];
mprotect(Align(ImAcDeclFunc),pageSize,PROT_EXEC | PROT_READ | PROT_WRITE);

在此之后,我将不得不找出ImAcDeclFunc(int a,int b);的汇编代码.现在我在组装时仍然很糟糕,那么这个功能将如何用于AT& T语法?这是我的大胆尝试:

push %ebp
movl %%ebp,%%esp
movl 8(%ebp),%%eax
movl 12(%ebp),%%edx
addl edx,eax
pop ebp
ret

现在,如果这段代码是正确的(我非常怀疑,请纠正我)我只需要在十六进制中找到这个代码的值(例如,’jmp’是0xE9,’inc’是0xFE),并直接使用这些值C ?如果我继续以前的C代码

*ImAcDeclFunc = 'hex value for push'; // This is 'push' from the first line
*(uint)(ImAcDeclFunc + 1) = 'address to push'; // This is %ebp from the first line
*(ImAcDeclFunc + 5) = 'hex value for movl' // This is movl from the second line
// and so on...

在我为整个代码/缓冲区完成此操作之后,这对于完全动态的_cdecl函数是否足够(即我可以将其转换为函数指针并执行int result =((int(*)(int,int) )ImAcDeclFunc)(firstArg,secondArg)?).
而且我对使用boost :: function或类似的东西不感兴趣,我需要这个函数是完全动态的,因此我的兴趣:)

注意:这个问题是我previous one的延续,但更具体.

@H_404_21@

解决方法

如果你拿这个lala.c:
int ImAcDeclFunc(int a,int b)
{
    return a + b;
}

int main(void)
{
    return 0;
}

你可以用gcc -Wall lala.c -o lala编译它.然后,您可以使用objdump -Dslx lala>>反汇编可执行文件. lala.txt.你会发现ImAcDeclFunc被组装到:

00000000004004c4 <ImAcDeclFunc>:
ImAcDeclFunc():
  4004c4:   55                      push   %rbp
  4004c5:   48 89 e5                mov    %rsp,%rbp
  4004c8:   89 7d fc                mov    %edi,-0x4(%rbp)
  4004cb:   89 75 f8                mov    %esi,-0x8(%rbp)
  4004ce:   8b 45 f8                mov    -0x8(%rbp),%eax
  4004d1:   8b 55 fc                mov    -0x4(%rbp),%edx
  4004d4:   8d 04 02                lea    (%rdx,%rax,1),%eax
  4004d7:   c9                      leaveq 
  4004d8:   c3                      retq

实际上这个功能相对容易复制到其他地方.在这种情况下,你完全正确地说你可以复制字节,它只会工作.

当您开始使用将相对偏移作为操作码的一部分的指令时,将出现问题.例如,相对跳转或相对呼叫.在这些情况下,您需要正确地重新定位指令,除非您碰巧能够将其复制到与最初位置相同的地址.

简而言之,要重新定位,您需要找到它最初所在的位置,并计算您将基于它的位置的差异,并重新定位每个相对指令的偏移量.这本身是可行的.你真正的困难是处理对其他函数调用,特别是对库的函数调用.在这种情况下,您需要保证链接库,然后以您定位的可执行格式定义的方式调用它.这非常重要.如果您仍然感兴趣,我可以指出您应该阅读的方向.

在上面的简单案例中,您可以这样做:

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

int main(void)
{
    char func[] = {0x55,0x48,0x89,0xe5,0x7d,0xfc,0x75,0xf8,0x8b,0x45,0x55,0x8d,0x04,0x02,0xc9,0xc3};

    int (* func_copy)(int,int) = mmap(NULL,sizeof(func),PROT_WRITE | PROT_READ | PROT_EXEC,MAP_PRIVATE | MAP_ANONYMOUS,0);

    memcpy(func_copy,func,sizeof(func));
    printf("1 + 2 = %d\n",func_copy(1,2));

    munmap(func_copy,sizeof(func));
    return EXIT_SUCCESS;
}

这在x86-64上工作正常.它打印:

1 + 2 = 3
@H_404_21@ @H_404_21@

猜你在找的C&C++相关文章