首页
社区
课程
招聘
[原创][原创]利用PEB结构体反调试
发表于: 2015-7-9 16:56 5537

[原创][原创]利用PEB结构体反调试

2015-7-9 16:56
5537
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期)

收藏
免费 0
支持
分享
最新回复 (4)
雪    币: 144
活跃值: (335)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
了解下原理
不过插件还是直接秒
2015-7-9 17:02
0
雪    币: 248
活跃值: (3789)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
BeingDebugged轻松干掉
2015-7-9 19:28
0
雪    币: 22
活跃值: (242)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
4
x86能搞过TP才是真理
2015-7-9 19:46
0
雪    币: 1042
活跃值: (495)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
好像都被ANTI了。~
2015-7-10 00:29
0
游客
登录 | 注册 方可回帖
返回
//