C++实现inline hook,注入后程序异常退出

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++实现inline hook,注入后程序异常退出相关的知识,希望对你有一定的参考价值。

被hook函数的地址为0x00492770。
实现代码如下:
#pragma pack(1)
typedef struct _JMPCODE

BYTE jmp; //E9 1字节
DWORD addr; //0x地址 4字节
JMPCODE,*PJMPCODE;

typedef int (__stdcall *myFunction)(LPCTSTR lpDesc, LPCTSTR lpSrc, int iLen);
myFunction oldFunctionAddr = (myFunction)0x00492770;

__declspec(naked) void __stdcall My_Function(LPCTSTR lpDesc, LPCTSTR lpSrc, int iLen)

//gameData << "My_Function Enter! " << endl;
__asm

push ebp
mov ebp,dword ptr[esp+10]
push esi


printf("---------printf %s------", lpSrc);
__asm

pop esi
mov ebx,oldFunctionAddr
add ebx,5
jmp ebx



VOID InLine_HookFunctionA()

JMPCODE Jmpcode;
Jmpcode.jmp=0xe9;
Jmpcode.addr=(DWORD)(My_Function)-(DWORD)(oldFunctionAddr)-5;

int ret = WriteProcessMemory(GetCurrentProcess(),oldFunctionAddr,&Jmpcode,sizeof(JMPCODE),NULL);


调用0x00492770的代码如下:
00CD4EEB . 51 push ecx
00CD4EEC . 8DAE 1C200000 lea ebp, dword ptr [esi+0x201C] ; |
00CD4EF2 . 50 push eax
00CD4EF3 . 52 push edx
00CD4EF4 . 8BCD mov ecx, ebp ; |
00CD4EF6 . 896C24 1C mov dword ptr [esp+0x1C], ebp ; |
00CD4EFA . E8 71D87BFF call 0x00492770

异常提示信息如下:
(13d0.1738): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=013cc320 ebx=00492775 ecx=00000000 edx=0dc4fe34 esi=00000000 edi=00000000
eip=00492779 esp=0dc4fe08 ebp=00000000 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
*** ERROR: Symbol file could not be found. Defaulted to export symbols for D:\xxxx\aaaa.exe
aaaa+0x92779:
00492779 8b4604 mov eax,dword ptr [esi+4] ds:0023:00000004=????????

从获取异常日志看是aaaa+0x92779异常导致,但没明白什么原因。哪位大侠帮忙分析下给点提示。谢谢!

参考技术A 你要搞清楚一个概念,DLL被加载后地址是要重定位的,所有的全局变量、函数这些,都会随DLL加载的基址不同,地址会进行对应偏移的。

你WriteProcessMemory那句,往oldFunctionAddr地址写东西,肯定会引起异常的,谁知道被你hook的程序这个地址是啥东西?有没有分配过内存呢?

你要往被注入进程写东西,就必须先用VirtualAllocEx申请内存,你一定要牢记这个概念,所有地址都是动态的,函数、全局变量只有偏移量是固定的。

PE基础6_远程线程注入-HOOK(消息-InLine-IAT)

注入

概述

DLL注入的初始动力源自于程序员对其他第三方应用程序进行功能扩展的愿望

注入方式有
  1. 注册表注入

  1. ComRes注入

  1. APC注入

  1. 消息钩子注入

  1. 远程线程注入

  1. 依赖可信进程注入

  2. 劫持进程创建注入

  1. 输入法注入

远程线程注入
//要加载的dll路径
WCHAR szDllPath[] = L"C:\\Users\\42140\\source\\repos\\34windows原理PE \\Debug\\16InjectDll.dll";
?
int main()

    //1.要注入,需要dll文件
    //2.找到要注入的进程PID
    DWORD dwPid;
    HWND hwnd = FindWindow(NULL, L"new 1 - Notepad++");
    GetWindowThreadProcessId(hwnd, &dwPid);
    //直接输入也行
    //printf("PID: ");
    //scanf_s("%d", &dwPid);
?
    //2.打开进程
    HANDLE hProcess = OpenProcess(
        PROCESS_ALL_ACCESS, FALSE, dwPid);
?
    //3.目标进程申请空间
    LPVOID pBuff = VirtualAllocEx(
        hProcess,
        NULL,
        sizeof(szdllPath),
        MEM_RESERVE | MEM_COMMIT,
        PAGE_EXECUTE_READWRITE);
?
    //4.向目标进程写入dll路径
    DWORD dwSize;
    WriteProcessMemory(
        hProcess,
        pBuff,                  //需要绝对路径
        szdllPath,
        sizeof(szdllPath),
        &dwSize
    );
