Windows Practice_Dll&Hook_DetourHook库

来源:互联网 发布:生产线显示屏 网络 编辑:程序博客网 时间:2024/06/05 10:15

Detours

Detours是经过微软认证的一个开源软件,下载地址,虽然是开源软件,但是它又分成了两个版本,分别是:

  • Detours Professional 3.0 is available for commercial use.
  • Detours Express 3.0 is available for immediate download under a no-fee license for research, non-commercial, and non-production use. Detours Express may be used to prototype (but not deploy) commercial projects.
    这两个版本的代码是一模一样的,所以如果你的公司稍微大一些的话,就不要使用Detours Professional 3.0版本,以免引来不必要的官司。

Detours编译生成对应的库

这个库实际上就做一件事情,那就是注入的事情。
下面我们来看一下如何使用这个开源库。下载回来的文件目录结构如下:
这里写图片描述
因为3.0版本支持32位和64位同时挂钩,所以我们可以进行32位的编译和64位的编译。首先我们来看如何编译32位库。
首先找到编译工具,如下所示:
这里写图片描述

打开后界面如下:
这里写图片描述
编译界面如下:
这里写图片描述
对于64位编译,找到64位的编译工具,编译完成界面如下所示:
这里写图片描述
最后就会生成对应的32位库和64位的库,它们的头文件都一样,如下图所示:
这里写图片描述

Detours库的使用

首先将lib库和include头文件拷贝到工程里面,然后就可以直接使用了。

// EasyHook.cpp : 定义控制台应用程序的入口点。 //#include "stdafx.h"#include <Windows.h>#include "../Detours/include/detours.h"#pragma comment(lib, "../Detours/lib.X86/detours.lib")static int (WINAPI *OldMessageBoxW)(HWND, LPCWSTR, LPCWSTR, UINT) = MessageBoxW;int WINAPI NewMessageBoxW(_In_opt_ HWND hWnd, _In_opt_ LPCWSTR lpText, _In_opt_ LPCWSTR lpCaption, _In_ UINT uType){    return OldMessageBoxW(hWnd, L"经过修改的MessageBox", lpCaption, uType);}void Hook(){    int error = DetourTransactionBegin();    if (error != NO_ERROR)    {        printf("DetourTransactionBegin Error\r\n");    }    error = DetourUpdateThread(GetCurrentThread());    if (error != NO_ERROR)    {        printf("DetourUpdateThread Error\r\n");    }    error = DetourAttach(&(PVOID&)OldMessageBoxW, NewMessageBoxW);    if (error != NO_ERROR)    {        printf("DetourAttach Error\r\n");    }    error = DetourTransactionCommit();    if (error != NO_ERROR)    {        printf("DetourTransactionCommit Error\r\n");    }}int main(){    MessageBoxW(nullptr, L"Test", L"Tips", MB_OK);    Hook();    MessageBoxW(nullptr, L"Test", L"Tips", MB_OK);    system("pause");    return 0;}
VS2015下简单的反汇编过程查看

我们说这个库与我们前面实现的挂钩方式不同,那么不同点在哪儿呢?我们使用反汇编调试一下:
这里写图片描述
从图上可以看出,我们可以看出在调用Hook函数的前后,我们的MessageBoxW函数的地址是没有发生变化的,那么它是怎么实现挂钩呢?
先别急我们再继续往下走,猜想可能的区别就是在于MessageBoxW函数里面的代码不一样了。首先我们来看一下调用Hook函数之前的MessageBoxW的汇编代码是什么样子的!!!如下图所示:
这里写图片描述
我们再看一下调用Hook函数之后的MessageBoxW函数的汇编代码
这里写图片描述
细心的朋友会马上发现,这不是第一行代码就直接跳转到我们自己的函数了吗?
下面是我们自己函数的汇编代码:
这里写图片描述
我们用vs2015就先调试到这儿,先让大家对这个库的原理有一个初步的了解。

