下你所需,载你所想!
汇集开发技术源码资料

APIHook类功能增强模块封装

:27.528KB :1 :2020-01-06 14:10:50

部分简介

程序调用API函数实现APIHook的功能增强,返回当前地址所指的汇编指令的长度.注意代码对齐,在OD中的地址不能断开.参考自dtcser的"易语言取汇编指令长度模块源码,非常好的源码,不过貌似只能用于32位的系统上。

动态调用各种函数.可以为_CDECL和_stdcall,忘了是哪位大神的手笔了...修改了一下,终于可以封装在类内部了(但是不确定有没有问题)

当函数头大于5个字节时,多余的以nop填充,防止破坏代码,我也不知道有没有这个必要。

返回新生成的函数头部地址,无需暂停Hook即可调用,可防止漏掉Hook,并且不会造成死循环.Hook卸载后,若不清除函数头,则可继续使用。

失败返回0.自动选择被调用地址,若新函数头生成失败,自动选择原始地址调用.可直接无缝调用原函数(支持_CDECL和_stdcall),参数必须都为整数型,非整数型请自行取址。

.如果真 (有效句柄 (FunctionAddr) = 假)
返回 (假)
.如果真结束
.如果真 (OldFuncAddr = FunctionAddr) ' 防止同一个Hook(同名的Hook)被重复安装,导致混乱
返回 (真) ' 返回真,表示安装成功
.如果真结束
OldFuncAddr = FunctionAddr
' 判断函数头长度,至少5个字节才够Jmp Hook 的,并且保证新生成的函数头正常使用,不会破坏代码的完整性.
头部临时位置 = OldFuncAddr
头部临时大小 = sizeofcode (头部临时位置) ' 如果等于或大于5,就直接备份这个长度,比如6个字节的函数头
被保存的头部大小 = 头部临时大小
.判断循环首 (被保存的头部大小 < 5) ' 刚进入函数第一行不可能就是call xxxx的形式,顶多是已经被hook变成Jmp xxxxx的形式,所以第一次不用判断出了Jmp的代码,第二行之后再判断
头部临时位置 = 头部临时位置 + 头部临时大小
头部临时大小 = sizeofcode (头部临时位置)
.如果真 (头部临时大小 = 5)
.判断开始 (指针到字节集 (头部临时位置, 1) = { 232 }) ' call
发现call的头长度位置 = 被保存的头部大小
call的原始地址 = 头部临时位置 + 5 + 取字节集数据 (指针到字节集 (头部临时位置 + 1, 4), #整数型, )
.默认

.判断结束

.如果真结束
被保存的头部大小 = 被保存的头部大小 + 头部临时大小
.判断循环尾 ()
.如果真 (被保存的头部大小 < 5)
被保存的头部大小 = 0
OldHeadCode = { }
返回 (假)
.如果真结束
' 下面更改保护属性,长度还是根据检测出来的长度
.如果真 (API_VirtualProtect (OldFuncAddr, 被保存的头部大小, 64, OldProtect) = 0) ' 属性改写失败,Hook不会成功
OldHeadCode = { }
连续赋值 (0, OldFuncAddr, OldProtect)
返回 (假)
.如果真结束
' 新处理过程
NewFuncAddr = NewProc
' 判断第一个字节是不是Jmp,即是否已经被Hook
OldHeadCode = 指针到字节集 (OldFuncAddr, 被保存的头部大小)
.如果 (指针到字节集 (OldFuncAddr, 1) = { 233 } 且 MultiJmp 且 sizeofcode (OldFuncAddr) = 5) ' 仅针对函数头第一个字节,这里其实可以根据需要判断第一个字节,因为我不知道还有没有jnz等等方式的Hook,自己拓展去吧(其实可以加一个方法,用于指定判断的条件,不过这样的东西,应该很少用到的吧?)
' 这里既然前面5个字节中第一个字节已经是Jmp了,说明被Hook了,所以只按照常规方法处理前5个字节即可
tempcode = 取字节集数据 (指针到字节集 (OldFuncAddr + 1, 4), #整数型, ) ' 原始的跳到的位置的机器码
tempcode = OldFuncAddr + 5 + tempcode ' 原始跳到的内存地址
NewHeadCode = 取空白字节集 (10)
NewHeadCode = { 233, 0, 0, 0, 0 }
NewFuncHead = API_lstrcpynA_字节集 (NewHeadCode, NewHeadCode, 0)
tempcode = tempcode - 5 - NewFuncHead ' 计算应该跳到的新的位置的机器码,保护原来的Hook
写到内存 (到整数 (tempcode), NewFuncHead + 1, 4)
.否则
' 生成新的函数头
NewHeadCode = 取空白字节集 (被保存的头部大小 + 5) ' 跳回来的Jmp,就是5个字节
NewHeadCode = OldHeadCode + { 233, 0, 0, 0, 0 }
NewFuncHead = API_lstrcpynA_字节集 (NewHeadCode, NewHeadCode, 0)
' =============判断头部是否包含call,计算出call后面的地址,并补丁
.判断开始 (发现call的头长度位置 ≠ 0)
temp被写到内存地址 = NewFuncHead + 发现call的头长度位置 + 1 ' 后面+1是因为共5字节,最后四个才是要写入的地址
temp被修正的地址 = call的原始地址 - 4 - temp被写到内存地址 ' -5+1=-4
写到内存 (到整数 (temp被修正的地址), temp被写到内存地址, 4)
' 调试输出文本 (“APIHook增强类-> 被Hook的地址:” + 到文本 (FunctionAddr) + “ -在内存位置:” + 到文本 (temp被写到内存地址) + “ -修正包含的call机器码地址(OD中的机器码):” + 到文本 (temp被修正的地址))
.默认

.判断结束
' =============
' ===下面写入并补丁跳回地址
temp被写到内存地址 = NewFuncHead + 被保存的头部大小 + 1 ' 后面+1是因为共5字节,最后四个才是要写入的地址
temp被修正的地址 = OldFuncAddr + 被保存的头部大小 - (NewFuncHead + 被保存的头部大小 + 5) ' 这个逻辑我怎么也看不懂了
写到内存 (到整数 (temp被修正的地址), temp被写到内存地址, 4)
.如果结束
输出调试文本 (“APIHook增强类-> 新函数头生成完毕!下面将判断C方式调用”)
' 调试输出文本 (“APIHook增强类-> 被Hook的地址:” + 到文本 (FunctionAddr) + “ -新函数头生成完毕!下面将判断C方式调用”)
' 强制修改为__cdecl方式调用
.如果真 (__cdecl)
指针 = NewProc + 28 ' 与我最早接触C调用的平栈方式相同,后来看到云外归鸟的代码才知道,这个易语言子程序call固定长度28
API_RtlMoveMemory_读取整数 (代码, 指针, 1) ' 实际读取的是单个字节
.如果真 (代码 = 194) ' 为 ret 000x
代码 = 195 ' 为 ret
.如果真 (API_VirtualProtect (指针, 1, 64, old) ≠ 0)
API_RtlMoveMemory_写入整数 (指针, 代码, 1) ' 修改为ret
isCdecl = 真 ' 标记为是被按照C方式处理了,以便以后还原
API_VirtualProtect (指针, 1, old, old)
输出调试文本 (“APIHook增强类-> 新过程被强制为C方式调用”)
' 调试输出文本 (“APIHook增强类-> 被Hook的地址:” + 到文本 (FunctionAddr) + “ -新过程被强制为C方式调用”)
.如果真结束

.如果真结束

.如果真结束
' 修改原始函数头,Jmp到新过程地址
Int = NewProc - OldFuncAddr - 5 ' Hook还按照通常处理方式,仅处理前5个字节(剩下的字节填充nop!),Hook中跳回来的时候,返回到被保存的头部下一句,而不是固定的第6个字节
JmpCode = { 233 } + 到字节集 (Int) + 写出Nop数量 ()
.如果真 (是否为空 (StartAtOnce))
StartAtOnce = 真
.如果真结束
.如果真 (StartAtOnce)
输出调试文本 (“APIHook增强类-> 函数头生成完毕!下面将暂停其他线程!”)
' 调试输出文本 (“APIHook增强类-> 被Hook的地址:” + 到文本 (FunctionAddr) + “ -函数头生成完毕!下面将暂停其他线程!”)
暂停其他线程 ()
输出调试文本 (“APIHook增强类-> 其他线程已经被挂起!下面将写入Hook!”)
' 调试输出文本 (“APIHook增强类-> 被Hook的地址:” + 到文本 (FunctionAddr) + “ -其他线程已经被挂起!下面将写入Hook!”)
写到内存 (JmpCode, OldFuncAddr, 被保存的头部大小) ' 安装Hook后,并没有还原内存属性,方便暂停以及继续Hook,提高效率
输出调试文本 (“APIHook增强类-> 写入Hook完毕!下面将恢复被挂起的线程!”)
' 调试输出文本 (“APIHook增强类-> 被Hook的地址:” + 到文本 (FunctionAddr) + “ -写入Hook完毕!下面将恢复被挂起的线程!”)
恢复其他线程 ()
输出调试文本 (“APIHook增强类-> 被挂起的线程恢复完毕!请查看线程状态!”)
' 调试输出文本 (“APIHook增强类-> 被Hook的地址:” + 到文本 (FunctionAddr) + “ -被挂起的线程恢复完毕!请查看线程状态!”)
.如果真结束
' 调试输出文本 (“APIHook增强类-> 被Hook的地址:” + 到文本 (FunctionAddr) + “ -处理完成!”)

APIHook类功能增强模块封装

热门推荐

相关文章