Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android apk反編譯:Smali語法入門教程

Android apk反編譯:Smali語法入門教程

編輯:關於Android編程

0x01 smali生成
使用apktool反編譯apk後,會在反編譯工程目錄下生成一個smali文件夾


其中android下存放所調用庫的smali文件,com才是我們自己寫的代碼的smali文件。
0x02 基礎語法
a.文件基本格式
基本信息
.class 
.super
.source
# eg.
.class
 public Lcom/reoky/crackme/challengeone/activities/ChallengeActivity;   
                                                                       
.super
 Landroid/support/v4/app/FragmentActivity;                             
                                                                        
.source "ChallengeActivity.java"  //經過混淆後這項可能為空
類變量聲明
.field  :
# eg.
.field actionBar:Landroid/app/ActionBar;  ActionBar actionBar;
局部變量聲明:
.local ,:
#eg
.local v0, "ans":Ljava/lang/String;  String ans="";
類方法聲明
.method  (參數原型)
    [.prologue]    // 指定代碼開始位置
    [.param]       // 指定方法參數
    [.line]        // 指定代碼在源代碼中的行數,混淆後可能不存在
    [.locals]  // 使用的局部變量個數
   
.end method
# eg
.method public onTabReselected(Landroid/app/ActionBar$Tab;Landroid/app/FragmentTransaction;)V
    .locals 0
    .param p1, "tab"    # Landroid/app/ActionBar$Tab;
    .param p2, "fragmentTransaction"    # Landroid/app/FragmentTransaction;  
    .prologue
    .line 55     //可能經過混淆後不存在
    return-void
