安全和逆向:如何逆向分析Android程序

经过前面对各种反编译工具apktool,dx2jar,jd-gui等工具的介绍,本章节我们结合一个实际的案例,向大家讲解如何分析Android程序。 
一、分析步骤 
1.使用dex2jar和jd-gui工具分析Java反编译源码; 
2.使用apktools,反编译Smail文件。由于Smail语法单独阅读比较困难,我们可以结合Java反编译的源码进行分析; 
3.根据相关的特征和线索,修改Smail源码,使用apktools重新打包; 
4.使用jarsigner重新签名apk,安装并验证修改是否正确,重复步骤3; 
二 、案例简介 
这里我们以最简单的用户登录为案例,校验用户输入用户名和密码通过,则Toast显示Login Success!,否则Login Faild!(运行如下图): 

三、分析实践 
1.使用dex2jar和jd-gui工具分析Java反编译登录页面源码NextActivity(相关工具的使用,查看《安全和逆向》系列博客相关文章): 

2.使用apktools(相关工具的使用,查看《安全和逆向》系列博客相关文章),反编译Smail主要Smail文件(如下图): 

3.分析由Java源码可知,相关的Smail文件为NextActivity.smail和NextActivity$1.smail文件(相关Smail语法,查看《安全和逆向》系列博客相关文章),详细如下: 
NextActivity.smail文件:

.class public Lcom/qunar/hotel/NextActivity;
.super Landroid/support/v7/app/AppCompatActivity;
.source "NextActivity.java" 

# instance fields
.field private mLogin:Landroid/widget/Button;
.field private mPassword:Landroid/widget/EditText;
.field private mUser:Landroid/widget/EditText; 

# direct methods
.method public constructor <init>()V
    .locals 0
 ... ...
    return-object v0
.end method 

# virtual methods
.method protected onCreate(Landroid/os/Bundle;)V
    .locals 2
    .param p1, "aSavedInstanceState"    # Landroid/os/Bundle; 

    .prologue
    .line 23 

    invoke-super {p0, p1}, Landroid/support/v7/app/AppCompatActivity;->onCreate(Landroid/os/Bundle;)V 

    .line 24
    sget v0, Lcom/qunar/hotel/R$layout;->activity_next:I
    invoke-virtual {p0, v0}, Lcom/qunar/hotel/NextActivity;->setContentView(I)V 

    .line 26
    sget v0, Lcom/qunar/hotel/R$id;->user:I
    invoke-virtual {p0, v0}, Lcom/qunar/hotel/NextActivity;->findViewById(I)Landroid/view/View;
    move-result-object v0
    check-cast v0, Landroid/widget/EditText;
    iput-object v0, p0, Lcom/qunar/hotel/NextActivity;->mUser:Landroid/widget/EditText; 

    .line 27
    sget v0, Lcom/qunar/hotel/R$id;->password:I
    invoke-virtual {p0, v0}, Lcom/qunar/hotel/NextActivity;->findViewById(I)Landroid/view/View;
    move-result-object v0
    check-cast v0, Landroid/widget/EditText;
    iput-object v0, p0, Lcom/qunar/hotel/NextActivity;->mPassword:Landroid/widget/EditText; 

    .line 28
    sget v0, Lcom/qunar/hotel/R$id;->login:I
    invoke-virtual {p0, v0}, Lcom/qunar/hotel/NextActivity;->findViewById(I)Landroid/view/View;
    move-result-object v0
    check-cast v0, Landroid/widget/Button;
    iput-object v0, p0, Lcom/qunar/hotel/NextActivity;->mLogin:Landroid/widget/Button; 

    .line 30
    iget-object v0, p0, Lcom/qunar/hotel/NextActivity;->mLogin:Landroid/widget/Button;
    new-instance v1, Lcom/qunar/hotel/NextActivity$1;
    invoke-direct {v1, p0}, Lcom/qunar/hotel/NextActivity$1;-><init>(Lcom/qunar/hotel/NextActivity;)V
    invoke-virtual {v0, v1}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V 

    .line 40
    return-void
.end method

NextActivity#1.smail文件:

.class Lcom/qunar/hotel/NextActivity$1;
.super Ljava/lang/Object;
.source "NextActivity.java" 

# interfaces
.implements Landroid/view/View$OnClickListener; 

# annotations
.annotation system Ldalvik/annotation/EnclosingMethod;
    value = Lcom/qunar/hotel/NextActivity;->onCreate(Landroid/os/Bundle;)V
.end annotation 

.annotation system Ldalvik/annotation/InnerClass;
    accessFlags = 0x0
    name = null
.end annotation 

# instance fields
.field final synthetic this$0:Lcom/qunar/hotel/NextActivity; 