?
    //DWORD WINAPI proc(LPVOID lpamam);
    //线程回调函数 参数只有一个
?
    //DWORD WINAPI  LoadLibrary(wchar_t * dllname);
    // 加载模块函数1 参数刚好只有一个
?
?
    //5.创建远程线程
    HANDLE hThread = CreateRemoteThread(
        hProcess,                                   //目标进程句柄
        NULL,                                       //安全属性
        NULL,                                       //默认栈大小
        (LPTHREAD_START_ROUTINE)LoadLibrary,        //回调函数
        pBuff,                                      //回调的参数
        NULL,                                       //创建标志
        NULL                                        //线程TID
    );
?
    //6.等待线程结束
    WaitForSingleObject(hThread, -1);
?
    //7.收尾工作
    CloseHandle(hThread);
    VirtualFreeEx(hProcess, pBuff, sizeof(szdllPath), MEM_FREE);
    CloseHandle(hProcess);

 

16InjectDll.dll
#include<Windows.h>
?
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )

    switch (ul_reason_for_call)
    
    case DLL_PROCESS_ATTACH:
    //添加MessageBox
        MessageBox(0, L"注入成功了", 0, 0);
        break;
    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        break;
    
    return TRUE;

 

 

HOOK

概述

HOOK中文名钩子

HOOK的函数:

系统提供的消息HOOK机制

自定义HOOK编程技巧

消息钩子

系统提供的消息钩子机制是由一系列的API提供的一种服务,这个系列的API可以完成对大多数应用程序关键节 点的Hook操作,为此,Windows为每种Hook类型维护了一个钩子链表,我们可以通过一个系统API来完成对整 个系统中所有符合此机制的关键点的Hook

消息钩子

//模块句柄
HANDLE g_hModule; 
//钩子句柄 
HHOOK  g_hook;
?
//键盘钩子的hook函数
LRESULT CALLBACK KeyboardProc(
    _In_ int    code,
    _In_ WPARAM wParam,
    _In_ LPARAM lParam
)

    //code如果小于0,不处理, lparam 键盘按下
    if (code >= 0 && lParam & 0x80000000)
    
        // wParam 按键码
        char msg[2] =  (char)wParam, 0 ;
        OutputDebugStringA(msg);
        OutputDebugStringA("\n");
    
?
    return CallNextHookEx(g_hook, code,wParam, lParam);

?
?
//开启消息钩子 void OnHook() 

    //做键盘钩子,hook所有钩子
    //消息钩子的副作用,如果这个程序没有加载当前模块,那么系统会自动将这个dll注入到目标进程中
    //这样也能实现dll注入
    g_hook = SetWindowsHookEx(
        WH_KEYBOARD,                //钩子类型
        KeyboardProc,               //钩子回调函数
        (HINSTANCE)g_hModule,       //当前模块句柄
        0                           //hook的线程,0表示全局
    );
?

//卸载消息钩子 void UnHook() 

    UnhookWindowsHookEx(g_hook);

?

 


?
?
头文件
//头文件内容
#include<Windows.h>
?
//消息钩子句柄
extern HHOOK g_hook;
// 当前钩子回调所在模块
extern HMODULE g_hmod;
?
?
//开启消息钩子
extern "C" _declspec(dllexport)void OnHook();
//卸载消息钩子
extern "C" _declspec(dllexport)void UnHook();

 


?
dllmain
//dllmain
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )

    switch (ul_reason_for_call)
     
    case DLL_PROCESS_ATTACH:
        g_hModule = hModule;
        OnHook();
        break;;
    case DLL_THREAD_ATTACH:
        break;;
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        UnHook();
        break;
    
    return TRUE;

 

 

测试
#include "pch.h"
#include <iostream>
#include <Windows.h>
typedef void ( *ONHOOK)();
typedef void (* UNHOOK)();
int main()

    //获取钩子函数
    HMODULE hmod = 
        LoadLibrary(L"..\\Debug\\03消息hookdll.dll");
    ONHOOK onhook = 
        (ONHOOK)GetProcAddress(hmod, "OnHook");
    UNHOOK unhook = 
        (UNHOOK)GetProcAddress(hmod, "UnHook");
     //开启hook
    onhook();
     //暂停
    system("pause");
     //关闭hook
    unhook();

 

 

自定义HOOK

自定义HOOK大致分为两类:

inline hook iat hook

inline hook 的跳转偏移:

跳转偏移 = 目录地址 - JMP所在地址 - 5

inline hook

cpp内容

