移动端安全的东西很多,花样也很多,不论是从硬件架构,操作系统,还是其他安全角度来讲,每接触一项新事物,都有可能需要学习一整个生态内的安全知识。
最近开学杂事逐渐增多,就把我自己关于Android的一些学习笔记和内容整理了下发出来,以铺大饼的形式尽量囊括在入门Android安全所学习过的一些知识点,希望对大家有所帮助。ps:以下内容没有具体例子的分析,原因是其中的大部分知识点,我都是从其他师傅们的文章和代码一路学习过来的。文章也整理了一下放有我自己学习下来感觉收获较大的资源链接。总结下来,对于一个平台的逆向工程技术需要掌握的技能大致如下:操作系统的安全架构
操作系统中可执行文件格式
各类工具的使用
反汇编代码的阅读理解
调试器的使用(单独从工具中列出来以示重要性)
网络抓包工具的使用
Android端的基本安全知识
Android端的调试逆向
Android端的漏洞挖掘
apktool:可以将apk文件反编译生成smali格式的反汇编代码,也可将apktool重新编译生成apk文件。这里提醒一点就是具体厂商apktool使用会涉及到具体的资源包。学习途径:官方文档
(https://developer.android.google.cn/studio/command-line/adb?hl=zh_cn2)adb:Android sdk自带的命令行工具,用于与设备通信,便于执行各种设备操作。学习途径:官方文档配上awesome系列基本上就够用了1. 官方文档
(https://ibotpeaches.github.io/Apktool/documentation/)
2. awesome-adb
(https://github.com/mzlogin/awesome-adb)
signapk,keytool和jarsigner: 用于给apk签名的工具(在这踩过坑,建议搞清楚),这里放一条我常用的解决办法,两条命令,前者是生成自己的密钥,后者是签名,具体选项代表自查:- keytool -genkey -keystore test.keystore -alias test -keyalg RSA -validity 10000
- jarsigner -verbose -keystore test.keystore -signedjar signed.apk unsigned.apk test
jd-gui和dex2jar: 反编译工具,通常用于阅读反编译生成的java代码当然这些都是些传统的工具,推荐在熟悉这些工具的具体运作方式之后再选择高效的集成工具,比如说jadx,jeb等。App的安装途径:系统程序安装,Android市场安装,adb工具安装,SD卡安装。
App安装过程可以追踪分析Android系统程序PackageInstaller中PackageInstallerActivity来去理解,具体内容这里不再展开。
Dalvik虚拟机:其设计的初衷也许是是提高运行效率并规避与oracle的版权纠纷。4. 基于寄存器架构,有一套完整的指令集(同时有些寄存器没有用到)5. 提供了对象生命周期管理,堆栈管理,线程管理,安全和异常管理,垃圾回收等功能6. Android程序都运行在android系统进程里,每个进程对应一个Dalvik虚拟机实例Dalivik文件结构与java文件结构不同,Dalvik虚拟机通过dx工具对java类文件中常量池进行分解,消除冗余信息后在组合成新常量池。又由于Dalvik虚拟机是基于寄存器架构的,相比于基于栈架构的java虚拟机,数据访问会快很多,同时Dalvik的指令即更加精简,程序的执行速度会快些。可见Dalvik属于Android运行时环境,和核心库共同承担Android应用程序的运行工作。这里有一点需要注意就是以消息通信的角度来看又可以分成另一个架构图,其中我们常关注的是native层和java层:
Android系统启动加载内核后----> 执行init进程 ----> 启动Zygote进程 ----> 初始化Dalvik虚拟机 ---> 启动system_server进入Zygote模式,用socket等待命令 ---> Zygote收到命令后fork一个Dalvik虚拟机实例来执行程序入口函数。fork后 ---> 虚拟机通过loadClassFromDex完成装载(用gDvm.loadedClass全局哈希表存储查询类) ---> dvmVerifyCodeFlow对代码检验 ---> FindClass查找装载main方法类 ---> dvmInterpret初始化解释器并执行字节码流。以上就是Dalvik在程序执行时的要点,还有其涉及到的JIT技术和Dalvik的汇编代码内容繁杂,建议直接阅读官方文档或者相应书籍。
其中dex文件主流反汇编工具有BakSmali与Dedexer,详细的dex文件格式内容也建议直接阅读相关资料或源码,这里就出DexFile的数据结构。Struct DexFile{
DexHeader Header;
DexStringId StringIds[stringIdsSize];
DexTypeId TypeIds[typeIdsSize];
DexProtoId ProtoIds[protoIdsSize];
DexFieldID FieldIds[fileIdsSize];
DexMethodId ClassDefs[classDefsSize];
DexData Data[];
DexLink LinkData;
}
模拟器体系结构
关于模拟器体系结构的梳理
(https://bbs.pediy.com/thread-255672.htm)这个链接放在这里的原因是作者自己曾经根深蒂固地把arm和android两个概念紧紧的结合在一起了,忽略了android studio创建的模拟器是Intel x86架构的,导致踩过坑。这里说是调试而不说逆向的原因是因为逆向的内容实在是太多了,入门可以参考《android软件安全与逆向分析》,《android攻防权威指南》以及《漏洞战争》中的部分内容来学习,这里选择调试中重要的内容来介绍。姑且就分为以下两者吧。
在 smali 语法中,使用的都是寄存器,但是其在解释执行的时候,很多都会映射到栈中。通常每个smali会对应一个类。
给定一个 smali 文件,我们可以使用如下方式将 smali 文件编译为 dex 文件。
在将 smali 文件编译成 dex 文件后,我们可以进一步执行。
首先,使用 adb 将 dex 文件 push 到手机上
1. 打开设备中需要调试的apk,在cmd中运行命令 :adb shell "dumpsys activity top | grep --color=always ACTIVITY",就可以看到需要调试apk的包名、主acitivity以及进程号(或者也可以使用adb shell "dumpsys activity activities | grep xxxActivity")
2. 使用命令以debug模式启动apk:adb shell am start -D -n 包名/主activity名,然后你的设备可以看到wait for debugger3. 再一次运行第一步的命令,获取新的进程号:adb shell "dumpsys activity top | grep --color=always ACTIVITY" 或者运行命令:adb shell "ps | grep 包名"亦可4. adb forward tcp:debug端口 jdwp:apk进程号5. 以上步骤可以直接在as中logcat里选定调试进程,然后选择Attach Debugger To Android Process6. 查看与包名相关JDWP命令:adb shell "ps -t | grep -A 8 包名"7. 查看所有JDWP进程命令:adb shell "ps -t | grep -B 6 JDWP"
之前尝试用apk改之理,但是由于版本太老了有较多不方便,所以弃坑,现在我通常是apktool反编译后修改,然后再编译并使用自签名,这样也可以达到修改安装使用的效果
其加载方式有system.load和system.loadlibrary两种,前者加载绝对路径,后者加载libs下的so文件,两者都会在内部调用doload函数,其流程大致如下
doload -> nativeload -> 对应到Dalvik_java_lang_Runtime_nativeLoad-> dvmLoadNativeCode加载相应的native code -> findSharedLibEntry(判断是否已经加载了这个库以及是否是对应的class loader) --如没有加载--> dlopen打开 --> si->CallConstructors()初始化 --> 创建表且用dlsym获取对应so文件中 JNI_OnLoad 函数。静态分析 java 层:没什么好说的,理解程序逻辑去做就好了。提取 so 文件
ida 反编译 so 文件阅读 so 代码
根据 java 层的代码来分析 so 代码。
根据 so 代码的逻辑辅助整个程序的分析。
在Android studio 3.12后已经将ddms移除了,所以官方的建议是:当我们不能使用ddms时意味着我们使用jdb进行转发时无法确定具体的port,有一种方法是加载程序运行时需要的so文件,然后在一些关键函数比如jniString()函数下断,运行apk后,然后attach其进程即可。当然有时候会需要在jni_load下断,而so文件又被处理或者干脆jni_load被加密了,这时需要pull出来libdvm so文件,参考我们加载方式的流程,直接查找dvmLoadNativeCode,函数中调用dlopen加载so,返回时so已经加载且已经初始化完成,调试下就能找到。
hook的方法很多,但原理就是这么几种,同时又有对Dalvik,ART,inline,GOT等对象hook,这个有太多大佬写过各种类型的hook了,hook的框架也有许多,展开分析内容太多了,就不再累述了,这里就推荐下以frida入门。
Frida hook分为注入进程,直接在源码中修改,以及动态链接三种方式frida的交互实现大致可以这么理解:默认监听27042端口,对目标进程gadget在启动时进行阻塞,直到实现attach进程或者在使用spawn()后再resume恢复进程,当然这些状态都可以通过配置修改,也可以提前设置好过滤器将特定脚本加载到特定应用中。由于frida是个轻量级的hook框架,所以还是比较容易添加自己想要的功能,具体请看官网的frida架构图。frida有一个功能可以为我们生成一个进程而不是将它注入到运行中的进程中,它注入到Zygote中,生成我们的进程并且等待输入。即spawn是注入zygote而attach是注入当前进程。这里有遇到过的一些小坑,分别是设备检测问题和windows端的编码问题:https://github.com/frida/frida/issues/1111https://github.com/rkern/line_profiler/issues/37一直想挖Android上的漏洞,但真正上手的时候发现自己缺乏很多真实场景的经验和思路,毕竟漏洞挖掘和ctf题差距还是不一般的大(汗),于是就整理了下Android上常见的问题,尽可能的去整理些思路出来。ps:这里有一个点没有涉及,就是关于Android端会涉及到较多的抓包分析工作,但无奈我是个二进制菜鸡,就不班门弄斧的推荐了。我们都知道Android四大组件,所以这里的大部分内容来自对瘦蛟舞大佬多年前文章的阅读笔记(汗,果然小白只能玩大佬玩剩下的)
activity的生命周期
launch mode
taskAffinity
task and activity
android:exported
android:permission
onCreate(Bundle savedInstanceState)
setResult(int resultCode, Intent data)
startActivity(Intent intent)
startActivityForResult(Intent intent, int requestCode)
onActivityResult(int requestCode, int resultCode, Intent data)
setResult (int resultCode, Intent data)
getStringExtra (String name)
addFlags(int flags)
setFlags(int flags)
setPackage(String packageName)
getAction()
setAction(String action)
getData()
setData(Uri data)
getExtras()
putExtra(String name, String value)
Activity分为四种,在考虑安全时分别从创建activity和使用activity时考虑。广播接收器既可以在manifest文件中声明,也可以在代码中进行动态的创建,并以调用Context.registerReceiver()的方式注册至系统。注意关注类型 protectionlevel 权限。
sendBroadcast(intent)
sendOrderedBroadcast(intent, null, mResultReceiver, null, 0, null, null)
onReceive(Context context, Intent intent)
getResultData()
abortBroadcast()
registerReceiver()
unregisterReceiver()
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
sendStickyBroadcast(intent)
ContentProvider用来存放和获取数据并使这些数据可以被所有的应用程序访问。它们是应用程序之间共享数据的唯一方法;不包括所有Android软件包都能访问的公共储存区域。
public void addURI (String authority, String path, int code)
public static String decode (String s)
public ContentResolver getContentResolver()
public static Uri parse(String uriString)
public ParcelFileDescriptor openFile (Uri uri, String mode)
public final Cursor query(Uri uri, String[] projection,String selection, String[] selectionArgs, String sortOrder)
public final int update(Uri uri, ContentValues values, String where,String[] selectionArgs)
public final int delete(Uri url, String where, String[] selectionArgs)
public final Uri insert(Uri url, ContentValues values)
public abstract void grantUriPermission (String toPackage, Uri uri, int modeFlags) //Grant permission to access a specific Uri to another package, regardless of whether that package has general permission to access the Uri's content provider. 临时授权
public abstract void revokeUriPermission (Uri uri, int modeFlags) //Remove all permissions to access a particular content provider Uri that were previously added with grantUriPermission(String, Uri, int). 移动授权
startService与bindService两者的区别就是使Service的周期改变。由startService启动的Service必须要有stopService来结束Service,不调用stopService则会造成Activity结束了而Service还运行着。bindService启动的Service可以由unbindService来结束,也可以在Activity结束之后(onDestroy)自动结束。onStartCommand()
OnBind()
OnCreate()
OnDestroy()
public abstract boolean bindService (Intent service, ServiceConnection conn, int flags)
startService()
protected abstract void onHandleIntent (Intent intent)
public boolean onUnbind (Intent intent)
2、Content Provider文件目录遍历漏洞3、AndroidManifest.xml中AllowBackup安全检测
有bug就要有patch,所以不可避免的会涉及到热修复,同时,加壳和混淆是为了保护产权。热修复可以理解为紧急补丁但无需重新发布版本的意思,主要分为代码修复,资源修复,so库修复,框架有热修复具体内容可以从这看
(https://www.cnblogs.com/popfisher/p/8543973.html)
- 看雪学院有js api文档,当然看官方文档也很舒服
- roysue大大的系列文章
(https://github.com/r0ysue/AndroidSecurityStudy)
- 泉哥博客关于frida fuzz的一些内容
(http://riusksk.me/2019/11/30/Frida%E6%A1%86%E6%9E%B6%E5%9C%A8Fuzzing%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8/)
- project zero:Adventures in Video Conferencing系列
- 蒸米师傅的安卓七种武器hook上下篇,清晰的介绍了一个轻便的hook框架
- 瘦蛟舞大大的文章
(https://github.com/WooyunDota/DroidDrops)
- GitHub上有一个awesome mobile ctf,推荐下:awesome-mobile-CTF
(https://github.com/xtiankisutsa/awesome-mobile-CTF)
- 非虫大佬在isc 2016会议上的一份ppt,仍有很好的学习意义,github上有分享
这篇纯粹是水文,断断续续地记录下来的,本来是打算放自己博客的,但后来一想放下自己的学习笔记或许对和我一样的小白们在道路上会有所帮助,就放个帖子。下次尽可能放些漏洞挖掘,fuzz以及有意思的mobile题:)看雪ID:Dawuge
https://bbs.pediy.com/user-837839.htm
*本文由看雪论坛 Dawuge 原创,转载请注明来自看雪社区。好书推荐