首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何确定程序跳到无效地址的位置--不需要单步执行?

问如何确定程序跳到无效地址的位置--不需要单步执行?
EN

Stack Overflow用户
提问于 2017-04-28 11:12:32
回答 2查看 2.1K关注 0票数 1

我正在调试一个多线程程序,它以RIP=0x0和堆栈上的大量零结尾。有没有办法找出程序之前只是一条指令的地方?当我尝试单步时,结果似乎不同(可能是一些种族条件),但是如果我只是启动程序并让它离开,它就会一直落在这里。

那么,在不进行单步或模拟的情况下,是否有任何方法可以在跳/调用零地址之前捕获它呢?是否有以前指令的注册地址?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-04-29 17:26:13

是否有以前指令的注册地址?

没有这样的寄存器,但是有分店追踪商店,GDB使用record btrace命令支持它。

注:以上维基百科文章:

英特尔处理器上的分支跟踪会导致40x应用程序运行时减慢。

下面是如何使用record btrace调试您的问题:

代码语言:javascript
复制
cat t.c
#include <string.h>
int bar()
{
  char buf[10];
  memset(buf, 0, sizeof(buf));
  memset(buf, 'A', 100);  // overflow
}

int foo()
{
  return bar();
}

int main()
{
  return foo();
}

gcc -g  t.c -fno-stack-protector

gdb -q ./a.out

(gdb) run
Starting program: /tmp/a.out

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400562 in bar () at t.c:7
7   }
(gdb) bt 5
#0  0x0000000000400562 in bar () at t.c:7
#1  0x4141414141414141 in ?? ()
#2  0x4141414141414141 in ?? ()
#3  0x4141414141414141 in ?? ()
#4  0x4141414141414141 in ?? ()
(More stack frames follow...)

很难调试:我们不知道这里发生了什么(我认为,这是对当前问题的建模)。

代码语言:javascript
复制
(gdb) start
Temporary breakpoint 1 at 0x400577: file t.c, line 16.
Starting program: /tmp/a.out

Temporary breakpoint 1, main () at t.c:16
16    return foo();
(gdb) record btrace
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400562 in bar () at t.c:7
7   }
(gdb) record instruction-history
719    0x00007ffff7a9e531 <memset+113>: movdqu %xmm8,0x20(%rdi)
720    0x00007ffff7a9e537 <memset+119>: movdqu %xmm8,-0x30(%rdi,%rdx,1)
721    0x00007ffff7a9e53e <memset+126>: movdqu %xmm8,0x30(%rdi)
722    0x00007ffff7a9e544 <memset+132>: movdqu %xmm8,-0x40(%rdi,%rdx,1)
723    0x00007ffff7a9e54b <memset+139>: add    %rdi,%rdx
724    0x00007ffff7a9e54e <memset+142>: and    $0xffffffffffffffc0,%rdx
725    0x00007ffff7a9e552 <memset+146>: cmp    %rdx,%rcx
726    0x00007ffff7a9e555 <memset+149>: je     0x7ffff7a9e4fa <memset+58>
727    0x00007ffff7a9e4fa <memset+58>:  repz retq
728    0x0000000000400561 <bar+52>: leaveq

上面的指令跟踪告诉我们,我们在从bar返回时就崩溃了,并且在返回之前正在执行memset。

代码语言:javascript
复制
(gdb) record instruction-history -
709    0x00007ffff7a9e4cd <memset+13>:  punpcklwd %xmm8,%xmm8
710    0x00007ffff7a9e4d2 <memset+18>:  pshufd $0x0,%xmm8,%xmm8
711    0x00007ffff7a9e4d8 <memset+24>:  cmp    $0x40,%rdx
712    0x00007ffff7a9e4dc <memset+28>:  ja     0x7ffff7a9e510 <memset+80>
713    0x00007ffff7a9e510 <memset+80>:  lea    0x40(%rdi),%rcx
714    0x00007ffff7a9e514 <memset+84>:  movdqu %xmm8,(%rdi)
715    0x00007ffff7a9e519 <memset+89>:  and    $0xffffffffffffffc0,%rcx
716    0x00007ffff7a9e51d <memset+93>:  movdqu %xmm8,-0x10(%rdi,%rdx,1)
717    0x00007ffff7a9e524 <memset+100>: movdqu %xmm8,0x10(%rdi)
718    0x00007ffff7a9e52a <memset+106>: movdqu %xmm8,-0x20(%rdi,%rdx,1)
(gdb)
699    0x00007ffff7a9e5b6 <memset+246>: retq
700    0x000000000040054b <bar+30>: lea    -0x10(%rbp),%rax
701    0x000000000040054f <bar+34>: mov    $0x64,%edx
702    0x0000000000400554 <bar+39>: mov    $0x41,%esi
703    0x0000000000400559 <bar+44>: mov    %rax,%rdi
704    0x000000000040055c <bar+47>: callq  0x400410 <memset@plt>

..。memset就是从这里来的。

代码语言:javascript
复制
705    0x0000000000400410 <memset@plt+0>:   jmpq   *0x200c02(%rip)        # 0x601018 <memset@got.plt>
706    0x00007ffff7a9e4c0 <memset+0>:   movd   %esi,%xmm8
707    0x00007ffff7a9e4c5 <memset+5>:   mov    %rdi,%rax
708    0x00007ffff7a9e4c8 <memset+8>:   punpcklbw %xmm8,%xmm8
票数 1
EN

Stack Overflow用户

发布于 2017-04-29 04:08:31

那么,在不进行单步或模拟的情况下,是否有任何方法可以在跳/调用零地址之前捕获它呢?

不是的。

是否有以前指令的注册地址?

不在x86上(在HPPA上有这样的寄存器)。

由于从后续注释中可以看出,您的堆栈溢出会擦除返回地址,并最终导致返回到0,请注意:

  • 在探测到这类溢出时,瓦兰的能力非常弱,
  • 地址消毒剂应该没有什么问题,直接指出堆栈溢出。

由于您怀疑存在种族状况,请注意,螺纹消毒剂更适合于查找这些条件。

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

https://stackoverflow.com/questions/43678834

复制
相关文章

相似问题

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