自己写的一个hook库 比较适合做inline hook

自己经常没事做做单机游戏的作弊软件玩,经常遇到需要写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();
}



mini_tool.cpp

#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貌似会有问题? 没深入了解了。。

以上解释大牛直接无视就好了...看代码就懂了...  代码刚刚写的 ,,也许有一些不好的地方... 测试没什么问题.. 好了就这样吧..

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值