.end method
public void onTabReselected(ActionBar$Tab tab, FragmentTransaction fragmentTransaction){
}
b.原始類型
B—byte
C—char
D—double
F—float
I—int
J—long
S—short
V—void
Z—boolean
[XXX—array
Lpackage/name/ObjName—object  // 前面表示對象所在包路徑
c.寄存器操作
傳入的參數寄存器由p表示,而函數內的本地寄存器則由v表示,多個的話則在後面加上0,1,2...
需要注意的是,在非static函數中,p0表示`this`,p1才表示第一個參數。
常量賦值
主要是各種const
const                   v0, 0x7F030018  # R.layout.activity_challenge   #從R中取出靜態值
const/4                 v3, 0x2   #4也可以換成16或者high16,表示取整數值
const-string            v2, "Challenge"  # 取字符串
const-class             v2, Context    #把類對象取出
變量間賦值
move  vx,vy   # 將vy的值賦值給vx,也可以是move-object等
move-result vx  # 將上個方法調用後的結果賦值給vx,也可以是move-result-object
return-object vx # 將vx的對象作為函數返回值
new-instance            v0, ChallengePagerAdapter  # 實例化一個對象存入v0中
對象賦值
iput-object             a,(this),b   將a的值給b,一般用於b的初始化
iget-object             a,(this),b   將b的值給a,一般用於獲取b的地址,接著調用它

# eg.
iput-object             v0, p0, ChallengeActivity->actionBar:ActionBar
iget-object             v0, p0, ChallengeActivity->actionBar:ActionBar
d.函數操作
最基礎的函數操作一般有以下四個:
1.private:invoke-direct
2.public|protected: invoke-virtual
3.static:invoke-static
4.parent:  invoke-super
基本調用形式:invoke-xxx {參數},類;->函數(參數原型)
# eg.
invoke-super {p0, p1}, Landroid/support/v4/app/FragmentActivity;->onCreate(Landroid/os/Bundle;)V
super.onCreate(savedInstanceState);  // 其中p0是this,其父類是FragmentActivity,p1,是savedInstanceState,其原型是Bundle;即調用p0->onCreate(p1)
0x03 程序語句相關語法
這裡列舉以下常見程序語句對應的smali語句,並與Android源碼相比較分析
a.判斷語句
if-eq vA, vB, :cond_X   如果vA等於vB則跳轉到:cond_X
if-ne vA, vB, :cond_X   如果vA不等於vB則跳轉到:cond_X
if-lt vA, vB, :cond_X   如果vA小於vB則跳轉到:cond_X
if-ge vA, vB, :cond_X   如果vA大於等於vB則跳轉到:cond_X
if-gt vA, vB, :cond_X   如果vA大於vB則跳轉到:cond_X
if-le vA, vB, :cond_X   如果vA小於等於vB則跳轉到:cond_X
if-eqz vA, :cond_X      如果vA等於0則跳轉到:cond_X
if-nez vA, :cond_X      如果vA不等於0則跳轉到:cond_X
if-ltz vA, :cond_X      如果vA小於0則跳轉到:cond_X
if-gez vA, :cond_X      如果vA大於等於0則跳轉到:cond_X
if-gtz vA, :cond_X      如果vA大於0則跳轉到:cond_X
if-lez vA, :cond_X      如果vA小於等於0則跳轉到:cond_X
b.循環語句
下面列出一個簡單的for循環,其他也差不多
public void encrypt(String str) {
    String ans = "";
    for (int i = 0 ; i
        ans += str.charAt(i);
    }
    Log.e("ans:",ans);
}
# public void encrypt(String str) {
.method public encrypt(Ljava/lang/String;)V
.locals 4
.param p1, "str"# Ljava/lang/String;
.prologue
# String ans = "";
const-string v0, ""
.local v0, "ans":Ljava/lang/String;
# for (int i  0 ; i
# int i=0 =>v1
const/4 v1, 0x0
.local v1, "i":I
:goto_0# for_start_place
# str.length()=>v2
invoke-virtual {p1}, Ljava/lang/String;->length()I
move-result v2
# i
if-ge v1, v2, :cond_0
# ans += str.charAt(i);
# str.charAt(i) => v2
new-instance v2, Ljava/lang/StringBuilder;
invoke-direct {v2}, Ljava/lang/StringBuilder;->()V
invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
move-result-object v2
#str.charAt(i) => v3
invoke-virtual {p1, v1}, Ljava/lang/String;->charAt(I)C
move-result v3
# ans += v3 =>v0
invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;->append(C)Ljava/lang/StringBuilder;
move-result-object v2
invoke-virtual {v2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
# i++
add-int/lit8 v1, v1, 0x1
goto :goto_0
# Log.e("ans:",ans);
:cond_0
const-string v2, "ans:"
invoke-static {v2, v0}, Landroid/util/Log;->e(Ljava/lang/String;Ljava/lang/String;)I
return-void
.end method
c.switch語句
public void encrypt(int flag) {
        String ans = null;
        switch (flag){
            case 0:
                ans = "ans is 0";
                break;
            default:
                ans = "noans";
                break;
        }
        Log.v("ans:",ans);
    }
#public void encrypt(int flag) {
.method public encrypt(I)V
    .locals 2
    .param p1, "flag"    # I
    .prologue
#String ans = null;
    const/4 v0, 0x0
    .local v0, "ans":Ljava/lang/String;
#switch (flag){
    packed-switch p1, :pswitch_data_0 # pswitch_data_0指定case區域的開頭及結尾

 

#default: ans="noans"
    const-string v0, "noans"
#Log.v("ans:",ans)
    :goto_0
    const-string v1, "ans:"
    invoke-static {v1, v0}, Landroid/util/Log;->v(Ljava/lang/String;Ljava/lang/String;)I
    return-void
#case 0: ans="ans is 0"
    :pswitch_0      #pswitch_
    const-string v0, "ans is 0"
    goto :goto_0  # break
    nop
    :pswitch_data_0 #case區域的結束
    .packed-switch 0x0   #定義case的情況
        :pswitch_0   #case 0
    .end packed-switch
.end method
    其中case定義情況有兩種:
1.從0開始遞增
packed-switch p1, :pswitch_data_0
...
:pswitch_data_0
.packed-switch 0x0
    :pswitch_0
    :pswitch_1
2.無規則switch
sparse-switch p1,:sswitch_data_0
...
sswitch_data_0
.sparse-switch
    0xa -> : sswitch_0
    0xb -> : sswitch_1 # 字符會轉化成數組
d.try-catch語句
public void encrypt(int flag) {
    String ans = null;
    try {
        ans = "ok!";
    } catch (Exception e){
        ans = e.toString();
    }
    Log.d("error",ans);
}
#public void encrypt(int flag) {
.method public encrypt(I)V
    .locals 3
    .param p1, "flag"    # I
    .prologue
#String ans = null;
    const/4 v0, 0x0
    .line 20
    .local v0, "ans":Ljava/lang/String;
#try { ans="ok!"; }
    :try_start_0  # 第一個try開始,
    const-string v0, "ok!"
    :try_end_0   # 第一個try結束(主要是可能有多個try)
    .catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_0
#Log.d("error",ans);
    :goto_0
    const-string v2, "error"
    invoke-static {v2, v0}, Landroid/util/Log;->d(Ljava/lang/String;Ljava/lang/String;)I
    return-void
#catch (Exception e){ans = e.toString();}
    :catch_0 #第一個catch
    move-exception v1
    .local v1, "e":Ljava/lang/Exception;
    invoke-virtual {v1}, Ljava/lang/Exception;->toString()Ljava/lang/String;
    move-result-object v0
    goto :goto_0
.end method
 

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved