吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 16727|回复: 39
收起左侧

[原创] 反调试技术及实例(一)

  [复制链接]
云在天 发表于 2019-3-1 15:06
本帖最后由 云在天 于 2019-3-1 22:46 编辑

反调试技术及实例(一)

前言

就软件而言,逆向工程是研究一个程序的过程,以获得关于它如何工作以及它使用了什么算法,通常大众认为逆向工程被用于非法活动。 例如,生成一个软件的注册机,不经过服务器验证使用软件功能等。

本文考虑了目前流行的Windows下的反调试方法。 想要完全保护软件不被破解是不可能的,各种反逆向的技术的也只是使过程尽可能复杂化(当然这就是大佬们的工作了,我这种小白也就只是说说)。

何为反调试技术(Anti-Debug)

当您将调试器载入或附加程序时,它会生成一个中断(Interrupt)。 程序可以用特定的程序来查找这个中断,并在找到它时自动退出。说白了就是不让你很轻松的调试。

Warning

要理解这里提到的示例和技术,需要汇编知识、一些 WinDbg 经验等。虽然我也没有,如感到不适,请关闭。

常用函数

IsDebuggerPresent

这可能是最简单的反调试方法了,调用 IsDebuggerPresent 函数。 MS给的解释是

Determines whether the calling process is being debugged by a user-mode debugger.

大体的意思是确定一个进程是否被用户模式下的调试器调试。
下面的代码展示了一个基本保护的例子:

int main()
{
    if (IsDebuggerPresent())
    {
        cout <<"兄弟,关了你的调试器吧" <<endl;
        exit(-1);
    }

运行截图如下
QQ20190228-212227@2x
我们看 IsDebuggerPresent 函数的内部,我们会发现以下代码:
QQ20190228-212431@2x

75E0C3F0 >  64:A1 30000000  mov eax,dword ptr fs:[0x30]
75E0C3F6    0FB640 02       movzx eax,byte ptr ds:[eax+0x2]
75E0C3FA    C3              retn

我们可以看到它把一个未知结构(相对于 fs 段的30偏移)传给了eax,然后读取了这个结构的2个偏移。 经过相关资料我们知道这个结构是PEB(Process Environment Block),如果我们看看 PEB 中的2个偏移量,我们会发现 BeingDebugged 字段:

typedef struct _PEB {
  BYTE                          Reserved1[2];
  BYTE                          BeingDebugged;
  BYTE                          Reserved2[1];
  PVOID                         Reserved3[2];
  PPEB_LDR_DATA                 Ldr;
  PRTL_USER_PROCESS_PARAMETERS  ProcessParameters;
  PVOID                         Reserved4[3];
  PVOID                         AtlThunkSListPtr;
  PVOID                         Reserved5;
  ULONG                         Reserved6;
  PVOID                         Reserved7;
  ULONG                         Reserved8;
  ULONG                         AtlThunkSListPtr32;
  PVOID                         Reserved9[45];
  BYTE                          Reserved10[96];
  PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
  BYTE                          Reserved11[128];
  PVOID                         Reserved12[1];
  ULONG                         SessionId;
} PEB, *PPEB;

换句话说,IsDebuggerPresent 函数读取 BeingDebugged 这个字段的值。 如果正在调试进程,则返回1,否则返回0。

怎么反反调试
  1. 打开OD,载入程序,切勿运行

  2. Ctrl+G,搜索IsDebuggerPresent并在所有调用这个函数的地方下断点,如图QQ20190228-215224@2x
    QQ20190228-215241@2x

  3. F9运行程序,程序会断到这个地方,F8单步一直到它进入程序的领空,如图。PS:这里论坛的OD做了些修改,所以这个函数在论坛OD里并没有作用,我换成了x32dbg。QQ20190228-221349@2x
    我们可以观察到右上角EAX是1,然后这里把它修改成0,然后运行就可以了
    QQ20190228-221649@2x

    CheckRemoteDebuggerPresent

    与 IsDebuggerPresent 函数不同,CheckRemoteDebuggerPresent 检查一个进程是否正在被另一个独立进程调试。下面是一个例子。

    BOOL isDebuggerPresent = false;
    if (CheckRemoteDebuggerPresent(GetCurrentProcess(), &isDebuggerPresent))
    {
                if (isDebuggerPresent)
                {
                        cout <<"兄弟,关了你的调试器吧" <<endl;
                        system("Pause");
                        exit(-1);
                }
    
    }

    我们继续看这个函数的内部,它调用了NtQueryInformationProcess,如图
    QQ20190228-224623@2x
    这个函数的作用是检索有关指定进程的信息(Retrieves information about the specified process.)
    我们看下这个函数的结构

    __kernel_entry NTSTATUS NtQueryInformationProcess(
    IN HANDLE           ProcessHandle,
    IN PROCESSINFOCLASS ProcessInformationClass,
    OUT PVOID           ProcessInformation,
    IN ULONG            ProcessInformationLength,
    OUT PULONG          ReturnLength
    );

    我们关注下这个函数里的ProcessInformationClass中的ProcessDebugPort这个值,它检索DWORD_PTR值,该值是进程的调试器的端口号。 非零值表示该进程正在ring3调试器的控制下运行。

    怎么反反调试

  • 如果你是个编程大牛,可以Hook NTQueryInformationProcess这个函数的返回值,这里我贴一个大牛的Demo

    #include <Windows.h>
    #include "mhook.h"
    typedef NTSTATUS(NTAPI *pfnNtQueryInformationProcess)(
    _In_      HANDLE           ProcessHandle,
    _In_      UINT             ProcessInformationClass,
    _Out_     PVOID            ProcessInformation,
    _In_      ULONG            ProcessInformationLength,
    _Out_opt_ PULONG           ReturnLength
    );
    const UINT ProcessDebugPort = 7;
    pfnNtQueryInformationProcess g_origNtQueryInformationProcess = NULL;
    NTSTATUS NTAPI HookNtQueryInformationProcess(
    _In_      HANDLE           ProcessHandle,
    _In_      UINT             ProcessInformationClass,
    _Out_     PVOID            ProcessInformation,
    _In_      ULONG            ProcessInformationLength,
    _Out_opt_ PULONG           ReturnLength
    )
    {
    NTSTATUS status = g_origNtQueryInformationProcess(
        ProcessHandle,
        ProcessInformationClass,
        ProcessInformation,
        ProcessInformationLength,
        ReturnLength);
    if (status == 0x00000000 && ProcessInformationClass == ProcessDebugPort)
    {
        *((PDWORD_PTR)ProcessInformation) = 0;
    }
    return status;
    }
    DWORD SetupHook(PVOID pvContext)
    {
    HMODULE hNtDll = LoadLibrary(TEXT("ntdll.dll"));
    if (NULL != hNtDll)
    {
        g_origNtQueryInformationProcess = (pfnNtQueryInformationProcess)GetProcAddress(hNtDll, "NtQueryInformationProcess");
        if (NULL != g_origNtQueryInformationProcess)
        {
            Mhook_SetHook((PVOID*)&g_origNtQueryInformationProcess, HookNtQueryInformationProcess);
        }
    }
    return 0;
    }
    BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpvReserved)
    {
    switch (fdwReason)
    {
    case DLL_PROCESS_ATTACH:
        DisableThreadLibraryCalls(hInstDLL);
        CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)SetupHook, NULL, NULL, NULL);
        Sleep(20);
    case DLL_PROCESS_DETACH:
        if (NULL != g_origNtQueryInformationProcess)
        {
            Mhook_Unhook((PVOID*)&g_origNtQueryInformationProcess);
        }
        break;
    }
    return TRUE;
    }
  • 如果 你不是一个编程大牛,请参照IsDebuggerPresent的方法去操作,这里就不再展开说明了

