【问题标题】:Parsing Call and Ret with ptrace.使用 ptrace 解析 Call 和 Ret。
【发布时间】:2016-08-20 06:50:36
【问题描述】:

我尝试使用 ptrace 从可执行文件中解析所有 Calls 和 Rets。 符合x64opcode,我找到了 Calls: 0xe8Rets: 0xc3, 0xc2, 0xca, 0xcb 的操作码。

自从我解析它们后,我发现 Rets 比 Calls 多。

有我跟踪的程序:

void func()                                                                                    
{                                                                                              
  write(1, "i", 1);                                                                            
}                                                                                              

int main(int ac)                                                                               
{                                                                                              
  func();                                                                                      
  return(0);                                                                                   
}

有我的追踪器:

int                     tracer(t_info *info)                                                   
{                                                                                              
  int                   status;                                                                
  long                  ptr;                                                                   
  int                   ret = 0;                                                                                 
  int                   call = 0;                                                                                


  waitpid(info->pid, &status, 0);                                                              
  while (WIFSTOPPED(status))                                                                   
    {                                                                                          
      ptrace(PTRACE_GETREGS, info->pid, NULL, info->regs);                                     
      ptr = ptrace(PTRACE_PEEKDATA, info->pid, info->regs->rip);                               
      if (((ptr & 0x000000ff) == 0xe8)) // Opcode for call                                                              
        {                                                                                      
          call++;                                                                              
        }                                                                                      
      else if (((ptr & 0x000000ff) == 0xc3) // Opcodes for rets                                
               || ((ptr & 0x000000ff) == 0xc2)                                                 
               || ((ptr & 0x000000ff) == 0xca)                                                 
               || ((ptr & 0x000000ff) == 0xcb))                                                
        {                                                                                      
          ret++;                                                                               
        }                                                                                      
      ptrace(PTRACE_SINGLESTEP, info->pid, 0, 0);                                              
      waitpid(info->pid, &status, 0);                                                          
    }                                                                                          
  printf("Calls: %i\nRets: %i\nDiff: %i\n", call, ret, call - ret);                                             
  return (0);                                                                                  
}

这是我的输出:

Calls: 656
Rets: 666
Diff: -10

为什么 retscalls 的数量不一样? 我错过了一些操作码吗? 有不返回的函数吗?

【问题讨论】:

  • 顺便说一句,您不在这里解析,而是您trace

标签: c assembly x86-64 ptrace


【解决方案1】:

例如,您会错过间接调用,例如

callq *(<expr>)

使用其他操作码。 Libc 标准初始化例程利用了这些。根据表达式,可能有多个操作码,两个示例:

ff d0                   callq  *%rax
41 ff 14 dc             callq  *(%r12,%rbx,8)

要全部获得它们可能并不容易。也许使用 libbfd 和 libopcodes 之类的库来解码指令会更容易和更清晰

【讨论】:

  • 此外,从技术上讲,您不需要配对 retcall,尽管这样做是个好主意。例如,在 32 位代码中,call next; next: pop eax 是获取当前eip 的常用习语。最好将其分解为适当的函数,但并非总是如此。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-07
  • 2016-11-27
  • 2015-09-04
  • 2015-06-25
  • 1970-01-01
  • 2021-12-07
  • 2016-11-23
相关资源
最近更新 更多