【Day 11】卑鄙源之 Hook (上) - 侦测 Hook

环境

  • Windows 10 21H1
  • Visual Studio 2019

前情提要

【Day 10】穿过 IE 的巴巴 - Hook IE 窃取明文密码讲了 Hook 的红队利用,从 IE 窃取明文密码。可能有些人已经开始感到焦虑了,难道我们没有方法抵挡攻击吗,所以这篇就介绍蓝队的防守方法。

从之前的 【Day 09】Hook 的奇妙冒险 - Ring3 Hook 可以知道,Hook 其实就是改掉原本的 Function,控制程序的进行,改成执行我们自己定义的 Function。基於这一点,我们能怎麽侦测 Hook 呢?

这篇文章会拿之前讲的 Hook IE 的偷取明文连线资讯的 POC 当作目标,实作侦测 Hook 的程序。

原理

Hook 的本质就是 Patch,它必须改掉原本的程序来达到控制程序的目的。根据这点,我们很容易就能想到一个侦测的方法,就是比对档案与记忆体的内容。

因为程序在载入 Image 时,并不是直接执行档案,而是把档案内容复制到记忆体中执行。也就是说,举 Hook IE 中的 wininet.dll 的 SendHttpRequestW 为例,我实际上改的是记忆体中的 SendHttpRequestW,而 wininet.dll 档案本身并没有被改动到。

因此只要比对没有被改动到的档案,与不确定有没有被改动的记忆体,在大部分的情况下,如果两者相同,就代表没有被 Hook。

虽然原理简单,却有不少魔鬼小细节,因此这个主题会分两篇讲解。这篇处理记忆体,下一篇处理档案。

从记忆体中找目标 Module

目前已知目标 Process 是 iexplorer.exe,目标 Module 是 WININET.DLL。首先可以看一下 EnumProcessModules 这个函数。其中 lphModule 放着所有 Module 的阵列,我们的目标 wininet.dll 就在这里面。

BOOL EnumProcessModules(
  HANDLE  hProcess,
  HMODULE *lphModule,
  DWORD   cb,
  LPDWORD lpcbNeeded
);

那要怎麽知道目前的这个 Module 是不是我们的目标呢?可以使用 GetModuleFileNameExW 这个函数。其中 lpFilename 就是 Module 的档案路径,只要比对它有没有包含 wininet.dll 字串就可以知道它是不是我们的目标。

DWORD GetModuleFileNameExW(
  HANDLE  hProcess,
  HMODULE hModule,
  LPWSTR  lpFilename,
  DWORD   nSize
);

取得 wininet.dll 这个 Module 的 Handle 後,可以使用 GetModuleInformation 取得有关这个 Module 的资讯。其中 Module 的 Base Address 就在 lpmodinfo 里面。lpmodinfo 是一个 MODULEINFO 结构。

BOOL GetModuleInformation(
  HANDLE       hProcess,
  HMODULE      hModule,
  LPMODULEINFO lpmodinfo,
  DWORD        cb
);

实作

实作流程

  1. 开启目标 Process (iexplore.exe 的 pid)
  2. 用 EnumProcessModules 取得所有的 Module Handle
  3. 用 GetModuleFileNameEx 取得目前的 Module Name
  4. 判断是不是目标 (WININET),是的话就记录下来
  5. 用 GetModuleInformation 取得 Module 资讯

POC

程序的专案可以参考我的 GitHub zeze-zeze/2021iThome

#include <windows.h>
#include <string>
#include <psapi.h>

int main(int argc, char* argv[]) {
    // 1. 开启目标 Process (iexplorer.exe 的 pid)
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 1912);
    if (!hProcess) {
        printf("OpenProcess failed: error %d\n", GetLastError());
        return 1;
    }

    // 2. 用 EnumProcessModules 取得所有的 Module Handle
    HMODULE hMods[1024], hModule = NULL;
    DWORD cbNeeded;
    if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) {
        for (int i = 0; i < (int)(cbNeeded / sizeof(HMODULE)); i++) {
            TCHAR szModPathName[MAX_PATH] = { 0 };

            // 3. 用 GetModuleFileNameEx 取得目前的 Module Name
            if (GetModuleFileNameEx(hProcess, hMods[i], szModPathName, sizeof(szModPathName) / sizeof(TCHAR))) {
                printf("%ls\n", szModPathName);

                // 4. 判断是不是目标 (WININET),是的话就记录下来
                std::wstring sMod = szModPathName;
                if (sMod.find(L"WININET") != std::string::npos) {
                    hModule = hMods[i];
                }
            }
            else {
                printf("GetModuleFileNameEx failed: error %d\n", GetLastError());
                return NULL;
            }
        }
    }
    else {
        printf("EnumProcessModulesEx failed: error %d\n", GetLastError());
        return 1;
    }
    if (hModule == NULL) {
        printf("Cannot find target module\n");
        return 1;
    }
    printf("\n\nWININET.dll handle: %p\n", hModule);
    
    // 5. 用 GetModuleInformation 取得 Module 资讯
    MODULEINFO lpmodinfo;
    if (!GetModuleInformation(hProcess, hModule, &lpmodinfo, sizeof(MODULEINFO))) {
        printf("GetModuleInformation failed: error %d\n", GetLastError());
        return 1;
    }
    return 0;
}

