Python灰帽子笔记二

通用寄存器:
寄存器可以被认为是位于CPU上的小型存储器。CPU获取数据的最快方式是直接访问寄存器。在X86指令集中,一个CPU具有8个通用寄存器:EAX,EDX,ECX,ESI,EDI,EBP,ESP,EBX。每一个都被安排了特定用途。CPU在执行某些指令时需要特点的寄存器协作以高效地完成其指令执行过程。
EAX累加器,用于执行一些常见的运算操作以及用于传递函数调用的返回值。可以基于存储在EAX中的值来判断一个函数调用所执行的操作是成功还是失败了。
EDX数据寄存器。被认为是EAX的延伸部分,用于协助一些复杂的运算指令如乘法、除法。EDX被用于存储这些指令的额外数据结果。EDX也可以用于通用目的数据存储,但是其最常见的用法是和EAX联合使用,协助执行更为复杂的运算。
ECX计数器。用于支持循环操作。存储一个字符串或者进行计数就是典型的循环操作。ECX是反向计数的。(汇编代码中计数都是反向进行的)
在X86汇编语言中,涉及数据处理的循环操作依赖于ESI, EDI。ESI为源变址寄存器,存储输入流的位置信息。EDI为目的变址寄存器,指向相关数据操作结果的存放的位置。可以简记ESI“读”,EDI"写”。
ESP和EBP分别被称为栈指针和基址指针。这些寄存器用于控制函数调用和相关的栈操作。当一个函数被调用时,调用参数连同函数的返回地址将先后被压入函数栈中。ESP始终指向函数栈的最顶端(esp指向了函数的返回地址),EBP寄存器用于指向函数栈的底端。某些情况下,编译器为了指令优化目的可能会避免将EBP寄存器用作栈帧指针。此时,EBP可以像其他通用寄存器一样另作他用。
EBX寄存器是唯一一个没有被指定特殊用途的寄存器,可以作为额外的存储单元来使用。
EIP寄存器始终指向当前正在执行的命令。当CPU穿行于二进制代码中时,EIP寄存器中的值随之更新以实时反映当前代码所执行的位置。
一个调试器应当能够读取和修改这些寄存器的内容,每个操作系统都会提供一组接口使调试器能够与CPU进行交互,以获取或修改寄存器中的值。


栈是一种非常重要的数据结构。栈中存储着有关函数如何被调用的信息,包括函数所接收的参数以及该函数在执行结束后该如何返回的相关信息。栈是一个先进后出的数据结构,参数在函数调用前入栈并在函数结束调用后出栈。ESP寄存器用于记录当前栈帧的顶部,而EBP寄存器用于记录当前栈帧的底部。栈是由内存高地址向内存低地址的方向增长的。
栈是二进制代码中实现函数调用的基石。
根据栈帧的内容与变化情况,调试器能够实时地跟踪函数调用情况,记录下程序“奔溃”瞬间的栈上信息,并最终捕获基于栈类型的溢出事件。


调试器内部实际上是一个无限循环,循环每执行一次,调试器就会使自己进入“阻塞”状态,以等待调试事件的发生。

一个调试器必须捕获以下几种常见的调试事件:断点触发,非法内存操作(也称为非法访问或者段违规),由被调试程序抛出的异常

调试器一般会提供三种最基本类型的断点:软断点、硬件断点和内存断点。
软断点能够使目标进程执行到位于某特定位置的指令时暂停执行。软断点实质上只是一个单字节长的指令,该指令可以使被调试的目标进程暂停执行并将控制器交给调试器的异常处理例程。
汇编指令是CPU可以识别和执行的指令的一种高级表现形式,称之为助记符。CPU并不直接识别这种形式的指令,它首先被转换为“操作码”(Opcode),这才是CPU真正可以识别和执行的机器语言。
硬件断点适用于:少量断点即可满足调试任务,湖综合调试目标实现了类似CRC校验的反调试机制。这种类型的断点的设置是通过使用位于CPU上的一组特殊的寄存器来实现的,我们称其为调试寄存器。一个典型的CPU有8个调试寄存器(寄存器DR0到DR7)分别用于设置和管理硬件断点。DR0到DR3用于存储所设硬件断点的内存地址,即意味着任何时刻最多只能使用4个硬件断点,寄存器DR4和DR5保留使用。寄存器DR6称为调试状态寄存器,记录了上一次断点触发所产生的调试事件类型信息。DR7实质上是硬件断点的激活开关,同时还存储着各个断点的触发条件信息。通过设置DR7寄存器特定的标记位,你可以为断点设置以下几种触发条件:当位于一个特定内存地址上的指令被执行时触发断点,当数据被写入一个特定内存地址时触发断点,当数据被读出或写入(不包括执行)一个特定非可执行内存地址时触发断点。

软断点使用INT3软中断事件,硬件断点使用1号中断(INT1),INT1事件被用于硬件断点和单步事件。

硬件断点的限制:1.在任意时刻最多只能设置4个断点2.最多只能对4个字节长的数据设置断点。

内存断点本质上不是真正的断点。当设置内存断点时,调试器实质上是改变一个内存区域或一个内存页的访问权限。内存页是操作系统可以一次处理的最小内存块。
几个不同的内存页访问权限的例子:
页可执行,页可读,页可写,保护页
保护页:对保护页的任何类型的访问将导致一次性异常,之后这个内存页会恢复到之前的状态。
大多数操作系统允许组合不同的访问权限。如,可以将某个内存页设置为读写权限,而将另一个内存页设置为读和执行权限。
我们最感兴趣的内存页访问权限是保护页。保护页可以用于隔离堆和栈,或者用于确保一个内存块的增长不会超出某一预定边界。保护页特性可以用来帮组我们实现内存断点机制,利用该特性,当进程访问一个特定区域的内容时,我们可以让进程暂停执行。

你可能感兴趣的:(Python灰帽子笔记二)