【问题标题】:Loading MachineCode From File Into Memory and Executing in C -- mprotect Failing将文件中的机器代码加载到内存中并在 C 中执行——mprotect 失败
【发布时间】:2011-01-27 03:06:00
【问题描述】:

您好,我正在尝试将原始机器代码加载到内存中并从 C 程序中运行它,现在当程序执行时它会在尝试在内存上运行 mprotect 以使其可执行时中断。我也不完全确定如果内存设置正确,它将执行。我目前在 Ubuntu Linux x86 上运行它(也许问题是 Ubuntu 的过度保护?)

我目前拥有的如下:

#include <memory.h>
#include <sys/mman.h>
#include <stdio.h>

int main ( int argc, char **argv )
{
 FILE *fp;
 int sz = 0;
 char *membuf;
 int output = 0;

 fp = fopen(argv[1],"rb");

 if(fp == NULL)
 {
  printf("Failed to open file, aborting!\n");
  exit(1);
 }

 fseek(fp, 0L, SEEK_END);
 sz = ftell(fp);
 fseek(fp, 0L, SEEK_SET);


 membuf = (char *)malloc(sz*sizeof(char));
 if(membuf == NULL)
 {
  printf("Failed to allocate memory, aborting!\n");
  exit(1);
 }

  memset(membuf, 0x90, sz*sizeof(char));

 if( mprotect(membuf, sz*sizeof(char), PROT_EXEC | PROT_READ | PROT_WRITE) == -1)
 {
  perror("mprotect");
  printf("mprotect failed!!! aborting!\n");
  exit(1);
 }



 if(!(fread(membuf, sz*sizeof(char), 1, fp)))
 {
  perror("fread");
  printf("Read failed, aborting!\n");
  exit(1);
 }
 __asm__
 ( 
  "call %%eax;"
  : "=a" (output)
       : "a" (membuf)
 );
 printf("Output = %x\n", output);

 return 0;
}

我确实收到了编译器警告:

/tmp/ccVnhHak.s: Assembler messages:
/tmp/ccVnhHak.s:107: Warning: indirect call without `*'

我还没有让程序访问这个代码,所以我无法查看我的汇编代码是否在做它应该做的事情。

【问题讨论】:

  • 对不起,这是针对 x86 Linux 特别是 Ubuntu 的。 (我猜Ubuntu的过度保护可能与它有关)
  • 这是什么故障?您是否尝试过简单地在 gdb 下运行它并观察接下来会发生什么?
  • 它得到的失败是 mprotect 返回 -1 表示失败。我目前不确定如何从 mprotect 获取特定的错误代码,以便找到错误。显然 errno 设置了它,但我不知道我需要如何访问它。
  • if( mprotect(membuf, sz*sizeof(char), PROT_EXEC | PROT_READ | PROT_WRITE) == -1) { perror("mprotect"); }
  • 您可以使用 perror() 作为获取错误描述的快速方法

标签: c memory machine-code mprotect


【解决方案1】:

好的,这就是答案,根据我们在 cmets 中的讨论 :)

内存区域应与系统页面大小对齐。 posix_memalign() 调用是在这种情况下分配内存的正确方法:)

【讨论】:

  • 所以它必须以我假设的页面大小的倍数分配,而不是从文件长度分配
  • 好吧,如果我做对了,只有地址对齐,而不是大小。大小以字节为单位(根据人名)
  • 好的,这似乎已经解决了 mprotect 错误。使用: membuf = (char )memalign(pagesize, szsizeof(char));而不是 malloc。
  • 好的,既然 mprotect 不再失败,是否有任何猜测为什么代码会产生段错误,gdb 在 ?? 中显示 0x0804b004? ()。我正在向它传递一个包含有效字节码的文件,而不是 ELF
  • @Chartreuse:您将需要在 GDB 中执行单指令步骤 si。从外观上看,您通过了第一条指令,因为地址没有以0 结尾。您可能没有希望获得符号,因此它将是?? (),但这并不是那么糟糕。在尝试加载之前在其他地方调试您的目标代码,仔细检查您的环境,如果遇到困难,请提出一个新问题。
【解决方案2】:

在 0x90(noop)字节之后添加一个 0xc3(返回指令)。您的程序可能会崩溃,因为它在 NOOP 的末尾运行,或者运行到未初始化的内存中,谁知道那里潜伏着什么,或者运行到可执行页面的末尾。如果不查看您正在加载的文件中的内容,我真的无法判断。

顺便说一句,strace 对于这类程序非常有用。它会告诉你 mprotect 中的错误是什么。

【讨论】:

    【解决方案3】:

    使用所有权限 PROT_EXEC | PROT_READ | PROT_WRIT 也不需要并且有点危险。 您通常不需要 PROT_WRITE,只需 exec 和 read 就足够了。

    一些安全内核甚至不允许 PROT_EXEC | PROT_WRIT。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-02
      • 2017-06-11
      • 1970-01-01
      • 1970-01-01
      • 2015-10-16
      • 1970-01-01
      • 1970-01-01
      • 2016-04-02
      相关资源
      最近更新 更多