开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 2773|回复: 1
收起左侧

[源码分享] 转一个任意位置hook函数源码(C内联汇编)

[复制链接]
结帖率:0% (0/1)
发表于 2013-1-31 18:54:32 | 显示全部楼层 |阅读模式   江苏省南京市
[e]
#include <iostream>
#include <windows.h>

#pragma warning( disable : 4311 )
#pragma warning( disable : 4312 )

#define HOOK_BYTES 5
typedef unsigned int uint;

uint hookAddr = 0;
char old_code[ HOOK_BYTES ];
char new_code[ HOOK_BYTES ];

void printRegisters( void );

bool hook( void )
{
DWORD dwFlag;
if ( VirtualProtect( ( void* )hookAddr, HOOK_BYTES, PAGE_EXECUTE_READWRITE, &dwFlag ) )
{
memcpy( old_code, ( void* )hookAddr, HOOK_BYTES );
memcpy( ( void* )hookAddr, new_code, HOOK_BYTES );
VirtualProtect( ( void* )hookAddr, HOOK_BYTES, dwFlag, &dwFlag );
return true;
}
return false;
}

void unhook( void )
{
DWORD dwFlag;
if ( VirtualProtect( ( void* )hookAddr, HOOK_BYTES, PAGE_EXECUTE_READWRITE, &dwFlag ) )
{
memcpy( ( void* )hookAddr, old_code, HOOK_BYTES );
VirtualProtect( ( void* )hookAddr, HOOK_BYTES, dwFlag, &dwFlag );
}
}

namespace global
{
uint gEAX = 0;
uint gEBX = 0;
uint gECX = 0;
uint gEDX = 0;
uint gESP = 0;
uint gEBP = 0;
uint gESI = 0;
uint gEDI = 0;

uint gRet = 0; // 临时的返回地址
uint gTmp = 0; // 一些临时的值保存
uint gPar = 0; // 被hook函数的正常返回地址
uint gCnt = 1; // 当前hook的次数
uint gMax = 0; // 最大hook次数,为0表示一直hook
bool bEnt = 0; // 是否为第一次进入hook函数
}

void __declspec( naked ) hook_jmp( void )
{
__asm
{
__entry:
pushad
{
cmp global::bEnt, 0 // 如果没有进入则表示需要unhook
je __first

cmp global::gMax, 0 // 如果为0,则一直启用hook逻辑
je __second

mov eax, global::gCnt
cmp eax, global::gMax // 如果当前hook次数没有达到最大次数,则继续
jl __second

mov global::gCnt, 1 // reset state
mov global::bEnt, 0 // reset state
mov global::gMax, 0 // reset state

mov eax, global::gPar // 被hook函数的正常返回地址
mov global::gRet, eax // 准备跳转到被hook函数的上层调用,结束hook
popad
jmp __ret
}

__first:
// 保存相关重要寄存器值
{
popad
mov global::gEAX, eax
mov global::gEBX, ebx
mov global::gECX, ecx
mov global::gEDX, edx
mov global::gESP, esp
mov global::gEBP, ebp
mov global::gESI, esi
mov global::gEDI, edi
}

// 第一次进入,unhook并监视相关状态
pushad
{
mov global::bEnt, 1 // 记录状态

mov edi, global::gEBP // 被hook函数的ebp
mov eax, [ edi + 4 ] // 被hook函数的返回地址(其上层调用地址)
mov global::gPar, eax // 保存返回地址
mov esi, __entry // 将被hook函数的返回地址修改为
mov [ edi + 4 ], esi // 本函数的首地址,以便执行完被hook函数的
// 剩余逻辑之后能够返回到本函数,决定是否
// 还需要hook。

call printRegisters // 打印寄存器值[测试],或者其他
call unhook // unhook

mov eax, hookAddr // 获得被hook的内存地址
mov global::gRet, eax
}
popad

pop global::gTmp // 移除本函数的返回地址,并将hook的地址设置
jmp __ret // 为本函数的返回地址,从而实现跳转

__second:
// 第二次进入, 继续hook, 这次进入是被hook函数ret返回的,没有新的ret地址被压栈
{
mov global::bEnt, 0 // 设置状态
add global::gCnt, 1 // 增加hook计数

call hook // hook

mov eax, global::gPar // 将被hook函数的返回地址设置为本函数的
mov global::gRet, eax // 返回地址,从而实现正常的函数流程
}
popad

__ret:
push global::gRet // 修改本函数的返回地址
ret
}
}

void setHookBytes( uint addr )
{
hookAddr = addr;
new_code[ 0 ] = ( char )0xe8; // call 指令机器码
( uint& )new_code[ 1 ] = ( uint )hook_jmp - addr - 5; // 计算跳转偏移
}

void printRegisters( void )
{
printf( "EAX = 0x%08x/n", global::gEAX );
printf( "EBX = 0x%08x/n", global::gEBX );
printf( "ECX = 0x%08x/n", global::gECX );
printf( "EDX = 0x%08x/n", global::gEDX );
printf( "ESP = 0x%08x/n", global::gESP );
printf( "EBP = 0x%08x/n", global::gEBP );
printf( "ESI = 0x%08x/n", global::gESI );
printf( "EDI = 0x%08x/n", global::gEDI );
}
[/e] 如上,hook_jmp函数即为我们自定义的hook函数,当被hook函数被hook之后,就会跳转到这个函数里,执行相关逻辑,上面我加了很详细的注释。应该很容易看懂。还是先看怎么使用这套方法,再来细说,代码如下:

[e]
void testHook( void )
{
printf( "This is a hook test 1./n" );
printf( "This is a hook test 2./n" );
printf( "This is a hook test 3./n" );
printf( "This is a hook test 4./n" );
printf( "______________________/n" );
}

int main( void )
{
uint hook_addr = 0x0042ec7b;
setHookBytes( hook_addr );

global::gMax = 2;
if ( hook() )
{
testHook();
testHook();
testHook();
}
system( "pause" );
return 0;
}
[/e]
原文地址
http://blog.csdn.net/masefee/article/details/6326634
结帖率:65% (20/31)
发表于 2013-5-27 08:53:14 | 显示全部楼层   广西壮族自治区玉林市
这样的好贴,竟然没人顶。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报电话0663-3422125,QQ: 793400750,邮箱:wp@125.la
网站简介:精易论坛成立于2009年,是一个程序设计学习交流技术论坛,隶属于揭阳市揭东区精易科技有限公司所有。
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备12094385号-1) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

快速回复 返回顶部 返回列表