实际测试

记得把 POC 的 pid 改成自己环境测试的 iexplore.exe 的 pid,然後要编成 x86 的执行档,因为目标 Process 是 32-bit。程序会列举所有 Image,虽然使用的函数不同,但这也算是完成 Sysinternals 中的 Listdlls.exe 的最基本功能。

# FindModule.exe
C:\Program Files (x86)\Internet Explorer\IEXPLORE.EXE
C:\WINDOWS\SYSTEM32\ntdll.dll
C:\WINDOWS\System32\KERNEL32.DLL
C:\WINDOWS\System32\KERNELBASE.dll
C:\WINDOWS\SYSTEM32\apphelp.dll
C:\WINDOWS\System32\USER32.dll
C:\WINDOWS\System32\win32u.dll
C:\WINDOWS\System32\GDI32.dll
C:\WINDOWS\System32\gdi32full.dll
C:\WINDOWS\System32\msvcp_win.dll
C:\WINDOWS\System32\ucrtbase.dll
C:\WINDOWS\System32\msvcrt.dll
C:\WINDOWS\System32\ADVAPI32.dll
C:\WINDOWS\System32\sechost.dll
C:\WINDOWS\System32\RPCRT4.dll
C:\WINDOWS\System32\combase.dll
C:\WINDOWS\SYSTEM32\iertutil.dll
C:\WINDOWS\System32\shcore.dll
C:\WINDOWS\System32\IMM32.DLL
C:\WINDOWS\System32\bcryptPrimitives.dll
C:\WINDOWS\SYSTEM32\msIso.dll
C:\WINDOWS\SYSTEM32\kernel.appcore.dll
C:\WINDOWS\SYSTEM32\IEFRAME.dll
C:\WINDOWS\System32\SHLWAPI.dll
C:\WINDOWS\System32\ole32.dll
C:\WINDOWS\System32\OLEAUT32.dll
C:\WINDOWS\System32\SHELL32.dll
C:\WINDOWS\SYSTEM32\USERENV.dll
C:\WINDOWS\SYSTEM32\VERSION.dll
C:\WINDOWS\SYSTEM32\NETAPI32.dll
C:\WINDOWS\SYSTEM32\WINHTTP.dll
C:\WINDOWS\SYSTEM32\WKSCLI.DLL
C:\WINDOWS\SYSTEM32\NETUTILS.DLL
C:\WINDOWS\WinSxS\x86_microsoft.windows.common-controls_6595b64144ccf1df_6.0.19041.1110_none_a8625c1886757984\comctl32.dll
C:\Program Files (x86)\Internet Explorer\IEShims.dll
C:\WINDOWS\System32\comdlg32.dll
C:\WINDOWS\system32\uxtheme.dll
C:\WINDOWS\SYSTEM32\MSHTML.dll
C:\WINDOWS\SYSTEM32\SspiCli.dll
C:\WINDOWS\SYSTEM32\powrprof.dll
C:\WINDOWS\SYSTEM32\UMPDC.dll
C:\WINDOWS\SYSTEM32\CRYPTBASE.DLL
C:\WINDOWS\SYSTEM32\urlmon.dll
C:\WINDOWS\SYSTEM32\srvcli.dll
C:\WINDOWS\System32\clbcatq.dll
C:\WINDOWS\system32\windows.storage.dll
C:\WINDOWS\system32\Wldp.dll
C:\WINDOWS\SYSTEM32\WININET.dll
C:\WINDOWS\system32\profapi.dll
C:\WINDOWS\System32\WS2_32.dll
C:\WINDOWS\SYSTEM32\ondemandconnroutehelper.dll
C:\WINDOWS\system32\mswsock.dll
C:\WINDOWS\SYSTEM32\IPHLPAPI.DLL
C:\WINDOWS\SYSTEM32\WINNSI.DLL
C:\WINDOWS\System32\NSI.dll
C:\Windows\System32\ieproxy.dll
C:\WINDOWS\System32\MSCTF.dll
C:\WINDOWS\SYSTEM32\IEUI.dll
C:\WINDOWS\SYSTEM32\d2d1.dll
C:\WINDOWS\SYSTEM32\DWrite.dll
C:\WINDOWS\SYSTEM32\dxgi.dll
C:\WINDOWS\SYSTEM32\ieapfltr.dll
C:\WINDOWS\SYSTEM32\CRYPTSP.dll
C:\WINDOWS\System32\bcrypt.dll
C:\WINDOWS\SYSTEM32\d3d11.dll
C:\WINDOWS\System32\DriverStore\FileRepository\iigd_dch.inf_amd64_7afabf937b5bd7bd\igd10iumd32.dll
C:\WINDOWS\System32\CRYPT32.dll
C:\WINDOWS\SYSTEM32\ncrypt.dll
C:\WINDOWS\SYSTEM32\NTASN1.dll
C:\WINDOWS\System32\DriverStore\FileRepository\iigd_dch.inf_amd64_7afabf937b5bd7bd\igdgmm32.dll
C:\WINDOWS\System32\DriverStore\FileRepository\iigd_dch.inf_amd64_7afabf937b5bd7bd\igc32.dll
C:\WINDOWS\SYSTEM32\dxcore.dll
C:\WINDOWS\System32\cfgmgr32.dll
C:\WINDOWS\system32\dataexchange.dll
C:\WINDOWS\system32\dcomp.dll
C:\WINDOWS\system32\twinapi.appcore.dll
C:\WINDOWS\SYSTEM32\TextShaping.dll
C:\WINDOWS\SYSTEM32\srpapi.dll
C:\WINDOWS\SYSTEM32\ninput.dll
C:\WINDOWS\system32\mlang.dll
C:\Windows\System32\jscript9.dll
C:\WINDOWS\SYSTEM32\dwmapi.dll
C:\WINDOWS\SYSTEM32\sxs.dll
C:\WINDOWS\System32\IDStore.dll
C:\WINDOWS\System32\SAMLIB.dll
C:\WINDOWS\System32\PROPSYS.dll
C:\WINDOWS\SYSTEM32\tbs.dll
C:\WINDOWS\System32\imagehlp.dll
C:\WINDOWS\system32\msimtf.dll
C:\WINDOWS\system32\directmanipulation.dll
C:\Windows\System32\vaultcli.dll
C:\WINDOWS\SYSTEM32\wintypes.dll
C:\WINDOWS\SYSTEM32\Secur32.dll
C:\WINDOWS\SYSTEM32\textinputframework.dll
C:\WINDOWS\System32\CoreMessaging.dll
C:\WINDOWS\System32\CoreUIComponents.dll
C:\WINDOWS\SYSTEM32\ntmarta.dll
C:\Windows\System32\OneCoreCommonProxyStub.dll


