|
哈喽,大家好,我就是那个不喜欢在大厂搬砖,不喜欢在研究院做研究,只喜欢创业做计算机底层课程的coder,子牙老师
我们用gdb调试器调试程序的时候,通过会一边调试一边看c代码,以确定程序走到那了 其实gdb能查看c代码,是基于gdb能查看汇编代码实现的。本篇文章就来讲讲gdb能查看汇编代码的底层实现
gdb查看c代码的底层原理,后面再问文章细讲。如果你对此感兴趣,可以关注公众号【硬核子牙】,届时阅读
先解释下两个词:汇编与反汇编。把人写的汇编程序编译成机器码的过程,称为汇编过程。将机器码翻译成人能看懂的汇编的过程,称为反汇编过程
接下来,进入正文。以下,enjoy
汇编与机器码开始正式内容之前,先来打点基础吧:介绍下汇编与机器码。机器码,还有一个非常学术的名词:硬编码,可能很少人听过
当你在gdb中执行这条命令,就能看到CPU程序计数器rip指向位置的汇编代码及机器码 其实早期的程序员是用0跟1进行编程的,打孔机时代。后来发现这样编程效率太低了,代码太难维护了,进入了硬编码编程时代,就是使用的十六进制编程。发现这样还是同样的问题,于是诞生了编译器,编程进入了汇编时代。然后进入c时代、c++时代、Java时代……
其实这里要探讨的是:机器码与汇编的关系,有规律吗?比如0x5a,对应的汇编是pop rdx,是固定的吗?是的。秘密就在这张图里 无论是汇编过程,即将汇编语言翻译成机器码。还是反汇编过程,将机器码翻译成汇编,都是基于这张图实现的。如果你想玩逆向如病毒、破解、外挂,这个是必学的
举两个例子吧
将汇编语言编程成机器码,如图 将机器码反汇编成汇编语言 如果你想看opcode,需要去查Intel手册,长这样 是不是像天书?当年学硬编码的时候,差点没把头学炸了。不过痛苦过了,现在是一片坦途,看任何技术,一眼到底
所以你现在知道汇编是如何编译成机器码的了,你也知道机器码是如何反汇编成汇编的了,后面的事情就好办了
gdb实现来看下disas是如何实现的 104行,先调用ptrace函数,request=PTRACE_GETREGS,拿到所有寄存器的指,从中再拿到CPU程序计数器rip的值
131行,调用ptrace函数,request=PTRACE_PEEKDATA,拿到程序计数器处的机器码,一次最多读8字节。调试器读内存的原理,前面的文章《gdb底层实现原理》,不记得的或不了解的小伙伴去复习一下
140行,基于capstone库实现将读到的机器码进行反汇编
gdb能够查看反汇编,就是这么实现的
如果你想自实行调试器,反汇编引擎,除了capstone,这些也可以考虑。这其中名气最大的,除了capstone,就是LLVM了,后面有空玩玩这个 我的课程《从零手写gdb调试器》是基于capstone实现的,gdb也是基于capstone实现的
step over/step out与此气氛都到这了,这两个就可以讲了。这两个是啥,看图 当程序在断点处停下来了,是不是一般有四个按钮:continue、step over、step into、step out。其中continue已经讲过了,在文章《gdb的放过去是怎么做到的》。step into也已经讲过了,在文章《gdb单步调试底层原理》。现在来讲step over,单步步过、step out,单步步出
step over的核心是识别函数调用指令call,跳过函数调用实现的。step out是识别函数返回指令ret,调过去实现的 你可能想说,call对应的机器码是0xe8,ret对应的机器码是0xc3,gdb能够识别啊,跟前面讲的内容有什么关系呢?0xe8有没有可能就是单纯的数字呢?0xc3有没有可能是其他指令的一部分呢?所以核心的就是,要精准确定0xe8的含义,所以必须要借助反汇编引擎实现
至此,关于单步的所有底层实现,你已全部知晓!怎么样?是不是很痛快!
|