【问题标题】:Illegal assembly instruction in CC中的非法汇编指令
【发布时间】:2018-03-21 05:03:15
【问题描述】:

我正在尝试使用 C 程序生成汇编指令跟踪。我正在使用 asm 函数插入在 x86_64 中非法的汇编指令并检测它们。

我有以下 C 程序 -

int main()
{
    asm(".byte 0x16"); // Illegal in x86_64
    asm(".byte 0x17"); // Illegal in x86_64
    return 0;
}

这是 main 函数的指令跟踪,这是预期的 -

.text:004004d6 55                               push   %rbp
.text:004004d7 48 89 e5                         mov    %rsp,%rbp
.text:004004da 16                               (bad)  
.text:004004db 17                               (bad)  
.text:004004dc b8 00 00 00 00                   mov    $0x0,%eax
.text:004004e1 5d                               pop    %rbp
.text:004004e2 c3                               retq   
.text:004004e3 66 2e 0f 1f 84 00 00 00 00 00    nopw  %cs:0x0(%rax,%rax,1)
.text:004004ed 0f 1f 00                         nopl   (%rax)

我正在使用英特尔 PIN 来运行程序跟踪,并根据我得到的指令进行某种分析。所以对于(坏的)指令,它们是非法的,从而导致程序崩溃。我检查跟踪中每条指令的指令地址以及下一条指令的地址。

Pin 所示指令 mov %rsp, %rbp 的下一条指令地址(地址 0x004004d7,0x16 指令之前的那个)为 0x0。当下一条指令是条件/无条件分支指令时,引脚显示 0x0。由于它也显示了错误指令,我怀疑错误指令正在调用异常处理程序,该处理程序终止程序并给出以下消息 -

Illegal instruction (core dumped)

我正在使用 Pin 来检测指令,当我得到非法指令时,我会进行某种模拟,然后删除该指令,以便跟踪可以进一步进行。

是否有任何类型的设置/标志来禁用这种非法指令异常生成?

我正在使用 gcc 来生成我的可执行文件,它可以简单地编译而不会产生错误。当我执行指令时,问题就来了。有没有什么设置在遇到非法指令时只是简单的跳过指令?

【问题讨论】:

  • 你为什么要在这个主题上发布一个又一个问题?您之前的问题中缺少什么让您问另一个问题?
  • 我不确定它是否适合您,但我会捕获异常,将指令修补到 nop 并继续。 (如果您愿意,我可以发布 Linux 的示例代码。但可能有一些特定于引脚的方法。)
  • @DavidSchwartz 我正在尝试做类似的事情,但似乎在我能够检测指令之前引发了异常。是的,linux 的例子有帮助,请分享一下
  • @fuz,我弄清楚了所有关于痕迹的事情。只是在执行指令之前,我似乎无法弄清楚为什么在检测指令时会引发异常。所以根据我的逻辑,我应该抓住指令,然后将其删除,这样就不会引发异常。我对 Pin 有点陌生,所以我没有找到关于我想要做什么的好的文档,所以我发现 stackoverflow 的答案最有帮助。以后我会尽量减少提问的数量。

标签: c gcc assembly intel-pin


【解决方案1】:

根据要求,这是我用来在单核机器上将ud2 未定义指令修补到nop nop 和在多核机器上修补nop lock 的代码。我删除了与您的用例完全不相关的代码:

void __gmon_start__(void)
{
   if(ill) return;
   ill=true;
   struct sigaction act;
   memset((void *) &act, 0, sizeof(act));
   act.sa_sigaction=sigill;
   act.sa_flags=SA_SIGINFO;
   sigaction(SIGILL, &act, NULL);
   // more code to set IsUP goes here
}

还有:

static void sigill(int, struct siginfo *info, void *extra)
{
    // Dynamically patch a 'ud2' to a 'nop lock' or a 'nop nop'

    // Begin with a full CPU sync (purge unmodified code)
    __asm__ __volatile__("cpuid" : : : "ax", "bx", "cx", "dx");

 // There was code here to acquire a mutex to prevent
 // multiple attempts to change the same code

  ucontext_t *uc=(ucontext_t *) extra;
  if (uc==NULL) { char *j=NULL; *j++; } // fatal

  unsigned char *instr=(unsigned char *) uc->uc_mcontext.gregs[14]; // EIP
  if(instr==NULL) { char *j=NULL; *j++; } // fatal


    if(instr[0] != 0x90)
    { // instruction wasn't already patched

     if ( (instr[0] != 0x0f) || // must be a ud2
            ((instr[1] != 0x0b) && (instr[1] != 0xb9)) )
      { char *j=NULL; *j++; } // fatal

      mprotect( (void *) ( ((int) instr) & ~(PAGESIZE-1)),
           PAGESIZE, PROT_WRITE | PROT_EXEC | PROT_READ);
      instr[0] = 0x90; // first byte is always a nop
      instr[1] = (IsUP) ? 0x90 : 0xf0;
      mprotect( (void *) ( ((int) instr) & ~(PAGESIZE-1)),
          PAGESIZE, PROT_EXEC | PROT_READ);
   }

  // mutex was released here

  // Reflush the CPU
  __asm__ __volatile__("cpuid" : : : "ax", "bx", "cx", "dx");
 }

对不起,代码是一团糟。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-22
    相关资源
    最近更新 更多