前段时间网上冲浪,发现了PC逆向中的一种无痕hook,基于VT的读写 执行分离的技术。
VT中,host通过exit事件监控guest的一举一动,稍微“大”一点的动作(进程切换、读写msr、执行cpuid等)都会在guest触发exit,回到host的handle函数处理,在VT框架中,host对guest有绝对的监控和处理的全力,所以业界通常把VT框架下的程序称为-1环,比操作系统的0环都低,很形象地说明了host的权限范围;VT中非常重要的一个模块EPT,gtest中任何读写实际物理内存的操作都需要通过EPT转换一遍,这个转换环节一旦出任何问题,导致转换到了错误的物理地址,都会导致guest读写物理内存失败;本文利用这个原理,让guest对host同一块物理地址的读和写分离:第三方程序(比如CE、PChunter、某些程序自带的CRC检测功能、windows自带的patch guard等)读物理页的时候返回一个结果,执行的时候又返回一个结果,以此骗过第三方程序对物理页内容的检查,这就是业界俗称的shadow walker。此技术可用于无痕hook!
简单来说,就是针对内容的读写操作和执行操作进行监控,分别返回不同的内容。那么,在移动端,能否通过信号捕获的机制去实现次功能呢。比如将text段的代码权限设置为“只执行”,此时运行的是hook代码,而当有程序去读取text段内容的时候(比如做CRC校验),因为hook函数被设置成了“只执行”,那么此时将触发异常,通过捕获该异常信号,把text段内容进行还原并将权限设置为“只读”。这样当读取text段内容的时候只能获得原来text段的内容,当后续执行代码的时候,又将触发“只读”权限的访问异常,再次捕获此信号,将text段内容改为hook后的内容,并将权限置为“只执行”。
有了大致思路,下面开始实现此类hook。这里选择对DobbyHook框架进行改造。之前读过Dobby的源码,感觉写的很不错,又花些时间重温了一下,两个字,优秀!另外Dobby是支持Plugin拓展的,无痕hook可以以一种plugin的方式加入到框架中。
先快速实现一个demo验证思路的可行性。
修改dladdr的内容权限,将其置为只执行,但其实压根不行,这里有2个坑。
也就是说,想让代码执行,权限必须是VM_PROT_READ|VM_PROT_EXECUTE,对于这种权限的text段,那也必然是可读的。。
但是,依然可以将函数的内容设置为只读,让它可以正常被读取,而执行的时候,通过捕获权限异常,去替换成hook代码再执行。(但是想想就知道这方案效率太低,而且执行的时候也是可读的。。执行完还得把权限改回只读)
对于实现无痕hook,貌似还有一丝机会,继续探索。直到后面的信号捕获环节。
开始进行关键的信号捕获,如果使用调试器进行调试,需要注意调试器会将信号拦截,导致调试的时候信号捕获逻辑不执行。这里笔者使用的是xcode,可以通过命令pro hand -p true -s false SIGSEGV
对特定的信号进行配置,使自定义的信号捕获逻辑生效。
结果,拦截了官方的31个信号,没一个能捕获这种异常。。一开始以为这属于SIGSEGV异常,可压根就不生成这种信号,也就不从捕获了。。至此,无痕hook方案探索以失败告终。
至于为什么会想到用信号捕获去实现hook,那是因为之前看见别人用信号捕获实现过单指令hook,不愁短函数啦。dobby虽然也有单指令hook的选项,但实现的原理是利用b指令跳转,而b指令的跳转范围太小了。。
DobbyHook(dladdr, dladdr_fake, &dladdr_org);
kern_return_t kr
=
mach_vm_protect(mach_task_self(), dladdr,
1
, true, VM_PROT_EXECUTE);
DobbyHook(dladdr, dladdr_fake, &dladdr_org);
kern_return_t kr
=
mach_vm_protect(mach_task_self(), dladdr,
1
, true, VM_PROT_EXECUTE);
/
*
*
Another invalid protection value to support execute
-
only protection.
*
VM_PROT_STRIP_READ
is
a special marker that tells mprotect to
not
*
set
VM_PROT_READ. We have to do it this way because existing code
*
expects the system to
set
VM_PROT_READ
if
VM_PROT_EXECUTE
is
set
.
*
VM_PROT_EXECUTE_ONLY
is
just a convenience value to indicate that
*
the memory should be executable
and
explicitly
not
readable. It will
*
be ignored on platforms that do
not
support this
type
of protection.
*
/
/
*
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2023-8-30 11:41
被ttxx编辑
,原因: