本文介绍了几种常见的静态反调试技术,包括PEB,LTS等
文中用到的程序资源https://download.csdn.net/download/weixin_45551083/12549567
TEB(Thread Environment Block,线程环境块)系统在此TEB中保存频繁使用的线程相关的数据。位于用户地址空间,在比 PEB 所在地址低的地方。进程中的每个线程都有自己的一个TEB。一个进程的所有TEB都以堆栈的方式,存放在从0x7FFDE000开始的线性内存中,每4KB为一个完整的TEB,不过该内存区域是向下扩展的。在用户模式下,当前线程的TEB位于独立的4KB段,可通过CPU的FS寄存器来访问该段,一般存储在[FS:0]。
PEB(Process Environment Block,进程环境块)存放进程信息,每个进程都有自己的PEB信息。位于用户地址空间。在Win 2000下,进程环境块的地址对于每个进程来说是固定的,在0x7FFDF000处,这是用户地址空间,所以程序能够直接访问。
mov eax,fs:[0x30]
mov PEB,eax
(2) 先获取TEB地址,再获取TEB
mov eax, fs:[0x18] ;0x18处是TEB地址
mov eax, ds:[eax+0x30]
+0x002 BeingDebugged
+0x00c Ldr
+0x018 ProcessHeap
+0x068 NtGlobalFlag
进程处于调试状态时,PEB.BeingDebugged成员的值设为1.在非调试状态下为0;
调试进程时,其堆内存区域中会出现一些特殊标识,表名它正处于被调试状态.最醒目的是.未使用的堆内存区域全部填充着0xEEFEEEFE.利用这一特征可判断是否处于被调试状态.
PEB.Ldr 指向_PEB_LDR_DATA结构体指针,_PEB_LDR_DATA恰好是在堆中创建的.检测_PEB_LDR_DATA是否是0xEEFEEEFE即可判断是否处于被调试
将填充着0xEEFEEEFE的区域写为NULL即可破解
PEB.ProcessHeap指向HEAP结构体.
HEAP结构体中与反调试有关的:
+0xC Flags
+0x10 ForceFlags
程序正常运行时,
HEAP.Flags=0x2
HEAP.ForceFlags=0
调试时会发生变化.
调试进程时,PEB.NtGlobalFlag会被置为0x70
破解:修改为0即可
// GetModuleHandle 函数声明 :
//获取已经载入进程空间的模块句柄
HMODULE WINAPI GetModuleHandle(
_In_opt_ LPCTSTR lpModuleName//需要获取句柄的模块名。
);
//GetProcAddress函数声明:
//获得函数地址
FARPROC GetProcAddress(
HMODULE hModule, // handle to DLL module
LPCSTR lpProcName // name of function
);
NtCurrentTeb()函数:返回一个指针,指向TEB
test esi esi
来判断esi是否为空(0).NtQueryInformationProcess顾名思义就是取进程信息 他是属于ntdll.dll里面的一个未公开的api函数
NTSYSAPI NTSTATUS NTAPI NtQueryInformationProcess (
IN HANDLE ProcessHandle, // 进程句柄
IN PROCESSINFOCLASS InformationClass, // 信息类型
OUT PVOID ProcessInformation, // 缓冲指针
IN ULONG ProcessInformationLength, // 以字节为单位的缓冲大小
OUT PULONG ReturnLength OPTIONAL // 写入缓冲的字节数
);
它的第二个参数可以用来查询进程的调试端口。如果进程被调试,那么返回的端口值会是-1,否则就是其他的值。由于这个函数是一个未公开的函数,因此需要使用LoadLibrary和GetProceAddress的方法获取调用 .
与调试有关的第二个参数(InformationClass)的值:
ProcessDebugPort(0x07) , ProcessDebugObjectHandle(0x1E) , ProcessDebugFlags(0x1F)
第二个参数指定不同的值 , 返回结果会返回在 ProcessInformation(第三个参数)
进程处于调试状态时,操作系统会为他分配1个调试端口(debug port) , InformationClass设为ProcessDebugPort(0x07) 时,调用NtQueryInformationProcess()函数就可以获取调试端口.
若处于调试状态 , 第三个参数会被置为0xFFFFFFFF(-1)
若处于非调试状态,第三个参数值会被设置为0
BOOL WINAPI CheckRemoteDebuggerPresent(
_In_ HANDLE hProcess,
_Inout_ PBOOL pbDebuggerPresent
);
如果调试器存在 (通常是检测自己是否正在被调试), 该函数会将pbDebuggerPresent
指向的值设为0xffffffff
.
调试进程时,会生成一个调试对象(Debug Obiect). NtQueryInformationProcess()第二个参数值为0x1E时 , 函数的第三个参数就能获取到调试对象句柄 ,
进程处于调试状态->调试句柄存在->返回值不为NULL
处于非调试状态 , 返回值为NULL
调试标志:Debug Flags
检测调试标志的值也可以判断进程是否处于被调试状态.
NtQueryInformationProcess()第二个参数为0x1F
第三个参数:
调试状态:0
非调试状态:1
编程中启用了TLS功能 , PE头文件里就会设置TLS表 具体位置:(IMAGE_TLS_DIRECTORY)位置:
IMAGE_NT_HEADERS->IMAGE_OPTIONAL_HEADER->IMAGE_DATA_DIRECTORY[9]
IMAGE_TLS_DIRECTORY里面有AddressOfCallbacks, 指向TLS回调函数VA的数组(可以有多个回调函数)
比较直接的反调试技术
(1) FindWindow() ->检测OllyDbg窗口
(2) CreateToolhelp32Snapshot()检测OllyDbg进程
… …