逆向1.檢測程序是否被調試


檢測程序是否被調試

BeingDebug

// 通過檢查 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;
}

 

PEB.NtGlobalFlag

#include <iostream>
#include <windows.h>// 通過 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;
}

 

通過判斷 PEB.ProcessHeap 中具體的標志位來確定是否被調試

#include <iostream>
#include <windows.h>// 通過判斷 PEB.ProcessHeap 中具體的標志位來確定是否被調試
// 對應不同的系統,標志位所在的偏移可能也不同,通過 dt _HEAP 
// 可以查看到當前系統中具體所在的位置
// Flags 與 ForceFlags 在正常情況下應為 2 與 0
// 如果是被附加狀態,那么無法判斷當前是否被調試
// 通過修改具體的字段進行反反調試,注意不同版本
bool CheckProcessHeap()
{
    UINT Flags = 0, ForceFlags = 0;
​
    __asm
    {
        ; 1. 獲取到 PEB
        mov eax, fs:[0x30]
        ; 2. 獲取到 ProcessHeap
        mov eax, [eax + 0x18]
        ; 3. 獲取到 Flags
        mov ecx, [eax + 0x40]
        mov Flags, ecx
        ; 4. 獲取到 ForceFlags
        mov eax, [eax + 0x44]
        mov ForceFlags, eax
    }
​
    return (Flags == 2 && ForceFlags == 0) ? false : true;
}
​
int main()
{
    if (CheckProcessHeap())
        printf("當前處於[被]調試狀態\n");
    else
        printf("當前處於[非]調試狀態\n");
​
    system("pause");
    return 0;
}

 

原理就是查詢 EPROCESS 結構體中相關的ProcessDebugPort字段

#include <iostream>
#include <windows.h>
​
#include <winternl.h>
#pragma comment(lib,"ntdll.lib")
​
​
// 原理就是查詢 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;
}

 

原理就是查詢 EPROCESS 結構體中相關的0x1E字段,

#include <iostream>
#include <windows.h>
​
#include <winternl.h>
#pragma comment(lib,"ntdll.lib")// 原理就是查詢 EPROCESS 結構體中相關的字段,
// 因為不能在 R3 修改 R0 的數據,所以只能 HOOK
bool CheckProcessDebugObjectHandle()
{
    HANDLE hProcessDebugObjectHandle = 0;
​
    NtQueryInformationProcess(
        GetCurrentProcess(),                // 目標進程句柄
        (PROCESSINFOCLASS)0x1E,             // 查詢信息類型(0x1E)
        &hProcessDebugObjectHandle,         // 輸出查詢信息
        sizeof(hProcessDebugObjectHandle),  // 查詢類型大小
        NULL);                              // 實際返回大小
// 如果它的值是非空的,就說明被調試了
    return hProcessDebugObjectHandle ? true : false;
​
}
​
​
int main()
{
    if (CheckProcessDebugObjectHandle())
        printf("當前處於[被]調試狀態\n");
    else
        printf("當前處於[非]調試狀態\n");
​
    system("pause");
    return 0;
}

 

原理就是查詢 EPROCESS 結構體中相關的0x1F字段,

#include <iostream>
#include <windows.h>
​
#include <winternl.h>
#pragma comment(lib,"ntdll.lib")// 原理就是查詢 EPROCESS 結構體中相關的字段,
// 因為不能在 R3 修改 R0 的數據,所以只能 HOOK
// 通過 HOOK 函數 NtQueryInformationProcess 可以
// 直接的解決所有的關於這個 API 的反調試,但是,由於
// 這個函數的功能非常的多,所以需要經過特定的篩選,篩
// 選的值就是需要查詢的類型 0x07, 0x1E, 0x1F
bool CheckProcessDebugFlag()
{
    BOOL bProcessDebugFlag = 0;
    NtQueryInformationProcess(
        GetCurrentProcess(),        // 目標進程句柄
        (PROCESSINFOCLASS)0x1F,     // 查詢信息類型
        &bProcessDebugFlag,         // 輸出查詢信息
        sizeof(bProcessDebugFlag),  // 查詢類型大小
        NULL);                      // 實際返回大小
// 值為 0 的話處於一個被調試的狀態
    return bProcessDebugFlag ? false : true;
}
​
​
int main()
{
    if (CheckProcessDebugFlag())
        printf("當前處於[被]調試狀態\n");
    else
        printf("當前處於[非]調試狀態\n");
​
    system("pause");
    return 0;
}

 

