zoukankan      html  css  js  c++  java
  • 逆向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("当前处于[被]调试状态
    ");
        else
            printf("当前处于[非]调试状态
    ");
    ​
        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("当前处于[被]调试状态
    ");
        else
            printf("当前处于[非]调试状态
    ");
    ​
        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("当前处于[被]调试状态
    ");
        else
            printf("当前处于[非]调试状态
    ");
    ​
        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("当前处于[被]调试状态
    ");
        else
            printf("当前处于[非]调试状态
    ");
    ​
        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("当前处于[被]调试状态
    ");
        else
            printf("当前处于[非]调试状态
    ");
    ​
        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("当前处于[被]调试状态
    ");
        else
            printf("当前处于[非]调试状态
    ");
    ​
        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("当前处于[被]调试状态
    ");
        else
            printf("当前处于[非]调试状态
    ");
    ​
        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("当前处于[被]调试状态
    ");
        else
            printf("当前处于[非]调试状态
    ");
    ​
        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...
    ");
        system("pause");
        return 0;
    }

    找窗口名

    #include <iostream>
    #include <windows.h>// 原理是通过查找窗口类或窗口名称对应的窗口是否存在来
    // 进行调试器或其它分析工具的检查。[缺点是窗口的的名字
    // 通常不是固定的,检查起来非常的不方便]
    // 还可以通过遍历进程的方式来检查调试器或其它工具是否
    // 存在。[缺点是可以通过修改 exe 的名字修改进程名]
    int main()
    {
        if (FindWindow(NULL, L"OllyDbg"))
            printf("存在调试器
    ");
        else
            printf("没检测到调试器
    ");
    ​
        return 0;
    }

     

  • 相关阅读:
    题解 P3717 【[AHOI2017初中组]cover】
    【题解】 [POI2012]FES-Festival (差分约束)
    【题解】 [HNOI2005]狡猾的商人(差分约束)
    【题解】 [SCOI2011]糖果 (差分约束)
    【题解】 POJ 1201 Intervals(差分约束)
    【题解】 Codeforces 919F A Game With Numbers(拓扑排序+博弈论+哈希)
    【题解】 [ZJOI2012]灾难 (拓扑排序+LCA)
    【题解】 [HAOI2016]食物链 (拓扑排序)
    【题解】 Luogu P1402 酒店之王 (二分图匹配)
    【题解】 [NOI2009]变换序列 (二分图匹配)
  • 原文地址:https://www.cnblogs.com/ltyandy/p/11166195.html
Copyright © 2011-2022 走看看