PEB(Process Environment Block,进程环境块)是存放进程信息的结构体,尺寸非常大,我们首先看看PEB结构体:
typedef struct _PEB { // Size: 0x1D8
000h UCHAR InheritedAddressSpace;
001h UCHAR ReadImageFileExecOptions;
002h UCHAR BeingDebugged; //Debug运行标志
003h UCHAR SpareBool;
004h HANDLE Mutant;
008h HINSTANCE ImageBaseAddress; //程序加载的基地址
00Ch struct _PEB_LDR_DATA *Ldr //Ptr32 _PEB_LDR_DATA
010h struct _RTL_USER_PROCESS_PARAMETERS *ProcessParameters;
014h ULONG SubSystemData;
018h HANDLE ProcessHeap;
01Ch KSPIN_LOCK FastPebLock;
020h ULONG FastPebLockRoutine;
024h ULONG FastPebUnlockRoutine;
028h ULONG EnvironmentUpdateCount;
02Ch ULONG KernelCallbackTable;
030h LARGE_INTEGER SystemReserved;
038h struct _PEB_FREE_BLOCK *FreeList
03Ch ULONG TlsExpansionCounter;
040h ULONG TlsBitmap;
044h LARGE_INTEGER TlsBitmapBits;
04Ch ULONG ReadOnlySharedMemoryBase;
050h ULONG ReadOnlySharedMemoryHeap;
054h ULONG ReadOnlyStaticServerData;
058h ULONG AnsiCodePageData;
05Ch ULONG OemCodePageData;
060h ULONG UnicodeCaseTableData;
064h ULONG NumberOfProcessors;
068h LARGE_INTEGER NtGlobalFlag; // Address of a local copy
070h LARGE_INTEGER CriticalSectionTimeout;
078h ULONG HeapSegmentReserve;
07Ch ULONG HeapSegmentCommit;
080h ULONG HeapDeCommitTotalFreeThreshold;
084h ULONG HeapDeCommitFreeBlockThreshold;
088h ULONG NumberOfHeaps;
08Ch ULONG MaximumNumberOfHeaps;
090h ULONG ProcessHeaps;
094h ULONG GdiSharedHandleTable;
098h ULONG ProcessStarterHelper;
09Ch ULONG GdiDCAttributeList;
0A0h KSPIN_LOCK LoaderLock;
0A4h ULONG OSMajorVersion;
0A8h ULONG OSMinorVersion;
0ACh USHORT OSBuildNumber;
0AEh USHORT OSCSDVersion;
0B0h ULONG OSPlatformId;
0B4h ULONG ImageSubsystem;
0B8h ULONG ImageSubsystemMajorVersion;
0BCh ULONG ImageSubsystemMinorVersion;
0C0h ULONG ImageProcessAffinityMask;
0C4h ULONG GdiHandleBuffer[0x22];
14Ch ULONG PostProcessInitRoutine;
150h ULONG TlsExpansionBitmap;
154h UCHAR TlsExpansionBitmapBits[0x80];
1D4h ULONG SessionId;
} PEB, *PPEB;
其中与反调试技术密切相关的成员如下所示:
002h UCHAR BeingDebugged;
00Ch struct _PEB_LDR_DATA *Ldr;
018h HANDLE ProcessHeap;
068h LARGE_INTEGER NtGlobalFlag;
接下来分别讲解以上4个PEB成员。
1:BeingDebugged。
当进程处于调试状态时,BeingDebugged的值会被设置为1,进程在非调试状态下运行时,其值被设置为0。所以我们可以通过判断这个成员的值来决定我们程序的运行流程。测试代码如下:
int main()
{
char result=0;
__asm
{
mov eax,fs:[0x30];//获取PEB的地址。
mov al,BYTE PTR [eax+2];
mov result,al;//得到BeingDebugged成员的值。
}
if(result==1)
printf("is debugging\n");
else
printf("not debugging\n");
system("pause");//为了观察方便,添加的。
return 0;
}
2:Ldr。
调试进程时,其堆内存就会出现一些特殊的标识,表示它正处于被调试状态。这些标识中最醒目的是在未使用的堆内存区域中填充着OxFEEEFEEE。我们利用这一特征即可判断进程是否处于被调试状态。PEB.Ldr成员指向一个_PEB_LDR_DATA结构体,而这个结构体就是在堆内存区域中创建的,所以我们可以扫描该区域来判断进程是否处于调试状态下。测试代码如下:
int main()
{
LPBYTE pLdr;
DWORD pLdrSig[4]={0xEEFEEEFE,0xEEFEEEFE,0xEEFEEEFE,0xEEFEEEFE};
__asm
{
mov eax,fs:[0x30]; //PEB地址
mov eax,[eax+0xC];//Ldr
mov pLdr,eax;
}
__try
{
while(1)
{
if(!memcmp(pLdr,pLdrSig,sizeof(pLdrSig)))
{
printf("is debuggig\n");
break;
}
else
{
pLdr++;
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
printf("not debugging\n");
}
system("pause");
return 0;
}
3:ProcessHeap
ProcessHeap是指向HEAP结构体的指针,在HEAP结构体中的两个成员Flags和Force Flags,它们的偏移分别为0xC和0x10,进程运行正常时,Heap.Flags 的成员值为0x2,HEAP.ForceFlags成员的值为0x0。进程处于调试状态时,这些值会发生变化。测试代码如下:(只测试了ForceFlags成员的值,测试Flags成员的值的方法是一样的)。
int main()
{
int result=0;
__asm
{
mov eax,fs:[0x30]; //PEB地址
mov eax,[eax+0x18];//ProcessHeap成员
mov eax,[eax+0x10];//ForceFlags成员
mov result,eax;
}
if(result!=0)
printf("is debugging\n");
else
printf("not debugging\n");
system("pause");
return 0;
}
4:NtGlobalFlag。
调试进程时,PEB.NtGlobalFlag成员的值为被设置成0x70。所以,检测该成员的值即可判断进程是否处于被调试状态。测试代码如下:
int main()
{
int result=0;
__asm
{
mov eax,fs:[0x30]; //PEB地址
mov eax,[eax+0x68];//NtGlobalFlag成员
mov result,eax;
}
if(result==0x70)
printf("is debugging\n");
else
printf("not debugging\n");
system("pause");
return 0;
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)