admin管理员组文章数量:1122850
自己经常没事做做单机游戏的作弊软件玩,经常遇到需要写hook的时候 ,于是乎就自己写了一个小巧的hook类库,
使用了beaengine的汇编引擎,如果是用来做系统apihook 也可以做到 只是没有detour那么简单无脑好用,我主要是用来做一些inline hook ,
监控/修改某些寄存器的值,刚刚随手写完了 就想着发上来吧,以后有需要也可以自己慢慢的拓展,目前只支持x86 。
void __stdcall myfunction(hook_context &context)
{
context.process_orignal_function = 0;
context.eax = mini_hook::get_instance()->get_orignal_function<decltype(MessageBoxA)*>("test")(0,"test","test",MB_OK);
}
int main()
{
mini_hook::get_instance()->hook_on((PVOID)MessageBoxA, (PVOID)myfunction,"test",4);
MessageBoxA(0, "123456", "123456", 0);
mini_hook::get_instance()->hook_detach("test");
MessageBoxA(0, "123456", "123456", 0);
return 0;
}
mini_hook.h
#pragma once
#include <windows.h>
#include <map>
struct hook_context
{
DWORD eax, ebx, ecx, edx, edi, esi, ebp, esp;
DWORD args_counts; //占坑保留...没用到
DWORD process_orignal_function;
};
struct hook_data
{
PVOID hook_address;
PVOID user_callback;
DWORD bad_code_len;
PVOID temp_function_address;
PVOID orignal_funtcion_address; // 这个原始函数调用目前只适用于hook在函数头部
byte bad_code[0x10] = { 0 };
};
class mini_hook
{
private:
mini_hook();
public:
static mini_hook * get_instance();
public:
~mini_hook();
void destroy();
hook_data* get_data(const char *flag);
hook_data* get_data(PVOID hooked_address);
void hook_on(PVOID hook_address, PVOID user_callback,const char * flag,int argsCounts=0);
void hook_detach(const char* flag);
void detach_all();
public:
template<typename T>
T get_orignal_function(const char * flag)
{
return reinterpret_cast<T>(m_hookinfo[flag].orignal_funtcion_address);
}
protected:
DWORD calc_badecode_len(PVOID address);
void write_jmp(DWORD address, DWORD dest);
DWORD read_jmp(PVOID address);
protected:
static mini_hook * m_pthis;
std::map< const char *, hook_data> m_hookinfo;
};
mini_hook.cpp
#include "stdafx.h"
#include "mini_hook.h"
#include "mini_tool.h"
#include "beaengine-win32/headers/BeaEngine.h"
#pragma comment(lib, "beaengine-win32\\Win32\\Lib\\BeaEngine.lib")
#define ASM_CODE_LEN 0x99
#define ASM_USERCALLBACK_OFFSET 0x3d
#define ASM_NOT_PROCESS_OFFSET 0x73
mini_hook::mini_hook()
{
}
mini_hook::~mini_hook()
{
}
/* hook MsgBoxA生成的汇编代码 代码可以简化挺多的,汇编比较差吧我...
$ ==> > 83EC 30 sub esp,0x30
$+3 > 890424 mov dword ptr ss:[esp],eax
$+6 > 895C24 04 mov dword ptr ss:[esp+0x4],ebx
$+A > 894C24 08 mov dword ptr ss:[esp+0x8],ecx
$+E > 895424 0C mov dword ptr ss:[esp+0xC],edx
$+12 > 897C24 10 mov dword ptr ss:[esp+0x10],edi
$+16 > 897424 14 mov dword ptr ss:[esp+0x14],esi
$+1A > 896C24 18 mov dword ptr ss:[esp+0x18],ebp
$+1E > 896424 1C mov dword ptr ss:[esp+0x1C],esp
$+22 > 50 push eax
$+23 > 8B4424 20 mov eax,dword ptr ss:[esp+0x20]
$+27 > 83C0 30 add eax,0x30
$+2A > 894424 20 mov dword ptr ss:[esp+0x20],eax
$+2E > B8 01000000 mov eax,0x1
$+33 > 894424 28 mov dword ptr ss:[esp+0x28],eax
$+37 > 8BC4 mov eax,esp
$+39 > 83C0 04 add eax,0x4
$+3C > 50 push eax
$+3D > E8 C2C4F0FF call minihook.000EC504
$+42 > 8BC4 mov eax,esp
$+44 > 8B4424 28 mov eax,dword ptr ss:[esp+0x28]
$+48 > 83F8 01 cmp eax,0x1
$+4B > 74 29 je short 001E0076
$+4D > 58 pop eax
$+4E > 8B4424 20 mov eax,dword ptr ss:[esp+0x20]
$+52 > 8B0424 mov eax,dword ptr ss:[esp]
$+55 > 8B5C24 04 mov ebx,dword ptr ss:[esp+0x4]
$+59 > 8B4C24 08 mov ecx,dword ptr ss:[esp+0x8]
$+5D > 8B5424 0C mov edx,dword ptr ss:[esp+0xC]
$+61 > 8B7C24 10 mov edi,dword ptr ss:[esp+0x10]
$+65 > 8B7424 14 mov esi,dword ptr ss:[esp+0x14]
$+69 > 8B6C24 18 mov ebp,dword ptr ss:[esp+0x18]
$+6D > 83C4 30 add esp,0x30
$+70 > 90 nop
$+71 > 90 nop
$+72 > 90 nop
$+73 > C2 1000 retn 0x10
$+76 > 58 pop eax
$+77 > 8B0424 mov eax,dword ptr ss:[esp]
$+7A > 8B5C24 04 mov ebx,dword ptr ss:[esp+0x4]
$+7E > 8B4C24 08 mov ecx,dword ptr ss:[esp+0x8]
$+82 > 8B5424 0C mov edx,dword ptr ss:[esp+0xC]
$+86 > 8B7C24 10 mov edi,dword ptr ss:[esp+0x10]
$+8A > 8B7424 14 mov esi,dword ptr ss:[esp+0x14]
$+8E > 8B6C24 18 mov ebp,dword ptr ss:[esp+0x18]
$+92 > 90 nop
$+93 > 90 nop
$+94 > 90 nop
$+95 > 90 nop
$+96 > 83C4 30 add esp,0x30
$+99 > 8BFF mov edi,edi
$+9B > 55 push ebp
$+9C > 8BEC mov ebp,esp
$+9E >- E9 10FDEE76 jmp user32.770CFDB3
*/
byte asm_code[] = { 0x83,0xEC,0x30,0x89,0x04,0x24,0x89,0x5C,0x24,0x04,0x89,0x4C,0x24,0x08,0x89,0x54,
0x24,0x0C,0x89,0x7C,0x24,0x10,0x89,0x74,0x24,0x14,0x89,0x6C,0x24,0x18,0x89,0x64,
0x24,0x1C,0x50,0x8B,0x44,0x24,0x20,0x83,0xC0,0x30,0x89,0x44,0x24,0x20,0xB8,0x01,
0x00,0x00,0x00,0x89,0x44,0x24,0x28,0x8B,0xC4,0x83,0xC0,0x04,0x50,0xE8,0xB0,0xEF,
0x00,0x00,0x8B,0xC4,0x8B,0x44,0x24,0x28,0x83,0xF8,0x01,0x74,0x29,0x58,0x8B,0x44,
0x24,0x20,0x8B,0x04,0x24,0x8B,
0x5C,0x24,0x04,0x8B,0x4C,0x24,0x08,0x8B,0x54,0x24,0x0C,0x8B,0x7C,0x24,0x10,0x8B,
0x74,0x24,0x14,0x8B,0x6C,0x24,0x18,0x83,0xC4,0x30,0x90,0x90,0x90,0x90,0x90,0xC3,0x58,0x8B,0x04,0x24,0x8B,
0x5C,0x24,0x04,0x8B,0x4C,0x24,0x08,0x8B,0x54,0x24,0x0C,0x8B,0x7C,0x24,0x10,0x8B,
0x74,0x24,0x14,0x8B,0x6C,0x24,0x18,0x90,0x90,0x90,0x90,0x83,0xC4,0x30 };
mini_hook* mini_hook::m_pthis = nullptr;
mini_hook * mini_hook::get_instance()
{
if (!m_pthis)
{
m_pthis = new mini_hook;
}
return m_pthis;
}
void mini_hook::destroy()
{
if (m_pthis)
{
detach_all();
delete m_pthis;
}
m_pthis = nullptr;
}
hook_data * mini_hook::get_data(PVOID hooked_address)
{
auto iter = m_hookinfo.begin();
while (iter != m_hookinfo.end())
{
if (iter->second.hook_address == hooked_address)
{
return reinterpret_cast<hook_data*>(&iter->second);
}
++iter;
}
return nullptr;
}
hook_data * mini_hook::get_data(const char *flag)
{
return reinterpret_cast<hook_data*>(&m_hookinfo[flag]);
}
DWORD mini_hook::calc_badecode_len(PVOID address)
{
DISASM ASM;
memset(&ASM, 0, sizeof(DISASM));
ASM.EIP = reinterpret_cast<UIntPtr>(address);
int bad_code_len = 0;
while (bad_code_len < 5)
{
auto len = Disasm(&ASM);
if (len != UNKNOWN_OPCODE)
{
bad_code_len += len;
ASM.EIP += len;
}
else
{
++bad_code_len;
++ASM.EIP;
}
}
return bad_code_len;
}
void mini_hook::hook_on(PVOID hook_address, PVOID user_callback, const char * flag,int argsCounts)
{
hook_data data;
data.hook_address = hook_address;
data.user_callback = user_callback;
DWORD bade_code_len = calc_badecode_len(hook_address);
DWORD jump_ret = reinterpret_cast<DWORD>(hook_address) + bade_code_len;
data.bad_code_len = bade_code_len;
memcpy(data.bad_code, hook_address, bade_code_len);
data.temp_function_address = VirtualAlloc(NULL, ASM_CODE_LEN + 0x20, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
byte jump_code[5] = { 0 };
jump_code[0] = 0xe9;
*reinterpret_cast<DWORD*>(jump_code + 1) = reinterpret_cast<DWORD>(data.temp_function_address)
- reinterpret_cast<DWORD>(hook_address)
- 5;
if (IsBadReadPtr(data.temp_function_address, 4))
{
return;
}
memcpy(data.temp_function_address, asm_code, ASM_CODE_LEN);
write_jmp(reinterpret_cast<DWORD>(data.temp_function_address) + ASM_USERCALLBACK_OFFSET,
reinterpret_cast<DWORD>(user_callback));
memcpy(reinterpret_cast<PVOID>(reinterpret_cast<DWORD>(data.temp_function_address) + ASM_CODE_LEN),
data.bad_code, bade_code_len);
mini_tool::mini_safe_write(reinterpret_cast<PVOID>(reinterpret_cast<DWORD>(data.temp_function_address) + ASM_CODE_LEN+bade_code_len ),
jump_code, 1);
write_jmp(reinterpret_cast<DWORD>(data.temp_function_address) + ASM_CODE_LEN + bade_code_len, jump_ret);
DISASM ASM;
memset(&ASM, 0, sizeof(DISASM));
ASM.EIP = reinterpret_cast<DWORD>(data.temp_function_address) + ASM_CODE_LEN;
int i = 0;
while (i < bade_code_len)
{
auto len = Disasm(&ASM);
if (len != UNKNOWN_OPCODE)
{
if ((strstr(ASM.CompleteInstr, "call") >= 0 && READ_BYTE_WITH_OFFSET(data.temp_function_address, ASM_CODE_LEN + i) == 0xe8) ||
(strstr(ASM.CompleteInstr, "jmp") >= 0 && READ_BYTE_WITH_OFFSET(data.temp_function_address, ASM_CODE_LEN + i) == 0xe9))
{
auto orignal_address = read_jmp(reinterpret_cast<PVOID>(reinterpret_cast<DWORD>(hook_address) + i));
write_jmp(reinterpret_cast<DWORD>(data.temp_function_address) + ASM_CODE_LEN + i, orignal_address);
}
i += len;
ASM.EIP += len;
}
else
{
++i;
++ASM.EIP;
}
}
DWORD old_protect;
VirtualProtect(hook_address, 5, PAGE_EXECUTE_READWRITE, &old_protect);
InterlockedExchange(reinterpret_cast<ULONG*> (hook_address), *reinterpret_cast<ULONG*>(jump_code));
InterlockedExchange(reinterpret_cast<ULONG*> (reinterpret_cast<DWORD>(hook_address)+1), *reinterpret_cast<ULONG*>(jump_code+1));
VirtualProtect(hook_address, 5, old_protect, &old_protect);
data.orignal_funtcion_address = reinterpret_cast<PVOID>(reinterpret_cast<DWORD>(data.temp_function_address) + ASM_CODE_LEN);
if (argsCounts !=0)
{
byte ret_code[3];
ret_code[0] = 0xc2;
*reinterpret_cast<WORD*>(ret_code + 1) = argsCounts * 4;
mini_tool::mini_safe_write(reinterpret_cast<PVOID>(reinterpret_cast<DWORD>(data.temp_function_address) + ASM_NOT_PROCESS_OFFSET), ret_code, 3);
}
m_hookinfo.insert(std::map<const char *, hook_data>::value_type(flag, data));
}
void mini_hook::write_jmp(DWORD address, DWORD dest)
{
DWORD code = dest - address - 5;
mini_tool::mini_safe_write(reinterpret_cast<PVOID>(address+1), &code, 4);
}
DWORD mini_hook::read_jmp(PVOID address)
{
return READ_DWORD_WITH_OFFSET(address, 1) + reinterpret_cast<DWORD>(address) + 5;
}
void mini_hook::hook_detach(const char* flag)
{
auto iter = m_hookinfo.begin();
while (iter != m_hookinfo.end())
{
if (_stricmp(flag, iter->first) == 0)
{
mini_tool::mini_safe_write(iter->second.hook_address, iter->second.bad_code, iter->second.bad_code_len);
VirtualFree(iter->second.temp_function_address, ASM_CODE_LEN, MEM_COMMIT);
m_hookinfo.erase(iter);
return;
}
++iter;
}
}
void mini_hook::detach_all()
{
if (m_hookinfo.size() == 0)
return;
auto iter = m_hookinfo.begin();
while (iter != m_hookinfo.end())
{
mini_tool::mini_safe_write(iter->second.hook_address, iter->second.bad_code, iter->second.bad_code_len);
VirtualFree(iter->second.temp_function_address, ASM_CODE_LEN, MEM_COMMIT);
++iter;
}
m_hookinfo.clear();
}
#include "stdafx.h"
#include <windows.h>
#include "mini_tool.h"
void mini_tool::mini_safe_write(PVOID address, PVOID memory, DWORD size)
{
DWORD old_protect;
if (IsBadReadPtr(address, size))
{
return;
}
VirtualProtect(address, size + 4, PAGE_EXECUTE_READWRITE,&old_protect);
memcpy(address, memory, size);
VirtualProtect(address, size + 4, old_protect, &old_protect);
}
DWORD mini_tool::calc_jump_address(DWORD address)
{
return address + READ_DWORD(address + 1) + 5;
}
void mini_tool::write_dwrod(PVOID address, DWORD value, DWORD offset /* = 0 */)
{
*(DWORD*)((DWORD)address + offset) = value;
}
void hook_on(PVOID hook_address, PVOID user_callback,const char * flag,int argsCounts=0);
这个函数第一个参数就是需要hook的地址 第二个参数就是你的过滤函数,第三个参数就是hook_data的标志,第四个参数默认是0 也就是你要hook的函数的参数个数。
第四个参数只有在你知道你要hook的函数原型(api hook)并且你是在函数的头部hook的时候才有用 其他时候慎用,因为看上面的汇编代码你就知道hook_context这个结构体里面
有一个process_original_function的成员 默认值是1 就是表示继续执行原始函数,如果你不想执行原始的函数你就可以在你的hook处理函数中将context的这个成员设置为0,
那么平栈的时候就会根据你的hook_on函数设置的参数个数来平栈,比如我hook的MsgBoxA 4个参数 那么就是retn 0x10,这样一般在函数的头部去hook 你知道参数的个数一般是没什么问题的,如果你是在某个函数的中间hook的 ,那么你必须要保证你设置process_original_function为0不继续执行原始函数的时候 直接retn args_coutns *4 的时候的堆栈是平衡的,如果你在某个函数的中间hook,然后在你的过滤函数里面设置为不继续执行原始函数,但是你没有设置参数个数 或者虽然你设置了参数个数但是retn 0x??之后的堆栈还是不平衡的,这样就是肯定不行的了。当然有兴趣的话可以给hook_data添加一个平栈函数的指针,然后写入你自定义分析出来的平栈代码,然后jmp 到你自己的平栈过程中去处理也是完全可以的。博主语文不好,可能说的乱七八糟,简而言之,你hook在某个api的头部那么你最好hook的时候设置清楚你hook的函数的参数个数,只有这样才能稳定的设置process_original_function这个成员,否则你不清楚函数的个数或者说懒得设置参数的个数 那么请你务必不要设置process_original_function这个成员!
也就是说process_original_function这个功能完全是搭配你hook时候设置的args_counts的。如果你还不懂,那么你就直接调用hook_on(address,callback);
void __stdcall callback(hook_context context)
{
// 在这里处理你要的东西
}
在你的过滤函数里面去监视你感兴趣的东西就好了 context里面的eax ebx等等寄存器你都可以读取和修改,你不懂的话那么你就不要动process_original_function这个成员即可。
另外你的回调函数最好写成__stdcall 这样的函数是自己平栈的,cdecl貌似会有问题? 没深入了解了。。
以上解释大牛直接无视就好了...看代码就懂了... 代码刚刚写的 ,,也许有一些不好的地方... 测试没什么问题.. 好了就这样吧..
版权声明:本文标题:自己写的一个hook库 比较适合做inline hook 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/biancheng/1726379928a1084816.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论