由于刚踏入Android逆向分析领域,因此有许多的不懂,所以得不断地去学习。
因为是入门,我又有一定的Android应用开发基础,所以先从一些简单工程的反编译开始入手,先了解一些反编译所用到的工具。
上一次写博客,记录了反编译工具dex2jar和jd-gui 的使用,这次继续记录另一款比较强大的反编译工具APKTool。
该工具的使用方法很简单,只需要在dos控制台里输入apktool d xxx.apk 则可以在当前文件夹生成一个装有该APK的smali文件夹。
通过记事本可打开smali文件,可以看到一套以smali语法写的编码,实际上就是android虚拟机Dalvik的汇编语言。
算了,本人语言表达技术不好,还是直接上图清晰明了:
第一步,编写一个简单的应用工程,并打包APK,用于下面的反编译(直接用上一次博客中用到的登录界面应用):
MainActivity.java:
public class MainActivity extends Activity { private final String ACCOUNT="samuel"; private final String PASSWORD="123456"; private EditText etAccount, etPassword; private Button btnLogin; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); etAccount=(EditText)findViewById(R.id.et_account); etPassword=(EditText)findViewById(R.id.et_password); btnLogin=(Button)findViewById(R.id.btn_login); btnLogin.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(isOK(etAccount.getText().toString(), etPassword.getText().toString())){ Toast.makeText(MainActivity.this, "登录成功", Toast.LENGTH_SHORT).show(); }else{ Toast.makeText(MainActivity.this, "登录失败", Toast.LENGTH_SHORT).show(); } } }); } private boolean isOK(String account, String password){ if(account.equals(ACCOUNT) && password.equals(PASSWORD)) return true; else return false; } }布局文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:layout_centerInParent="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="帐号:"/> <EditText android:id="@+id/et_account" android:layout_width="100dp" android:layout_height="wrap_content" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="密码:"/> <EditText android:id="@+id/et_password" android:layout_width="100dp" android:layout_height="wrap_content" /> </LinearLayout> <Button android:id="@+id/btn_login" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:text="登录"/> </LinearLayout> </RelativeLayout>
第二步,下载APKTool,下面底部附有下载连接:
第三步,dos下cd到APKTool的位置,再输入apktool d login.apk,回车进入反编译,完了后在当前文件夹下生成login文件夹,该文件夹里有smali文件:
第四步,用记事本打开login->smali中的LoginActivity.smali:
.class public Lcom/samuelzhan/logintest/LoginActivity; .super Landroid/app/Activity; # instance fields .field private final a:Ljava/lang/String; .field private final b:Ljava/lang/String; .field private c:Landroid/widget/EditText; .field private d:Landroid/widget/EditText; .field private e:Landroid/widget/Button; # direct methods .method public constructor <init>()V .locals 1 invoke-direct {p0}, Landroid/app/Activity;-><init>()V const-string v0, "samuel" iput-object v0, p0, Lcom/samuelzhan/logintest/LoginActivity;->a:Ljava/lang/String; const-string v0, "123456" iput-object v0, p0, Lcom/samuelzhan/logintest/LoginActivity;->b:Ljava/lang/String; return-void .end method .method static synthetic a(Lcom/samuelzhan/logintest/LoginActivity;)Landroid/widget/EditText; .locals 1 iget-object v0, p0, Lcom/samuelzhan/logintest/LoginActivity;->c:Landroid/widget/EditText; return-object v0 .end method .method static synthetic a(Lcom/samuelzhan/logintest/LoginActivity;Ljava/lang/String;Ljava/lang/String;)Z .locals 1 invoke-direct {p0, p1, p2}, Lcom/samuelzhan/logintest/LoginActivity;->a(Ljava/lang/String;Ljava/lang/String;)Z move-result v0 return v0 .end method .method private a(Ljava/lang/String;Ljava/lang/String;)Z .locals 1 const-string v0, "samuel" invoke-virtual {p1, v0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z move-result v0 if-eqz v0, :cond_0 const-string v0, "123456" invoke-virtual {p2, v0}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z move-result v0 if-eqz v0, :cond_0 const/4 v0, 0x1 :goto_0 return v0 :cond_0 const/4 v0, 0x0 goto :goto_0 .end method .method static synthetic b(Lcom/samuelzhan/logintest/LoginActivity;)Landroid/widget/EditText; .locals 1 iget-object v0, p0, Lcom/samuelzhan/logintest/LoginActivity;->d:Landroid/widget/EditText; return-object v0 .end method # virtual methods .method protected onCreate(Landroid/os/Bundle;)V .locals 2 invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V const v0, 0x7f040019 invoke-virtual {p0, v0}, Lcom/samuelzhan/logintest/LoginActivity;->setContentView(I)V const v0, 0x7f0c0050 invoke-virtual {p0, v0}, Lcom/samuelzhan/logintest/LoginActivity;->findViewById(I)Landroid/view/View; move-result-object v0 check-cast v0, Landroid/widget/EditText; iput-object v0, p0, Lcom/samuelzhan/logintest/LoginActivity;->c:Landroid/widget/EditText; const v0, 0x7f0c0051 invoke-virtual {p0, v0}, Lcom/samuelzhan/logintest/LoginActivity;->findViewById(I)Landroid/view/View; move-result-object v0 check-cast v0, Landroid/widget/EditText; iput-object v0, p0, Lcom/samuelzhan/logintest/LoginActivity;->d:Landroid/widget/EditText; const v0, 0x7f0c0052 invoke-virtual {p0, v0}, Lcom/samuelzhan/logintest/LoginActivity;->findViewById(I)Landroid/view/View; move-result-object v0 check-cast v0, Landroid/widget/Button; iput-object v0, p0, Lcom/samuelzhan/logintest/LoginActivity;->e:Landroid/widget/Button; iget-object v0, p0, Lcom/samuelzhan/logintest/LoginActivity;->e:Landroid/widget/Button; new-instance v1, Lcom/samuelzhan/logintest/a; invoke-direct {v1, p0}, Lcom/samuelzhan/logintest/a;-><init>(Lcom/samuelzhan/logintest/LoginActivity;)V invoke-virtual {v0, v1}, Landroid/widget/Button;->setOnClickListener(Landroid/view/View$OnClickListener;)V return-void .end method
第五步,修改smali文件,让登录系统无论帐号密码是否正确,均可以实现登录成功,即破解:
修改返回值,让它只返回0x1,即true
第六步,重新打包:
在dos下,cd到apktool.jar当前的位置,输入apktool b <刚刚反编译生成文件夹的路径>
反编译后和打包后的login文件夹会多出两个文件夹,dist里有打包后的apk
第七步,因为反编译后签名被破坏,需要重新签名才能在手机上安装:
签名工具很多,我这里使用的是Auto-sign,下面附加下载
用记事本打开批处理文件Sign.bat,并修改
修改后保存,并运行Sign.bat文件
多出一个已签名的APK,至此反编译修改smali文件重新打包的工作基本已完成,现在验证一下,是否输入任意的帐号密码也能显示登录成功。
效果图:
本来输入的帐号密码应该是 samuel 123456,现在随便输入都可以显示“登录成功”提示字符,说明破解成功了~
工具下载:APKTool & Auto-sign