WININET.dll handle: 71280000

参考资料


<<:  前端工程师也能开发全端网页:挑战 30 天用 React 加上 Firebase 打造社群网站|Day26 根据主题筛选文章列表

>>:  【程序】开始任务起手式 转生成恶役菜鸟工程师避免 Bad End 的 30 件事 - 13

Day 17. slate × Immutable

接着我们要进入到 slate 的下一个重点章节: Immutability 。 虽然这已经算是一个...

【Day 26】情境模拟:再好看也没用 !? 设计稿被工程师说太难做不出来 QQ

接下来,会就六角学院 UI 设计入门 课程中,针对团队合作时会碰到的情境稍作讨论。 设计稿再好看也没...

Day 13 「难兄难弟」 单元测试、Code Smell 与重构 - Data Clump 与 Primitive Obsession 篇

图片截自三立新闻 与笔者年纪相当的朋友,肯定还记得小时候有个非常红的电示节目叫「龙兄虎弟」吧。当时...

D28 / Compose 可以用来做 Desktop App? - Compose JB

写到最後三天了,想要聊聊和 Android 不完全相关的东西。感谢JetBrains 的开发,和 K...

[Day10] 回圈练习

do while 与 while 的分别 do while 先执行回圈内的循环,再进行检查,判断为 ...