x64dbg反汇编软件的反汇编过程查看

下面我们将使用x64dbg反汇编软件进行一步一步的跟踪我们的代码。(对于这个工具使用就不再说明了,感兴趣的朋友可以去了解一下。)
首先,我们找到main函数的反汇编代码,为了简单起见,我们直接在第二个MessageBoxW函数上下一个断点,如下图所示:
这里写图片描述
其次,我们运行到断点处
这里写图片描述
进入第二个MessageBoxW函数,如下:
这里写图片描述
从上图中我们看到第一行代码是一个跳转指令,正好跳转到我们自己的函数,我们就再进入我们自己的函数,如下图所示:
这里写图片描述
里面有一个call指令,调用OldMessageBoxW函数,我们再进入
这里写图片描述
上图就是这个Hook库的关键代码了,我们用方框圈起来。我们可以看出,总共有5个字节,这5个字节正好是1个字节的jmp加上4个字节的地址。这就是著名的5字节inline Hook!
剩下的就不详细说明了。
为了能够更好的查看调用Hook的挂钩过程,我们使用源代码的方式进行跟踪一边。

Hook库源代码的挂钩过程跟踪

使用源码的好处就是我们能够跟踪到源码中,看看源码是怎么实现的。工程结构和代码如下图所示:
这里写图片描述
实际上我们在了解一个新的库的时候,如果有文档的话,看文档和demo是最好的学习方式,恰好Detours给了我们详细的文档和示例代码。这里我们就不多做说明了。

简单的反调试

很多时候,我们不希望别人对我们的程序进行调试,尤其是修改里面的一些功能,这里我们就以Win32程序为例。

// CheckMe.cpp : 定义应用程序的入口点。//#include "stdafx.h"#include "CheckMe.h"#include <process.h>#define MAX_LOADSTRING 100// 全局变量: HINSTANCE hInst;                                // 当前实例WCHAR szTitle[MAX_LOADSTRING];                  // 标题栏文本WCHAR szWindowClass[MAX_LOADSTRING];            // 主窗口类名// 此代码模块中包含的函数的前向声明: ATOM                MyRegisterClass(HINSTANCE hInstance);BOOL                InitInstance(HINSTANCE, int);LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);unsigned int __stdcall CheckMeThread(void *param){    while (true)    {        DWORD dwPrevTime = GetTickCount();        Sleep(1000);        if (GetTickCount() - dwPrevTime > 2000)        {            ExitProcess(-1);        }    }    return 0;}int APIENTRY wWinMain(_In_ HINSTANCE hInstance,                     _In_opt_ HINSTANCE hPrevInstance,                     _In_ LPWSTR    lpCmdLine,                     _In_ int       nCmdShow){    UNREFERENCED_PARAMETER(hPrevInstance);    UNREFERENCED_PARAMETER(lpCmdLine);    // TODO: 在此放置代码。    CloseHandle((HANDLE)_beginthreadex(nullptr, 0, CheckMeThread, nullptr, 0, nullptr));    // 初始化全局字符串    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);    LoadStringW(hInstance, IDC_CHECKME, szWindowClass, MAX_LOADSTRING);    MyRegisterClass(hInstance);    // 执行应用程序初始化:     if (!InitInstance (hInstance, nCmdShow))    {        return FALSE;    }    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CHECKME));    MSG msg;    // 主消息循环:     while (GetMessage(&msg, nullptr, 0, 0))    {        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))        {            TranslateMessage(&msg);            DispatchMessage(&msg);        }    }    return (int) msg.wParam;}////  函数: MyRegisterClass()////  目的: 注册窗口类。//ATOM MyRegisterClass(HINSTANCE hInstance){    WNDCLASSEXW wcex;    wcex.cbSize = sizeof(WNDCLASSEX);    wcex.style          = CS_HREDRAW | CS_VREDRAW;    wcex.lpfnWndProc    = WndProc;    wcex.cbClsExtra     = 0;    wcex.cbWndExtra     = 0;    wcex.hInstance      = hInstance;    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CHECKME));    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_CHECKME);    wcex.lpszClassName  = szWindowClass;    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));    return RegisterClassExW(&wcex);}////   函数: InitInstance(HINSTANCE, int)////   目的: 保存实例句柄并创建主窗口////   注释: ////        在此函数中,我们在全局变量中保存实例句柄并//        创建和显示主程序窗口。//BOOL InitInstance(HINSTANCE hInstance, int nCmdShow){   hInst = hInstance; // 将实例句柄存储在全局变量中   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);   if (!hWnd)   {      return FALSE;   }   ShowWindow(hWnd, nCmdShow);   UpdateWindow(hWnd);   return TRUE;}////  函数: WndProc(HWND, UINT, WPARAM, LPARAM)////  目的:    处理主窗口的消息。////  WM_COMMAND  - 处理应用程序菜单//  WM_PAINT    - 绘制主窗口//  WM_DESTROY  - 发送退出消息并返回////LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){    switch (message)    {    case WM_COMMAND:        {            int wmId = LOWORD(wParam);            // 分析菜单选择:             switch (wmId)            {            case IDM_ABOUT:                DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);                break;            case IDM_EXIT:                DestroyWindow(hWnd);                break;            default:                return DefWindowProc(hWnd, message, wParam, lParam);            }        }        break;    case WM_PAINT:        {            PAINTSTRUCT ps;            HDC hdc = BeginPaint(hWnd, &ps);            // TODO: 在此处添加使用 hdc 的任何绘图代码...            EndPaint(hWnd, &ps);        }        break;    case WM_DESTROY:        PostQuitMessage(0);        break;    default:        return DefWindowProc(hWnd, message, wParam, lParam);    }    return 0;}// “关于”框的消息处理程序。INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam){    UNREFERENCED_PARAMETER(lParam);    switch (message)    {    case WM_INITDIALOG:        return (INT_PTR)TRUE;    case WM_COMMAND:        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)        {            EndDialog(hDlg, LOWORD(wParam));            return (INT_PTR)TRUE;        }        break;    }    return (INT_PTR)FALSE;}

