
NB模块v5.6修复内存泄露易语言源码NB模块 v5.6 新超级Hook 最终修复说明
一、修复目的
本次修复主要针对“新超级Hook”长期运行后可能出现的以下问题:
1. 远程内存及进程句柄持续泄漏;
2. Hook线程句柄未正确保存或关闭;
3. 销毁Hook时仍有回调正在执行,导致微信进程崩溃;
4. 远程执行代码尚未结束就释放代码内存;
5. Hook创建失败时,已申请的资源没有完整回收;
6. HookEx提前关闭进程句柄,导致后续暂停、恢复或销毁失败;
7. 64位Hook远程线程方式的栈空间恢复不匹配;
8. 回调参数使用特殊“通用型”,重新粘贴源码后无法生成模块。
二、需要覆盖的源码文件
完整修复涉及以下四个NB模块源码文件:
1. 代码HOOK类_HOOK_EX.class.e.txt
2. 代码HOOK类_新超级Hook.class.e.txt
3. 代码HOOK新超级Hook子程序.static.e.txt
4. 自定义类型.e.txt
如果此前已经覆盖过完整修复源码,最终兼容调整只需要再次覆盖:
代码HOOK类_新超级Hook.class.e.txt
三、新超级Hook主要修复内容
1. 进程句柄所有权
为每条Hook记录增加“拥有进程句柄”标记。
由“开始Hook”内部打开的进程句柄,在Hook销毁时由本类负责关闭。
由调用者传入“开始Hook2”的进程句柄,默认不由本类擅自关闭。
这样可以避免句柄永久泄漏,也不会误关调用者仍在使用的句柄。
2. Hook创建失败清理
创建Hook过程中,如果出现以下任意失败:
– 远程代码内存申请失败;
– 寄存器保存区申请失败;
– 回调地址无效;
– 消息窗口或消息编号创建失败;
– 远程句柄复制失败;
– 跳板代码写入失败;
– 原地址跳转写入失败;
会按实际申请情况回收远程代码区、寄存器区、复制句柄和本地进程句柄。
3. 远程线程句柄修复
远程线程创建后会保存真实线程句柄。
同步方式先等待线程真正结束,再关闭线程句柄。
异步方式不再把错误寄存器值当作线程句柄使用。
避免线程句柄不断累积,以及错误关闭无效句柄。
4. 64位栈平衡修复
64位远程线程回调代码统一按照实际申请的栈空间恢复RSP。
修复了申请空间和释放空间不一致的问题,避免长期运行后出现栈破坏、随机异常或微信崩溃。
5. 远程复制句柄回收
远程线程方式需要把当前进程句柄复制到目标进程。
修复后会记录目标进程中的复制句柄,并在销毁Hook时通过DuplicateHandle配合DUPLICATE_CLOSE_SOURCE关闭远程源句柄。
避免每次安装Hook都在微信进程中遗留一个无法回收的句柄。
6. 安全销毁Hook
销毁顺序调整为:
1)暂停Hook,恢复原始代码;
2)等待已经进入回调的调用退出;
3)确认没有活动回调后释放远程跳板代码;
4)释放寄存器保存区;
5)关闭目标进程中的复制句柄;
6)按所有权关闭本地进程句柄;
7)清空本条Hook记录。
如果活动回调在限定时间内没有退出,销毁操作返回失败,不强行释放仍在使用的内存。
这样处理的原则是:宁可暂时保留少量资源,也不释放正在执行的代码导致微信崩溃。
7. 子类化窗口过程恢复
新超级Hook使用窗口消息执行本地回调。
修复后会保存原窗口过程,并在卸载最后一个Hook时恢复原窗口过程,清空消息编号和子类化窗口句柄。
避免模块退出后窗口过程仍指向已经失效的模块代码。
8. Hook ID与数组边界检查
暂停Hook、继续Hook、销毁Hook和读取Hook记录前增加ID有效性检查。
无效ID、0、负数或超过记录数组范围的ID会直接返回失败,不再访问越界数组成员。
9. HookEx修复
修复HookEx创建成功后立即关闭进程句柄的问题。
HookEx记录会保留实际进程句柄、原始代码和跳转代码,确保暂停、恢复和销毁操作能够正确执行。
修复创建失败时返回错误Hook ID以及部分远程内存未释放的问题。
10. GetModuleHandle所有权修复
通过GetModuleHandle取得的模块句柄不属于调用者。
删除了对此类句柄调用FreeLibrary的错误逻辑,避免意外减少系统模块引用计数。
四、回调参数兼容调整
原模块的回调接口参数使用特殊“通用型”:
回调接口,通用型,参考
该类型依赖原作者保存在易语言工程内部的“通用型模板”。
重新粘贴或重新建立子程序后,界面虽然可能仍显示“通用型”,但内部类型标识会丢失,生成模块时会提示:
没有找到名为“通用型”的数据类型。
最终版本将以下四个子程序的“回调接口”统一改为易语言原生“子程序指针”:
1. 开始Hook
2. 开始Hook2
3. 开始Hook_本地
4. 开始Hook_64
模块内部使用:
回调子程序 = 到整数 (回调接口)
调用端保持原来的写法:
&微信HOOK_消息
&微信HOOK_事件
调用端不要再使用“到整数(&回调子程序)”,也不要把回调接口改回“通用型”。
五、软件端正确调用示例
HID_消息 = 新超级HOOK.开始Hook(进程ID,Hook地址,{ 5 },&微信HOOK_消息,1,1,,)
HID_事件 = 新超级HOOK.开始Hook(进程ID,Hook地址,{ 5 },&微信HOOK_事件,1,1,,”edi esi”)
回调子程序参数格式:
消息Hook:
进程句柄,整数型
寄存器地址,整数型
HookID,整数型
事件Hook:
进程句柄,整数型
寄存器地址,整数型
HookID,整数型
六、推荐的关闭顺序
软件退出或重新连接微信前,应按以下顺序处理:
1. 停止接收新的业务任务;
2. 调用暂停Hook;
3. 调用销毁Hook;
4. 等待正在执行的微信远程调用正常结束;
5. 关闭软件自身创建的线程句柄;
6. 最后销毁窗口和结束进程。
不要在微信远程调用仍在执行时使用“强制结束线程”。
不要在远程线程超时后立即释放其代码内存。
不要直接终止机器人进程代替正常卸载Hook。
七、使用方法
1. 先备份原始NB模块工程;
2. 覆盖本说明第二节列出的源码;
3. 检查四个Hook入口的回调接口类型是否为“子程序指针”;
4. 重新生成NB模块;
5. 在软件工程中删除旧NB模块引用;
6. 重新添加刚生成的修复版NB模块;
7. 确认软件调用端直接传递“&回调子程序”;
8. 重新静态编译软件。
八、验证说明
已完成的静态检查:
1. 修改文件中的如果、判断、循环结构均成对;
2. Hook ID访问增加边界保护;
3. 申请内存的主要失败路径具有对应释放;
4. 进程句柄所有权已区分;
5. 远程线程句柄和远程复制句柄具有关闭路径;
6. 销毁前具有活动回调等待保护;
7. 最终覆盖源码不再依赖特殊“通用型”。
仍需实际运行验证的项目:
1. 当前微信版本对应的Hook偏移是否正确;
2. 连续运行数小时后的私有内存和句柄数量;
3. 高频群消息情况下的响应情况;
4. 关闭软件时微信是否能够保持正常运行;
5. 微信更新后Hook地址和数据结构是否发生变化。
本修复不能保证跨微信版本继续有效。微信版本变化后,Hook偏移、寄存器和消息结构都可能需要重新分析。
九、文件版本说明
本说明对应的最终兼容方案:
– NB回调参数:子程序指针;
– 软件调用方式:直接使用&回调子程序;
– 保留原软件已知可用的消息业务执行路径;
– 包含新超级Hook的内存、句柄、失败清理和安全销毁修复。


评论(0)