反調試


反調試

1.  IsDebuggerPresent()   該函數讀取當前進程的PEBBeingDebugged的值用於判斷自己是否處於調試狀態

BOOL

APIENTRY

IsDebuggerPresent(VOID)

{

    return NtCurrentPeb()->BeingDebugged;

}

 

x86下windbg查看PEB結構

可知在PEB偏移0x002處獲得BeingDebugged    

kd>  dt _PEB

nt!_PEB

   +0x000 InheritedAddressSpace : UChar

   +0x001 ReadImageFileExecOptions : UChar

   +0x002 BeingDebugged    : UChar

   +0x003 BitField         : UChar

   +0x003 ImageUsesLargePages : Pos 0, 1 Bit

   +0x003 IsProtectedProcess : Pos 1, 1 Bit

   +0x003 IsLegacyProcess  : Pos 2, 1 Bit

   +0x003 IsImageDynamicallyRelocated : Pos 3, 1 Bit

   +0x003 SkipPatchingUser32Forwarders : Pos 4, 1 Bit

   +0x003 SpareBits        : Pos 5, 3 Bits

   +0x004 Mutant           : Ptr32 Void

   +0x008 ImageBaseAddress : Ptr32 Void

   +0x00c Ldr              : Ptr32 _PEB_LDR_DATA

   +0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS

   +0x014 SubSystemData    : Ptr32 Void

   +0x018 ProcessHeap      : Ptr32 Void

   ......

PEB(進程環境塊)結構體存儲在TEB(線程環境塊)中,

TEB結構如下

kd> dt _teb

nt!_TEB

   +0x000 NtTib            : _NT_TIB

   +0x01c EnvironmentPointer : Ptr32 Void

   +0x020 ClientId         : _CLIENT_ID

   +0x028 ActiveRpcHandle  : Ptr32 Void

   +0x02c ThreadLocalStoragePointer : Ptr32 Void

   +0x030 ProcessEnvironmentBlock : Ptr32 _PEB

   +0x034 LastErrorValue   : Uint4B

   +0x038 CountOfOwnedCriticalSections : Uint4B

   +0x03c CsrClientThread  : Ptr32 Void

   +0x040 Win32ThreadInfo  : Ptr32 Void

   +0x044 User32Reserved   : [26] Uint4B

   +0x0ac UserReserved     : [5] Uint4B

   +0x0c0 WOW32Reserved    : Ptr32 Void

   ......

其中_NT_TIB結構如下

kd> dt _NT_TIB

nt!_NT_TIB

   +0x000 ExceptionList    : Ptr32 _EXCEPTION_REGISTRATION_RECORD

   +0x004 StackBase        : Ptr32 Void

   +0x008 StackLimit       : Ptr32 Void

   +0x00c SubSystemTib     : Ptr32 Void

   +0x010 FiberData        : Ptr32 Void

   +0x010 Version          : Uint4B

   +0x014 ArbitraryUserPointer : Ptr32 Void

   +0x018 Self             : Ptr32 _NT_TIB

......

  其中+0x018 Self 是一個指向TIB的指針.同時也是TEB結構體的首地址

FS段寄存器中 地址FS:0指向當前線程TEB。

當我們需要TEB地址時,可以利用 mov eax, fs:[0x18]得到。且從上文可知在TEB偏移0x30處得到PEB地址。

固可以通過fs:[30h}獲得當前進程的PEB。

BOOL IsDebuggerPresentPEB()

{

#if defined (ENV64BIT)

PPEB pPeb = (PPEB)__readgsqword(0x60);

 

#elif defined(ENV32BIT)

PPEB pPeb = (PPEB)__readfsdword(0x30);

 

#endif

 

if (pPeb->BeingDebugged == 1)

return TRUE;

else

return FALSE;

}

內聯匯編版本

BOOL MYIsDebuggerPresent()

      __asm{

            mov eax, fs:[0x30]

              movz eax, byte ptr [eax+]

}

 

 

   

