二进制学习-反跟踪技术

0x00.BeingDebugged

1.    PEB(Process Environment Block,进程环境块):

 (1).   有种保护技术会检测是否有调试器正在调试保护软件,然后需要获取是否被调试的消息,这个消息存储在PEB结构中,PEB结构:

typedef struct _PEB {
  BYTE                          Reserved1[2];
  BYTE                          BeingDebugged; //被调试状态
  BYTE                          Reserved2[1];
  PVOID                         Reserved3[2];
  PPEB_LDR_DATA                 Ldr;
  PRTL_USER_PROCESS_PARAMETERS  ProcessParameters;
  BYTE                          Reserved4[104];
  PVOID                         Reserved5[52];
  PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
  BYTE                          Reserved6[128];
  PVOID                         Reserved7[1];
  ULONG                         SessionId;
} PEB, *PPEB;
 (2).   BYTE BeingDebugged  这里就是记录程序的调试状态的,(1代表被调试,0代表没有被调试)我们可以使用 BOOL WINAPI IsDebuggerPresent(void);这个函数来检测是否有调试器存在,返回非0值代表被调试,如果返回0代表没有被调试
 (3).   存储在另一个名为TEB(Thread Environment Block,线程环境块),Windows在调入进程,创建线程时,操作系统均会为每个线程分配TEB,而且FS段寄存器总是被设置成使得地址FS:0指向当前线程的TEB数据,这就为存取TEB数据提供了途径。Windows一般通过TEB间接得到PEB( https://en.wikipedia.org/wiki/Win32_Thread_Information_Block

FS:[0x30] 4 NT Linear address of Process Environment Block (PEB)
 mov         eax,dword ptr fs:[00000030h]  //获取PEB结构基地址
 movzx       eax,byte ptr [eax+2]                       //根据PEB结构,BeingDebugged
 ret  
所以利用以上远离OD可以清除掉BeingDebugged位来隐藏调试器

 (4).  然而!!!在WINDOWS XP SP2后的系统有了一个特性,PEB地址随机化!所以换一些套路来得到PEB  -。-

 (5).  下面两个函数就可以找到PEB,具体细节可以到对应网站查看。

//https://msdn.microsoft.com/en-us/library/windows/desktop/ms679363(v=vs.85).aspx

BOOL WINAPI GetThreadSelectorEntry(
  _In_  HANDLE      hThread,
  _In_  DWORD       dwSelector,
  _Out_ LPLDT_ENTRY lpSelectorEntry
);
 
//https://msdn.microsoft.com/en-us/library/ms684280(VS.85).aspx

NTSTATUS WINAPI NtQueryInformationProcess(
  _In_      HANDLE           ProcessHandle,
  _In_      PROCESSINFOCLASS ProcessInformationClass,
  _Out_     PVOID            ProcessInformation,
  _In_      ULONG            ProcessInformationLength,
  _Out_opt_ PULONG           ReturnLength
);
 (6).   然而,这个BeingDebugged的问题并没有那么简单,通过查看源码发现(虽然我看不太懂源码),如果BeingDebugged的值改成TRUE,那么NtGlobalFlag也会被设置为:

FLG_HEAP_ENABLE_TAIL_CHECK(0X10)

FLG_HEAP_ENABLE_FREE_CHECK(0X20)

FLG_HEAP_VALIDATE_PARAMETERS(0X40)

这些标志是在ntdll!LdrpInitializeExecutionOptions()里设置的。请注意NtGlobalFlag的默认值可以通过gflags.exe或者在注册表以下位置创建条目来修改:

HKLM\Software\Microsoft\Windows Nt\CurrentVersion\Image File Execution Options

 (7).   Heap Magic(看不懂系列):因为FLG_HEAP_VALIDATE_PARAMETERS被设置了,因此RtlCreateHeap选择用RtlDebugCreateHeap创建调试堆

PVOID RtlCreateHeap(
  _In_     ULONG                Flags,
  _In_opt_ PVOID                HeapBase,
  _In_opt_ SIZE_T               ReserveSize,
  _In_opt_ SIZE_T               CommitSize,
  _In_opt_ PVOID                Lock,
  _In_opt_ PRTL_HEAP_PARAMETERS Parameters
);

总之是因为创建调试堆的时候堆中的一些Flag位被设置了一些标记。堆中的内存也被填充了很多特定字节,这样就会被检测到调试器(这个坑以后再填...)

 (8).   彻底干掉BeingDebugged:在编写调试器的时候,创建进程并调用WaitForDebugEvent后,在第一次LOAD_DLL_DEBUG_EVENT时置BeingDebugged为FALSE,第二次LOAD_DLL_DEBUG_EVENT时置BeingDebugged为TRUE,这样就会停在系统断点,安全的清除掉BeingDebugged了。

0x01.Native:

1.   CheckRemoteDebuggerPresent:

//https://msdn.microsoft.com/en-us/library/ms679280(VS.85).aspx

BOOL WINAPI CheckRemoteDebuggerPresent(
  _In_    HANDLE hProcess,
  _Inout_ PBOOL  pbDebuggerPresent
);
不受BeingDebugged位的影响

2.  ProcessDebugPort:

CheckRemoteDebuggerPresent的过程中对调用NtQueryInformationProcess(Native API)

//https://msdn.microsoft.com/en-us/library/ms687420(VS.85).aspx

NTSTATUS WINAPI ZwQueryInformationProcess(
  _In_      HANDLE           ProcessHandle,
  _In_      PROCESSINFOCLASS ProcessInformationClass,
  _Out_     PVOID            ProcessInformation,
  _In_      ULONG            ProcessInformationLength,
  _Out_opt_  PULONG           ReturnLength
);
//根据不同的ProcessInformationClass查询关于一个进程对象的信息。

Value Meaning
ProcessBasicInformation
0

Retrieves a pointer to a PEB structure that can be used to determine whether the specified process is being debugged, and a unique value used by the system to identify the specified process.

It is best to use the CheckRemoteDebuggerPresent and GetProcessId functions to obtain this information.

ProcessDebugPort
7

Retrieves a DWORD_PTR value that is the port number of the debugger for the process. A nonzero value indicates that the process is being run under the control of a ring 3 debugger.

It is best to use the CheckRemoteDebuggerPresent or IsDebuggerPresent function.

ProcessWow64Information
26

Determines whether the process is running in the WOW64 environment (WOW64 is the x86 emulator that allows Win32-based applications to run on 64-bit Windows).

It is best to use the IsWow64Process function to obtain this information.

ProcessImageFileName
27

Retrieves a UNICODE_STRING value containing the name of the image file for the process.

ProcessBreakOnTermination
29

Retrieves a ULONG value indicating whether the process is considered critical.

Note  This value can be used starting in Windows XP with SP3. Starting in Windows 8.1, IsProcessCritical should be used instead.
 

CheckRemoteDebuggerPresent的过程中对调用NtQueryInformationProcess,查询了某个进程的ProcessDebugPort(7),这个值是系统与调试器通信的端口句柄。BeingDebugged被清除不会影响调试,但是若将调试端口设置为0,系统就不会向用户态调试器发送调试事件通知,调试器就无法正常工作。

3.   ThreadHideFromDebugger:

//https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/ntddk/nf-ntddk-zwsetinformationthread

NTSTATUS ZwSetInformationThread(
  _In_ HANDLE          ThreadHandle,
  _In_ THREADINFOCLASS ThreadInformationClass,
  _In_ PVOID           ThreadInformation,
  _In_ ULONG           ThreadInformationLength
);
//http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FThread%2FTHREAD_INFORMATION_CLASS.html

typedef enum _THREAD_INFORMATION_CLASS {
   
    ThreadBasicInformation,
    ThreadTimes,
    ThreadPriority,
    ThreadBasePriority,
    ThreadAffinityMask,
    ThreadImpersonationToken,
    ThreadDescriptorTableEntry,
    ThreadEnableAlignmentFaultFixup,
    ThreadEventPair,
    ThreadQuerySetWin32StartAddress,
    ThreadZeroTlsCell,
    ThreadPerformanceCount,
    ThreadAmILastThread,
    ThreadIdealProcessor,
    ThreadPriorityBoost,
    ThreadSetTlsArrayAddress,
    ThreadIsIoPending,
    ThreadHideFromDebugger


} THREAD_INFORMATION_CLASS, *PTHREAD_INFORMATION_CLASS;
为进程设置ThreadHideFromDebugger可以禁止某一个线程产生调试事件。

如果进程成功建立了一个映射,就会调用这个函数,如果进程和一个调试端口连接,就会通知调试器发生了LOAD_DLL_DEBUG_EVENT事件。若线程的HideFromDebugger为TRUE,代码在中间返回,调试器就什么都不知道了。

4.   Debug Object:

http://www.mengwuji.net/thread-628-1-1.html 这篇大神写的吊吊吊!)

调试器与被调试程序建立关系有两种途径:在创建进程的时候设置DEBUG_PROCESS,或者调用DebugActiveProcess附加到某个已经运行的进程上,我们从后者入手。

//https://msdn.microsoft.com/en-us/library/windows/desktop/ms679295(v=vs.85).aspx

BOOL WINAPI DebugActiveProcess(
  _In_ DWORD dwProcessId
);
DebugActiveProcess函数很简单,可以总结它只干了三件事情,按顺序分别是:
(1).   创建一个调试对象。
(2).   得到被调试进程的handle。

(3).   附加指定的进程。

创建调试对象是调用了DbgUiConnectToDbg函数,这个函数没有参数,调用了ZwCreateDebugObject,返回值是NTSTATUS

ZwCreateDebugObject函数也甚是简单,填充好一些参数直接调用ZwCreateDebugObject就完事儿了,注意这里创建调试对象成功后,输出的句柄是保存在TEB->DbgSsReserved[1]中。普通的进程中TEB->DbgSsReserved[1]为NULL。可以通过DbgUiGetThreadDebugObject来得到这个量的准确偏移量。

ZwCreateDebugObject实际上调用了ObCreateObject创建对象,因此可以用ZwQueryObject查询所有对象的类型,若发现名为DebugObject的数目不为0,说明系统中存在调试器


5.   Native API:

(1).   Native API 是指以二进制方式,函式库 (DLL) 直接开放的应用程式开发接口 (Application Programming Interface),可以直接由 C/C++ 来呼叫存取使用。

参考这两篇别人的博客

(https://www.cnblogs.com/findumars/p/5931684.html)

(http://blog.csdn.net/kingswb/article/details/51873233)

自己理解起来很吃力。跪了跪了

6.   SDT:

系统描述表(System Descriptor Table,SDT)中有系统服务表(System Sevice Table)表项

7.   Nt和Zw:

 (1).   ntdll.dll中Zw.... 和Nt....函数都是导向ntoskrnl.exe的Stub函数。

 (2).   ntoskrnl.exe中所有Zw....函数也是Stub函数,导向ntoskrnl中的Nt....函数。

 (3).   ntoskrnl.exe中的Nt....函数所有Stub函数的目的地,是真正在做事情的函数。


0x02.Hook和AntiHook

1.   OD中的HideOD插件可以自动挂钩Native API,让这些教科书式的反调试无效(GET了,轮子我还时会用的!)

2.   HideOD插件只是简单的利用了Ring3层的简单钩子,滤掉了ThreadHideFromDebugger这个动作。(然而我还没学过钩子,所以觉得没那么简单,先挖坑,再补!

3.   等学会了钩子再把坑填上。。。


猜你喜欢

转载自blog.csdn.net/qq_39153247/article/details/79236920