反調試與反反調試

[TOC]ide

反調試與反反調試

什麼是反調試? 什麼是反反調試?

靜態反調試

  • 特色:通常在調試開始時阻攔調試者,調試只須要找到緣由後就能夠一次性突破函數

  • PEB :star:工具

    • BeginDebug : 調試標誌位
    // 經過檢查 PEB.BeingDebuged 字段判斷是否被調試
    // 能夠在目標程序運行以前修改對應的字段爲 0 進行反反調試
    bool CheckBeingDebugged()
    {
    	__asm 
    	{
    		; 獲取到 PEB 的內容
    		mov eax, fs:[0x30]
    		; 獲取 PEB 內偏移爲 2 大小爲 1 字節的字段
    		movzx eax, byte ptr[eax + 2]
    	}
    }
    
    
    int main()
    {
    	if (CheckBeingDebugged())
    		printf("當前處於[被]調試狀態\n");
    	else
    		printf("當前處於[非]調試狀態\n");
    
    	system("pause");
    	return 0;
    }
    // 使用 IsDebuggerPresent 原理一樣是判斷 PEB.BeingDebuged
    // 經過 HOOK 函數和修改對應字段的方式能夠進行反調試
    
    int main()
    {
    	if (IsDebuggerPresent())
    		printf("當前處於[被]調試狀態\n");
    	else
    		printf("當前處於[非]調試狀態\n");
    
    	system("pause");
    	return 0;
    }
    • Ldr 內存狀態
    • Heap (Flags, Force Flags): 堆狀態
    • NtGlobalFlag : 內核全局標記
      • 經過PEB.NtGlobalFlag 判斷是否被調試,當處於被調試狀態時PEB.NtGlobalFlag 保存的是 0x70,能夠經過修改標誌反反調試
    bool CheckNtGlobalFlag()
    {
    	__asm
    	{
    		; 獲取到 PEB, 保存在 FS :[0x30]
    		mov eax, fs : [0x30]
    		;獲取到 NtGlobalFlag 字段的內容
    		mov eax, [eax + 0x68]
    	}
    }
    int main()
    {
    	if (CheckNtGlobalFlag())
    		printf("當前處於[被]調試狀態\n");
    	else
    		printf("當前處於[非]調試狀態\n");
    
    	system("pause");
    	return 0;
    }
  • TEBspa

    • StaticUnicodeString :靜態緩衝區
  • 使用原始 API插件

    • NtQuerySystemInformationProcess()
      • ProcessDebugPort(0x07): 獲取調試端口
      • ProcessDebugObjectHandle(0x1E): 獲取調試句柄
      • ProcessDebugFlag(0x1F): 獲取調試標記
    • NtQuerySystemInformation():
      • SystemKernelDeBuggerInformation(0x23) :獲取系統調試狀態 (雙機
    • NtQueryObject() : 遍歷系統內核
  • 攻擊調試器調試

    • NtSetInformationThread()
      • ThreadHideFormDebugger(0x11)
  • 打開進程檢查code

    • SetDebugPrivilege :arrow_right: 檢查進程是否具備調試權限
  • 利用**TLS**回調函數orm

  • 使用普通API進程

    • 父進程的檢查
      • 若是一個進程被正常打開,那麼它的父進程應該是 Explorer.exe,也就是資源管理器,若是判斷不是,就可能被調試,提供參考。
    bool CheckParentProcess()
    {
    
    	struct PROCESS_BASIC_INFORMATION {
    		ULONG ExitStatus; 			// 進程返回碼
    		PPEB  PebBaseAddress;		// PEB 地址
    		ULONG AffinityMask;			// CPU 親和性掩碼
    		LONG  BasePriority;			// 基本優先級
    		ULONG UniqueProcessId;		// 本進程PID
    		ULONG InheritedFromUniqueProcessId; // 父進程PID
    	}stcProcInfo;
    
    	// 查詢到目標進程的對應信息,主要是 父進程 ID
    	NtQueryInformationProcess(
    		GetCurrentProcess(), 
    		ProcessBasicInformation, 
    		&stcProcInfo,
    		sizeof(stcProcInfo), 
    		NULL);
    
    	// 查詢資源管理器對應的 PID
    	DWORD ExplorerPID = 0;
    	DWORD CurrentPID = stcProcInfo.InheritedFromUniqueProcessId;
    	GetWindowThreadProcessId(FindWindow(L"Progman", NULL), &ExplorerPID);
    
    	// 比對兩個 PID 的值,相同就OK,不一樣就可能被調試
    	return ExplorerPID == CurrentPID ? false : true;
    }
    
    
    int main()
    {
    	if (CheckParentProcess())
    		printf("當前處於[被]調試狀態\n");
    	else
    		printf("當前處於[非]調試狀態\n");
    
    	system("pause");
    	return 0;
    }
    • 窗口名檢查
      • 原理是經過查找窗口類或窗口名稱對應的窗口是否存在來進行調試器或其它分析工具的檢查。[缺點是窗口的的名字一般不是固定的,檢查起來很是的不方便]
      • 還能夠經過遍歷進程的方式來檢查調試器或其它工具是否存在。[缺點是能夠經過修改 exe 的名字修改進程名]
    int main()
    {
    	if (FindWindow(NULL, L"OllyDbg"))
    		printf("存在調試器\n");
    	else
    		printf("沒檢測到調試器\n");
    
    	return 0;
    }
    • 進程名檢查
      • 原理就是查詢 EPROCESS 結構體中相關的字段,由於不能在 R3 修改 R0 的數據,因此只能 HOOK
    bool CheckProcessDebugPort() 
    {
    	int nDebugPort = 0;
    	NtQueryInformationProcess(
    		GetCurrentProcess(), 	// 目標進程句柄
    		ProcessDebugPort, 		// 查詢信息類型(7)
    		&nDebugPort, 			// 輸出查詢信息
    		sizeof(nDebugPort), 	// 查詢類型大小
    		NULL); 					// 實際返回數據大小
    
    	// 若是返回的是 -1 ,那麼就被調試了
    	return nDebugPort == 0xFFFFFFFF ? true : false;
    }
    
    
    int main()
    {
    	if (CheckProcessDebugPort())
    		printf("當前處於[被]調試狀態\n");
    	else
    		printf("當前處於[非]調試狀態\n");
    
    	system("pause");
    	return 0;
    }
    • 文件名及文件路徑檢查
    • 註冊表檢查
    • 。。。

動態反調試

  • 特色:通常在調試的過程當中阻攔調試者,可在調試的過程當中被頻繁觸發所以須要調試者隨時關注
  • 使用SEH
    • 異常
    • 斷點
    • SetUnhandleedExceptionFilter()
  • 時間檢查
  • 單步檢查
  • 補丁檢查
  • 反反彙編
  • 偷取代碼
  • 分頁保護
  • 虛擬機

OllyDbg插件編寫

  1. 插件一般是以什麼樣的方式存在的?

一般以DLL的方式存在的,可是後綴名可能會有變化內存

  1. 應用程序如何找到全部的插件?

全部的插件都應該被保護到具體的路徑中

  1. 應用程序怎樣知道是否符合本身的要求?
  • 插件必須提供指定的名稱的函數說明本身的信息,插件還須要經過對應名稱的函數提供具體的功能
相關文章
相關標籤/搜索