利用PEB结构体实现反调试

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()
{
         charresult=0;
         __asm
         {
                   moveax,fs:[0x30];// 获取PEB 的地址。
                   moval,BYTE PTR [eax+2];
                   movresult,al;// 得到BeingDebugged 成员的值。
         }
         if(result==1)
                   printf("isdebugging\n");
         else
                   printf("notdebugging\n");
         system("pause");// 为了观察方便,添加的。
         return0;
}
2 Ldr
调试进程时,其堆内存就会出现一些特殊的标识,表示它正处于被调试状态。这些标识中最醒目的是在未使用的堆内存区域中填充着OxFEEEFEEE 。我们利用这一特征即可判断进程是否处于被调试状态。PEB.Ldr 成员指向一个_PEB_LDR_DATA 结构体,而这个结构体就是在堆内存区域中创建的,所以我们可以扫描该区域来判断进程是否处于调试状态下。测试代码如下:
int main()
{
         LPBYTEpLdr;
         
         DWORDpLdrSig[4]={0xEEFEEEFE,0xEEFEEEFE,0xEEFEEEFE,0xEEFEEEFE};
         __asm
         {
                   moveax,fs:[0x30]; //PEB 地址
                   moveax,[eax+0xC];//Ldr
                   movpLdr,eax;
         }
         __try
         {
                   while(1)
                   {
                if(!memcmp(pLdr,pLdrSig,sizeof(pLdrSig)))
                            {
                                printf("is debuggig\n");
                                break;
                            }
                       else
                            {
                                pLdr++;
                            }
                   }
         }
         __except(EXCEPTION_EXECUTE_HANDLER)
         {
                   printf("notdebugging\n");
         }
         
   system("pause");
         return0;
}
3 ProcessHeap
ProcessHeap 是指向 HEAP 结构体的指针,在 HEAP 结构体中的两个成员 Flags Force Flags ,它们的偏移分别为 0xC 0x10 ,进程运行正常时, Heap.Flags 的成员值为 0x2,HEAP.ForceFlags 成员的值为 0x0 。进程处于调试状态时,这些值会发生变化。测试代码如下:(只测试了 ForceFlags 成员的值,测试 Flags 成员的值的方法是一样的)。整理发布 香樟
int main()
{
         intresult=0;
         __asm
         {
                   moveax,fs:[0x30]; //PEB 地址
                   moveax,[eax+0x18];//ProcessHeap 成员
                   moveax,[eax+0x10];//ForceFlags 成员
                   movresult,eax;
         }
         if(result!=0)
                   printf("isdebugging\n");
         else
                   printf("notdebugging\n");
         system("pause");
         return0;
}
4 NtGlobalFlag
调试进程时,PEB.NtGlobalFlag 成员的值为被设置成0x70 。所以,检测该成员的值即可判断进程是否处于被调试状态。测试代码如下:
int main()
{
         intresult=0;
         __asm
         {
                   moveax,fs:[0x30]; //PEB 地址
                   moveax,[eax+0x68];//NtGlobalFlag 成员
                   movresult,eax;
         }
         if(result==0x70)
                   printf("isdebugging\n");
         else
                   printf("notdebugging\n");
         system("pause");
         return0;

你可能感兴趣的:(利用PEB结构体实现反调试)