赞
踩
Android系统由于其开源的属性,市场上针对开源代码定制的ROM参差不齐,在系统层面的安全防范和易损性都不一样,Android应用市场对app的审核相对iOS来说也比较宽泛,为很多漏洞提供了可乘之机。市场上一些主流的app虽然多少都做了一些安全防范,但由于大部分app不涉及资金安全,所以对安全的重视程度不够;而且由于安全是门系统学科,大部分app层的开发人员缺乏安全技术的积累,措施相对有限。
据了解:反编译 Android apk 现象的发生主要原因,在于开发商投入市场的Android apk包未经任何加固保护。总之就是现在的移动APP安全测试的需求迅速扩大,相关测试技能对于大家的日常工作来说是必不可少的。
本人就最近研究APP,整理了APP安全测试做了部分总结。在针对APP进行渗透测试时,业务逻辑层和web端测试大同小异,所以着重介绍APP自身所特有的漏洞:反编译、二次打包、签名校验等;
客户端:
传统逆向分析类(反编译、调试、加密/签名破解…)
用户已经中招类(输入记录、导出组件、进程注入…)
服务端:
系统组件类(MS12-020、ShellShock、心血、ST2…)
业务应用类(注入跨站越权执行上传下载弱口令…)
本章我主要介绍的本地客户端的测试,所需要的环境、工具、APK文件结构、架构、测试点等。
以下目录结构如下,本篇所涉及到的在红框范围。
2.1 客户端测试工具-工具推荐(环境准备):
JDK:因为Android应用都包含JAVA外壳,所以JAVA环境是必要的。没有JAVA,就没有apktool、Eclipse、jarsigner。
ADT:ADT中除了神器adb(Android Debug Bridge)和Monitor,还包含了Emulator虚拟机和Eclipse开发环境;另有较为新锐的替代品Android Studio。
GDB:作为大名鼎鼎的跨平台调试工具,GDB在实际测试中主要用于DUMP内存,从而发现敏感信息、解密数据、脱壳等等;
NDK:NDK可以在Windows上编译Android(arm)使用的Native层可执行文件(C/C++),各项Native层测试工具都可用NDK制作;
安卓设备:已root的真实手机/Emulator,不推荐x86虚拟机(VirtualBox/Genymotion)。x86虽然运行快,但是兼容性不佳,尤其客户APP涉及Native层时有时会出现莫名其妙的异常
模拟器选择x86的还是基于ARM架构的区别:
- ARM架构注重的是续航能力,x86架构注重的是性能;
- 在目前大部分的移动设备(只能手机,平板等)和大部分的移动终端(超市消费时候刷卡的Pos机,ATM等)都是ARM的CPU,最主要因为续航能力;
- 而大部分的台式机和笔记本电脑,则是使用x86架构的CPU,因为这些设备更需要高性能的运转和高效的运算;
- 从目前来看,android手机目前还是arm架构占绝对主流,市场调研,目前90%的android手机都是arm架构的。
2.2 客户端测试工具-工具推荐(实用功能):
BurpSuite/Fiddler:针对HTTP进行各种操作的利器
Wireshark:偶尔遇到不走HTTP的APP时,定位代码用
ApkTool:功能众多,主要用来解包和打包Apk文件
SignApk:对Apk文件进行签名,否则无法安装运行
Dex2Jar:将Dex文件转换为Jar文件,便于反编译JAVA
Smali2Java:直接从APK中反编译JAVA
JD-GUI/Luyten:可以反编译Class/Jar文件,在Dex2Jar之后使用
IDA:当APP存在Native层代码时,用于进行逆向分析
ApkTool:功能众多,主要用来解包和打包Apk文件,推荐一个图形化懒人工具:ApkIDE。
2.3 客户端测试 - 工具推荐(Xposed)
Xposed框架:
XposedBridge:JAR文件,Xposed开发所必需的接口库
XposedInstaller:APK文件,Xposed运行环境,注意5.0前后版本不同
JustTrustMe
Xposed模块,能够解除绝大多数常见SSL函数库的证书校验
注:通过修改本地客户端的方法实现的通信加密攻击不能记为风险
BlockSecureFlag:
Xposed模块,能够解除所有APP的FLAG_SECURE设置
注:适用于截屏时提示“内存不足XXXX”的场景
Surrogate:
Xposed模块,能够手动配置修改任意函数的返回值,多用于固定化随机密钥
注:灵活性不如XPOSED开发,但使用方便,适合开发基础不深的同学
2.4 客户端测试 – APK文件结构
Android应用(APK文件)通常是由以下四部分组成的:
1.清单文件(AndroidManifest.xml、/META-INF)
内含APK的包名、组件列表、启动组件、公共权限声明、各个组件的权限声明等一系列声明信息
2.Dalvik可执行文件(classes.dex、classes2.dex、…)
Java源代码->Smali中间代码->Dalvik机器码->Dalvik虚拟机->ARM/x86机器码
classes.dex中的便是Dalvik机器码
3.Native可执行文件(/lib)
其中包含很多.so链接库,多为C/C++编写而成的ARM/x86代码
可以通过JNI(Java-Native Interface)与JAVA层相互调用
4.资源文件(/assets、/res、零散放置的其它种种)
除了图片等数据性质的文件之外,还有可能会有其它三种文件
2.5 客户端测试 - 反编译保护
把apk当成zip并解压,得classes.dex
执行:dex2jar.bat classes.dex文件路径
得classes.dex.jar
使用jd-gui或luyten打开jar文件,即可得JAVA代码
jd-gui虽然搜索功能较好,但解析代码(尤其是混淆过的代码)时经常出BUG。luyten在这方面更加稳定,可以将两者结合使用。
有些APK会包含多个dex,全部转换成jar后合并压缩包即可
2.5.1 代码混淆器:开源版or商业版
混淆器可以通过一些方法来保护你的代码不被反编译,他们不会阻止反编译器或者dex2jar对你的代码进行逆向过程,但是他们会使反编译出来的代码变得更难理解,最简单的方式,他们将APK中所有的变量和方法的名字和字符串转换成一到两个字符的字符串,这就从JAVA源码中去掉了很多代码的含义,使其更难找到一些特定的信息,比如说找到一个API key 或者你存储用户登录信息的位置,好的混淆器会改变代码的流程,大多数情况下可以把业务逻辑隐藏起来,混淆器不会阻止一个一心想要破解你这个应用的黑客去理解你代码所做的事情,但他会让这个过程显得更难了。
跟很多java反编译器一样,也有很多的java混淆器,比如ProGuard,yGuard,RetroGuard,DashO,Allatori,Jshrink,Smokescreen,JODE,JaveGuard,Zelix Klassmaster,以及jCloak,这些还只是其中一小部分,甚至还有一款Android 的classes,dex混淆器,叫作Apkfuscator,你可以从http://github.com/strazzere/APKfusctor上 获取,或者你也可以试下http://shield4j.com上的Shield4j。
ProGuard是一个混淆代码的开源项目,它的主要作用是混淆代码,殊不知ProGuard还包括以下4个功能。
压缩(Shrink):检测并移除代码中无用的类、字段、方法和特性(Attribute)。
优化(Optimize):对字节码进行优化,移除无用的指令。
混淆(Obfuscate):使用a,b,c,d这样简短而无意义的名称,对类、字段和方法进行重命名。
预检(Preveirfy):在Java平台上对处理后的代码进行预检,确保加载的class文件是可执行的。
Progurad是免费的,而且已经集成到Android ADT中了,使用起来很方便。Proguard只能保护代码,却不能保护我们的apk文件。任何人都可以使用apktool工具,反编译我们开发的apk文件,进而更改其中各种资源,或者更改部分代码,甚至是注入代码,然后再打包回apk,二次发布后,达到自己的目的。或者是加入了广告,或者是增加了恶意木马病毒等。不需要multi-dex。Proguard会对输入的jar文件按照shrink - optimize - obfuscate - perverify的顺序依次进行处理,最后得到输出jar文件。Proguard使用library jars来辅助对input jars类之间的依赖关系进行解析, library jars自身不会被处理,也不会被包含到output jars中。
它能发现并删除无用类、字段(field)、方法和属性值(attribute)。它也能优化字节码 并删除无用的指令。最后,它使用简单无意义的名字来重命名你的类名、字段名和方法名。经过以上操作的jar文件会变得更小,并很难进行逆向工程。但是有耐心的攻击者仍能分析出代码结构
DexGuard 是GuardSquare公司推出的移动应用App安全软件,经过特别设计用于防止安卓系统上的应用APP与SDK遭受逆向工程与各类安全入侵的威胁
DexGuard是收费的,DexGuard是在Proguard基础上,加入了更多的保护措施。使用DexGuard混淆后,生成的apk文件,就无法正常使用apktool反编译了。尽管还是能够反编译出部分资源文件,但是由于反编译过程不完全,就无法再打包成apk了。这样就保护了我们的apk文件,不会被二次打包发布了。代码混淆力度更大 + 资源混淆 + so加壳等。自带multi-dex扫描
2.6 客户端测试 - 安装包签名
使用JDK中的jarsigner.exe检查安装包的签名:
jarsigner.exe -verify APK文件路径 -verbose -certs
2.6.1什么是通用签名?
搭建好Android开发环境后(使用Eclipse或Android Studio),对APK签名的默认密钥存在debug.keystore文件中。在linux和Mac上debug.keystore文件位置是在~/.android路径下,在windows目录下文件位置是C:\user\用户名.android路径下。
除了debug.keystore外,在AOSP发布的Android源码中,还有以下几个证书是公开的,任何人都可以获取,在源码的build/target/product/security目录中:
2.6.2通用签名风险:
(1)如果攻击者的应用包名与目标应用相同,又使用了相同的密钥对应用进行签名,攻击者的应用就可以替换掉目标应用;
(2)另外目标应用的自定义权限android:protectionlevel为“signature”或者“signatureOrSystem”时,保护就形同虚设;
(3)如果设备使用的是第三方ROM,而第三方ROM的系统也是用AOSP默认的签名,那么使用如果使用系统级签名文件签名过的应用,权限就得到了提升。
以乌云公开的WooYun-2014-67027为例,有安全研究人员发现有一个数字证书签名被很多银行的手机客户端所使用。与此同时还发现了几款个人开发者类应用也使用了此证书签名。而这种数字签名被滥用的行为存在极大的安全隐患。
解压应用安装包,可用keytool查看应用的签名证书信息: keytool -printcert -v -file META-INF/CERT.RSA
经挖掘和分析,研究人员发现目前共有23款不同银行手机银行客户端使用该签名:
在应用市场内,目前共发现6款个人开发的应用同时使用该数字证书签名:
事情发生的原因是银行的外包开发管理不严,不同银行的APP居然用同样的数字证书签名,并且开发者还将证书用于了个人APP的开发中。如果签名证书被恶意攻击者获取,可以编写安装是能直接替换掉这些银行客户端的恶意APP。
还可以使用AOSP通用签名提升应用权限: 直接编译AOSP源码得到的ROM,使用AOSP的默认证书,在设置->关于手机,版本号中可查看到:
对于普通的用默认debug.keystore证书签名的App,如果在AndroidManfiest.xml的manifest节点加入android:sharedUserId=”android.uid.system”这个属性,安装时会提示错误:
如果对app-debug.apk使用AOSP提供的platform.x509.pem和platform.pk8重新签名,则可以安装成功:
查看应用的进程属性,已是system用户组。
目前有不少的第三方ROM使用的AOSP提供的默认签名
个人开发者在往开源平台上传代码时,注意不要将签名证书的私钥上传。
2.7 客户端测试 - 完整性校验
ApkTool+SignApk:
解包后可修改并重新打包;
可查看AndroidManifest.xml;
可查看smali源码(适用于JAVA反编译失败的情况);
解包:
java -jar apktool.jar d -f apk文件路径 -o 解包目标文件夹
打包:
java -jar apktool.jar b -f 待打包的文件夹 -o 输出apk路径
APK必须进行签名后,方可安装和运行:
java -jar signapk.jar testkey.x509.pem testkey.pk8 待签名apk文件路径 签名后输出apk路径
1.用ApkTool将目标APK文件解包;
2.随便找一个解包目录里的资源文件,修改之;
3.推荐找到启动logo图进行修改(因为容易确认结果);
4.用ApkTool,将解包目录重新打包成未签名的APK文件;
5.用SignApk,对未签名的APK文件进行签名;
6.将签了名的APK安装、运行、确认是否存在自校验;
签名绕过方式:
测试。使用ApkIDE重打包后 直接安装运行,在Loading过程中会弹出修改提示,如下图,说明软件检测到了被非法修改。
下面的操作是,将官方包的RSA拖出来,置换掉我们修改后的RSA文件,名字尽量与SF保持一致即CERT,然后安装 可完美运行。
2.8 客户端测试 - 组件导出安全
什么是组件?
组件有什么用?
安卓系统的组件共有四种,其主要用途分别为:
Activity:呈现可供用户交互的界面,是最常见的组件;
Service:长时间执行后台作业,常见于监控类应用;
Content Provider:在多个APP间共享数据,比如通讯录;
Broadcast Receiver:注册特定事件,并在其发生时被激活
什么是权限声明?
安卓系统定义了许多权限声明项,分别对应一些操作系统功能
权限声明有什么用?
如果一个APP或组件在没有声明权限的情况下就调用相关API,会被拒绝访问;
但如果声明了相关权限,安装的时候就会有提示;
这样一来,用户就可以评估使用该APP可能带来的风险
什么是组件导出?
简而言之,就是别的APP也可以访问这个组件。
再总而言之,就是组件权限的控制。
组件导出有什么用?
组件导出有什么危害?
2.8.1 四大组件详细介绍
Activity是Android组件中最基本也是最为常见用的四大组件之一,是一个负责与用户交互的组件。Activity组件中存在以下常见的漏洞。 (1)activity绑定browserable与自定义协议activity设置“android.intent.category.BROWSABLE”属性并同时设置了自定义的协议android:scheme意味着可以通过浏览器使用自定义协议打开此activity。可能通过浏览器对app进行越权调用。(2)ActivityManager漏洞ActivityManager类中的killBackgroundProcesses函数,用于杀死进程,属于风险API。还有通过ActivityManager被动嗅探intent。Intent嗅探脚本首先调用一个Context.getSystemService()函数,并传给它一个ACTIVITY_SERVICE标志的标识符,该函数返回一个ActivityManager类的实例,它使得该脚本能够与activity manager进行交互,并通过这个对象调用ActivityManager.getRecentTasks()方法。最后把intent相关的信息格式化成字符串返回出来。
作为Android中四大组件之一,拥有重要的地位。Service具有和Activity一样的级别,只是没有界面,是运行于后台的服务。其他应用组件能够启动Service,并且当用户切换到另外的应用场景,Service将持续在后台运行。另外,一个组件能够绑定到一个service与之交互(IPC机制),例如,一个service可能会处理网络操作,播放音乐,操作文件I/O或者与内容提供者(content provider)交互,所有这些活动都是在后台进行。从表面上看service并不具备危害性,但实际上service可以在后台执行一些敏感的操作。Service存在的安全漏洞包括:权限提升,拒绝服务攻击。没有声明任何权限的应用即可在没有任何提示的情况下启动该服务,完成该服务所作操作,对系统安全性产生极大影响。
当应用广播接收器默认设置exported='true',导致应用可能接收到第三方恶意应用伪造的广播,利用这一漏洞,攻击者可以在用户手机通知栏上推送任意消息,通过配合其它漏洞盗取本地隐私文件和执行任意代码。Android 可以在配置文件中声明一receiver或者动态注册一个receiver来接收广播信息,攻击者假冒APP构造广播发送给被攻击的receiver,是被攻击的APP执行某些敏感行为或者返回敏感信息等,如果receiver接收到有害的数据或者命令时可能泄露数据或者做一些不当的操作,会造成用户的信息泄漏甚至是财产损失。
Content Provider为存储和获取数据提供统一的接口。可以在不同的应用程序之间共享数据。
2.8.2 组件测试工具-drozer
Drozer是MWRLabs开发的一款Android安全测试框架。是目前最好的Android安全测试工具之一。具体使用方法可参考Android安全测试框架Drozer(使用篇)。
环境准备:
1 手机获得root权限
2 adb.exe、配置android环境变量
3 手机usb连接开启debug模式(在设置>关于手机>连续点击多次版本号,即可开启开发者模式)
4 Window下安装drozer
5安装完drozer后在其目录下把agent.apk安装到手机
连接准备:
1 drozer console devices
image.png
image.png
启动drozer:adb forward tcp:31415 tcp:31415
//将pc端31415的所有数据转发到手机上的31415端口drozer console connect
//使用drozer console 连接agent
image.png
获取手机上所有安装的app包名:run app.package.list 加上”-f [app关键字]”查找某个app,如
run app.package.list -f sieve
image.png
获取sieve的基本信息
run app.package.info –a com.mwr.example.sieve
image.png
可以看到sieve的版本信息,数据存储目录,用户ID,组ID,共享库,权限等信息
run app.package.attacksurface com.mwr.example.sieve
image.png
进一步获取每个组件的攻击面信息,如activity
run app.activity.info
这条命令将导出你设备上的所有的activity
run app.activity.info -a com.mwr.example.sieve
image.png
其中. MainLoginActivity是app启动时的主界面,必须可以导出,但其他两个activity正常情况下是不能导出的
用drozer来启动可导出且不需要权限的activity
run app.activity.start --component com.mwr.example.sieve com.mwr.example.sieve.PWList
image.png
获取content provider的信息
run app.provider.info -a com.mwr.example.sieve
image.png
结合上面查看攻击面的信息,这2个content provider都可导出,com.mwr.example.sieve.DBContentProvider/Keys 是需要读写权限的
image.png
2.8.3客户端测试 - 组件导出安全配置
组件完全满足以下条件之一,则可以导出
显式声明了android:exported="true"
未显式声明android:exported="false";
组件不是Content Provider;
组件包含<intent-filter>;
未显式声明android:exported="false";
组件是Content Provider;
声明API最小版本<17;
AndroidManifest.xml
image.png
AndroidManifest.xml是Android应用的入口文件,它描述了package中暴露的组件(activities, services, 等等),他们各自的实现类,各种能被处理的数据和启动位置。 除了能声明程序中的Activities, ContentProviders, Services, 和In
android:allowClearUserData(‘true’ or ‘false’)
用户是否能选择自行清除数据,默认为true,程序管理器包含一个选择允许用户清除数据。当为true时,用户可自己清理用户数据,反之亦然
AndroidManifest.xm一些特定属性的介绍,可自行百度。下面只是几个举例:
android:allowTaskReparenting(‘true’ or ‘false’)
是否允许activity更换从属的任务,比如从短信息任务切换到浏览器任务
android:debuggable
这个从字面上就可以看出是什么作用的,当设置为true时,表明该APP在手机上可以被调试。默认为false,在false的情况下调试该APP,就会报以下错误:
- Device XXX requires that applications explicitely declare themselves as debuggable in their manifest.
- Application XXX does not have the attribute ‘debuggable’ set to TRUE in its manifest and cannot be debugged.
android:exported 是Android中的四大组件 Activity,Service,Provider,Receiver 四大组件中都会有的一个属性。
总体来说它的主要作用是:是否支持其它应用调用当前组件。
默认值:如果包含有intent-filter 默认值为true; 没有intent-filter默认值为false。
2.9 客户端测试 - 本地敏感信息安全
查看应用程序所在目录(需root权限)
一般为:/data/data/{APP包(package)名}/
如遇.db文件,多为SQLite数据库。
正常的文件权限最后三位应为空(类似“rw-rw----”),目录可以多一个执行位(类似“rwxrwx—x”)
image.png
image.png
Android系统的五种数据存储形式:
分别是文件存储、SP存储、数据库存储、contentprovider 内容提供者、网络存储
以I/O流的形式把数据存入手机内存或SD卡,可以存储大数据,如音乐、图片或视频等。对于手机内存来说系统会根据每个应用的包名创建一个/data/data/包名/的文件夹,访问自己包名下的目录是不需要权限的,并且 Android 已经提供了非常简便的 API 可以直接去访问该文件夹。访问时可以用getFilesDir()和getCacheDir(),两个的区别是系统会自动清理后者中的内容。
SD卡中的文件通常位于mnt/sdcard目录下,不同生产商生产的手机这个路径可能不同。操作sd卡的时通常要判断下sd卡是否可用以及剩余空间是否足够,因为部分手机的SD卡可卸载,SD卡处于非挂载状态时,无法进行读写操作。另外一点,对SD卡的读取和写入操作均需要相应的权限,否则无法完成。获取SD卡路径的方法是Environment.getExternalStorageDirectory(),其余操作与文件存储基本类似。
image.png
可以看到goatdroid应用的用户名和密码都以明文的形式存储在 shared preferences中SP存储本质上是一个XML文件,以键值对的形式存入手机内存中。常用于存储简单的参数设置,如登陆账号密码的存储,窗口功能状态的存储等,该存储文件位于:data/data/包名/shared_prefs文件夹中。使用的时候,首先需要通过context.getSharedPrefrences(String name,int mode)获取SharedPrefrences的实例对象,存储数据时,用SharedPrefrences的实例对象得到SharedPrefrences文件的编辑器,在编辑器中用putXxx()添加数据,之后务必用commit提交数据,否则无法获取数据。取数据时,直接用getXxx()方法。
image.png
sp存储自动生成xml文件,其的路径如下:
image.png
数据库所有信息都存储在单一文件内,占用内存小,并且支持基本SQL语法,是项目中经常被采用的一种数据存储方式,通常用于存储用户信息等,例如在手机上做一个学生信息管理系统。SQLite 是一款内置到移动设备上的轻量型的数据库,SQLiteOpenHelper 是Android 提供的一个抽象工具类,负责管理数据库的创建、升级工作。数据库的路径为:/data/data/应用包名/databases/数据库。
从手机文件中导出数据库文件并不可以直接打开,因此可以用可视化工具和sqlite3操作工具进行查看。这里介绍sqlite3工具的使用。具体需要的步骤如下:
1. 执行adb shell命令进入Linuxne内核;
2. 使用cd进入数据库所在的路径 cd: /data/data/应用包名/databases;
3. 进入数据库模式: sqlite3 数据库名.db;
4. 执行SQL语句
image.png
Content Provider,中文名是内存提供者,Android四大组件之一,内容提供者是应用程序之间共享数据的接口,以数据库形式存入手机内存,可以共享自己的数据给其他应用使用。之所以需要设计一个单独的控件来操作数据,是为了实现应用程序之间的数据传递。通过查看DDMS中的目录结构可以看出,数据库文件对于其他应用来说是不可读、不可写,而日常生活中又需要获取其他应用的数据,尤其是系统自带软件的数据。比如打开QQ或者微信时会提示是否同步联系人,又比如备份短信的时候,这些都需要访问和操作其他应用的数据库。因此谷歌工程师在底层软件中集成了大量的方法利用内存提供者的原理,类似于在数据库中提供一个对外访问的路径,供其他应用访问。
具体操作是:创建内容提供者解析器,定义要访问的Uri的路径。Uri路径有着固定的格式:”content://主机名/匹配字符”。 利用内容提供者解析器进行增删改查,和要操作的数据库之间建立联系。以上内容通常用来理解内容提供者的工作原理,实际工作中很少用到自定义的内容提示者。实际中用的比较多的是用内容提供者操作系统联系人、系统短信等系统应用的数据库。
先看一下短信和手机联系人有关的数据库所在的路径。短信在Android 模拟器下存放在的路径是:/data/data/com.android.providers.telephony/databases/目录,联系人在Android 模拟器下存放在的路径是:/data/data/com.android.providers.contacts/databases/目录。对于短信数据库我们关心的表数据有:address、type、body、date,分别表示发送者号码、短信类型(收还是发)、短信内容、日期。对于联系人数据库的三张表一定要按照一定的顺序依次查找才能得到相关的数据,在这不做解释。尽管开发的时候不需要了解短信和手机联系人的数据库路径,但是要明白短信和手机联系人的数据是存在数据库中的,同时数据库对外是不开放的。
与短信有关的数据库的目录结构:
image.png
网络存储是最容易理解的一种存储方式了。其实说简单点就是文件的上传和下载。经常听到的云备份就是这种形式。优势也很明显,即把数据存储到服务器,不存储在本地,使用的时候直接从网络获取,避免了手机端信息丢失以及其他的安全隐患。因此,对于这种形式就不作多的解释
2.10客户端测试 - 本地敏感信息安全
用logcat命令查看APP的日志
清空日志 :logcat -c
实时查看日志 :logcat
一次性输出 :logcat -d
image.png
发布APP前,去掉Log输出代码
用DDMS命令查看APP的日志
image.png
image.png
2.11 客户端测试 – 签名文件的分析检测
对apk进行签名需要用到签名证书和签名工具。Android系统要求对APP进行签名的数字证书可以由开发者自己生成。签名工具有jarsigner和signapk。jarsigner是Java本身自带的一个工具,他也可以对jar进行签名的;而signapk是专门为了Android应用程序apk进行签名的工具。二者的区别是:jarsigner工具签名时使用的是keystore签名文件,signapk工具签名时使用的是pk8,x509.pem文件。
2.11.1 签名文件分析
应用签名完后在应用的META-INF目录下会有三个文件:
CERT.RSA、CERT.SF和MANIFEST.MF。
image.png
说明:这是Android签名验证过程的第一步,保证每个APK包内的每个文件与MANIFEST.MF中的摘要值一一对应,修改某个文件内容,必须修改MANFEST.MF文件中的摘要值,使他们对应起来。
说明:这是签名认证过程的第二步,这一步做的是多第一步得到的签名文件的摘要,比如第一步中对文件和MANIFEST.MF摘要都改了,这一步中MANIFEST.MF的摘要值也要修改,否则就对应不起来。
所以,前面这两步,做的都是摘要,是为第三步骤做准备的,第三步骤才是最重要的
说明:在这一步,即使开发者修改了程序内容,并生成了新的摘要文件,MANIFEST.MF能与内容对应起来,CERT.SF也能与内容对应起来,但是攻击者没有开发者的私钥,所以不能生成正确的签名文件(CERT.RSA)。系统在对程序进行验证的时候,用开发者公钥对不正确的签名文件进行解密,得到的结果对应不起来,所以不能通过检验,不能成功安装文件。
2.11.2 签名工具使用:
jarsigner是JDK提供的针对jar包签名的通用工具, jarsigner只支持V1签名,位于JDK/bin/jarsigner.exe;
apksigner是Google官方提供的针对Android apk签名及验证的专用工具, 默认同时使用V1和V2签名,以兼容Android 7.0以下版本,位于Android SDK/build-tools/SDK版本/apksigner.bat。
不管是apk包,还是jar包,本质都是zip格式的压缩包,所以它们的签名过程都差不多(仅限V1签名),以上两个工具都可以对Android apk包进行签名。
V1和V2签名的区别:
在Android Studio中点击菜单 Build->Generate signed apk... 打包签名过程中,
可以看到两种签名选项 V1(Jar Signature) V2(Full APK Signature),
从Android 7.0开始, 谷歌增加新签名方案 V2 Scheme (APK Signature);
但Android 7.0以下版本, 只能用旧签名方案 V1 scheme (JAR signing)
V1签名:
来自JDK(jarsigner), 对zip压缩包的每个文件进行验证, 签名后还能对压缩包修改(移动/重新压缩文件)
对V1签名的apk/jar解压,在META-INF存放签名文件(MANIFEST.MF, CERT.SF, CERT.RSA),
其中MANIFEST.MF文件保存所有文件的SHA1指纹(除了META-INF文件), 由此可知: V1签名是对压缩包中单个文件签名验证
V2签名:
来自Google(apksigner), 对zip压缩包的整个文件验证, 签名后不能修改压缩包(包括zipalign),
对V2签名的apk解压,没有发现签名文件,重新压缩后V2签名就失效, 由此可知: V2签名是对整个APK签名验证
V2签名优点很明显:
查看V1和V2签名方式
一个检测apk是否支持v1、v2 签名的工具,SignApkV2 签名检测工具
直接调用:ApkSignerTool.verify(String apkPath)
命令行:
java -jar CheckAndroidSignature.jar xxxx.apk
结果:
{"ret":0,"msg":"","isV1OK":true,"isV2":true,"isV2OK":true,"keystoreMd5":"8f701cdd1c0d8856e440363185c7daf7"}
image.png
2.11.3 签名步骤
Eclipse或Android Studio在Debug时,对App签名都会使用一个默认的密钥库:
默认在C:\Users\用户名.android\debug.keystore(非安全签名)
密钥库名: debug.keystore
密钥别名: androiddebugkey
密钥库密码: android
生成密钥对
进入JDK/bin, 输入命令
keytool -genkeypair -keystore 密钥库名 -alias 密钥别名 -validity 天数 -keyalg RSA
参数:
-genkeypair 生成一条密钥对(由私钥和公钥组成)
-keystore 密钥库名字以及存储位置(默认当前目录)
-alias 密钥对的别名(密钥库可以存在多个密钥对,用于区分不同密钥对)
-validity 密钥对的有效期(单位: 天)
-keyalg 生成密钥对的算法(常用RSA/DSA,DSA只用于签名,默认采用DSA)
-delete 删除一条密钥
提示: 可重复使用此条命令,在同一密钥库中创建多条密钥对
例如:
在debug.keystore中新增一对密钥,别名是release
keytool -genkeypair -keystore debug.keystore -alias release -validity 30000
image.png
为什么报错了:
这是因为权限问题:你的jdk目录在c盘,当前用户无写入权限。
所以要么更改jdk的保存目录,要么更改权限
方法一更改保存目录:就是讲jdk从c盘挪到其它盘。
方法二更改权限:以管理员身份运行CMD。
我已管理员权限运行CMD
image.png
进入JDK/bin, 输入命令
keytool -list -v -keystore 密钥库名
参数:
-list 查看密钥列表
-v 查看密钥详情
例如:
keytool -list -v -keystore debug.keystore
image.png
现在debug.keystore密钥库中有两对密钥, 别名分别是androiddebugkey release
3.签名
方法一(jarsigner,只支持V1签名)
进入JDK/bin, 输入命令
jarsigner -keystore 密钥库名 xxx.apk 密钥别名
从JDK7开始, jarsigner默认算法是SHA256, 但Android 4.2以下不支持该算法,
所以需要修改算法, 添加参数 -digestalg SHA1 -sigalg SHA1withRSA
jarsigner -keystore 密钥库名 -digestalg SHA1 -sigalg SHA1withRSA xxx.apk 密钥别名
参数:
-digestalg 摘要算法
-sigalg 签名算法
例如:
用JDK7及以上jarsigner签名,不支持Android 4.2 以下
jarsigner -keystore debug.keystore MyApp.apk androiddebugkey
用JDK7及以上jarsigner签名,兼容Android 4.2 以下
jarsigner -keystore debug.keystore -digestalg SHA1 -sigalg SHA1withRSA MyApp.apk androiddebugkey
进入Android SDK/build-tools/SDK版本, 输入命令
apksigner sign --ks 密钥库名 --ks-key-alias 密钥别名 xxx.apk
若密钥库中有多个密钥对,则必须指定密钥别名
apksigner sign --ks 密钥库名 --ks-key-alias 密钥别名 xxx.apk
禁用V2签名
apksigner sign --v2-signing-enabled false --ks 密钥库名 xxx.apk
参数:
--ks-key-alias 密钥别名,若密钥库有一个密钥对,则可省略,反之必选
--v1-signing-enabled 是否开启V1签名,默认开启
--v2-signing-enabled 是否开启V2签名,默认开启
例如:
- 在debug.keystore密钥库只有一个密钥对
apksigner sign --ks debug.keystore MyApp.apk
在debug.keystore密钥库中有多个密钥对,所以必须指定密钥别名
apksigner sign --ks debug.keystore --ks-key-alias androiddebugkey MyApp.ap
4.签名验证
方法一(keytool,只支持V1签名校验)
进入JDK/bin, 输入命令
keytool -printcert -jarfile MyApp.apk (显示签名证书信息)
参数:
-printcert 打印证书内容
-jarfile <filename> 已签名的jar文件 或apk文件
image.png
进入Android SDK/build-tools/SDK版本, 输入命令apksigner verify -v --print-certs xxx.apk
参数:
-v, --verbose 显示详情(显示是否使用V1和V2签名)
--print-certs 显示签名证书信息
例如:
- apksigner verify -v MyApp.apk
- Verifies
- Verified using v1 scheme (JAR signing): true
- Verified using v2 scheme (APK Signature Scheme v2): true
- Number of signers: 1
image.png
image.png
Apk 包中的META-INF目录下,有一个CERT.RSA,它是一个PKCS7 格式的文件。
要查看apk签名信息及证书内容,即CERT.RSA文件,可用以下命令:
keytool -printcert -file path
APK解压后的文件,将签名文件中CERT.RSA拿出来用apktool 单独查看
image.png
image.png
2.12 客户端测试 - 键盘记录保护
常见的Android键盘记录主要依靠读取/dev/input/event0设备
需要root。
需要编写专门的Native测试工具
键盘、触屏之类均能捕获到。
也有通过注册输入法来窃听键盘的方法。
image.png
2.13 客户端测试 - 屏幕录像测试
即连续截屏,通过视觉反馈效果来窃听密码等敏感信息:
adb shell /system/bin/screencap -p 安卓设备中的输出png路径
需要root。
screencap输出到安卓设备中,不是输出到电脑中。
注意: FLAG_SECURE会妨碍screencap,敏感信息输入不提供视觉反馈
但对于root权限下直接读取屏幕缓存的方法是不起作用的,测试中不被认定为有效修复。
image.png
image.png
2.14 客户端测试 - 进程注入保护
设法在目标APP的进程空间中执行一段代码。
一般的方法是在Native层通过pTrace,让远程进程加载一个.so链接库,从而侵入目标进程空间。
需要root;
需要编写专门的Native测试工具;
GDB也使用了类似的方法来操作远程进程。
image.png
反调试技术实现复杂,一般通过加壳解决
2.15 客户端测试 - Activity/界面劫持保护
在目标APP启动时,立即弹出一个假界面覆盖之。
一般是通过Broadcast Receiver来监听目标APP的android.intent.action.BOOT_COMPLETED事件。
在JAVA层完成,不需要root
诱骗用户在假界面上操作,以获取其敏感信息,很难察觉Android 5.0以后从系统机制层面解决了这个问题,因此如果APK声明的最小API版本≥21,
此项无需测试,直接记为安全。
ApkTool解包后会产生apktool.yml,内含关于API版本的声明信息。
image.png
image.png
2.16 客户端测试 – 调试信息检测
检测程序(含服务器端和客户端)调试信息是否关闭,调试信息中是否写入敏感信息
通过运行程序,查看logcat等调试日志信息,是否有泄漏重要的URL地址、提示信息、调试信息等敏感关键字以及程序逻辑的关键流程。对于HTML页面,需要在浏览器端打开,并检查其中的JS代码等是否存留其他调试信息
这里我们用的方式是DDMS:
DDMS 的全称是Dalvik Debug Monitor Service,是 Android 开发环境中的Dalvik虚拟机调试监控服务。
这个工具存放在SDK-tools路径下,启动方法: [1]
直接双击ddms.bat运行;
在Eclipse调试程序的过程中启动DDMS
image.png
双击ddms打开
image.png
我们看到有很多日志输出,可以观察运行日志中是否带有敏感数据
然后我们找到我们要分析的那个应用包
image.png
看他的进程ID是2484
image.png
然后下面的输出进程都是2484的
image.png
实时日志中若输出调试信息,攻击者可根据输出信息分析应用程序的运行逻辑,对应用程序进行恶意破坏;也可能泄露用户敏感信息。
2.17 客户端测试 –Sqlite .db文件的导出
我们的app里面用到sqlite数据库的时候, 会生成一个db文件,保存在我们手机中。有的时候,在调试数据库,很想看一下里面的表结构是否正确,这个时候就十分苦恼,因为这个db文件不能够直接拿出来,我们知道,在DDMS里面有一个FileExplorer,它里面保存着手机中的各个文件夹,但是尝试打开里面的文件夹的时候,却发现怎么点都没有东西,是真的没有吗?其实是我们没有获取到访问这个文件夹的权限。下面我们就开始一步一步的拿到真机调试中的db文件。
DDMS可以直接看手机里文件,如图:
image.png
image.png
Data/data/应用包名databases/
image.png
image.png
我们可以看到.db文件就是他的sqllite文件。可以直接导出
如果打开文件权限不够的话,这里利用就可以利用adb直接给打开的路径授权:
比如:
进去adb 然后chmod 777 /data/data/com.demo.app/databases/
在导出.db文件后,可以本地打开.db文件,分析是否存在敏感信息
推荐工具:
image
2.18 客户端测试 – Sqlite加密检测
Android 系统的Sqlite数据库是一个轻量级且没有加密功能的数据库,但有时候我们的数据库保存了一些重要的信息,不想让别人知道,就需要对数据库加密。但大多数的加密都需要收费的,而Sqlcipher是免费的。下面我们用sqlcipher来加密数据库。
配置工程:
注意assets下的文件
image.png
我们可用工具,对APP解包后,分析.so文件,
用APK改之理解包了一个APK:
image.png
分析出Sqlite数据库已做加密,做加密后的文件.db导出后是无法打开的:
image.png
转载自安全脉搏 https://www.secpulse.com/archives/74861.html
作者:白帽札记
链接:https://www.jianshu.com/p/b43b67f1a419
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。