2.  __readgsqword(0x60)得到指向PEB64的指針,__readfsdword(0x30)得到指向PEB32的指針,pPeb->BeingDebugged .

3.  CheckRemoteDebuggerPresent(GetCurrentProcess(), &bIsDbgPresent)

4.  BOOL HeapFlags()64位下,得到指向PEB的地址加上0x30的偏移得到pProcessHeap,由於pHeapFlags在不同版本的操作系統中位置不一,需要IsWindowsVistaOrGreater()判斷大概版本,高於VISTA的版本pProcessHeap解星號加上0x70的偏移得到pHeapFlags,低於高於VISTA的版本pProcessHeap解星號加上0x14的偏移得到pHeapFlags
32位下,得到指向PEB的地址加上0x18的偏移得到pProcessHeap,由於pHeapFlags在不同版本的操作系統中位置不一,需要IsWindowsVistaOrGreater()判斷大概版本,高於VISTA的版本pProcessHeap解星號加上0x40的偏移得到pHeapFlags,低於VISTA的版本pProcessHeap解星號加上0x0C的偏移得到pHeapFlags。判斷*pHeapFlags > 2 是否為真

5.  __readgsqword(0x30)得到TEB64指針.*(DWORD64*)(_teb64 + 0x60)得到PEB64結構體,PEB64取偏移0xBC得到NTGlobalFlag
__readfsdword(0x18)得到TEB32指針.*(DWORD64*)(_teb32 + 0x30)得到PEB32結構體,PEB32取偏移0x68得到NTGlobalFlag
假如是wow64下的__readfsdword(0x18)得到TEB64指針.*(DWORD64*)(_teb64 + 0x60)得到PEB64結構體,PEB64取偏移0xBC得到NTGlobalFlag當進程被調試時,NTGlobalFlag會被置為FLG_HEAP_ENABLE_TAIL_CHECK (0x10), FLG_HEAP_ENABLE_FREE_CHECK(0x20), FLG_HEAP_VALIDATE_PARAMETERS(0x40)0x70

6.  BOOL HeapForceFlags()64位下,得到指向PEB的地址加上0x30的偏移得到pProcessHeap,由於pHeapForceFlags在不同版本的操作系統中位置不一,需要IsWindowsVistaOrGreater()判斷大概版本,高於VISTA的版本pProcessHeap解星號加上0x74的偏移得到pHeapFlags,低於高於VISTA的版本pProcessHeap解星號加上0x18的偏移得到pHeapFlags
32位下,得到指向PEB的地址加上0x18的偏移得到pProcessHeap,由於pHeapForceFlags在不同版本的操作系統中位置不一,需要IsWindowsVistaOrGreater()判斷大概版本,高於VISTA的版本pProcessHeap解星號加上0x44的偏移得到pHeapForceFlags,低於VISTA的版本pProcessHeap解星號加上0x10的偏移得到pHeapFlags。判斷*pHeapFlags > 2 是否為真

7.  通過LoadLibrary  得到ntdll的句柄hNtdll,通過GetProcAddressntdll模塊中得到NtQueryInformationProcess  const int ProcessDbgPort = 7;
NtQueryInfoProcess(GetCurrentProcess(),
 ProcessDbgPort, 
&IsRemotePresent, 
dProcessInformationLength, 
NULL) IsRemotePresent不等於0時 進程被調試

8.  通過LoadLibrary  得到ntdll的句柄hNtdll,通過GetProcAddressntdll模塊中得到NtQueryInformationProcess  const int ProcessDebugFlags =  0x1f;
NtQueryInfoProcess(GetCurrentProcess(),
 ProcessDebugFlags,
 &NoDebugInherit, 
sizeof(DWORD), 
NULL);NoDebugInherit精確等於0時,被調試

9.  通過LoadLibrary  得到ntdll的句柄hNtdll,通過GetProcAddressntdll模塊中得到NtQueryInformationProcess  const int ProcessDebugObjectHandle =  0x1e;NtQueryInfoProcess(GetCurrentProcess(), ProcessDebugObjectHandle, &hDebugObject, dProcessInformationLength, NULL);hDebugObject不為空

