0%

逆向工程核心原理_高级逆向分析技术

TLS(Thread Local Storage)回调函数

首先需要注意的一点就是,TLS回调函数是在程序进入OEP之前调用的,因此利用这一特性可以在此设置反调试。

简要说明TLS定义:TLS是各线程的独立的数据存储空间,使用TLS技术可在线程内部独立使用或修改进程的全局数据或静态数据,就像对待自身的局部变量一样。

那么TLS回调函数是指

image-20220409084748247

值得一提的是,TLS表是需要在编程中开启TLS功能才会被设置在PE头文件中

IMAGE_TLS_DIRECTORY结构体有两种版本,32位和64位。

AddressOfCallBacks: 指向TLS注册的回调函数的函数指针(地址)数组(这个逆向时就很重要了)

通过TLS回调函数和DLLmain的定义比较可以发现,二者是类似的

image-20220409085002301

image-20220409085011556

上述图一中,reason是指调用TLS函数的原因

如图所示

image-20220409085140790

分别是DLL进程/线程附加;DLL进程/线程分离

image-20220409182903022

关于调试TLS函数和手动添加TLS函数此处不在描述,过程中涉及对PE文件结构知识的回顾,重在实践。

TEB

贴上书中的定义

image-20220410113647863

丛书中的描述可知,TEB结构体的成员多而复杂,但在用户模式调试中起重要作用的成员有两个

image-20220410113850420

先看ProcessEnvironmentBlock,它是指向PEB—进程环境块结构体的指针.每个进程对应一个PEB结构体

再看NtTib成员,TEB结构体的第一个成员为_NT_TIB(Thread Information Block—线程信息块)结构体

下图为其结构体定义

image-20220410114802311

self成员为该结构体的自引用指针,同时因为该结构体为TEB的第一个结构体成员,所以它同时也是指向TEB结构体的指针。

TEB访问方法(用户模式下)

这里对FS段寄存器做了说明

原文解释的很清楚

image-20220410120445854

由上可知,FS实际存储的是SDT的索引

image-20220410120647654

PEB(进程环境块)

PEB是存放进程信息的结构体

根据PEB结构体地址我们可以用如下方式访问PEB结构体

image-20220410121548028

PEB的重要成员

image-20220410121808724

先看第一个成员,顾名思义,用来检测当前进程是否处于调试状态,是则返回1,否则返回0.

image-20220410122356393

可以看到该API就是通过调用该成员实现检测当前进程是否处于调试状态。

接下来是第二个成员

该进程用来获取进程的ImageBase

image-20220410122602024

上图的API用来获取ImageBase,实现方法与上一个API类似。

再下一个Ldr,该成员是指向PEB_LDR_DATA结构体的指针,结构体成员如下图所示

image-20220410122801231

该成员可直接获取加载到进程的DLL模块的加载基地址

可以看到结构体中有三个_LIST_ENTRY类型的成员。,该结构体定义如下图

image-20220410123646015

最后两个成员都应用于反调试技术。进程处于调试状态时,有特定值。

SEH

image-20220410151204978

SEH机制在程序源代码中使用try,except,finally关键字来实现。

书中第一个例子的异常触发是由于访问未分配的内存。

image-20220410162947013

操作系统的异常处理方法大致可根据程序运行情况分为两大类

  1. 正常运行时处理
  2. 调试运行时处理

第一种操作系统会将异常交给进程处理,若进程代码有相应的解决代码,则顺利处理,否则终止进程运行。

第二种则是交给调试器处理。调试器的权限很多,除了与被调试的进程有几乎一样的权限外,还有被调试者的虚拟内存,寄存器的读写权限。在遇到异常时,调试器会暂停运行,异常处理完后继续调试

下图为几种处理方法

image-20220410165322561

一下是操作系统所定义的—异常

image-20220410165654556

书中着重讨论了5种

EXCEPTION_ACCESS_VIOLATION(C0000005)

这就是访问不存在或不具访问权限的内存区域是所触发的异常—非法访问异常(最常见)

image-20220410170337983

EXCEPTION_BREAKPOINT(80000003)

这就是调试器实现断点的原理,CPU遇到被设置了断点的代码会暂停运行。

实现方法:

​ INT3为设置断点命令的汇编语言,所对应的机器码为0xCC。CPU若遇到了该指令,即触发该异常

EXCEPTION_ILLEGAL_INSTRUCTION(C000001D)

CPU遇到无法解析(在该CPU架构下未定义)的指令时触发异常

EXCEPTION_INT_DIVIDE_BY_ZERO(C0000094)

小学数学经典错误,整数除法当中,分母为0.当然,若分母为某个变量,变量在某个时刻为0,也会触发该异常

。比如一个变量自己跟自己异或,返回0

EXCEPTION_SINGLE_STEP

单步过后程序暂停,程序进入单步模式后,每执行一次单步,就触发一次该异常。

image-20220410172513951

SEH链

原图简洁明了

image-20220410172810751

异常处理函数的定义

image-20220410172842993

该函数传入四个参数,返回一个枚举类型.四个参数都保存异常的相关信息,第三个参数是指向CONTEXT结构体的指针.

该结构体的定义如下

image-20220410180000470

该结构体用来备份CPU寄存器的值(多线程环境下需要).每个线程内部都拥有一个CONTEXT结构体,当CPU暂时离开当前线程去执行其他线程时,CPU寄存器的值就会保存到当前的CONTEXT结构体中,再次运行该线程时,就会用保存的值覆盖寄存器的值,从之前暂停的代码处继续执行.正是因此,OS才可以在多线程下安全运行各线程.

image-20220410180451097

所返回的枚举类型如下

image-20220410183502324

在异常发生时执行异常代码的线程会被中断运行,转而运行SEH,OS会把线程的CONTEXT结构体指针传递给异常处理函数的相应参数.

第一个成员是一个结构体,其定义如下

image-20220410174054428

其中,第一个成员用来指出异常类型;第四个则用来表示发生异常的代码地址.

TEB结构体的第一个成员是TEB.NtTib.ExceptionList,通过它可以很容易地访问进程的SEH链.

image-20220410185707466

SEH安装方法

image-20220410185822888

后面的调试建议动手调,没有什么需要特别说明的。

关于IA32指令解析,就像是在教你如何查阅程序员的字典一样,跟着阅读即可。