2012年7月11日 星期三

Decompile Android dex

我們都知道 Android 是用 Java 撰寫的,也知道  Java 編譯出來的 .class 檔
其實是給 JVM 看的 Byte code ,其實 Android 所編譯出來的 class 檔會再
經過編譯轉換成給 Dalvik VM 看的 byte code,也就是我們會在 apk 檔案中
看到的 classes.dex 檔案。

classes.dex 檔案裏面包含了所有的 class , 我們可以透過幾個工具來進行
Decompile 的動作:


1. Dedexer - dex => ddx (內容為 Dalvik Byte code)
2. smali - dex => smali (內容為 Dalvik Byte code)
3. Dex2jar - 將 dex 轉為 jar , 也就是轉為 .class 並封裝起來
4. JD-GUI - 非常好用的 Java Decompile 工具,是將 .class 轉為 .java
5. Java Bytecode Editor - 就如字面上的意思,對象是 .class 檔

 基本上 Dedexer 和 smali 轉換出來的內容是一樣的,但是 smali 另外
有提供再將 .smali 編譯回 .dex 的功能,而且輸出較為強大,所以建
議使用 smali。

Dex2Jar 則是直接將 dex 轉回 .class , 並以封裝好的 jar 呈現
可以搭配 JD-GUI 觀察 java source code。
但是使用這個工具轉換出來的 java code 還要再編譯回去我沒試過
編譯回去的檔案檔案大小有差異,無法保證可以運作。

如果要看懂成是在寫什麼,採用 Dex2Jar + JD-GUI 是很好的選擇
JD-GUI 是將 class (也就是 java bytecode)變成我們看得懂的 .java code
但是經過 dex2jar 轉換,無法保證內容會為完整無誤,而且 JD-GUI 在
某些情況也會有轉不出來或者是「內容詭異 」的情況出現。

而如果要能夠修改後再編回 dex , 就採用 smali 了,使用方式也很簡單,
在 Project Site 可以抓到 baksmali.jar和 smali.jar,前者是 dex=>smali
後者是 smali => dex

使用:( .jar 檔案可能會包含版本號,自己注意一下)
java -jar baksmali.jar -o output_folder the_dex_file
(PS : 加入 -b 可以關閉除錯輸出,但建議是開著比較好找)

要編譯回來就使用 smali.jar :
java -jar smali.jar -o output_dex_name the_source_folder


值得一提的是, Java Bytecode 和 Dalvik Bytecode 是不一樣的
Java 是 Stack based , Dalvik 是 register based , 參考底下,大概
就可以理解了:(// 後面的註解是我加上去的,編譯的時候不能保留阿XD)

Java Code
--
public class TestClass
{
 public int testMethod(int a,int b){
  int c=a+b;
  return c+1;
 }
}

--
Java Byte Code
--
.method public testMethod(II)I
iload_1 //讀出第一個參數 , 型態為 i => int
iload_2 //讀出第二個參數
iadd // 加起來(上面兩個) , i => int
istore_3 // 存到 var3 (上面加起來的結果),型態是 i => int
iload_3 //讀出 var 3
iconst_1 //讀取常數 "1" , 型態 i => int
iadd //加起來 (上面兩個) i => int
ireturn // 傳回整數 (上面的結果) , i => int
.end method
// 這就是所謂的 stack based
--
Dalvik Byte Code
--
.method public testMethod(II)I
.limit registers 5 // 五個變數要註冊
; this: v2 (Ltw/darkk6/test/TestClass;) // this 註冊為 v2
; parameter[0] : v3 (I) //參數 1 註冊為 v3 , 型態 I => int
; parameter[1] : v4 (I) //參數 2 註冊為 v4 , 型態 I => int
 add-int v0,v3,v4 //整數相加, v0 = v3+v4
 add-int/lit8 v1,v0,1 //整數相加 : v0 加上 lit8 (lit8 就是這邊的 1) , 存到 v1
 return v1 // 傳回 v1
.end method
---
(前面分號開頭的應該只是註解,寫出來提醒使用者這幾個變數的註冊情況)

[注意:]
使用 smali 和 dedexer 反編譯出來的 bytecode 有部分不會相同上面的是由
Dedexer 所反編譯,利用 smali 在方法參數和註冊的部分會有點差異:

Delvik Byte Code by Smali
--
.method public testMethod(II)I
    .registers 5 //註冊五個變數
    add-int v0, p1, p2 //p1 和 p2 是參數1 和 參數2
    add-int/lit8 v1, v0, 0x1
    return v1
.end method
--

不過基本上 Dalvik Bytecode 比較容易理,要進行修改也容易許多。

Dalvik Bytecode : http://www.netmite.com/android/mydroid/dalvik/docs/dalvik-bytecode.html

沒有留言:

張貼留言