跳转至

CNSS_RE_18_03_17

本次交流会还有提及vm一类的代码保护技术,详细演示文档见群文件

SEH相关

TEB(Thread Environment Block,线程环境块)

系统在此TEB中保存频繁使用的线程相关的数据。位于用户地址空间,在比 PEB 所在地址低的地方。进程中的每个线程都有自己的一个TEB。一个进程的所有TEB都以堆栈的方式,存放在从0x7FFDE000开始的线性内存中,每4KB为一个完整的TEB,不过该内存区域是向下扩展的。在用户模式下,当前线程的TEB位于独立的4KB段,可通过CPU的FS寄存器来访问该段,一般存储在[FS:0]。

// 
// Thread Environment Block (TEB) 
// 
typedef struct _TEB 
{ 
NT_TIB Tib; /* 00h */ 
PVOID EnvironmentPointer; /* 1Ch */ 
CLIENT_ID Cid; /* 20h */ 
PVOID ActiveRpcHandle; /* 28h */ 
......
Tib结构体如下:
typedef struct _NT_TIB 
{ struct _EXCEPTION_REGISTRATION_RECORD ExceptionList; 
PVOID StackBase; 
PVOID StackLimit; 
PVOID SubSystemTib; 
union { 
PVOID FiberData; 
DWORD Version; 
}; 
PVOID FiberData; 
PVOID ArbitraryUserPointer; 
struct _NT_TIB *Self; 
} NT_TIB; 
typedef NT_TIB *PNT_TIB;

TIB的第一个参数ExceptionList指向的便是SEH链表,它很简单,其大致定义如下:

typedef struct _EXCEPTION_REGISTRATION_RECORD{
    PEXCEPTION_REGISTRATION_RECORD Next;
    PEXCEPTION_DISPOSITION Handler;
} EXCEPTION_REGISTRATION_RECORD;

RDTSC

x86 CPU中存在一个名为TSC(Time Stamp Counter,时间戳计数器)的64位寄存器。CPU对每个时钟周期计数,然后保存到TSC,RDTSC指令便是用来将TSC的值读入 EDX:EAX 寄存器中。

INT 2D

INT2D原为内核模式中用来触发断点异常的指令,也可以在用户模式下触发异常。但**程序调试运行时不会触发异常**,只是**忽略**。这种在正常运行与调试运行中表现出的不同,可以很好地应用到反调试技术中。

INT 2D的特性:

在调试模式中执行完INT 2D指令后,下一条指令的第一个字节将被忽略,后一个字节将会被识别为新的指令继续执行。

SEH里得到的INT 2D异常的EIP也是指令+2的地址。

得益于上面的特性,单步执行该指令时,调试器并不会在下一条指令处断下来,而达到一种F9的效果。

TLS 回调函数

所谓TLS回调函数是指,每当创建/终止进程时会自动调用执行的函数。有意思的是,创建进程的主线程时也会自动调用回调函数,且其调用先于EP代码。反调试技术利用的就是TLS回调函数的这一特征。