Todo

还有其他的一些检测调试器的技术,比如检测断点啊,检测进程之类的,这些会在以后的帖子里讲到,还希望大家多多关注一下


云在天
吾爱破解论坛
2019年02月28日23:05:11

免费评分

参与人数 26吾爱币 +40 热心值 +24 收起 理由
sszth + 1 + 1 我很赞同!
wbangmsli + 1 + 1 哥哥爱你
哈勃卫星 + 1 + 1 谢谢@Thanks!
Hmily + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
sunnylds7 + 1 + 1 热心回复!
liphily + 3 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
CalvinMcCain + 1 谢谢@Thanks!
vince991 + 1 + 1 谢谢@Thanks!
Yancy-Lan + 1 谢谢@Thanks!
念夕空 + 2 + 1 云大佬出品,必属精品
w20064360 + 1 热心回复!
萌音520 + 1 + 1 我很赞同!
唐马儒先生 + 1 + 1 用心讨论,共获提升!
qn542231788 + 1 很棒的教程,每天进步一点点
whdfog + 1 + 1 用心讨论,共获提升!
CrazyNut + 3 + 1 膜拜大佬
a48602 + 1 + 1 谢谢@Thanks!
无痕软件 + 3 + 1 我很赞同!
天舞宝轮 + 1 + 1 热心回复!
黑的思想 + 2 + 1 用心讨论,共获提升!
不羁的生命 + 1 + 1 谢谢@Thanks!
haogl + 1 + 1 不错,简单明了!希望大牛继续出这样的教程!
Hnldxjh + 1 + 1 谢老师的无私奉献!
lcwxxf + 1 + 1 谢谢@Thanks!
老罗791 + 1 + 1 围观。。
D小小贱 + 3 + 1 看不懂,反正膜拜就对了

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

a48602 发表于 2019-3-1 17:15
找  IsDebuggerPresent 跟 CheckRemoteDebuggerPresent 這二個,簡單易懂,
Hook 這個對小白還是有點難懂,慢慢想想看,謝謝樓主的教學。
KaQqi 发表于 2019-3-1 21:46
苏紫方璇 发表于 2019-3-1 15:59
别的不说,先学了一个单词Waring

同意,我一直以为只有warning

最后一段代码看起来好难受...
lcwxxf 发表于 2019-3-1 15:15
Hnldxjh 发表于 2019-3-1 15:24
谢老师的无私奉献!
喝酒.jpg
bioboom 发表于 2019-3-1 15:52
牛,学习了
苏紫方璇 发表于 2019-3-1 15:59
别的不说,先学了一个单词Waring
kikyoulin 发表于 2019-3-1 16:00
感谢云大佬分享。插件帮我们跳过了很多东西,但这些还是必须掌握的基础
haogl 发表于 2019-3-1 16:01
不错不错,简单明了!我这种小白也能看懂!感谢大牛的教程!希望有更多类似的教程!
天舞宝轮 发表于 2019-3-1 16:42
感谢大牛的教程!
klamauk 发表于 2019-3-1 17:49
谢谢分享教程。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-16 07:50

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表