8.4 ProcessHeap
ProcessHeap 是Windows
进程的默认堆,每个进程都有一个默认的堆,用于在进程地址空间中分配内存空间。默认情况下ProcessHeap
由内核进行初始化,该堆中存在一个未公开的属性,它被设置为加载器为进程分配的第一个堆的位置(进程堆标志),ProcessHeap
标志位于PEB
结构中偏移为0x18
处,第一个堆头部有一个属性字段,这个属性叫做ForceFlags
属性偏移为0x44
,该属性为0说明程序没有被调试,非0说明被调试,另外的Flags
属性为2说明被调试,不为2则说明没有被调试。
0:000> dt !_peb
ntdll!_PEB+0x000 InheritedAddressSpace : UChar+0x001 ReadImageFileExecOptions : UChar+0x002 BeingDebugged : UChar+0x018 ProcessHeap : Ptr32 Void // 找到Process偏移地址0:000> !heap // 找出堆区首地址Heap Address NT/Segment Heap1270000 NT Heap0:000> !heap -a 1270000 // 查询heep的内存
Index Address Name Debugging options enabled1: 01270000 Segment at 01270000 to 0136f000 (00006000 bytes committed)Flags: 40000062ForceFlags: 40000060Granularity: 8 bytesSegment Reserve: 00100000Segment Commit: 000020000:000> dt _HEAP 1270000 // 找到ForceFlags标志的偏移地址
ntdll!_HEAP+0x000 Segment : _HEAP_SEGMENT+0x000 Entry : _HEAP_ENTRY+0x040 Flags : 0x40000062+0x044 ForceFlags : 0x40000060
这里需要注意一点,堆区在不同系统中偏移值是不同的,在Windows10
系统中ForceFlags
属性位于堆头部偏移量为0x44
处,而默认情况如果被调试则ForceFlags
属性为0x40000060
,而Flags
标志为0x40000062
,有了这些参考那么通过汇编语言实现将变得很容易,如下代码则是通过汇编分别读取这两个堆头参数;
#include <stdio.h>
#include <windows.h>// 两种方式输出
int IsDebug(DWORD x)
{DWORD Debug = 0;if (x == 1){__asm{mov eax, fs:[0x18] // TED基地址mov eax, [eax + 0x30] // PEB基地址mov eax, [eax + 0x18] // 定位 ProcessHeapmov eax, [eax + 0x44] // 定位到 ForceFlagsmov Debug, eax}}if (x == 2){__asm{mov eax, fs:[0x18] // TED基地址mov eax, [eax + 0x30] // PEB基地址mov eax, [eax + 0x18] // 定位 ProcessHeapmov eax, [eax + 0x40] // 定位到 Flagsmov Debug, eax}}return Debug;
}int main(int argc, char * argv[])
{if (IsDebug(1) && IsDebug(2)){printf("[-] 进程正在被调试 \n");}else{printf("[*] 进程正常 \n");}system("pause");return 0;
}
另一种通过C语言实现的反调试版本,其反调试原理与上方相同,只不过此处我们使用了系统的API来完成检测标志位的。
#include <stdio.h>
#include <windows.h>
#include <winternl.h>typedef NTSTATUS(NTAPI *typedef_ZwQueryInformationProcess)(IN HANDLE ProcessHandle,IN PROCESSINFOCLASS ProcessInformationClass,OUT PVOID ProcessInformation,IN ULONG ProcessInformationLength,OUT PULONG ReturnLength OPTIONAL);BOOL IsDebug()
{HANDLE hProcess = NULL;DWORD ProcessId = 0;PROCESS_BASIC_INFORMATION Pbi;typedef_ZwQueryInformationProcess pZwQueryInformationProcess = NULL;ProcessId = GetCurrentProcessId();hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);if (hProcess != NULL){HMODULE hModule = LoadLibrary("ntdll.dll");pZwQueryInformationProcess = (typedef_ZwQueryInformationProcess)GetProcAddress(hModule, "ZwQueryInformationProcess");NTSTATUS Status = pZwQueryInformationProcess(hProcess, ProcessBasicInformation, &Pbi, sizeof(PROCESS_BASIC_INFORMATION), NULL);if (NT_SUCCESS(Status)){DWORD ByteRead = 0;DWORD ProcessHeap = 0;ULONG PebBase = (ULONG)Pbi.PebBaseAddress;DWORD ForceFlagsValue = 1;ReadProcessMemory(hProcess, (LPCVOID)(PebBase + 0x18), &ProcessHeap, 2, &ByteRead);ReadProcessMemory(hProcess, (LPCVOID)(ProcessHeap + 0x40), &ForceFlagsValue, 4, &ByteRead);if (ForceFlagsValue != 0){return TRUE;}}CloseHandle(hProcess);}return FALSE;
}int main(int argc, char * argv[])
{if (IsDebug()){printf("[-] 正在被调试 \n");}system("pause");return 0;
}
更多推荐
8.4 ProcessHeap
发布评论