讨论一个注入hook完成后的清理问题,技术讨论。。。

rageliu 2016-09-26 10:12:49
加精
问题描述:

采用全局钩子的方式将dll注入了目标进程,并成功hook了目标进程里的函数Fun。使其调用时会先进入我的函数Fun_My。这些都没有问题。但是在我要卸载钩子的时候,如果刚好代码执行在我的函数Fun_My的代码里。就会崩溃。因为我已经卸载了dll,也就是dll已经不在目标进程里了。这时候Fun_My也是无效的内容了,并不是以前的正确的代码段。所以目标进程就崩溃了。

这种情况下,在我的dll执行detach即将卸载的时候,如何确保代码并不在Fun_My里面执行呢。

当然我肯定是提前执行了对函数的unhook的,只是最后的一次hook到的函数,可能还在Fun_My里面执行,还没有执行完返回。这就出了问题。

大家有遇到过么,或是思考过这个问题,有啥好的处理方法啊,关于技术的意见建议讨论都欢迎。感谢。
...全文
4262 86 打赏 收藏 转发到动态 举报
写回复
用AI写文章
86 条回复
切换为时间正序
请发表友善的回复…
发表回复
BeanJoy 2016-10-12
  • 打赏
  • 举报
回复
在被hook的进程下申请两段内存,hook时先跳转到第一段内存,然后再跳转到dll中的代码执行,然后再跳转到第二段内存执行。 第一段内存的代码主要是加锁,判断dll是否被卸载,如果被卸载,就跳转到原被hook的函数处,然后再跳转到第二段内存;否则直接跳转到dll的代码执行。 第二段内存的代码就是解锁。 dll卸载时,加锁,设置卸载标记,卸载。 申请的两段内存不用释放。
zd3870262 2016-10-05
  • 打赏
  • 举报
回复
将卸载线程和调用线程hook在同一个线程就OK了
rageliu 2016-09-28
  • 打赏
  • 举报
回复
因为attach和detach一定是串行的。或是理解为它们一定在同一个线程。代码在它们之间,肯定会被串行话。 调用如果来自其他地方,也就是其他线程,这样就不在它们的线程里。才会出问题。。
zwfgdlc 2016-09-28
  • 打赏
  • 举报
回复
引用 81 楼 rageliu 的回复:
不用纠结是否先hook。 注意我说的好么,调用来自attach就不对。。。。 注意我说的好么,调用来自attach就不对。。。。 注意我说的好么,调用来自attach就不对。。。。 注意我说的好么,调用来自attach就不对。。。。
明白,看来我想得太简单了
rageliu 2016-09-28
  • 打赏
  • 举报
回复
不用纠结是否先hook。 注意我说的好么,调用来自attach就不对。。。。 注意我说的好么,调用来自attach就不对。。。。 注意我说的好么,调用来自attach就不对。。。。 注意我说的好么,调用来自attach就不对。。。。
rageliu 2016-09-28
  • 打赏
  • 举报
回复
这是因为你代码有问题,把messagebox的调用放到了attach。被你自己强行写成串行执行了。 如果messagebox的调用来自程序其他地方,不来自attach。注意是不来自attach!!!!!就有问题了阿 把messagebox的调用放到了attach。被你自己强行写成串行执行了。 把messagebox的调用放到了attach。被你自己强行写成串行执行了。 把messagebox的调用放到了attach。被你自己强行写成串行执行了。 把messagebox的调用放到了attach。被你自己强行写成串行执行了。 如果messagebox的调用来自程序其他地方,不来自attach。注意是不来自attach!!!!!就有问题了阿 如果messagebox的调用来自程序其他地方,不来自attach。注意是不来自attach!!!!!就有问题了阿 如果messagebox的调用来自程序其他地方,不来自attach。注意是不来自attach!!!!!就有问题了阿 如果messagebox的调用来自程序其他地方,不来自attach。注意是不来自attach!!!!!就有问题了阿
zwfgdlc 2016-09-28
  • 打赏
  • 举报
回复
//inline Hook,函数头部写入E9 xxxx方式 pfnMessageBox = HookApi(TEXT("user32.dll"), "MessageBoxW", HookMessageBox, 5); 我是先HOOK了MessageBox再调用MessageBox,既然已经HOOK了,调用MessageBox肯定是会跳转到DLL中HookMessageBox函数,然后在那执行循环延时10秒. MessageBox(NULL, TEXT("123456"), NULL, MB_ICONASTERISK);
rageliu 2016-09-28
  • 打赏
  • 举报
回复
引用 77 楼 zwfgdlc 的回复:
我确定是UnHook()都执行了,并且我的EXE进程都已经退出了,被注入的进程还在执行循环代码,最后MessageBox弹出后,DLL才从进程中卸载
老大,你怎么就没明白呢。这个流程不就对了吗。。 这是因为你代码有问题,把messagebox的调用放到了attach。被你自己强行写成串行执行了。 如果messagebox的调用来自程序其他地方,不来自attach。注意是不来自attach!!!!!就有问题了阿。
zwfgdlc 2016-09-28
  • 打赏
  • 举报
回复
我确定是UnHook()都执行了,并且我的EXE进程都已经退出了,被注入的进程还在执行循环代码,最后MessageBox弹出后,DLL才从进程中卸载
rageliu 2016-09-28
  • 打赏
  • 举报
回复
我尝试解释下你测试为什么不出问题。 按我的理解,attach一定会先于detach调用完毕。它们一定是会串行调用。所以你在attach里的调用。永远会在detach后面。所以不出问题
rageliu 2016-09-28
  • 打赏
  • 举报
