使用minhook库

最近要做一个小工具,就是找出给浏览器传递命令行url的模块。有很多恶意的dll注入到explorer里面,然后hook explorer创建进程的动作,当点击浏览器快捷方式的后,explorer启动浏览器,恶意dll就给浏览器附加上一个url参数,从而浏览器一启动就打开那个url,相当于篡改了浏览器默认的主页。

为了找出这个恶意dll,一般会看看explorer加载的dll,看看有哪些可以的,慢慢排除。但是也有一些狡猾的dll,只是在每天打开的前几次篡改或者随机篡改,篡改完自己就从explorer里面卸掉。

于是写了一个工具,hook住NTDLL里面的NtCreateProcess。记录下NtCreateProcess的调用栈,从而可以找出hook创建进程api的恶意dll。之前一直都是用detours库来hook api的,但是这个库免费版不支持x64,于是去网上找到了这个minhook库,用法也比较简单,支持x86/x64,github链接:https://github.com/TsudaKageyu/minhook。

先来个hook MessageBoxW的简单例子。

引用minhook库文件和头文件:

#include "MinHook.h"

#if defined _M_X64
#pragma comment(lib, "libMinHook.x64.lib")
#elif defined _M_IX86
#pragma comment(lib, "libMinHook.x86.lib")
#endif

定义MessageBoxW的hook函数:

typedef int(WINAPI *fnMessageBoxW)(_In_opt_ HWND hWnd, _In_opt_ LPCWSTR lpText,
                                   _In_opt_ LPCWSTR lpCaption, _In_ UINT uType);
fnMessageBoxW real_MessageBoxW = nullptr;
int WINAPI HookMessageBoxW(_In_opt_ HWND hWnd, _In_opt_ LPCWSTR lpText,
                           _In_opt_ LPCWSTR lpCaption, _In_ UINT uType) {

  return real_MessageBoxW(hWnd, L"hook!", lpCaption, uType);
}

HookMessageBoxW是我们要替换原来MessageBoxW的函数。真正的MessageBoxW函数指针会保存在real_MessageBoxW里面。

下面是minhook工作的代码:

    if (MH_Initialize() != MH_OK) {
      return 1;
    }

    if (MH_CreateHook(&MessageBoxW, &HookMessageBoxW,
                      reinterpret_cast<LPVOID *>(&real_MessageBoxW)) != MH_OK) {
      return 1;
    }

    if (MH_EnableHook(&MessageBoxW) != MH_OK) {
      return 1;
    }

MH_Initialize是初始化库,然后调用MH_CreateHook来用HookMessageBoxW替换MessageBoxW,把真正的MessageBoxW函数指针保存到real_MessageBoxW里面。

MH_CreateHook完成之后hook默认是不启用的,所以还需要调用MH_EnableHook。

MessageBoxW是有文档的api,对于CreateProcessInternalW这种没文档的api,稍微改变一下。我们需要自己去load原始的api地址。

typedef BOOL(WINAPI *fnCreateProcessInternalW)(
    HANDLE hToken, LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
    LPSECURITY_ATTRIBUTES lpProcessAttributes,
    LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
    DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory,
    LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation,
    PHANDLE hNewToken);
fnCreateProcessInternalW real_CreateProcessInternalW = nullptr;
fnCreateProcessInternalW raw_CreateProcessInternalW = nullptr;
BOOL WINAPI HookCreateProcessInternalW(
    HANDLE hToken, LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
    LPSECURITY_ATTRIBUTES lpProcessAttributes,
    LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
    DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory,
    LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation,
    PHANDLE hNewToken) {
  return real_CreateProcessInternalW(
      hToken, lpApplicationName, lpCommandLine, lpProcessAttributes,
      lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
      lpCurrentDirectory, lpStartupInfo, lpProcessInformation, hNewToken);
}
    raw_CreateProcessInternalW = (fnCreateProcessInternalW)GetProcAddress(
      GetModuleHandle(TEXT("kernel32.dll")), "CreateProcessInternalW");

    if (MH_Initialize() != MH_OK) {
      return 1;
    }

    if (MH_CreateHook(raw_CreateProcessInternalW, &HookCreateProcessInternalW,
                      reinterpret_cast<LPVOID *>(&real_CreateProcessInternalW)) != MH_OK) {
      return 1;
    }

    if (MH_EnableHook(raw_CreateProcessInternalW) != MH_OK) {
      return 1;
    }

raw_CreateProcessInternalW存放的是原始dll里面load到的地址。