編輯:關於Android編程
由於剛踏入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; } }布局文件:
第二步,下載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()V .locals 1 invoke-direct {p0}, Landroid/app/Activity;-> ()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;-> (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,現在隨便輸入都可以顯示“登錄成功”提示字符,說明破解成功了~
ShaderShader是一個基類,表示在繪制期間顏色的水平跨度它的子類被嵌入在Paint中使用,調用paint.setShader(shader)。除Bit
單純使用GridView通用的兩種給GridView 添加分割線的方法;http://stackoverflow.com/questions/7132030/androi
本篇博客給大家分享一個效果比較好的側滑菜單的Demo,實現點擊左邊菜單切換Fragment。效果如下: 主Activity代碼:package com.infz
Android aapt自動打包工具概念在Android.mk中有LOCAL_AAPT_FLAGS配置項,在gradle中也有aaptOptions,那麼aapt到底是干