Brief
随着隐私越来越受到大家关注,对于设备信息的获取越来越困难。同时,一些基于Hook制作的隐私监控工具会将一些常见的获取隐私数据的接口全部都hook掉;为了能更加隐蔽的拿到这些设备ID,窃闻某些APP采用“SVC”指令的方式来获取一些设备唯一ID,感觉很有趣的样子。于是自己写了一些DEMO来体验这一新奇的方式,同时也思考下这种方式给未来检测场景带来的挑战;
什么是利用SVC来获取设备唯一ID
我们知道在Android上有许多可以作为设备指纹的id,都是存储在文件系统中的。采集这些ID可以使用Android提供的一些系统接口来获取,也可以直接通过读取相应文件的方式。而文件读取的操作,最终都会走到libc的open
函数打开文件、read
函数读取文件。那么通过Frida hook住libc中的相应关键方法就可以方便的时刻记录进程的文件操作了。
那么,有没有方法可以绕过这些函数而实现文件的读写操作呢?
以openat
方法为例,看下其实现的过程:
1 | .text:00000000000DDDA0 __openat ; CODE XREF: open64+D4↑p |
最后的最后,libc中的这些函数都会相应的syscall来依赖内核来完成相应的功能。通过unistd.h
文件可以了解全部可以被使用的系统调用(前提是没有secomp等机制的拦截)。因此,如果我们绕开libc中的相应函数,而直接采用使用syscall来完成相应调用的话,就可以绕开一些Hook工具而直接获取到我们想要的内容了。
由于,在ARM架构中,最后都是通过SVC来完成内核陷入。因此才有了本章节标题的这种奇怪称呼。不过通过上面的描述,应该大体了解我要做什么了。
Demos
我测试了两种比较典型的直接使用系统调用来完成libc中函数的调用。
由于需要避免调用libc中的函数,需要写一些汇编代码来完成syscall的调用,比较简单的可以直接将syscall.S
引入到项目中来编译。这里我直接写了一个函数来“包裹”syscall的调用:
1 | size_t inline raw_syscall(size_t a, size_t b, ...) { |
Demo 1: 文件读写函数重写
我们以存储着IP地址的/sys/class/net/p2p0/address
为例:
1 | int main(int argc, char** argv) { |
Demo 2 : Socket 读写函数的重写
这个Demo的灵感来源是不久前在Github上关注到的一个项目,在Android Native中利用NetLink提供的接口来获取MAC地址;在ifaddrs.h
中提供了一个函数getifaddrs
可以获取到ifconfig
拿到的内容,仅需简单解析下就可以获取到MAC地址:
1 | void normal_get_mac() { |
通过AOSP提供的代码,可以获取到netlink相关的源代码:http://aospxref.com/android-10.0.0_r47/xref/bionic/libc/bionic/
1 | int mgetifaddrs(ifaddrs** out) { |
官方的接口通过NetlinkConnection
创建了一个socket来获取信息,其中SendRequest发送请求,ReadResponses来读取返回内容。因此改写ReadResponses如下:
1 | bool NetlinkConnection::ReadResponses(void callback(void*, nlmsghdr*), void* out) { |
一些额外的思考
使用上述的方式来采集一些设备信息,确实可以更加隐蔽且更加具有迷惑性。配合一些成熟代码混淆的技术,很难发现其采集设备信息的行为。但是,syscall本身同样可以作为一个用于监控的特征,后面,我也将尝试利用Frida框架来实现通用的监控方案。
除了提供隐蔽性以外,改方式并没有其他的作用。简单的说,它并不能实现访问原本无法访问到的数据。原本没有读取权限的文件仍然无法读取,通过netlink获取的MAC地址也仍然会收到随机MAC地址的影响。
最后,与我本人而言,这次经历还是稍微恢复了点点编码技术,也提升了点点IDA调试技巧。