如果一個進程被正常打開,那么它的父進程應該是 Explorer.exe, 也就是資源管理器,如果判斷不是,就可能被調試,提供參考

#include <iostream>
#include <windows.h>
​
#include <winternl.h>
#pragma comment(lib,"ntdll.lib")// 如果一個進程被正常打開,那么它的父進程應該是 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;
}

 

查詢當前的系統是否處於被調試狀態,同樣可以 HOOK

#include <iostream>
#include <windows.h>
​
#include <winternl.h>
#pragma comment(lib,"ntdll.lib")// 查詢當前的系統是否處於被調試狀態,同樣可以 HOOK
bool CheckSystemKernelDebuggerInformation() 
{
    struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION {
        BOOLEAN KernelDebuggerEnabled;
        BOOLEAN KernelDebuggerNotPresent;
    }DebuggerInfo = { 0 };
​
    NtQuerySystemInformation(
        (SYSTEM_INFORMATION_CLASS)0x23,         // 查詢信息類型
        &DebuggerInfo,                          // 輸出查詢信息
        sizeof(DebuggerInfo),                   // 查詢類型大小
        NULL);                                  // 實際返回大小
    return DebuggerInfo.KernelDebuggerEnabled;
}
​
​
int main()
{
    if (CheckSystemKernelDebuggerInformation())
        printf("當前處於[被]調試狀態\n");
    else
        printf("當前處於[非]調試狀態\n");
​
    system("pause");
    return 0;
}

 

隱藏線程讓調試器找不到

#include <iostream>
#include <windows.h>
​
typedef enum THREAD_INFO_CLASS {
    ThreadHideFromDebugger = 17
};
​
// 這個函數被用於設置線程的信息
typedef NTSTATUS(NTAPI* ZW_SET_INFORMATION_THREAD)(
    IN  HANDLE          ThreadHandle,
    IN  THREAD_INFO_CLASS   ThreadInformaitonClass,
    IN  PVOID           ThreadInformation,
    IN  ULONG           ThreadInformationLength);
​
// 可以通過 HOOk 的方式進行反反調試
void ZSIT_DetachDebug()
{
    ZW_SET_INFORMATION_THREAD Func;
​
    // 獲取到函數,因為這是一個未公開函數
    Func = (ZW_SET_INFORMATION_THREAD)GetProcAddress(
        LoadLibrary(L"ntdll.dll"), "ZwSetInformationThread");
​
    // 需要設置的線程,需要設置的類型,不考慮,不考慮
    Func(GetCurrentThread(), ThreadHideFromDebugger, NULL, NULL);
}
​
​
int main()
{
    ZSIT_DetachDebug();
    printf("runnning...\n");
    system("pause");
    return 0;
}

 

找窗口名

#include <iostream>
#include <windows.h>// 原理是通過查找窗口類或窗口名稱對應的窗口是否存在來
// 進行調試器或其它分析工具的檢查。[缺點是窗口的的名字
// 通常不是固定的,檢查起來非常的不方便]
// 還可以通過遍歷進程的方式來檢查調試器或其它工具是否
// 存在。[缺點是可以通過修改 exe 的名字修改進程名]
int main()
{
    if (FindWindow(NULL, L"OllyDbg"))
        printf("存在調試器\n");
    else
        printf("沒檢測到調試器\n");
​
    return 0;
}

 

 


免責聲明!

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



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