每次遇到jni接口进入高度混淆的动态库,进行静态分析是一件头疼的事情。
如果能够实时获取到整个代码的运行路径,筛选调用pc值,便可以只做局部代码分析。目前我开发实验室里实现的一套方案是,1.定制内核改写ptrace逻辑,2.在app端结合类xposed框架进行调试声明3.服务端专用线程,被sigtrap第一次唤醒,写入硬件初始断点(杜绝函数头跳板特征检测),具体设置第n个调试寄存器的断点信息可参考:4.在断点处前向读取标记下一分支类代码b/bl/br/bx/be/bne/ret,
5.在分支附近进行single_step,对link级别的指令,记录调用层级+-1,整个trace过程中限制调用层级,忽略过深的调用。
6.跳转指令single_step后,判断pc值是否在当前库映射地址范围,跳出的情形不做trace。本方案的服务端直接写的本地可执行程序,123是实现抓取场景限制,456同时兼顾了执行效率和流程分析块的简化,限制于当前so库。 那为什么要费劲搞这个呢,因为unidbg是个瘸子!再怎么仿真的环境依旧是仿真,能够在实机上运行的代码从效率和准确度上都有不可比拟的优势。以及本方案是 真·用户进程so库空间无侵入 的trace+hook方案,随便你怎么CRC,因为所有.text段指令内容就没有变动过。对于懒人的缺点在于,需要自己一步步地去写trace逻辑,没有frida/xposed/QBDI等那么方便完整的接口和愈发。
分析到这一步还能看下去的人,造个轮子应该也没啥,你失去了便捷的优势,但是获得了自由。细节部分,看大家意向,如果感兴趣想讨论的人多,后续更新部分demo代码于github。基础知识需参考:
arm64硬件断点 97eK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6^5N6s2g2D9P5g2)9J5k6h3y4F1i4K6u0r3j5i4u0@1K9h3y4D9k6g2)9J5c8X3q4J5L8e0j5@1i4K6u0V1K9$3g2J5L8X3g2D9i4K6u0V1M7X3g2K6k6h3q4J5j5$3S2Q4x3X3b7#2// 修改第n个调试寄存器信息
---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-286210.htm
[原创]古墓派反native混淆方案:实机调试
120 浏览
9 回复
感谢分享
请教一下,我现在通过传入pic 和 用户空间地址到一个kpm 内核模块,里面执行register_user_hw_breakpoint方法, 发现返回异常。 是不是缺少了什么前置操作吗?
feng504x
请教一下,我现在通过传入pic 和 用户空间地址到一个kpm 内核模块,里面执行register_user_hw_breakpoint方法, 发现返回异常。 是不是缺少了什么前置操作吗?
什么平台啊,内核中注册硬件断点需要配置对应回调来处理异常,像被ptrace中的话这个异常是自动会被设置成给调试进程挂上sigtrap,以便被tracer捕获异常处理。
如果只是单纯的用内核接口写入用户空间硬件断点的话,异常回调没设置好就会直接导致用户进程退出,可能你需要自己写这个回调的处理逻辑。
可以参考下内核里arch/arm64/kernel/ptrace.c下注册硬件断点的回调安装流程。
请教一下,我现在通过传入pic 和 用户空间地址到一个kpm 内核模块,里面执行register_user_hw_breakpoint方法, 发现返回异常。 是不是缺少了什么前置操作吗?
什么平台啊,内核中注册硬件断点需要配置对应回调来处理异常,像被ptrace中的话这个异常是自动会被设置成给调试进程挂上sigtrap,以便被tracer捕获异常处理。
如果只是单纯的用内核接口写入用户空间硬件断点的话,异常回调没设置好就会直接导致用户进程退出,可能你需要自己写这个回调的处理逻辑。
可以参考下内核里arch/arm64/kernel/ptrace.c下注册硬件断点的回调安装流程。
感谢分享
感谢分享
学习学习
学习学习
学习
cy