• 2022CTF培训(一)脱壳技术&Hook入门


    附件下载链接

    脱壳技术

    寻找 OEP

    根据跨段指令寻找 OEP

    绝大多数加壳程序会在被加密的程序中加上一个或多个段(Section),在最后跳转至 OEP 时一般都是通过一个跨段跳转指令进行转移,所以依据跨段的转移指令(JMP 等)就可找到真正的入口点,并且在该跳转指令前一般会有 POPAD / POPFD 指令出现(恢复入口现场)。

    在 x32dbg 中 Ctrl+B 搜索 E9
    在这里插入图片描述
    找到长跳转指令
    在这里插入图片描述
    在该位置下断点后执行即可进入程序真正的入口点,此时程序已完成脱壳。
    在这里插入图片描述
    使用 Scylla 将程序 dump 下来。虽然 dump 下来的程序无法运行,但是已经可以使用 IDA 进行静态分析。
    在这里插入图片描述

    根据堆栈平衡原理寻找 OEP

    该方法即为广为人知的“ESP 定律”法,对绝大部分压缩壳都很有效,原理便是基于栈平衡,壳段代码在保存现场后,我们对 ESP 指向的内存单元下硬件访问断点,那么在壳段代码恢复现场时定会访问到这个单元,此时我们 EIP 所处的位置处于壳段代码末尾,距离跨段指令也就不远了。

    当壳程序入口点执行完 pushad 后再栈顶下一个硬件断点。
    在这里插入图片描述
    运行程序即可在壳段代码末尾断下来。
    在这里插入图片描述

    观察法直接寻找 OEP

    在有了一定的逆向分析经验后,我们可以对各种壳的特征略知一二,例如对于 UPX 来说,其跨段 JMP 往往处于壳段代码的靠后位置,如果我们了解这一点,可以直接去壳段代码尾寻找跨段 JMP,下普通断点,最后得到 OEP,这种方法非常简便,但需要有一定的逆向经验储备。

    利用 OllyDump 插件寻找 OEP

    OllyDump 插件自带寻找 OEP 的功能。
    在这里插入图片描述
    在这里插入图片描述
    此时利用 OllyDump 脱壳。
    在这里插入图片描述
    自动修复导入表后脱壳程序可以正常运行。

    在这里插入图片描述

    输入表重建

    在 Dump 操作结束之后,程序并不能直接运行,很大程度上是因为输入表并没有被修复好。

    导入表结构:
    在这里插入图片描述

    利用 ImportREConstructor 修复导入表

    运行未脱壳的程序,然后按如下步骤进行,注意查看找到的导入表是否有效。

    在这里插入图片描述
    修正转储应选择前面 x32Dbg dump 出的程序文件,修复后生成一个新文件。该文件可正常运行。
    在这里插入图片描述

    手工修复 IAT 表

    调试发现程序调用的3种 API 函数。
    在这里插入图片描述
    由此可找到程序的 IAT 表。
    在这里插入图片描述

    在 dump 出的文件中选择一处空白位置构造 IAT 表。

    首先先构造 IMAGE_IMPORT_DESCRIPTOR 的 Name 成员指向的字符串 Kernel32.dllUser32.dll
    然后构造 IMAGE_IMPORT_BY_NAME 数组。
    在这里插入图片描述
    之后构造 INT 表,注意 RVA 和 FOA 的转换。
    在这里插入图片描述
    构造 IMAGE_IMPORT_DESCRIPTOR 表,其中 IAT 地址是前面动调得到的。
    在这里插入图片描述
    最后再PE头修复数据目录表项中导入表的地址和大小。保存后和正常运行。

    在这里插入图片描述

    Hook入门

    Inline Hook

    直接修改指令的 Hook 方式

    32位的任务管理器(C:\Windows\SysWOW64目录下)结束任务调用的是 TerminateProcess 函数。
    在这里插入图片描述

    在这里插入图片描述
    手动修改使得跳过该函数并平衡堆栈,发现目标进程并没有被杀死。因此尝试 Hook 该函数使得任务管理器无法结束进程。

    这里采用 Dll 注入的方式进行 HOOK 。
    首先编写注入代码:

    // dllmain.cpp : 定义 DLL 应用程序的入口点。
    #include "pch.h"
    
    BYTE JMP[5],TMP[5];
    bool hooked;
    void* addr;
    
    HANDLE WINAPI MyTerminateProcess(HANDLE hProcess, UINT uExitCode) {
        return NULL;
    }
    
    void HookTerminateProcess() {
        HMODULE hModule = LoadLibrary(L"Kernel32.dll");
        if (hModule == NULL) {
            MessageBox(NULL, L"Failed to load library.", NULL, 0);
            return;
        }
        addr = (void*)GetProcAddress(hModule, "TerminateProcess");
        if (addr == NULL) {
            MessageBox(NULL, L"Failed to get process address.", NULL, 0);
            return;
        }
        DWORD newProtect = PAGE_EXECUTE_READWRITE, oldProtect;
        VirtualProtect(addr, 5, newProtect, &oldProtect);
        memcpy(TMP, addr, 5);
        JMP[0] = 0xE9;
        *(DWORD*)&JMP[1] = (DWORD)MyTerminateProcess - (DWORD)addr - 5;
        memcpy(addr, JMP, 5);
        VirtualProtect(addr, 5, oldProtect, &newProtect);
        hooked = TRUE;
    }
    
    void UnHook() {
        if (!hooked) {
            return;
        }
        DWORD newProtect = PAGE_EXECUTE_READWRITE, oldProtect;
        VirtualProtect(addr, 5, newProtect, &oldProtect);
        memcpy(addr, TMP, 5);
        VirtualProtect(addr, 5, oldProtect, &newProtect);
        hooked = FALSE;
    }
    
    BOOL APIENTRY DllMain( HMODULE hModule,DWORD  ul_reason_for_call,LPVOID lpReserved) {
        switch (ul_reason_for_call) {
        case DLL_PROCESS_ATTACH:
            HookTerminateProcess();
            break;
        case DLL_THREAD_ATTACH:
            break;
        case DLL_THREAD_DETACH:
            break;
        case DLL_PROCESS_DETACH:
            UnHook();
            break;
        }
        return TRUE;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    利用注入工具将该 dll 注入到任务管理器中。

    在这里插入图片描述
    火绒剑分析进程发现注入成功。任务管理器也无法强制结束进程。
    在这里插入图片描述
    使用火绒扫描发现该 HOOK。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    Qt 国际化翻译
    Java方法的重载
    如何使用java实现第三方支付
    (2022版)一套教程搞定k8s安装到实战 | 生产环境关键性配置
    实战讲解Kibana开发工具(Dev tools)操作ES:CURD(图+文)
    【2023高教社杯】D题 圈养湖羊的空间利用率 问题分析、数学模型及MATLAB代码
    接口测试 Jmeter 接口测试 —— 请求 Headers 与传参方式
    基于PCIe的多路视频采集与显示子系统
    arcgis栅格计算器:将栅格图层指定值设置为Nodata及栅格图层求交
    四十二、《大数据项目实战之用户行为分析》多框架整合实时分析用户行为日志数据流
  • 原文地址:https://blog.csdn.net/qq_45323960/article/details/127883048