# direct methods
.method constructor <init>(Lcom/qunar/hotel/NextActivity;)V
    .locals 0
    .param p1, "this$0"    # Lcom/qunar/hotel/NextActivity; 

    .prologue
    .line 30 

    iput-object p1, p0, Lcom/qunar/hotel/NextActivity$1;->this$0:Lcom/qunar/hotel/NextActivity;
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V 

    return-void
.end method 

# virtual methods
.method public onClick(Landroid/view/View;)V
    .locals 4
    .param p1, "aView"    # Landroid/view/View; 

    .prologue
    const/4 v3, 0x0 

    //判断用户名和密码的正确性
    .line 33
    iget-object v0, p0, Lcom/qunar/hotel/NextActivity$1;->this$0:Lcom/qunar/hotel/NextActivity;
    # getter for: Lcom/qunar/hotel/NextActivity;->mUser:Landroid/widget/EditText;
    invoke-static {v0}, Lcom/qunar/hotel/NextActivity;->access$000(Lcom/qunar/hotel/NextActivity;)Landroid/widget/EditText;
    move-result-object v0
    invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
    move-result-object v0
    invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String;
    move-result-object v0
    const-string v1, "user"
    invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
    move-result v0
    //如果equals方法返回true
    if-eqz v0, :cond_0
    iget-object v0, p0, Lcom/qunar/hotel/NextActivity$1;->this$0:Lcom/qunar/hotel/NextActivity;
    # getter for: Lcom/qunar/hotel/NextActivity;->mPassword:Landroid/widget/EditText;
    invoke-static {v0}, Lcom/qunar/hotel/NextActivity;->access$100(Lcom/qunar/hotel/NextActivity;)Landroid/widget/EditText;
    move-result-object v0
    invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
    move-result-object v0
    invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String;
    move-result-object v0
    const-string v1, "123456"
    invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
    move-result v0
    //如果equals方法返回true
    if-eqz v0, :cond_0 

    //登录成功弹出Login Scuess Tost提示
    .line 34
    iget-object v0, p0, Lcom/qunar/hotel/NextActivity$1;->this$0:Lcom/qunar/hotel/NextActivity;
    invoke-virtual {v0}, Lcom/qunar/hotel/NextActivity;->getApplication()Landroid/app/Application;
    move-result-object v0
    iget-object v1, p0, Lcom/qunar/hotel/NextActivity$1;->this$0:Lcom/qunar/hotel/NextActivity;
    invoke-virtual {v1}, Lcom/qunar/hotel/NextActivity;->getResources()Landroid/content/res/Resources;
    move-result-object v1
    sget v2, Lcom/qunar/hotel/R$string;->login_success:I
    invoke-virtual {v1, v2}, Landroid/content/res/Resources;->getString(I)Ljava/lang/String;
    move-result-object v1
    invoke-static {v0, v1, v3}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
    move-result-object v0
    invoke-virtual {v0}, Landroid/widget/Toast;->show()V 

    .line 38
    :goto_0
    return-void 

    //登录失败弹出Login Faild Tost提示
    .line 36
    :cond_0
    iget-object v0, p0, Lcom/qunar/hotel/NextActivity$1;->this$0:Lcom/qunar/hotel/NextActivity;
    invoke-virtual {v0}, Lcom/qunar/hotel/NextActivity;->getApplication()Landroid/app/Application;
    move-result-object v0
    iget-object v1, p0, Lcom/qunar/hotel/NextActivity$1;->this$0:Lcom/qunar/hotel/NextActivity;
    invoke-virtual {v1}, Lcom/qunar/hotel/NextActivity;->getResources()Landroid/content/res/Resources;
    move-result-object v1
    sget v2, Lcom/qunar/hotel/R$string;->login_faild:I
    invoke-virtual {v1, v2}, Landroid/content/res/Resources;->getString(I)Ljava/lang/String;
    move-result-object v1
    invoke-static {v0, v1, v3}, Landroid/widget/Toast;->makeText(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;
    move-result-object v0
    invoke-virtual {v0}, Landroid/widget/Toast;->show()V
    goto :goto_0
.end method 

4.分析相关Smail和Java文件,通过相关login_success,Toast,equals等关键字,阅读出基本的代码逻辑。该案例在Java源码中已经清晰得出用户名和密码为user,123456,这里我们演示如何通过分析修改smail文件“破译”。阅读关键代码如下,我们可以将if(mUser.getText().toString().equals("user"))语句修改为if("user".equals("user")),同理if("12345".equals("123456")),即invoke-virtual {v0, v1}修改为invoke-virtual {v1, v1}即可“绕过”用户名和密码验证。实际开发情况会比较复杂,这里我们仅仅简单修改用于演示分析过程;

//mUser.getText()
invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
move-result-object v0
//mUser.getText().toString()
invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String;
move-result-object v0
const-string v1, "user"
//if(mUser.getText().toString.equals("user"))
invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v0
//if(mUser.getText().toString.equals("user") == true)
if-eqz v0, :cond_0 

5.重新打包并签名apk(相关工具的使用,查看《安全和逆向》系列博客相关文章),安装后验证如下图,成功“绕过”用户名和密码验证; 

时间: 2024-11-07 18:27:30

安全和逆向:如何逆向分析Android程序的相关文章

Chapter2——如何分析Android程序(一)

前几天买了<Android软件安全与逆向分析>这本书,决定在这里记一些笔记. 第一章介绍了如何搭建环境,此处略去:第二章开始讲分析Android程序. 下面按顺序记录关键内容. -------------------------------------- 2.1.编写一个需要填写注册码的APK 要破解要现有「试验品」,作者编写了一个叫做crackme02的APP, 主要代码有: MessageDigest digest = MessageDigest.getInstance("MD5

在Eclipse中使用MAT分析Android程序内存使用状况(转)

对于Android这种手持设备来说,通常不会带有太大的内存,而且一般用户都是长时间不重启手机,所以编写程序的时候必须要非常小心的使用内存,尽量避免有内存泄露的问题出现.通常分析程序中潜在内存泄露的问题是一件很有难度的工作,一般都是由团队中的资深工程师负责,而且随着程序代码量的提高,难度还会逐步加大. 今天要介绍一个在Eclipse中使用的内存分析工具——MAT(Eclipse Memory Analyzer,主页在http://www.eclipse.org/mat/).它是一个功能非常丰富的J

【Bugly干货分享】手把手教你逆向分析 Android 程序

很多人写文章,喜欢把什么行业现状啊,研究现状啊什么的写了一大通,感觉好像在写毕业论文似的,我这不废话,先直接上几个图,感受一下. 第一张图是在把代码注入到地图里面,启动首页的时候弹出个浮窗,下载网络的图片,苍老师你们不会不认识吧? 第二张图是微信运动步数作弊,6不6?ok,那我们从头说起 1.反编译 Android 的反编译,相信大家都应该有所了解,apktool.JEB 等工具我们先看一下 Apk 文件的结构吧,如下图: 1.META-INF:签名文件(这个是如何生成的后面会提到)2.res:

分析Android程序之破解第一个程序

破解Android程序通常的方法是将apk文件利用ApkTool反编译,生成Smali格式的反汇编代码,然后阅读Smali文件的代码来理解程序的运行机制,找到程序的突破口进行修改,最后使用ApkTool重新编译生成apk文件并签名,最后运行测试,如此循环,直至程序被成功破解. 1. 反编译APK文件 ApkTool是跨平台的工具,可以在windows平台与linux平台下直接使用.使用前到:http://code.google.com/p/android-apktool/  下载ApkTool,

如何分析Android程序之破解第一个程序

破解Android程序通常的方法是将apk文件利用ApkTool反编译,生成Smali格式的反汇编代码,然后阅读Smali文件的代码来理解程序的运行机制,找到程序的突破口进行修改,最后使用ApkTool重新编译生成apk文件并签名,最后运行测试,如此循环,直至程序被成功破解. 1. 反编译APK文件 ApkTool是跨平台的工具,可以在windows平台与linux平台下直接使用.使用前到:http://code.google.com/p/android-apktool/  下载ApkTool,

如何用MAT分析Android程序的内存泄露

本文结合<Android开发艺术探索>书籍中的内存分析例子来讲解如何利用MAT工具来查找内存泄漏(以AndroidStudio开发工具为例). 1.下载MAT(Eclipse Memory Analyzer)工具,windows64位网盘下载地址:http://pan.baidu.com/s/1pLlbOBD,或者通过官网下载:https://www.eclipse.org/mat/downloads.php,下载完毕后解压即可,目录结构如下: 2.模拟内存泄漏的场景,源码如下,启动退出三次a

如何使用MAT分析Android程序的内存问题

 Please refer to https://developer.android.com/tools/debugging/debugging-memory.html,http://android-developers.blogspot.com/2011/03/memory-analysis-for-android.html. In DDMS, got an Android  HPROF file. Run SDK tool hprof-conv.exe to convert the An

Android程序backtrace分析方法

如何分析Android程序的backtrace 最近碰到Android apk crash的问题,单从log很难定位.从tombstone里面得到下面的backtrace. *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***Build fingerprint: 'Android/msm8996/msm8996:7.1.2/N2G47H/20180921.193127:userdebug/test-keys'Revisio

Android 程序结构

Android程序在创建时,Android Studio就为其构建了基本结构,设计者可以在此结构上开发应用程序,因此掌握Android程序结构是很有必要的. 下面以HelloWorid程序为例,分析Android 程序结构: 在图中,可以看到一个Android程序由多个文件以及文件夹组成,这些文件分别用于不同的功能,具体分析如下: manifests 用于存放AndroidManifest xml文件(又称清单文件).该文件是整个项目的配置文件.在程序中定义的四大组件都需要在这个文件中注册,另外