这样对于一个新手来说,他使用OD来调试这个程序就很难达到目的了。

那么难道我们没有其它办法来对这样的程序进行调试吗?答案是有的。
因为我们知道这个程序使用的是GetTickCount函数进行的检查,那么我们就可以将这个函数Hook住,来达到反反调试的目的。

反反调试

利用Hook库进行反反调试的演示。
这里写图片描述
上图显示了我们要用到的三个工程:
其中CheckMe使我们要反反调试的一个对象,也就是上面的代码,它增加了一个线程来检测是否被调试,如果发现被调试,那么就直接结束进程。
HookTickCount是一个Dll程序,用来挂钩的
HookGetTickCountLoad是用来将HookTickCount的Dll程序注入到CheckMe程序中。下面我们来看HookTickCount的源代码

// dllmain.cpp : 定义 DLL 应用程序的入口点。#include "stdafx.h"#include <Windows.h>#include "../Detours/include/detours.h"#pragma comment(lib, "../Detours/lib.X86/detours.lib")static DWORD (WINAPI *Old_GetTickCount)(VOID) = GetTickCount;DWORD WINAPI New_GetTickCount(VOID){    return 0;}extern "C" _declspec(dllexport) void Hook(){    // 使用Hook库,必须至少有一个导出函数来帮助做一些事情,否则就会注入失败。}BOOL APIENTRY DllMain( HMODULE hModule,                       DWORD  ul_reason_for_call,                       LPVOID lpReserved                     ){    if (DetourIsHelperProcess())    {        return TRUE;    }    if (ul_reason_for_call == DLL_PROCESS_ATTACH)    {        DetourRestoreAfterWith();        DetourTransactionBegin();        DetourUpdateThread(GetCurrentThread());        DetourAttach(&(PVOID&)Old_GetTickCount, New_GetTickCount);        DetourTransactionCommit();    }    else if (ul_reason_for_call == DLL_PROCESS_DETACH)    {        DetourTransactionBegin();        DetourUpdateThread(GetCurrentThread());        DetourDetach(&(PVOID&)Old_GetTickCount, New_GetTickCount);        DetourTransactionCommit();    }    return TRUE;}