#include "inlinehook.h"
//原始字节
char g_oldbyte[5] = 0;
//新跳转字节
char g_newbyte[5] = 0xE9,0;
//目标地址 hook的回调函数
int  WINAPI MyMessageBox(
    _In_opt_ HWND hWnd,
    _In_opt_ LPCWSTR lpText,
    _In_opt_ LPCWSTR lpCaption,
    _In_ UINT uType)

    
    UnHook();
    int  ret = MessageBox(0, L"你被hook了", 0, 0);
    OnHook();
    return  ret;

?
?
extern "C" _declspec(dllexport) void OnHook()

    //1. 获取MessageBox的真正地址
    LPVOID pMessageBox = 
        GetProcAddress(LoadLibrary(L"user32.dll"), "MessageBoxW");
    //2. 计算跳转偏移
    //跳转偏移 = 目标地址 - 指令所在 - 5
    DWORD offset = (DWORD)MyMessageBox - (DWORD)pMessageBox - 5;
    //3. 构建跳转指令   E9  跳转偏移
    *(DWORD*)(g_newbyte + 1) = offset;
    //4 .修改目标页属性
    DWORD  dwProtect;
    VirtualProtectEx(
        GetCurrentProcess(),
        pMessageBox,
        5,
        PAGE_EXECUTE_READWRITE,
        &dwProtect
    );
    //5. 备份原始字节
    memcpy(g_oldbyte, pMessageBox, 5);
    //6. Hook  MessageBox函数
    memcpy(pMessageBox, g_newbyte,5);
    //7 .修改目标页属性
    VirtualProtectEx(
        GetCurrentProcess(),
        pMessageBox,
        5,
        dwProtect,
        &dwProtect
    );

?
?
extern "C" _declspec(dllexport) void UnHook()

    //1. 获取MessageBox的真正地址
    LPVOID pMessageBox = GetProcAddress(LoadLibrary(L"user32.dll"), "MessageBoxW");
    //2 .修改目标页属性
    DWORD  dwProtect;
    VirtualProtectEx(
        GetCurrentProcess(),
        pMessageBox,
        5,
        PAGE_EXECUTE_READWRITE,
        &dwProtect
    );
    //3. 还原  MessageBox函数
    memcpy(pMessageBox, g_oldbyte, 5);
    //4 .还原目标页属性
    VirtualProtectEx(
        GetCurrentProcess(),
        pMessageBox,
        5,
        dwProtect,
        &dwProtect
    );

 

头文件内容
#include<Windows.h>
?
// 跳转偏移 =  目标地址 - 指令所在 - 5
// MessageBox      指令所在
// MyMessageBox    目标地址
?
?
//原始字节
extern char g_oldbyte[5];
?
//新跳转字节
extern char g_newbyte[5];
?
int  WINAPI MyMessageBox(
    _In_opt_ HWND hWnd,
    _In_opt_ LPCWSTR lpText,
    _In_opt_ LPCWSTR lpCaption,
    _In_ UINT uType);
?
extern "C" _declspec(dllexport) void OnHook();
?
extern "C" _declspec(dllexport)void UnHook();

 


?
dllmain
#include "inlinehook.h"
?
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )

    switch (ul_reason_for_call)
    
    case DLL_PROCESS_ATTACH:
        OnHook();
        break;
    case DLL_THREAD_ATTACH:break;
    case DLL_THREAD_DETACH:break;
    case DLL_PROCESS_DETACH:
        UnHook();
        break;
    
    return TRUE;

 

测试
#include "pch.h"
#include <iostream>
#include<Windows.h>
int main()

    //愉快的奔跑
    MessageBox(0, L"愉快的奔跑", 0, 0);
    //开启hook
    HMODULE hmod = LoadLibrary(L"..\\Debug\\05InlineHookdll.dll");
    MessageBox(0, L"愉快的奔跑", 0, 0);
    //卸载
    FreeLibrary(hmod);

 

 

IAT HOOK
cpp
#include"IatHook.h"
?
typedef  int  ( WINAPI* MESSAGEPRO)(
    _In_opt_ HWND hWnd,
    _In_opt_ LPCWSTR lpText,
    _In_opt_ LPCWSTR lpCaption,
    _In_ UINT uType);
// Iat地址指针
DWORD * g_Iat;
//原始函数地址
MESSAGEPRO  g_oldfun;
//初始化函数
void InitHook()

    g_Iat = GetIatAddress("user32.dll", "MessageBoxW");
    g_oldfun = (MESSAGEPRO)*g_Iat; 

?
//获取IAT地址
DWORD * GetIatAddress(const char * szDllName, const char * szFunName)

    //1.获取当前进程加载地址
    char  *pBuff = (char *)GetModuleHandle(0);
    //2. 获取DOS头
    PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)pBuff;
