cover_image

Android逆向工程之“矛”-攻击篇

唐湘良 三七互娱技术团队
2023年05月08日 09:28

         图片

一、Android逆向工程   

特别提示:本文只为更好的防范可能的攻击做技术上的讨论,破解他人的App获取非法利益属于违法行为,请慎重!

逆向工程(reverse engine)是拆解软件应用程序以了解其工作原理,并对其进行修改的过程。可用于多种目的,例如分析安全漏洞、研究应用程序的内部工作流程,或自定义修改。最终是使应用内部工作流程符合自己的预期。
其实逆向工程在安卓中的应用,生活中也经常会遇到,例如各种汉化的软件,破解版游戏等,就是使用了逆向工程相关技能。
一个典型逆向工程的流程如下图所示:

图片

1、拿到要拆解的目标文件。在安卓中一般是apk文件。

2、反编译拆解apk包。这一步会借用一些第三方的拆解工具,例如脱壳,apktool反编译dex和res资源,将dex文件反编译为jar包等。

3、分析源码逻辑,修改中间文件,达成修改目的。修改的方式丰富多样,相关的工具也是百花齐放,这一步也是逆向工程攻防对抗最关键的地方。例如apktool反编译后会生成Smali文件,可以在里面插入一些自定义代码,例如输出关键结果的log,或直接修改某个逻辑条件,例如在针对SO文件调试分析时,可以借助IDA工具,这里又会涉及到关于调试debug开关的对抗等。

4、代码修改完成后,需要回编译重新生成apk包,这时生成的包可能是没有签名sign的,需要重新签名以支持安装。

5、调试修改的apk应用,循环应用上述流程,直到达成修改目标。



二、逆向工程之 “矛”  

知己知彼,百战不殆 - 《孙子兵法·谋攻篇》

只有对攻击手段有充分的了解,才能更好应对App安全问题,做好防御措施。以下详细描述逆向工程拆解包的流程:

1、获取Apk目标文件  

在针对Apk的攻击中,第一步就是要获取其 APK(Android Package Kit)文件,如果有apk包链接可以直接下载,那直接下载到本地就好,但如果应用只安装在你的手机中,又找不到对应的下载包时,该如何处理呢?我们可以通过 adb(Android Debug Bridge) 相关命令来获取apk文件:
先确保手机正常链接,能使用adb环境
# 显示已连接adb的设备列表$ adb devices
>>>输出:List of devices attachedMDX5T20911002698 device

此时在控制台输出了已处于连接状态的我的设备MDX5T20911002698。接下来我们以设备已安装的《微信》App为例,获取到当前版本的Apk文件:

# 1. 打开目标应用,获取当前应用的相关包名adb shell dumpsys window | grep mCurrentFocus# [window:adb shell dumpsys window | findstr mCurrentFocus]
>>>输出: mCurrentFocus=Window{4c1c551 u128 com.tencent.mm/com.tencent.mm.ui.LauncherUI}

命令正常执行的话,应该可以拿到微信app的包名:com.tencent.mm,下一步我们将apk包从设备拉取到本地:    

# 2. 获取对应包名在设备中的apk包路径adb shell pm path com.tencent.mm
>>>输出:package:/data/app/~~LAjt0dVDv2d3IFq1WbamYA==/com.tencent.mm-G2ejabdWZcEqDZJFvaw-1g==/base.apk
# 3. 将相关apk包,下载到本地设备adb pull /data/app/~~LAjt0dVDv2d3IFq1WbamYA==/com.tencent.mm-G2ejabdWZcEqDZJFvaw-1g==/base.apk ./
>>>输出:1 file pulled. 35.4 MB/s (249620210 bytes in 6.731s)

此时,在执行adb命令的目录,已获取到微信App对应的 base.apk 文件。

2、分析Apk文件  

拿到apk文件后,下一步就是进行分析。分析之前先来看下apk包的结构:

图片

一个典型的apk文件,包括:
AndroidManifest.xml清单文件每个应用都必须包含。描述了应用的名字,版本,权限,引用的库文件,该xml文件是编译过的,需要借助工具反编译。
classes.dex是Android平台能被虚拟机识别的可执行文件,包括所有java文件编译后的字节码,在apk中可能有1个或者多个dex文件,是逆向工程的重点关注目
res目录,包括了所有的layout、drawable等资源文件,平时看到的汉化、改应用名称,就是通过修改该目录的资源文件来实现的。目录里面的xml文件是编译过的,需要借助工具反编译。
lib目录,存放的是对应cpu架构的so文件。so文件也是逆向工程中的重点,大部分核心逻辑在so文件中实现。
assets目录,存放的是一些配置文件,也可以是音视频资源,和res的主要区别是放这里的文件不会经过编译,可以直接查看。
resources.arsc,编译后的二进制资源文件,本质是一个映射着资源和id的映射表,通过R文件中的id就可以找到对应的资源。
META-INF目录,存放的签名信息,用来保证apk包的完整性和系统的安全,同包名但不同签名的apk,在Android系统中不能被覆盖安装。
其中dex文件和so文件,涉及到程序的逻辑,是我们要关注的核心。而要将虚拟机识别的dex文件解析为人类能识别的代码逻辑,可以借助一些常用的查看apk源码的集成工具,例如 Jadx、JD-GUI、Jeb、AndroidKiller 等。

