用 Hook 模拟断点问题

adintr 2013-06-28 12:37:45
在进程内模拟调试器的断点操作:
1. 插入断点时, 改写断点位置的 5 个字节为一条调用断点处理函数的 call 指令. 比如 call __handle_break_point; 当然, 改写前会把原来的代码保存到相应的地方.
2. 断点命中后, 跳转到了 __handle_break_point 函数, 并在进行一系列的操作后, 得到 g 命令继续执行代码.
3. 要继续执行之前的代码, 我得把保存的代码还原回去, 然后在回到进入断点的地方开是执行.

这一切都没问题, 程序继续运行, 可是刚刚下断点已经不存在了, 被写回去了. 也就是说断点只能被命中一次!

为此, 我需要找到一个时机, 重新把下断点的 call __handle_break_point 指令写回去. 但是, 程序开是运行后我已经失去控制权了, 请教大家, 有没有好的办法来重新写入断点? 简单一点的, 最好是别要求用反汇编引擎去反汇编代码, 然后对反汇编的代码做很多分析的.
...全文
269 17 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
www_adintr_com 2013-06-28
  • 打赏
  • 举报
回复
一般来说, 调式器在恢复断点后会单步执行一次, 跳过了断点位置的指令后重新写入断点. 可以试试模仿这种行为. 不过调试器的断点指令只有 1 个字节, 你的断点指令有 5 个字节, 但步执行一次不一定就跳过去了.
yiyefangzhou24 2013-06-28
  • 打赏
  • 举报
回复
路过,看大神讨论
赵4老师 2013-06-28
  • 打赏
  • 举报
回复
《30天自制操作系统》
图灵狗 2013-06-28
  • 打赏
  • 举报
回复
中断返回之后,跳过下一条指令(即软中断指令)试试看。
引用 8 楼 adlay 的回复:
[quote=引用 7 楼 turingo 的回复:] 应该是插入单指令的软中断,然后在中断响应的地方再去call,直接插入call指令后面都乱了。 [quote=引用 6 楼 adlay 的回复:] [quote=引用 4 楼 turingo 的回复:] 到处瞎溜达,你5个字节的断点确实没怎么看明白。
一个 call 指令就 5 个字节, 他的其实不是断点, 是钩子, 只是想模拟断点那样的行为.[/quote][/quote] 插入单指令也会乱的, 所以函数执行到了的时候都必须先把断点原来的内容拷贝回去恢复了再执行.[/quote]
www_adintr_com 2013-06-28
  • 打赏
  • 举报
回复
引用 7 楼 turingo 的回复:
应该是插入单指令的软中断,然后在中断响应的地方再去call,直接插入call指令后面都乱了。 [quote=引用 6 楼 adlay 的回复:] [quote=引用 4 楼 turingo 的回复:] 到处瞎溜达,你5个字节的断点确实没怎么看明白。
一个 call 指令就 5 个字节, 他的其实不是断点, 是钩子, 只是想模拟断点那样的行为.[/quote][/quote] 插入单指令也会乱的, 所以函数执行到了的时候都必须先把断点原来的内容拷贝回去恢复了再执行.
图灵狗 2013-06-28
  • 打赏
  • 举报
回复
应该是插入单指令的软中断,然后在中断响应的地方再去call,直接插入call指令后面都乱了。
引用 6 楼 adlay 的回复:
[quote=引用 4 楼 turingo 的回复:] 到处瞎溜达,你5个字节的断点确实没怎么看明白。
一个 call 指令就 5 个字节, 他的其实不是断点, 是钩子, 只是想模拟断点那样的行为.[/quote]
www_adintr_com 2013-06-28
  • 打赏
  • 举报
回复
引用 4 楼 turingo 的回复:
到处瞎溜达,你5个字节的断点确实没怎么看明白。
一个 call 指令就 5 个字节, 他的其实不是断点, 是钩子, 只是想模拟断点那样的行为.
www_adintr_com 2013-06-28
  • 打赏
  • 举报