?
    //3. 获取NT头
    PIMAGE_NT_HEADERS pNt = 
        (PIMAGE_NT_HEADERS)(pDos->e_lfanew + (DWORD)pBuff);
?
    //4.数据目标表第1项
    DWORD ImportRva = pNt->OptionalHeader.DataDirectory[1].VirtualAddress;
?
    //5.转换成VA地址
    PIMAGE_IMPORT_DESCRIPTOR pImport =
        (PIMAGE_IMPORT_DESCRIPTOR)(ImportRva + (DWORD)pBuff);
?
?
    //6.遍历导出表
    //找到指定模块的导出地址
    while (pImport->FirstThunk)
    
        //6.1 比较指定模块名是否符号
        char * pDllName= 
            (char *)(pImport->Name + (DWORD)pBuff);
        //找到的指定模块了
        if (_stricmp(pDllName, szDllName) == 0)
        
            //6.2 遍历IAT和INT
            PIMAGE_THUNK_DATA  pIAT =
                (PIMAGE_THUNK_DATA ) (pImport->FirstThunk + (DWORD)pBuff);
            PIMAGE_THUNK_DATA  pINT = 
                (PIMAGE_THUNK_DATA )(pImport->OriginalFirstThunk + (DWORD)pBuff);
?
            //6.3 找到指定函数对应的地址
            while (pINT->u1.Ordinal)
            
                //如果是名称导出的再比较函数名
                if (!(pINT->u1.Ordinal & 0x80000000))
                
                    //获取函数名
                    PIMAGE_IMPORT_BY_NAME FunName =
                        (PIMAGE_IMPORT_BY_NAME)
                        (pINT->u1.Function + (DWORD)pBuff);
                    if (strcmp(FunName->Name, szFunName) == 0)
                    
                        //找到函数地址
                        return  (DWORD *)pIAT;
?
                        //0x40001000    MyMessageBox
                        //0x40001004    CreateWindows
                    
                
                pINT++;
                pIAT++;
            
        
        //移动到下一个导入表
        pImport++;
    
    return 0;

?
?
?
extern "C" _declspec(dllexport) void OnHook()

    DWORD dwOldProtect;
    //修改页属性
    VirtualProtect(g_Iat, 4, PAGE_EXECUTE_READWRITE, &dwOldProtect);
    //hook IAT
    *g_Iat = (DWORD)MyMessageBox;
    //恢复页属性
    VirtualProtect(g_Iat, 4, dwOldProtect, &dwOldProtect);

?
extern "C" _declspec(dllexport)void UnHook()

    DWORD dwOldProtect;
    //修改页属性
VirtualProtect(g_Iat, 4, PAGE_EXECUTE_READWRITE, &dwOldProtect);
//恢复函数
*g_Iat = (DWORD)g_oldfun;
//恢复页属性
VirtualProtect(g_Iat, 4, dwOldProtect, &dwOldProtect);

?
//目标地址 hook的回调函数
int  WINAPI MyMessageBox(
_In_opt_ HWND hWnd,
_In_opt_ LPCWSTR lpText,
_In_opt_ LPCWSTR lpCaption,
_In_ UINT uType)

return g_oldfun(hWnd, L"你被IAT   hook了", L"^-^", NULL);
?

 

头文件
#include<windows.h>
void InitHook();
//获取IAT地址
DWORD * GetIatAddress(const char * szDllName, const char * szFunName);
extern "C" _declspec(dllexport) void OnHook();
extern "C" _declspec(dllexport)void UnHook();
//目标地址 hook的回调函数
int  WINAPI MyMessageBox(
    _In_opt_ HWND hWnd,
    _In_opt_ LPCWSTR lpText,
    _In_opt_ LPCWSTR lpCaption,
    _In_ UINT uType);

 

dllmain
#include"IatHook.h"
?
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )

    switch (ul_reason_for_call)
    
    case DLL_PROCESS_ATTACH:
        InitHook();
        OnHook();
        break;
        
    case DLL_THREAD_ATTACH:break;
    case DLL_THREAD_DETACH:break;
    case DLL_PROCESS_DETACH:
        UnHook();
        break;
    
    return TRUE;

 

测试
int main()

    LoadLibrary(L"..\\Debug\\07IatHookdll.dll");
    MessageBox(0,0,0,0);

 

 

以上是关于C++实现inline hook,注入后程序异常退出的主要内容,如果未能解决你的问题,请参考以下文章

PE基础6_远程线程注入-HOOK(消息-InLine-IAT)

android inline hook

x86平台inline hook原理和实现

C++ Hook注入DLL 完整例子

C++ Hook注入DLL 完整例子

C++ Hook注入DLL 完整例子