Jadx,一款可以将Dex文件转为Java代码的可视化工具,支持apk、aab、aar等文件,也支持GUI可视化和CMD命令行两种模式。
工具主页(https://github.com/skylot/jadx/releases
直接拖动apk文件到界面即可,提供了搜索、查看引用、debug等丰富功能。

图片

JD-GUI,一款能查看class文件对应java源码的GUI可视化工具。
工具主页(https://github.com/java-decompiler/jd-gui
相比jadx,比较方便查看jar包的源码。

图片

JEB、AndroidKiller大同小异,自行下载探索。
借助这些工具,可以轻易以关键字定位搜索到相应的class、res,进一步梳理相关核心逻辑,拿到关键突破点,这些点一般包括接口加解密方法、业务key、核心判断条件等。

3、反编译Apk文件  

按逆向工程的流程,当定位到要修改的核心类文件路径后,就可以尝试修改包原有的逻辑了。
修改Java层的逻辑,需要处理dex文件,这里借用Apktool 工具先将apk包反编译,修改处理后再回编译成apk。Apktool 工具会将apk包中的dex文件反编译成Smali文件(Smali 是 Android 的虚拟机所使用的一种 dex 格式的中间语言),同时也会反编译res和清单文件,变成可读版本。
3.1、Apktool工具和使用   
从其网站 ( https://ibotpeaches.github.io/Apktool/ )下载并安装最新版本的 apktool 
可以使用以下命令反编译APK:
# 默认反编译dex文件和resapktool d app.apk
# 也可以支持只反编译dex,保留resapktool d -s app.apk
#或者只反编译res,保留dexapktool d -r app.apk

按默认设置反编译后的目录如下:

 图片

可以看到dex文件被反编译为多个smali目录,smali开头的目录对应apk包里的多个classes.dex文件。smali目录里的文件路径和代码是一致的,按路径找到要修改的smali文件就可以尝试修改了。
3.2、Smali 文件格式  
在修改 Smali 前先了解下 Smali 是啥东西。以下是一个com/gameapp/sqwy/BuildConfig.java 路径下的java文件生成的对应 Smali:
# class.class public final Lcom/gameapp/sqwy/BuildConfig;.super Ljava/lang/Object;.source "BuildConfig.java"  # static fields.field public static final APK_SUFFIX:Ljava/lang/String; = "base"  .field public static final APPLICATION_ID:Ljava/lang/String; = "com.gameapp.sqwy"  .field public static final BUILD_TYPE:Ljava/lang/String; = "release"  .field public static final DEBUG:Z = true  .field public static final VERSION_CODE:I = 0x5a  .field public static final VERSION_NAME:Ljava/lang/String; = "2.6.2"  # direct methods.method public constructor <init>()V   .locals 0     .line 6   invoke-direct {p0}, Ljava/lang/Object;-><init>()V     return-void.end method


可以看到 Smali 由类声明区、字段区、方法区构成,其中都涉及到各种字节码类型的描述符,

如下表:

图片

类声明区。Java 中的对象在 Smali 中都是以Lpackage/name/ObjectName; 的形式来表示,在上面的Smali实例 Lcom/gameapp/sqwy/BuildConfig,其中前面的L 表示这是一个对象类型, com/gameapp/sqwy/ 表示该对象所在的包路径,BuildConfig 是对象的名字,表示对象名称的结束。

字段区。即 java 中类的成员变量,表示格式实例:APK_SUFFIX:Ljava/lang/String; = "base",字段名与字段类型是以冒号 : 分隔,其中冒号后的 Ljava/lang/String 表示该字段的类型。

方法区。方法的声明以 .method 开头,.end method 结尾,方法的调用示例:invoke-direct {p0}, Ljava/lang/Object;->()V,其中 invoke-direct 标识直接调用该方法。关于smali修改用到的常用指令,可以参考下表来修改:


图片图片

3.3、定位分析方式   
核心信息查找法
可以以关键字全局搜索,定位到要修改的信息,信息包括res中的资源名、toast弹出的文案、变量名称等。
代码动态调试法
可以在指定位置,强制抛出Exception的方式来定位调用的堆栈。
代码注入法
先用java在demo中写log输出代码,然后反编译demo,将封装的方法手动注入到指定的 Smali 逻辑中。例如有一个java的log工具类,类路径为: com.test.utils.LogUtils,方法名为 debug(Object o)
#Obj 为需要打印的变量invoke-static {Obj}, Lcom/test/utils/LogUtils;->debug(Ljava/lang/Object;)V


4、回编译   

当完成 Smali 或者so里面代码逻辑的定位和修改后,就可以继续使用apktool工具将包回编译生成apk文件,命令如下:


apktool b you-compile-dir
该命令会在你的反编译缓存目录生成dist文件夹,最终生成的apk文件会输出到里面。要注意此apk是未签名的apk,需要进行重新签名。

5、重签名  

未签名的应用是无法安装到安卓系统的,所以在回编译完成后,需要使用jarsigner工具完成最终签名,命令如下:
jarsigner-keystore ./YOU_KEYSTORE_FILE.jks-storepass PASSWORD-keypass PASSWORD-signedjar XXX_signed.apk XXX.apk SIGN_ALIAS-digestalg SHA1 -sigalg SHA1withRSA

 最终生成一个已签名的apk文件,可以正常安装到设备中测试功能了。

三、总结  

本文讲解了逆向工程大概的攻击流程,带大家了解逆向工程攻击的情况,只是作为基础入门,真正的攻防策略比这更复杂,每一步骤都有更深入的应用。攻防策略总是在不断对抗中升级进化,在我们日常的Android开发中,了解常用的攻防手段,才能做到成竹在胸,做出安全高质量的产品。

图片
引用资料:
1、https://aglowiditsolutions.com/blog/protect-android-app-from-reverse-engineering/
2、https://github.com/baidurom/tutorials/blob/master/Tutor-Smali-Grammar.pdf
3、https://code.google.com/p/smali/

继续滑动看下一个
三七互娱技术团队
向上滑动看下一个