回复
也就是detach都只新完毕了,attach的调用却正在执行??? 怎么感觉就很怪呢 关键就是对messagebox的调用,并不是注入进程其他地方调用过来的,而是你在attach调用的。。。
rageliu 2016-09-28
  • 打赏
  • 举报
回复
我明白你的意思。但是你不觉得比较怪么。 Hook(); Sleep(5000); UnHook(); 这里的Hook() 会安装钩子,安装钩子是不是会注入dll。那么dll里的attach会不会同步执行完毕呢?如果会。那attach里对messagebox的调用,会不会已经执行了?? 你测试的时候,确定UnHook()都执行了,attach调用过去的messagebox却正在执行?
zwfgdlc 2016-09-28
  • 打赏
  • 举报
回复
引用 72 楼 rageliu 的回复:
to zwfgdlc: 你这个测试的代码貌似不对。 将调用放在DLL_PROCESS_ATTACH里是不行的。 因为attach和detach肯定是串行的啊。这么写就不会有多线程环境了。
你仔细看下我代码中的逻辑, 当EXE执行UnHook()时,被注入的进程正在执行DLL领空HookMessageBox()函数中的do...while循环代码, 不正是你所说的那样"但是在我要卸载钩子的时候,如果刚好代码执行在我的函数Fun_My的代码里。就会崩溃。"
rageliu 2016-09-28
  • 打赏
  • 举报
回复
to zwfgdlc: 你这个测试的代码貌似不对。 将调用放在DLL_PROCESS_ATTACH里是不行的。 因为attach和detach肯定是串行的啊。这么写就不会有多线程环境了。
rageliu 2016-09-28
  • 打赏
  • 举报
回复
to zwfgdlc: 附加到目标进程调试。 断case DLL_PROCESS_DETACH:和__asm。 看看到detach的时候,上面循环是否执行完成。
rageliu 2016-09-28
  • 打赏
  • 举报
回复
引用 64 楼 schlafenhamster 的回复:
"在DLL中case DLL_PROCESS_DETACH里加了Sleep(10000)延时10秒," 可行
为什么可行,那我假设fun_my里有个运算,耗时11秒。怎么办? 只是假设出问题的情况。当然10秒了,肯定
引用 69 楼 void_main_void 的回复:
[quote=引用 17 楼 rageliu 的回复:] [quote=引用 13 楼 void_main_void 的回复:] 遍历所有线程,除了卸载进程所有线程全部暂停,然后卸载线程先卸载HOOK,然后在恢复有所线程。
感谢回复。 你的想法和我觉得最理想的处理方式不谋而合!!!! 我的想法是:首先unhook所有我钩了的函数。然后枚举所有线程,暂停,取该线程的调用堆栈。判断调用堆栈里是否有我dll模块所在的加载地址。如果没有,那该线程没问题。如果有就记录该线程句柄。然后sleep一下后重复上面的判断。直到确定所有线程的调用堆栈里,没有我dll的调用。然后可以完全卸载dll。 这也是我想到最理想的方式。 但是,,,凡是都有但是。。。。 枚举线程,暂停线程,取堆栈等等系列操作,存在需要权限,会失败等等问题。导致判断流程有问题不在准确。一旦不能100%确保正确,那么也就意味着整个方案的失败。[/quote] 去参考微软的 Detours 源码。[/quote] 肯定的告诉你,它是有这个问题的。当然我用的是免费版,不确定付费版是否有解决,毕竟1万刀,付不起。
满衣兄 2016-09-27
  • 打赏
  • 举报
回复
dll detach的时候直接去掉回调的函数不行吗
void_main_void 2016-09-27
  • 打赏
  • 举报
回复
引用 17 楼 rageliu 的回复:
[quote=引用 13 楼 void_main_void 的回复:] 遍历所有线程,除了卸载进程所有线程全部暂停,然后卸载线程先卸载HOOK,然后在恢复有所线程。
感谢回复。 你的想法和我觉得最理想的处理方式不谋而合!!!! 我的想法是:首先unhook所有我钩了的函数。然后枚举所有线程,暂停,取该线程的调用堆栈。判断调用堆栈里是否有我dll模块所在的加载地址。如果没有,那该线程没问题。如果有就记录该线程句柄。然后sleep一下后重复上面的判断。直到确定所有线程的调用堆栈里,没有我dll的调用。然后可以完全卸载dll。 这也是我想到最理想的方式。 但是,,,凡是都有但是。。。。 枚举线程,暂停线程,取堆栈等等系列操作,存在需要权限,会失败等等问题。导致判断流程有问题不在准确。一旦不能100%确保正确,那么也就意味着整个方案的失败。[/quote] 去参考微软的 Detours 源码。
rageliu 2016-09-27
  • 打赏
  • 举报
回复
引用 13 楼 void_main_void 的回复:
遍历所有线程,除了卸载进程所有线程全部暂停,然后卸载线程先卸载HOOK,然后在恢复有所线程。
感谢回复。 你的想法和我觉得最理想的处理方式不谋而合!!!! 我的想法是:首先unhook所有我钩了的函数。然后枚举所有线程,暂停,取该线程的调用堆栈。判断调用堆栈里是否有我dll模块所在的加载地址。如果没有,那该线程没问题。如果有就记录该线程句柄。然后sleep一下后重复上面的判断。直到确定所有线程的调用堆栈里,没有我dll的调用。然后可以完全卸载dll。 这也是我想到最理想的方式。 但是,,,凡是都有但是。。。。 枚举线程,暂停线程,取堆栈等等系列操作,存在需要权限,会失败等等问题。导致判断流程有问题不在准确。一旦不能100%确保正确,那么也就意味着整个方案的失败。
hugh_z 2016-09-27
  • 打赏
  • 举报
回复
66666666666666
加载更多回复(65)

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