【问题标题】:Obscure runtime error when running machine code运行机器代码时出现模糊的运行时错误
【发布时间】:2016-05-21 00:15:23
【问题描述】:

我需要帮助来弄清楚为什么我在尝试运行我的机器代码时会在运行时崩溃。代码在“3”和“result = %li”之间崩溃。

注意:假设所有代码都经过错误检查。为了人们阅读本文,我删除了错误检查代码。

机器规格:

Windows 10 Home 64-bit
Intel(R) Core(TM) i7-4712MQ

我正在运行的代码:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

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

  printf("Loading code\n");

  LPVOID m = VirtualAlloc(NULL, 16, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);

  printf("1\n");

  unsigned char code[] = {
    //return x+2;

    0x55,                      //push   %rbp
    0xe5, 0x89, 0x48,          //mov    %rsp,%rbp
    0xc8, 0x89,                //movl    %ecx,%eax
    0x02, 0xc0, 0x83,          //add    $0x2,%eax
    0xc9,                      //leaveq
    0xc3,                      //retq
    0x90                       //nop
  };
  memcpy(m, code, sizeof(code)); 

  printf("2\n");

  PDWORD trash;
  VirtualProtect(m, 16, PAGE_EXECUTE_READ, trash); 

  printf("3\n");

  long int (*addTwo)(long int) = m;
  long int answer = addTwo(2);
  printf("result = %li\n", answer);

  VirtualFree(m, 0, MEM_RELEASE);
  return 0;
}

【问题讨论】:

  • 检查VirtualProtect的返回值。成功了吗? (您还应该检查来自VirtualAlloc 的返回值,但我认为这有效,否则memcpy 会崩溃。)如果VirtualProtect 成功,那么最好的办法是在汇编模式下启动调试器,并且在addTwo的声明处放一个断点。
  • 为了这里的人,我删除了所有的检查代码。 @user3386109 Windows 有本机调试器还是我应该安装 gdb?
  • 为了便于阅读和理解:遵循公理:每行只有一个语句,每个语句(最多)一个变量声明。。注意 'unsigned char code[]` 将数据放在 .data 部分而不是 .text 部分中,并且 .data 部分中的项目不可执行
  • typedef 将long 重新定义为(*)(long)。可能不是你想要的。
  • 代码似乎没有考虑Endianness的影响

标签: c windows runtime machine-code


【解决方案1】:

您似乎正在使用堆栈内存来存储自动变量:

0x10, 0x4d, 0x89,           //mov    %ecx,0x10(%rbp)
0x10, 0x45, 0x8b,            //mov    0x10(%rbp),%eax

但是你的偏移量是错误的,将0x10 添加到%rpb 将使结果地址指向之前的堆栈帧;要指向局部变量,您应该从 BP 中减去。此外,您甚至不需要为此使用堆栈,只需执行movl %ecx, %eax

【讨论】:

  • 我已经调整了代码,但我仍然在同一个地方崩溃。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-05
  • 1970-01-01
  • 2018-01-08
  • 1970-01-01
相关资源
最近更新 更多