HookGetTickCountLoad程序实现:

//////////////////////////////////////////////////////////////////////////////////  Test DetourCreateProcessWithDll function (withdll.cpp).////  Microsoft Research Detours Package, Version 3.0.////  Copyright (c) Microsoft Corporation.  All rights reserved.//#include <stdio.h>#include <windows.h>#include "../Detours/include/detours.h"#pragma comment(lib, "../Detours/lib.X86/detours.lib")#pragma warning(push)#if _MSC_VER > 1400#pragma warning(disable:6102 6103) // /analyze warnings#endif#include <strsafe.h>#pragma warning(pop)////////////////////////////////////////////////////////////////////////////////void PrintUsage(void){    printf("Usage:\n"           "    withdll.exe [options] [command line]\n"           "Options:\n"           "    /d:file.dll   : Start the process with file.dll.\n"           "    /v            : Verbose, display memory at start.\n"           "    /?            : This help screen.\n");}//////////////////////////////////////////////////////////////////////////////////  This code verifies that the named DLL has been configured correctly//  to be imported into the target process.  DLLs must export a function with//  ordinal #1 so that the import table touch-up magic works.//struct ExportContext{    BOOL    fHasOrdinal1;    ULONG   nExports;};static BOOL CALLBACK ExportCallback(_In_opt_ PVOID pContext,                                    _In_ ULONG nOrdinal,                                    _In_opt_ LPCSTR pszSymbol,                                    _In_opt_ PVOID pbTarget){    (void)pContext;    (void)pbTarget;    (void)pszSymbol;    ExportContext *pec = (ExportContext *)pContext;    if (nOrdinal == 1) {        pec->fHasOrdinal1 = TRUE;    }    pec->nExports++;    return TRUE;}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////void TypeToString(DWORD Type, char *pszBuffer, size_t cBuffer){    if (Type == MEM_IMAGE) {        StringCchPrintfA(pszBuffer, cBuffer, "img");    }    else if (Type == MEM_MAPPED) {        StringCchPrintfA(pszBuffer, cBuffer, "map");    }    else if (Type == MEM_PRIVATE) {        StringCchPrintfA(pszBuffer, cBuffer, "pri");    }    else {        StringCchPrintfA(pszBuffer, cBuffer, "%x", Type);    }}void StateToString(DWORD State, char *pszBuffer, size_t cBuffer){    if (State == MEM_COMMIT) {        StringCchPrintfA(pszBuffer, cBuffer, "com");    }    else if (State == MEM_FREE) {        StringCchPrintfA(pszBuffer, cBuffer, "fre");    }    else if (State == MEM_RESERVE) {        StringCchPrintfA(pszBuffer, cBuffer, "res");    }    else {        StringCchPrintfA(pszBuffer, cBuffer, "%x", State);    }}void ProtectToString(DWORD Protect, char *pszBuffer, size_t cBuffer){    if (Protect == 0) {        StringCchPrintfA(pszBuffer, cBuffer, "");    }    else if (Protect == PAGE_EXECUTE) {        StringCchPrintfA(pszBuffer, cBuffer, "--x");    }    else if (Protect == PAGE_EXECUTE_READ) {        StringCchPrintfA(pszBuffer, cBuffer, "r-x");    }    else if (Protect == PAGE_EXECUTE_READWRITE) {        StringCchPrintfA(pszBuffer, cBuffer, "rwx");    }    else if (Protect == PAGE_EXECUTE_WRITECOPY) {        StringCchPrintfA(pszBuffer, cBuffer, "rcx");    }    else if (Protect == PAGE_NOACCESS) {        StringCchPrintfA(pszBuffer, cBuffer, "---");    }    else if (Protect == PAGE_READONLY) {        StringCchPrintfA(pszBuffer, cBuffer, "r--");    }    else if (Protect == PAGE_READWRITE) {        StringCchPrintfA(pszBuffer, cBuffer, "rw-");    }    else if (Protect == PAGE_WRITECOPY) {        StringCchPrintfA(pszBuffer, cBuffer, "rc-");    }    else if (Protect == (PAGE_GUARD | PAGE_EXECUTE)) {        StringCchPrintfA(pszBuffer, cBuffer, "g--x");    }    else if (Protect == (PAGE_GUARD | PAGE_EXECUTE_READ)) {        StringCchPrintfA(pszBuffer, cBuffer, "gr-x");    }    else if (Protect == (PAGE_GUARD | PAGE_EXECUTE_READWRITE)) {        StringCchPrintfA(pszBuffer, cBuffer, "grwx");    }    else if (Protect == (PAGE_GUARD | PAGE_EXECUTE_WRITECOPY)) {        StringCchPrintfA(pszBuffer, cBuffer, "grcx");    }    else if (Protect == (PAGE_GUARD | PAGE_NOACCESS)) {        StringCchPrintfA(pszBuffer, cBuffer, "g---");    }    else if (Protect == (PAGE_GUARD | PAGE_READONLY)) {        StringCchPrintfA(pszBuffer, cBuffer, "gr--");    }    else if (Protect == (PAGE_GUARD | PAGE_READWRITE)) {        StringCchPrintfA(pszBuffer, cBuffer, "grw-");    }    else if (Protect == (PAGE_GUARD | PAGE_WRITECOPY)) {        StringCchPrintfA(pszBuffer, cBuffer, "grc-");    }    else {        StringCchPrintfA(pszBuffer, cBuffer, "%x", Protect);    }}static BYTE buffer[65536];typedef union{    struct    {        DWORD Signature;        IMAGE_FILE_HEADER FileHeader;    } ih;    IMAGE_NT_HEADERS32 ih32;    IMAGE_NT_HEADERS64 ih64;} IMAGE_NT_HEADER;struct SECTIONS{    PBYTE   pbBeg;    PBYTE   pbEnd;    CHAR    szName[16];} Sections[256];DWORD SectionCount = 0;DWORD Bitness = 0;PCHAR FindSectionName(PBYTE pbBase, PBYTE& pbEnd){    for (DWORD n = 0; n < SectionCount; n++) {        if (Sections[n].pbBeg == pbBase) {            pbEnd = Sections[n].pbEnd;            return Sections[n].szName;        }    }    pbEnd = NULL;    return NULL;}ULONG PadToPage(ULONG Size){    return (Size & 0xfff)        ? Size + 0x1000 - (Size & 0xfff)        : Size;}BOOL GetSections(HANDLE hp, PBYTE pbBase){    DWORD beg = 0;    DWORD cnt = 0;    SIZE_T done;    IMAGE_DOS_HEADER idh;    if (!ReadProcessMemory(hp, pbBase, &idh, sizeof(idh), &done) || done != sizeof(idh)) {        return FALSE;    }    if (idh.e_magic != IMAGE_DOS_SIGNATURE) {        return FALSE;    }    IMAGE_NT_HEADER inh;    if (!ReadProcessMemory(hp, pbBase + idh.e_lfanew, &inh, sizeof(inh), &done) || done != sizeof(inh)) {        printf("No Read\n");        return FALSE;    }    if (inh.ih.Signature != IMAGE_NT_SIGNATURE) {        printf("No NT\n");        return FALSE;    }    beg = idh.e_lfanew        + FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader )        + inh.ih.FileHeader.SizeOfOptionalHeader;    cnt = inh.ih.FileHeader.NumberOfSections;    Bitness = (inh.ih32.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) ? 32 : 64;#if 0    printf("%d %d count=%d\n", beg, Bitness, cnt);#endif    IMAGE_SECTION_HEADER ish;    for (DWORD n = 0; n < cnt; n++) {        if (!ReadProcessMemory(hp, pbBase + beg + n * sizeof(ish), &ish, sizeof(ish), &done) || done != sizeof(ish)) {            printf("No Read\n");            return FALSE;        }        Sections[n].pbBeg = pbBase + ish.VirtualAddress;        Sections[n].pbEnd = pbBase + ish.VirtualAddress + PadToPage(ish.Misc.VirtualSize);        memcpy(Sections[n].szName, ish.Name, sizeof(ish.Name));        Sections[n].szName[sizeof(ish.Name)] = '\0';#if 0        printf("--- %p %s\n", Sections[n].pbBeg, Sections[n].szName);#endif    }    SectionCount = cnt;    return TRUE;}BOOL DumpProcess(HANDLE hp){    ULONG64 base;    ULONG64 next;    MEMORY_BASIC_INFORMATION mbi;    printf("  %12s %8s %8s: %3s %3s %4s %3s : %8s\n", "Address", "Offset", "Size", "Typ", "Sta", "Prot", "Ini", "Contents");    printf("  %12s %8s %8s: %3s %3s %4s %3s : %8s\n", "------------", "--------", "--------", "---", "---", "----", "---", "-----------------");    for (next = 0;;) {        base = next;        ZeroMemory(&mbi, sizeof(mbi));        if (VirtualQueryEx(hp, (PVOID)base, &mbi, sizeof(mbi)) == 0) {            break;        }        if ((mbi.RegionSize & 0xfff) == 0xfff) {            break;        }        next = (ULONG64)mbi.BaseAddress + mbi.RegionSize;        if (mbi.State == MEM_FREE) {            continue;        }        CHAR szType[16];        TypeToString(mbi.Type, szType, ARRAYSIZE(szType));        CHAR szState[16];        StateToString(mbi.State, szState, ARRAYSIZE(szState));        CHAR szProtect[16];        ProtectToString(mbi.Protect, szProtect, ARRAYSIZE(szProtect));        CHAR szAllocProtect[16];        ProtectToString(mbi.AllocationProtect, szAllocProtect, ARRAYSIZE(szAllocProtect));        CHAR szFile[MAX_PATH];        szFile[0] = '\0';        DWORD cb = 0;        PCHAR pszFile = szFile;        if (base == (ULONG64)mbi.AllocationBase) {#if 0            cb = pfGetMappedFileName(hp, (PVOID)mbi.AllocationBase, szFile, ARRAYSIZE(szFile));#endif            if (GetSections(hp, (PBYTE)mbi.AllocationBase)) {                next = base + 0x1000;                StringCchPrintfA(szFile, ARRAYSIZE(szFile), "%d-bit PE", Bitness);            }        }        if (cb > 0) {            for (DWORD c = 0; c < cb; c++) {                szFile[c] = (szFile[c] >= 'a' && szFile[c] <= 'z')                    ? szFile[c] - 'a' + 'A' : szFile[c];            }            szFile[cb] = '\0';        }        if ((pszFile = strrchr(szFile, '\\')) == NULL) {            pszFile = szFile;        }        else {            pszFile++;        }        PBYTE pbEnd;        PCHAR pszSect = FindSectionName((PBYTE)base, pbEnd);        if (pszSect != NULL) {            pszFile = pszSect;            if (next > (ULONG64)pbEnd) {                next = (ULONG64)pbEnd;            }        }        CHAR szDesc[128];        ZeroMemory(&szDesc, ARRAYSIZE(szDesc));        if (base == (ULONG64)mbi.AllocationBase) {            StringCchPrintfA(szDesc, ARRAYSIZE(szDesc), "  %12I64x %8I64x %8I64x: %3s %3s %4s %3s : %s",                             (ULONG64)base,                             (ULONG64)base - (ULONG64)mbi.AllocationBase,                             (ULONG64)next - (ULONG64)base,                             szType,                             szState,                             szProtect,                             szAllocProtect,                             pszFile);        }        else {            StringCchPrintfA(szDesc, ARRAYSIZE(szDesc), "  %12s %8I64x %8I64x: %3s %3s %4s %3s : %s",                             "-",                             (ULONG64)base - (ULONG64)mbi.AllocationBase,                             (ULONG64)next - (ULONG64)base,                             szType,                             szState,                             szProtect,                             szAllocProtect,                             pszFile);        }        printf("%s\n", szDesc);    }    return TRUE;}//////////////////////////////////////////////////////////////////////// main.//int CDECL main(int argc, char **argv){    BOOLEAN fNeedHelp = FALSE;    BOOLEAN fVerbose = FALSE;    LPCSTR rpszDllsRaw[256];    LPCSTR rpszDllsOut[256];    DWORD nDlls = 0;    for (DWORD n = 0; n < ARRAYSIZE(rpszDllsRaw); n++) {        rpszDllsRaw[n] = NULL;        rpszDllsOut[n] = NULL;    }    int arg = 1;    for (; arg < argc && (argv[arg][0] == '-' || argv[arg][0] == '/'); arg++) {        CHAR *argn = argv[arg] + 1;        CHAR *argp = argn;        while (*argp && *argp != ':' && *argp != '=')            argp++;        if (*argp == ':' || *argp == '=')            *argp++ = '\0';        switch (argn[0]) {          case 'd':                                     // Set DLL Name          case 'D':            if (nDlls < ARRAYSIZE(rpszDllsRaw)) {                rpszDllsRaw[nDlls++] = argp;            }            else {                printf("withdll.exe: Too many DLLs.\n");                fNeedHelp = TRUE;                break;            }            break;          case 'v':                                     // Verbose          case 'V':            fVerbose = TRUE;            break;          case '?':                                     // Help            fNeedHelp = TRUE;            break;          default:            fNeedHelp = TRUE;            printf("withdll.exe: Bad argument: %s\n", argv[arg]);            break;        }    }    if (arg >= argc) {        fNeedHelp = TRUE;    }    if (nDlls == 0) {        fNeedHelp = TRUE;    }    if (fNeedHelp) {        PrintUsage();        return 9001;    }    /////////////////////////////////////////////////////////// Validate DLLs.    //    for (DWORD n = 0; n < nDlls; n++) {        CHAR szDllPath[1024];        PCHAR pszFilePart = NULL;        if (!GetFullPathNameA(rpszDllsRaw[n], ARRAYSIZE(szDllPath), szDllPath, &pszFilePart)) {            printf("withdll.exe: Error: %s is not a valid path name..\n",                   rpszDllsRaw[n]);            return 9002;        }        DWORD c = (DWORD)strlen(szDllPath) + 1;        PCHAR psz = new CHAR [c];        StringCchCopyA(psz, c, szDllPath);        rpszDllsOut[n] = psz;        HMODULE hDll = LoadLibraryExA(rpszDllsOut[n], NULL, DONT_RESOLVE_DLL_REFERENCES);        if (hDll == NULL) {            printf("withdll.exe: Error: %s failed to load (error %d).\n",                   rpszDllsOut[n],                   GetLastError());            return 9003;        }        ExportContext ec;        ec.fHasOrdinal1 = FALSE;        ec.nExports = 0;        DetourEnumerateExports(hDll, &ec, ExportCallback);        FreeLibrary(hDll);        if (!ec.fHasOrdinal1) {            printf("withdll.exe: Error: %s does not export ordinal #1.\n",                   rpszDllsOut[n]);            printf("             See help entry DetourCreateProcessWithDllEx in Detours.chm.\n");            return 9004;        }    }    //////////////////////////////////////////////////////////////////////////    STARTUPINFOA si;    PROCESS_INFORMATION pi;    CHAR szCommand[2048];    CHAR szExe[1024];    CHAR szFullExe[1024] = "\0";    PCHAR pszFileExe = NULL;    ZeroMemory(&si, sizeof(si));    ZeroMemory(&pi, sizeof(pi));    si.cb = sizeof(si);    szCommand[0] = L'\0';    StringCchCopyA(szExe, sizeof(szExe), argv[arg]);    for (; arg < argc; arg++) {        if (strchr(argv[arg], ' ') != NULL || strchr(argv[arg], '\t') != NULL) {            StringCchCatA(szCommand, sizeof(szCommand), "\"");            StringCchCatA(szCommand, sizeof(szCommand), argv[arg]);            StringCchCatA(szCommand, sizeof(szCommand), "\"");        }        else {            StringCchCatA(szCommand, sizeof(szCommand), argv[arg]);        }        if (arg + 1 < argc) {            StringCchCatA(szCommand, sizeof(szCommand), " ");        }    }    printf("withdll.exe: Starting: `%s'\n", szCommand);    for (DWORD n = 0; n < nDlls; n++) {        printf("withdll.exe:   with `%s'\n", rpszDllsOut[n]);    }    fflush(stdout);    DWORD dwFlags = CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED;    SetLastError(0);    SearchPathA(NULL, szExe, ".exe", ARRAYSIZE(szFullExe), szFullExe, &pszFileExe);    if (!DetourCreateProcessWithDllsA(szFullExe[0] ? szFullExe : NULL, szCommand,                                     NULL, NULL, TRUE, dwFlags, NULL, NULL,                                     &si, &pi, nDlls, rpszDllsOut, NULL)) {        DWORD dwError = GetLastError();        printf("withdll.exe: DetourCreateProcessWithDllEx failed: %d\n", dwError);        if (dwError == ERROR_INVALID_HANDLE) {#if DETOURS_64BIT            printf("withdll.exe: Can't detour a 32-bit target process from a 64-bit parent process.\n");#else            printf("withdll.exe: Can't detour a 64-bit target process from a 32-bit parent process.\n");#endif        }        ExitProcess(9009);    }    if (fVerbose) {        DumpProcess(pi.hProcess);    }    ResumeThread(pi.hThread);    WaitForSingleObject(pi.hProcess, INFINITE);    DWORD dwResult = 0;    if (!GetExitCodeProcess(pi.hProcess, &dwResult)) {        printf("withdll.exe: GetExitCodeProcess failed: %d\n", GetLastError());        return 9010;    }    for (DWORD n = 0; n < nDlls; n++) {        if (rpszDllsOut[n] != NULL) {            delete[] rpszDllsOut[n];            rpszDllsOut[n] = NULL;        }    }    return dwResult;}/////////////////////////////////////////////////////////////////// End of File.

最后使用x32od 调试的时候,将已经运行起来的CheckMe程序附加上就可以进行调试了!!!是不是很酷呢???

除了上面的5字节注入外还有一些其他的注入方式
- APC注入
- 输入法注入,在切换输入法的时候进行注入,并且不会被查杀
- 劫持注入,平时的程序都要加载系统Dll,但是有一个加载顺序,先加载自身Dll,那么我就可以写一个同名的Dll让你加载,达到劫持注入的目的。
- WriteProcessMemory注入,在启动进程后会暂停主,然后写入一个LoadLibrary函数,然后再启动一个远线程,然后执行LoadLibrary里面的代码,从而达到注入的目的。
- 还有无Dll注入,也就是注入代码

mhook库

官网下载地址
这里就不多做介绍了,它的代码比较简洁,能够用于商业和非商业。

原创粉丝点击