首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在内存中执行机器码

在内存中执行机器码
EN

Stack Overflow用户
提问于 2010-01-07 19:35:46
回答 9查看 23.3K关注 0票数 31

我正在试图弄清楚如何执行存储在内存中的机器代码。

我有以下代码:

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{
    FILE* f = fopen(argv[1], "rb");

    fseek(f, 0, SEEK_END);
    unsigned int len = ftell(f);
    fseek(f, 0, SEEK_SET);

    char* bin = (char*)malloc(len);
    fread(bin, 1, len, f);

    fclose(f);

    return ((int (*)(int, char *)) bin)(argc-1, argv[1]);
}

上面的代码在GCC中编译得很好,但当我尝试从命令行执行该程序时,如下所示:

代码语言:javascript
复制
./my_prog /bin/echo hello

程序出现了分段错误。我已经知道问题出在最后一行,因为注释掉它会停止段错误。

我认为我做得不太对,因为我还在想着函数指针。

这个问题是一个错误的造型,还是别的什么?

EN

回答 9

Stack Overflow用户

回答已采纳

发布于 2010-01-07 19:38:36

在我看来,您正在加载ELF图像,然后尝试直接跳到ELF头文件中?http://en.wikipedia.org/wiki/Executable_and_Linkable_Format

如果您正在尝试执行另一个二进制文件,为什么不在您正在使用的任何平台上使用进程创建函数?

票数 12
EN

Stack Overflow用户

发布于 2010-01-07 19:37:34

您需要一个具有写入执行权限的页面。如果您使用的是unix,请参见mmap(2)和mprotect(2)。您不应该使用malloc来完成此操作。

此外,请阅读其他人所说的,您只能使用您的加载器运行原始机器代码。如果你尝试运行一个ELF头文件,它可能仍然会有段错误。

关于回复和downmods的内容:

1- OP说他正在尝试运行机器代码,所以我回答了这个问题,而不是执行可执行文件。

2-了解为什么不混合使用malloc和mman函数:

代码语言:javascript
复制
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>

int main()
{
    char *a=malloc(10);
    char *b=malloc(10);
    char *c=malloc(10);
    memset (a,'a',4095);
    memset (b,'b',4095);
    memset (c,'c',4095);
    puts (a);
    memset (c,0xc3,10); /* return */

    /* c is not alligned to page boundary so this is NOOP.
     Many implementations include a header to malloc'ed data so it's always NOOP. */
    mprotect(c,10,PROT_READ|PROT_EXEC);
    b[0]='H'; /* oops it is still writeable. If you provided an alligned
    address it would segfault */
    char *d=mmap(0,4096,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_PRIVATE|MAP_ANON,-1,0);
    memset (d,0xc3,4096);
    ((void(*)(void))d)();
    ((void(*)(void))c)(); /* oops it isn't executable */
    return 0;
}

它在Linux x86_64上准确地显示了这种行为,在其他实现中肯定会出现其他丑陋的行为。

票数 30
EN

Stack Overflow用户

发布于 2010-01-07 19:51:12

使用malloc的运行良好。

好了,这是我的最终答案,请注意我使用了原始发帖者的代码。我正在从磁盘加载此代码的编译版本到堆分配区域"bin",就像原始代码一样(名称是固定的,不使用argv,值0x674是来自;

代码语言:javascript
复制
objdump -F -D foo|grep -i hoho
08048674 <hohoho> (File Offset: 0x674):

这可以在运行时使用BFD (二进制文件描述符库)或其他东西来查找,您可以调用其他二进制文件(不仅仅是您自己),只要它们静态地链接到同一组lib。

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>

unsigned char *charp;
unsigned char *bin;

void hohoho()
{
   printf("merry mas\n");
   fflush(stdout);
}

int main(int argc, char **argv)
{
   int what;

   charp = malloc(10101);
   memset(charp, 0xc3, 10101);
   mprotect(charp, 10101, PROT_EXEC | PROT_READ | PROT_WRITE);

   __asm__("leal charp, %eax");
   __asm__("call (%eax)" );

   printf("am I alive?\n");

   char *more = strdup("more heap operations");
   printf("%s\n", more);

   FILE* f = fopen("foo", "rb");

   fseek(f, 0, SEEK_END);
   unsigned int len = ftell(f);
   fseek(f, 0, SEEK_SET);

   bin = (char*)malloc(len);
   printf("read in %d\n", fread(bin, 1, len, f));
   printf("%p\n", bin);

   fclose(f);
   mprotect(&bin, 10101, PROT_EXEC | PROT_READ | PROT_WRITE);

   asm volatile ("movl %0, %%eax"::"g"(bin));
   __asm__("addl $0x674, %eax");
   __asm__("call %eax" );
   fflush(stdout);

   return 0;
}

奔跑着。

代码语言:javascript
复制
co tmp # ./foo
am I alive?
more heap operations
read in 30180
0x804d910
merry mas

您可以使用UPX来管理文件的加载/修改/执行。

另外,对于之前断开的链接,我深表歉意:

票数 13
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2019923

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档