10.  通過GetProcAddressntdll模塊中得到NtSetInformationThreadThreadInformationClass設置為0x11(ThreadHideFromDebugger),用於隱藏調試器中的線程,調用之后調試器與該線程不再關聯  NtSetInformationThread(GetCurrentThread(), ThreadHideFromDebugger, NULL, 0);當函數成功時,被調試

11.  CloseHandle_InvalideHandle()當進程被調試時,調用CloseHandle並傳入無效句柄,會得到一個STATUS_INVALID_HANDLE的異常,函數返回TRUE__try NtClose_((HANDLE)0x99999999);}__except (EXCEPTION_EXECUTE_HANDLER) {return TRUE;}

12.  UnhandledExcepFilterTest () 設置一個SetUnhandledExceptionFilter。然后利用RaiseException提出一個異常交給異常處理機制 由於沒有設置相應的異常處理程序 當進程被調試時,會通知進程的調試器,而不會調用UnhandledExceptionFilter

13.  OutputDebugStringAPI(),只在XP2000中適用。OutputDebugString()用於輸出字符串給調試器顯示。若GetLastError被置為Val,說明調試器與進程關聯。

14.  HardwareBreakpoints(),初始化PCONTEXT ctx,將ctx->ContextFlags = CONTEXT_DEBUG_REGISTERS。通過GetThreadContext(GetCurrentThread(), ctx)得到寄存器信息,硬件斷點,用Dr0-Dr7七個寄存器控制。Dr1-Dr3存放了斷點地址,若有一個寄存器存放了斷點地址說明 被調試

15.  SoftwareBreakpoints(),NOTE this check might not work on x64 because of alignment 0xCC bytes.軟件斷點 INT 332位下被編譯成0xCC建立兩個函數A B,在B中調用A。計算A B地址之間的偏移,將A強制類型轉換成PUCHAR型放置在變量v1中, 兩個函數地址之間的偏移為長度 以字節為單位查詢是否存在0xCC  

16.  Interrupt_0x2d()AddVectoredExceptionHandler()注冊一個定向的情況處理__int2d()是一個用asm寫的函數,利用指令 int 2dh測試進程是否被調試,當進程沒有關聯調試器,會返回一個異常進入我們設置的定向情況處理。無需手動Rip或Eip++

17.  Interrupt_3()AddVectoredExceptionHandler()注冊一個定向的情況處理__debugbreak() Microsoft專用將在代碼中引起斷點,並在其中提示用戶運行調試程序。當進程沒有關聯調試器,會返回一個異常,當情況為異常斷點時需要我們手動將RipEip++

18.  MemoryBreakpoints_PageGuard(),動態分配大小為SystemInfo.dwPageSize的一塊內存,並將0xC3ret寫入內存中,最后將這塊內存VirtualProtect屬性置為PAGE_EXECUTE_READWRITE | PAGE_GUARD可讀寫,頁面保護)。以函數的形式調用這塊內存的首地址,觀察是否拋出異常。線程試圖訪問具備PAGE_GUARD屬性的內存。該內存可以被訪問,但同時EXCEPTION_GUARD_PAGE異常會被拋出 此時進程沒有被調試。

19.  CanOpenCsrss()當進程被調試且被提權到administrator時,該進程可以打開Csrss進程

20.  NtYieldExecutionAPI()

21.  NtQueryObject_ObjectTypeInformation()

22.  NtQueryObject_ObjectAllTypesInformation()

23.  SetHandleInformatiom_ProtectedHandle(),創建了一個互斥體對象,利用SetHandleInformation將我們互斥體對象句柄標志改為HANDLE_FLAG_PROTECT_FROM_CLOSE,最后關閉句柄會拋出異常HANDLE_FLAG_PROTECT_FROM_CLOSE


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM