《逆向工程核心原理》》<06> 高级逆向分析技术
来源:互联网 发布:多媒体制作软件工具 编辑:程序博客网 时间:2024/06/05 20:30
0x00 TLS回调函数
TLS (Thread Local Storage, 线程局部储存) 回调函数常用于反调试, 程序运行EP代码前会先调用它。
00. TLS
通过pe文件的可选头中的
IMAGE_DATA_DIRECTORY[9]
可以找到IMAGE_TLS_DIRECTORY
, 其中重要的成员的是AddressOfCallbacks
, 该值指向含有TLS回调函数地址(VA)地址, 这意味着可以向同一程序注册多个TLS回调函数(数组以NULL值结束)。回调函数地址数组。进程启动运行时, (执行EP代码前)系统会逐一调用存储在该数组中的函数。
01. TLS回调函数
01.0.所有TLS回调函数是指, 每当创建/终止进程的线程时会自动调用执行的函数。也就是说, 创建或终止某线程时, TLS回调函数都会自动调用执行,前后共2次。
01.1.IMAGE_TLS_CALLBACK
typedef VOID(NTAPI *PIMAGE_TLS_CALLBACK)( PVOID DllHandle, //模块句柄 (即加载地址) DWORD Reason, //调用TLS回调函数的原因 PVOID Reserved);
01.2.Reason
#define DLL_PROCESS_ATTACH 1#define DLL_THREAD_ATTACH 2#define DLL_THREAD_DETACh 3#define DLL_PROCESS_ATTACh 0
顾名思义, DLL_PROCESS在main()函数创建和终止后作为原因调用TLS回调函数; DLL_THREAD在线程创建和终止后作为原因调用TLS回调函数。
02. 调试TLS回调函数
将OD的Make first pause of切到System break point, 调试器最初暂停的位置是系统启动断点, 之后参考TLS回调函数的地址(通过PE文件可以找到), 在回调函数的起始地址下断点后, 变可以调试了。
0x01 TEB
TEB (Thread Environment Block, 线程环境块), 该结构体包含进程中运行线程的各种信息, 进程中的每个线程都对应·一个TEB结构体。
00. TEB的重要成员
+0x000 NtTib :_NT_TIB...+0x030 ProcessEnvironmentBlock : Ptr32_PEB
Nt_Tib成员
TIB (Thread Information Block, 线程信息块), 其中的ExceptionList
成员指向_EXCEPTION_REGISTRATION_RECORD
结构体组成的链表, 它用于Windows OS的SEH;Self
成员是_NT_TIB
结构体的自引用指针, 也是TEB结构体的指针(+0x018)。ProcessEnvironmentBlock成员
ProcessEnvironmentBlock
成员值指向PEB (进程环境块)结构体的指针, 每个进程对应一个PEB结构体。
01. TEB的访问方法
利用Ntdll!NtCurrentTeb()API
返回当前线程的TEB结构体地址, API返回FS:[18]
的值, 也就是上文提到的Self
成员的指针值, 而该值也恰好是FS段寄存器的起始地址。FS段寄存器用来指示当前线程的TEB结构体, 实际上, FS段寄存器持有SDT的索引, 而该索引持有实际TEB地址。
注: SDT位于内核内存区域, 其地址存储在特殊的寄存器GDTR (Global Descriptor Table Register, 全局描述符表寄存器中)。
02. TEB重要成员的地址表示
- FS:[0x00] == SEH起始地址
FS:[0x00] = TEB.NtTib.ExceptionList = address of SEH
- FS:[0x18] == TEB起始地址
FS:[0x18] = TEB.NtTib.Self = address of TEB = FS:[0x00]
- FS:[0x30] == PEB起始地址
FS:[0x30] = TEB.ProcesssEnvironmentBlock = address of PEB
0x02 PEB
PEB (Process Environmnet Block, 进程环境块), 是存放进程信息的结构体。
00. PEB的重要成员
+0x002 BeingDebugged : UChar+0x008 ImageBaseAddress : Ptr32 Void+0x00c Ldr : Ptr _PEB_LDR_DATA+0x018 ProcessHeap : Ptr32 Void+0x068 NtGlobalFlag : Uint48
BeingDebugged成员
该成员用于检测进程是否处于被调试的状态,: 是为01, 否为00。ImageBaseAddress成员
该成员用于表示进程的ImageBase。Ldr成员
0.该成员是指向_PEB_LDR_DATA结构体的指针, 当模块(DLL)加载到进程后, 通过PEB.Ldr成员可以直接获取该模块的加载基地址。
1 _PEB_LDR_DATA结构体含有3个_LIST_ENTRY类型的成员, 而_LIST_ENTRY结构体提供了双向链表机制, 链表保存的是_LDR_DATA_TABLE_ENTRY结构体的信息。
2.每个加载到进程中的DLL模块都有与之对应的_LDR_DATA_TABLE_ENTRY结构体, 这些结构体相互链接, 形成_LIST_ENTRY双向链表。ProcessHeap & NtGlobalFlag成员
该成员与PEB.BeingDebugged成员类似, 处于调试状态时会持有特定值, 可用于反调试技术。
01. PEB的访问方法
直接获取PEB地址
MOV EAX, DWORD PTR FS:[30] ; FS:[30] = address of PEB
先获取TEB地址, 再通过+0x30的偏移获取PEB的地址
MOV EAX, DWORD PTR FS:[18] ; FS:[18] = address of TEB
MOV EAX, DWORD PTR DS:[EAX+30] ; DS:[EAX+30] = address of PEB
0x03 SEH
SEH (Structured Exception Handling, 结构化异常处理)是Windows OS默认的异常处理机制。
00. OS的异常处理方法
- 正常运行时的异常处理方法
进程运行过程中若发生异常, OS会委托进程处理。若进程代码中存在具体的异常处理机制(如SEH异常处理器)代码, 则能顺利处理相关异常, 程序继续运行; 但如果进程内部没有具体实现SEH, 则相关机场无法处理, OS会启动默认的异常处理机制, 终止进程运行。 - 调试运行时的异常处理方法
若被调试进程内部发生异常, OS会首先把异常抛给调试进程处理。调试器几乎拥有被调试者的所有权限, 它不仅可以运行、终止被调试者, 还拥有被调试进程的虚拟内存、寄存器的读写权限。所以调试过程中发生的所有异常都要先交由调试器管理 (被调试者的SEH依据优先顺序推给调试器)。
于是, 被调试者发生异常时, 调试器暂停运行, 采取某种措施处理异常, 完成后继续调试。
遇到异常可以采取的几种方法:
(1)直接修改异常: 代码, 寄存器, 内存
(2)将异常抛给被调试者处理
如果被调试者内部存在SEH能够处理异常, 那么异常通知会发送给被调试者, 由被调试者自行处理。这与程序正常运行时的异常处理方式是一样的。
(3)OS默认的异常处理机制
终止被调试进程, 同时结束调试。
01. 常见异常
0.EXCEPTION_ACCESS_VIOLATION(C0000005)
试图访问不存在或不具备访问权限的内存区域时, 就会发生非法访问异常。
1.EXCEPTION_BREAKPONIT(80000003)
在运行代码中设置断点后, CPU尝试执行该地址处的指令, 将发生此异常。调试器利用该异常实现断点功能。具体实现为把1字节替换成CC (INT3)。
2.EXCEPTION_ILLEGAL_INSTRUCTION(C000001D)
CPU遇到无法解析的指令时引发该异常。
3.EXCEPTION_INT_DIVIDE_BY_ZERO(C0000094)
Integer除法运算中, 若分母为0, 则引发该异常。
4.EXCEPTION_SINGLE_STEP(80000004)
Single1 Step(单步)的含义是执行一条指令, 然后暂停。CPU进入单步模式后, 每执行一条指令就会引发该异常, 然后暂停运行。将EFLAGS寄存器的TF (Trap Flag, 陷阱标志)位设置为1后, CPU就会进入单步工作模式
02. SEH具体实现
0. SEH链
SEH以链的形式存在。第一个异常处理器中若未处理相关异常, 它就会被传递到下一个异常处理器, 直到得到处理。从技术层面看, SEH是由_EXCEPTION_REGISTRATION_RECORD
结构体组成的链表。
tydef _EXCEPTION_REGISTRATION_RECORD{ PEXCEPTION_REGISTRATION_RECORD Next; PEXCEPTION_DISPOSITION Handler;} _EXCEPTION_REGISTRATION_RECORD, *PEXCEPTION_REGISTRATION_RECORD;
Nex成员是指向下一个此结构体的指针;
Handler成员是异常处理函数(异常处理器)。
注: 若Next成员为FFFFFFFF, 则表示它是链表的最后一个结点。
1. 异常处理函数
1.0.
异常处理器的定义:
EXCEPTION_DISPOSITION _except_handler( EXCEPTION_RECORD *pRecord, PEXCEPTION_REGISTRATION_RECORD *pFrame, CONTEXT *pContext, PVOID *pValue);
该异常处理函数由系统调用, 是一个回调函数, 系统调用它时会给出这4个参数, 这4个参数保存着异常相关的的信息。
参数0— EXCEPTION_RECORD结构体的定义
typedef struct _EXCEPTION_RECORD{ DWORD ExceptionCode; // 异常代码 DWORD ExceptionFlags; struct _EXCEPTION_RECORD *ExceptionRecord; PVOID ExceptionAddress; // 异常发生地址 DWORD NumberParameters; ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; // 15}
参数1— PEXCEPTION_REGISTRATION_RECORD结构体
此结构体指针, 指向SEH链的起始地址。
参数2— CONTEXT结构体
CONTEXT结构体用来备份CPU寄存器的值。每个线程内部都拥有1个CONTEXT结构体。
注: CPU离开当前线程时, 会将此时寄存器的值保存在当前线程的CONTEXT结构体; CPU再次运行该线程, 会使用保存在CONTEXT结构体的值来覆盖寄存器的值, 然后从之前暂停的代码处继续执行。通过这种方式, OS可以在多线程环境下安全运行各线程。
1.1.
异常发生时, 执行异常代码的线程就会中断运行, 转而运行SEH, 此时OS会把线程的CONTEXT结构体的指针传递给异常处理器的相应参数。
CONTEXT结构体成员中有一个Eip成员, 在异常处理函数中将参数传递过来的CONETXT.Eip设置为其他地址, 然后返回异常处理函数。这样, 之前暂停的线程会执行新设置的EIP地址处的代码。
typedef enum _EXCEPTION_DISPOSITION{ ExceptionContinueExecution = 0, // 继续执行异常代码 ExceptionContinueSearch = 1, // 运行下一个异常处理器 ExceptionNestedException = 2, // 在OS内部使用 ExceptionCollidedUnwid = 3 // 在OS内部使用} EXCEPTION_DISPOSITON;
2. TEB.NtTib.ExceptionList
通过TEB结构体的Ntlib成员可以访问进程的SEH链。 TEb.NtTib.Exception = FS:[0]
3. SEH安装方法
PUSH @MyHandler ; 异常处理器PUSH DWORD PTR FS:[0] ; Head of SEH Linked ListMOV DWORD PTR FS:[0], ESP ; 添加链表
将自身的EXCEPTION_REGISTRATION_RECORD结构体链接到此结构体链表。
detail:
第1步, 把异常处理器的地址PUSH进栈 (作为参数Handler);
第2步, 把原本SEH链第一个结构体的地址PUSH进栈 (作为参数Next);
第3步, 将ESP此时的值([ESP+0]为Next, [ESP+4]为Handler)复制到FS:[0], 成为新的SEH链的第一个结构体的地址。
4. SEH删除方法
POP DWORD PTR FS:[0]ADD ESP,4
detail:
第1步, 将ESP+0pop至FS:[0], 还原为安装前的SEH链的第一个结构体的地址。
第2步, 清理栈, 将Handler和Next参数消除。
- 《逆向工程核心原理》》<06> 高级逆向分析技术
- 《逆向工程核心原理》
- 《逆向工程核心原理》
- 逆向工程核心原理
- (逆向工程核心原理)小白初探逆向_1:逆向分析Hello World!程序
- <逆向工程核心原理> 静态反调试技术总结
- <逆向工程核心原理> 动态反调试技术总结
- 《逆向工程核心原理》》<07> 反调试技术
- 《逆向工程核心原理》相关说明
- 逆向工程核心原理读书笔记-代码注入
- 逆向工程核心原理读书笔记-代码注入
- 《逆向工程核心原理》<04-34> 高级全局API钩取
- 《逆向工程核心原理》<04-30> 通过Debug修改代码实现API钩取的技术
- 《逆向工程核心原理》<04-32> 通过DLL注入实现IAT钩取的技术
- 《逆向工程核心原理》<01-08> abex` crackme #2 -Check按钮处理代码的部分分析
- 逆向工程核心原理学习笔记(十二):分析abex' crackme #1
- 逆向工程核心原理学习笔记(十二):分析abex' crackme #1
- 高级文件格式逆向分析
- 【GamePlay3D游戏引擎学习笔记】——GamePlay3D游戏引擎VS2015搭建
- 【开发也是好测试系列】(二)——pytest之fixture
- 最长公共子序列
- 6月总结
- 互联网应用课程笔记
- 《逆向工程核心原理》》<06> 高级逆向分析技术
- 一个神奇高效的工具-正则表达式(四)
- 图着色问题
- Zookeeper集群搭建
- 一个神奇高效的工具-正则表达式(五)
- Hdu 4057 AC自动机+DP
- 《逆向工程核心原理》》<07> 反调试技术
- 增强学习 | 多臂赌博机模型进阶
- Ubuntu 16.04 mysql安装配置