随便记一点学习的内容,凭感觉写的可能有误,主要是懂个大概就行,一时半会也摸不到内核里面的操作,还是使用各种框架、工具的脚本小子。
开始的想法
首先想要通过外部调试安卓应用:frida、xposed这种工具够用,一般是通过jadx或者是别的il2cppdump获取到应用运行时的类,然后进行插桩、hook、查看函数调用链、篡改程序执行行为这些,感觉能找到关键类在哪里就够用。
所以了解要怎么找到对应的函数、以及这两个工具的运行原理就变得重要。下面一点一点来。
两个工具的原理、区别
Frida
Frida是通过进程注入:ptrace系统调用或者其他注入技术,将Frida的引擎注入到目标进程中,提供修改的入口,并通过inlinehook来实现的调试。Frida的引擎里面就包含了Javascript的V8/QuickJS引擎、允许使用js编写hook脚本,而动态插桩是通过在运行时修改函数的机器码,插入jump命令拦截函数调用后再恢复 原调用 实现的。
听起来就像 Windows 里面的 远程线程注入、再inlinehook,作为动态调试的工具十分方便。
Xposed
Xposed是在Zygote fork进程时加载,相当于DLL劫持,把自身的模块功能插入到应用里面执行,一般不适合调试的时候使用、而是作为最终 补丁/插件 打到应用中,要求必须有ROOT权限的环境,相较于frida的进程注入也更加容易被检测。
继续深入了解Android架构
操作系统间的区别:
与Linux、Windows不太一样的是,安卓的进程分配比较效率:从主Zygote (受精卵) 里面fork(孵化)出来,并继承android framework的类,通过反射获取其他共享只读内存资源、相当于直接传递指针数据,不需要创建更多新内存空间,所以效率非常高。
Linux中的进程都是独立的个体,Windows也最多共享DLL,到了安卓就是共享整个framework。
关于Framework:
我的理解就是:共享的动态链接库,相当于Kernel.dll(当然framework之上还有一层Linux架构,这个并非真的Kernel),里面包含了很多系统调用类。在开发安卓应用的时候使得开发者无需关心底层实现,只需要调用framework中的类、就可以让同样的代码运行在不同的手机上,结合之前Xposed的原理、以及安卓应用启动的了解可以得出安卓应用进程的启动链:
Zygote收到frok信号 -> (这一段可以注入Xposed模块) -> 继承framework的类(指针数据) -> 载入应用自身的类 -> 进程成功创建 (-> Frida远程注入进程来修改执行)
不同进程之间的通信是通过Binder来实现的,类似于linux中的socket/pipe、windows的远程线程调用。理解这个之后很多安卓攻防也就懂个大概了,应用层、native层的对抗不就是windows的R0、R3对抗吗?只要有了firda这样进程注入的工具可以访问到内存、也就可以像CE一样动态修改应用里面的数据。
这么强大的功能当然需要Root
在Android系统里面的系统安全主要是由SELinux来负责的,管理了不同应用有什么不同的权限,能够干哪些事情,这块目前而言笔者比较模糊:像Magisk这种Root应用实现原理就是在boot启动阶段通过系统漏洞去强行获得Root账户的权限,相当于以管理员账户登录windows,而在Magisk的框架下就允许使用模块去修改内核的执行行为(层层套娃:Xposed修改应用的framework,Magisk修改系统的内核允许Xposed修改应用的framework)。
大致攻防:
有了framework这个应用运行基础,安卓应用能够执行的行为非常有限:无法直接访问硬件、无法直接查看系统敏感信息、要向其他应用交互还得发个请求什么的,
一般应用开发的话:Java层就有点类似于 前端页面js、html什么的都塞在里面,而native层就有点类似于 游戏引擎负责底层操作、跨平台复用、敏感数据调用,
总而言之
大概有了这个背景知识了解之后,对安卓逆向就没有那么陌生了,一切像回家一样。