回复
引用 3 楼 adintr 的回复:
呵呵, 这么久没上 CSDN 了, 一上来就碰到你, 最近在忙啥? 我这个没有单步执行环境呀, 正在考虑该怎么模拟单步执行功能, 还没头绪. 再帮忙看看还有其它办法没有?
还那样. 我想不出什么完美的办法, 如果允许使用反汇编引擎, 可以找到跳过断点后的下一条指令, 在那个位置下一个临时断点, 临时断点命中的时候在去重新落实断点. 不过由于你的跳转指令占用了 5 个字节, 原始的指令可能包含各种跳转之类的, 它的下一条指令也不是那么好找的. 还有一种就是修改堆栈中断点所在函数的返回地址, 修改成自己的某个函数地址后函数返回的时候就会调用你的函数, 就可以去重新下断点了. 这样的缺点就是必须等到函数返回后才能重新下断点, 如果函数包含递归调用, 在递归的时候你的断点就没法命中了. 另外还有开个线程或者 Timer 来一直检测是否有断点没落实, 去执行下断点的操作. 但这个就更不可控了. 另外, 你这样的断点还有一个问题, 你的断点改写了 5 个字节, 里面可能包含多条指令, 其余位置的指令有可能跳转到你改动的字节的中间, 这样你的跳转不会触发, 而且接下来的代码会全都乱掉的.
图灵狗 2013-06-28
  • 打赏
  • 举报
回复
到处瞎溜达,你5个字节的断点确实没怎么看明白。
引用 3 楼 adintr 的回复:
[quote=引用 1 楼 adlay 的回复:] 一般来说, 调式器在恢复断点后会单步执行一次, 跳过了断点位置的指令后重新写入断点. 可以试试模仿这种行为. 不过调试器的断点指令只有 1 个字节, 你的断点指令有 5 个字节, 但步执行一次不一定就跳过去了.
呵呵, 这么久没上 CSDN 了, 一上来就碰到你, 最近在忙啥? 我这个没有单步执行环境呀, 正在考虑该怎么模拟单步执行功能, 还没头绪. 再帮忙看看还有其它办法没有?
引用 2 楼 turingo 的回复:
参考http://blog.jobbole.com/23463/系列文章。
都怀疑你有没有把题目看完[/quote]
adintr 2013-06-28
  • 打赏
  • 举报
回复
引用 1 楼 adlay 的回复:
一般来说, 调式器在恢复断点后会单步执行一次, 跳过了断点位置的指令后重新写入断点. 可以试试模仿这种行为. 不过调试器的断点指令只有 1 个字节, 你的断点指令有 5 个字节, 但步执行一次不一定就跳过去了.
呵呵, 这么久没上 CSDN 了, 一上来就碰到你, 最近在忙啥? 我这个没有单步执行环境呀, 正在考虑该怎么模拟单步执行功能, 还没头绪. 再帮忙看看还有其它办法没有?
引用 2 楼 turingo 的回复:
参考http://blog.jobbole.com/23463/系列文章。
都怀疑你有没有把题目看完
图灵狗 2013-06-28
  • 打赏
  • 举报
回复
参考http://blog.jobbole.com/23463/系列文章。
adintr 2013-06-28
  • 打赏
  • 举报
回复
引用 16 楼 adlay 的回复:
[quote=引用 13 楼 adintr 的回复:] 如果能响应中断我就不纠结了, 关键是这不是一个真正的调试器, 也不是一个进程, 只是注入到进程里面的一个 dll. 操作系统是不会把调试事件分发给我的. 就算会分发, 操作系统也会在分发前把目标进程的所有线程都暂停住, 而我也在那个进程里....
可以试试用捕获异常的方法看能不能捕获到断点异常, 单步执行异常这些. 包括 SEH 和 VEH 都可以试下.[/quote] 我试了竟然真的可以... 看来我的实现方式得调整一下了
www_adintr_com 2013-06-28
  • 打赏
  • 举报
回复
引用 13 楼 adintr 的回复:
如果能响应中断我就不纠结了, 关键是这不是一个真正的调试器, 也不是一个进程, 只是注入到进程里面的一个 dll. 操作系统是不会把调试事件分发给我的. 就算会分发, 操作系统也会在分发前把目标进程的所有线程都暂停住, 而我也在那个进程里....
可以试试用捕获异常的方法看能不能捕获到断点异常, 单步执行异常这些. 包括 SEH 和 VEH 都可以试下.
图灵狗 2013-06-28
  • 打赏
  • 举报
回复
那这样看起来似乎无解了。
引用 13 楼 adintr 的回复:
[quote=引用 7 楼 turingo 的回复:] 应该是插入单指令的软中断,然后在中断响应的地方再去call,直接插入call指令后面都乱了。 [quote=引用 6 楼 adlay 的回复:] [quote=引用 4 楼 turingo 的回复:] 到处瞎溜达,你5个字节的断点确实没怎么看明白。
一个 call 指令就 5 个字节, 他的其实不是断点, 是钩子, 只是想模拟断点那样的行为.[/quote][/quote] 如果能响应中断我就不纠结了, 关键是这不是一个真正的调试器, 也不是一个进程, 只是注入到进程里面的一个 dll. 操作系统是不会把调试事件分发给我的. 就算会分发, 操作系统也会在分发前把目标进程的所有线程都暂停住, 而我也在那个进程里....[/quote]
adintr 2013-06-28
  • 打赏
  • 举报
回复
引用 9 楼 turingo 的回复:
中断返回之后,跳过下一条指令(即软中断指令)试试看。 [quote=引用 8 楼 adlay 的回复:] [quote=引用 7 楼 turingo 的回复:] 应该是插入单指令的软中断,然后在中断响应的地方再去call,直接插入call指令后面都乱了。 [quote=引用 6 楼 adlay 的回复:] [quote=引用 4 楼 turingo 的回复:] 到处瞎溜达,你5个字节的断点确实没怎么看明白。
一个 call 指令就 5 个字节, 他的其实不是断点, 是钩子, 只是想模拟断点那样的行为.[/quote][/quote] 插入单指令也会乱的, 所以函数执行到了的时候都必须先把断点原来的内容拷贝回去恢复了再执行.[/quote][/quote] 如何跳过下一条指令?
adintr 2013-06-28
  • 打赏
  • 举报
回复
引用 7 楼 turingo 的回复:
应该是插入单指令的软中断,然后在中断响应的地方再去call,直接插入call指令后面都乱了。 [quote=引用 6 楼 adlay 的回复:] [quote=引用 4 楼 turingo 的回复:] 到处瞎溜达,你5个字节的断点确实没怎么看明白。
一个 call 指令就 5 个字节, 他的其实不是断点, 是钩子, 只是想模拟断点那样的行为.[/quote][/quote] 如果能响应中断我就不纠结了, 关键是这不是一个真正的调试器, 也不是一个进程, 只是注入到进程里面的一个 dll. 操作系统是不会把调试事件分发给我的. 就算会分发, 操作系统也会在分发前把目标进程的所有线程都暂停住, 而我也在那个进程里....
adintr 2013-06-28
  • 打赏
  • 举报
回复
引用 5 楼 adlay 的回复:
[quote=引用 3 楼 adintr 的回复:] 呵呵, 这么久没上 CSDN 了, 一上来就碰到你, 最近在忙啥? 我这个没有单步执行环境呀, 正在考虑该怎么模拟单步执行功能, 还没头绪. 再帮忙看看还有其它办法没有?
还那样. 我想不出什么完美的办法, 如果允许使用反汇编引擎, 可以找到跳过断点后的下一条指令, 在那个位置下一个临时断点, 临时断点命中的时候在去重新落实断点. 不过由于你的跳转指令占用了 5 个字节, 原始的指令可能包含各种跳转之类的, 它的下一条指令也不是那么好找的. 还有一种就是修改堆栈中断点所在函数的返回地址, 修改成自己的某个函数地址后函数返回的时候就会调用你的函数, 就可以去重新下断点了. 这样的缺点就是必须等到函数返回后才能重新下断点, 如果函数包含递归调用, 在递归的时候你的断点就没法命中了. 另外还有开个线程或者 Timer 来一直检测是否有断点没落实, 去执行下断点的操作. 但这个就更不可控了. 另外, 你这样的断点还有一个问题, 你的断点改写了 5 个字节, 里面可能包含多条指令, 其余位置的指令有可能跳转到你改动的字节的中间, 这样你的跳转不会触发, 而且接下来的代码会全都乱掉的. [/quote] 如果实在没有其它办法, 修改函数返回地址的办法勉强可以.递归调用断不下来就算了. 我的使用场景有限, 一般都会断在函数的开头, 应该不会出现有指令跳转到它的中间. 如果有遇到了再说.

3,882

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 其它技术问题
社区管理员
  • 其它技术问题社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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