apk反彙編之smali語法

類型

Dalvik的字節碼中擁有兩個主要的類型:基類和引用類型。引用類型


引用類型是對象和數組,其他的一切都是基類

基類被一個簡單的字符描述。我沒有提出這些縮寫詞———他們實際以字符串的形式存儲於dex文件中
他們被定義與dex格式網頁文檔中(在AOSP庫中的路徑是dalvik/docs/dex-format.html)
V 空類型---僅僅可以用來作爲返回類型
Z Boolean 布爾型
B Byte字節型
S Short短整型(16位)
C Char字符型
I Int 整形
J long (64 bits)長整型(64位)
F Float浮點型
D double (64 bits)雙精度型(64位)

對象採用這樣的形式Lpackage/name/ObjectName---開始的L表明這是一個對象類型,package/name/就是該對象,對象名是是對象的名稱,並且分號表明對象名的結束。這個等同於java語言中的package.name.ObjectName結構,舉個更具體的例子,“ Ljava/lang/String;”就等同於java語言的“java.lang.String”。數組採用[I的形式—這代表一個一維整形數組就像java語言中的int[]。而多維數組,你簡單的增加字符‘[’就行了,例如[[I=int[][](最大的維度是255).你也可以使用數組對象,例如[Ljava/lang/String就是一個字符串數組。

方法

方法總是被定義爲一個非常複雜的包括方法,方法名,參數類型和返回值的形式。

所有的這些信息被要求對於虛擬機而言可以找到正確的方法並且能夠表現字節碼上的靜態分析(爲了確認揮着選擇最優化)。他們採用如下形式
Lpackage/name/ObjectName;->MethodName(III)Z
在這個例子中,你應該識別出“ Lpackage/name/ObjectName; 是一個類, MethodName明顯是一個方法名,(III)Z是方法的簽名,‘III’在這個例子中是三個整形參數,Z是表示返回一個布爾類型的返回值。

They take the form
Lpackage/name/ObjectName;->MethodName(III)Z
In this example, you should recognize Lpackage/name/ObjectName; as a type. MethodName is obviously the name of the method. (III)Z is the method's signature. III are the parameters (in this case, 3 ints), and Z is the return type (bool).
方法的參數一個接一個的列舉在右邊,中間沒有分號。給出一個更復雜的例子:
method(I[[IILjava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
在java語言中,他應該是這樣的
String method(int, int[][], int, String, Object[])




域同樣的被指定爲一個冗長的包括域,域名,域類型的形式。此外,它也允許虛擬機找到正確的域來表現字節編碼的靜態分析。
它們採用如下形式:
Lpackage/name/ObjectName;->FieldName:Ljava/lang/String;
這相當的不言自明---分別表示域名,域名和域類型




在dalvik字節碼中,寄存器總是32位可以存放任何類型的值,2個寄存器可以用來存放64位類型(長整形和雙精度型)

指定方法中的寄存器數字

這裏有兩種辦法來指定一種方法中的多個寄存器。寄存器直接指定方法中的寄存器總數,或者區域變量直接指定方法中的非參數寄存器數。寄存器總數包括方法中參數所需的所有寄存器。

多少參數傳入方法

當一個方法被調用,方法中的參數被放置到最近的幾個寄存器。如果一個方法擁有兩個參數和五個寄存器,這些參數會被存放到最後的兩個寄存器V3和V4.

動態方法的第一個參數總是被調用的第一個對象,例如讓你寫一個動態方法 LMyObject;->callMe(II)V,這個方法有兩個整形參數,但是還有一個隱含的參數‘LMyObject’在兩個整形參數之前,所以總共有三個參數在這個方法中。

我們假設你在一個方法中制定了5個寄存器(v0-v4),既不是寄存器5管理也不是本地寄存器2管理(2個本地寄存器和3個參數寄存器)

當該方法被調用後,被調用的對象是V2,第一個整型參數是V3,第二個是V4。在靜態方法中也是同樣的,除非沒有隱含的this指針參數。

寄存器名稱

對於寄存器這裏有兩種命名方案—標準的V命名方案和對於參數寄存器的P命名方案。

以p命名的第一個寄存器就是方法中的第一個參數寄存器,所以讓我們回到之前的總共擁有5個寄存器其中3個參數的例子。下表中顯示了爲每個寄存器的標準v命名,緊接着是爲參數寄存器的p命名

v0 the first local register
第一個本地寄存器
v1 the second local register
第二個本地寄存器
v2 p0 the first parameter register
第一個參數寄存器
v3 p1 the second parameter register
第二個參數寄存器
v4 p2 the third parameter register
第三個參數寄存器

你可以通過每個名稱類參照參數寄存器—這沒有什麼兩樣

p命名方案是作爲一個實用的內容被引入的來解決編輯smali編碼中的共同的難點。

假設你有一個已經存在的方法擁有一定數目的參數,你想增加一些代碼到這個方法,你會發現你需要一個額外的寄存器。

你會想,沒什麼大不了的,我僅僅在寄存器管理中增加寄存器數目就可以了。但是不幸的是,這並不容易。請記住方法中的參數是寄存在最近的寄存器中的。如果你增加寄存器數—你會改變方法參數的在寄存器中的輸入。所以你就不得不改變寄存器管理並且重編號參數寄存器

但是如果是你在方法中使用p命名模式來引用參數寄存器,你可以很容易的改變方法中的寄存器數而不必擔心重編號任何存在的寄存器。

注意:默認baksmali對於參數寄存器使用p命名模式來命名。如果你因爲某些原因不適用p命名而強制使用V命名模式,你可以使用-p/--no-parameter-registers來選擇。
Long/Double values
長整型/雙精度型值

鑑於以前提到過,長整型和雙精度型(用J和D分別代表)的基本單元是64位,需要使用2個寄存器。

當你引用方法中的參數時必須牢牢記住。

例如,我們夾着你擁有一個非靜態的方法LMyObject;->MyMethod(IJZ)V。方法的參數是“LMyObject;”,整形,長整形和布爾型。所以在這個方法中會要求五個寄存器來存放所有的參數。並且,當你以後調用這個方法時,你爲了調用該指令不得不在寄存器列表中指定兩個寄存器來存放任何64位的參數


Baksmali現在可以來反編譯odex文件,並且選擇性的deodex他們。

注意:本頁說明僅僅應用於baksmali v0.96-v1.1。v1.2以上版本開始不再要求deodexrant.隨心版本說明可以在http://code.google.com/p/smali/wiki/DeodexInstructions找到。

詳細介紹

他要求deodexrant 的幫助,這是一個較小的可以在手機上運行並且連接到dalvik酷的二進制文件

他的目的在從正在運行的dalvik中獲得類似寄存器表,域偏移量等信息提供給baksmali
Deodexrant的語法如下:
deodexerant <odex_file> <port>


接着baksmali擁有一個新的選項來告訴deodex文件,語法如下:
baksmali -x <host>:<port> <odex_file>

你也可以用-x :<port> 作爲 –x localhots:<port>的快捷方式

主要的事情你必須記住的是當你將文件deodex化的時候,當odex文件被創建的時候你必須運行一些“bootclasspath”jar文件

最容易滿足的這個的是當你嘗試deodex的時候運行在硬件上。如果你需要從不同的硬件上deodex一些文件時也有可能改變根目錄環境,但是我會將它作爲一個練習留給讀者

我們假設你正在運行一個基於美國移動商的官方版本的rom,並且蘋果程序在/system/app目錄下被deodex。一個deodex交互會像如下情形:
adb push deodexerant /data/local
adb shell chmod 755 /data/local/deodexerant
adb forward tcp:1234 tcp:1234
adb pull /system/app/Calculator.odex .
adb shell /data/local/deodexerant /system/app/Calculator.odex 1234 &
java -jar baksmali.jar -x :1234 Calculator.odex

你會活得一系列的smali文件在外層目錄下,準備好用smali反編譯這些dex文件。

注意我如何適應adb來通過usb來通信。如果你試着用wifi這個將會很慢。

鑑於baksmali向deodex製造了大量短小的同步請求,潛在上抑制了性能,所以usb連接比wifi用時更少
Troubleshooting
解決問題
When deodexing, there are several common issues you may run into.
當進行deodex的時候,可能會有幾個問題你會遇上
The most common, which is almost guaranteed to happen if you're deodexing an entire build, is an error which is something like "Cannot find class Lfoo/bar; for common superclass lookup".
最常見保證很有可能發生的是如果你deodex一個完整的構造,會出現一個類似的錯誤“Cannot find class Lfoo/bar; for common superclass lookup”。
這是由於當odex文件擁有在標準的BOOTCLASSPATH一個額外的附屬物超出了jars的範圍
This is caused when the odex file has an additional dependency, beyond the jars in the normal BOOTCLASSPATH. To resolve the issue, you need to find which jar contains the class mentioned in the error message, and then add that to the BOOTCLASSPATH environment variable (on the phone/device/emulator) before running deodexerant.
爲了解決這個問題,你需要找到那個包含錯誤信息提示的那個類的jar文件並且在運行deodexrant前將它添加到BOOTCLASSPATH環境變量中。
You can usually guess which jar it is from the class name, but if not, you can disassemble the jars and find which one has that class.
通常你可以根據類名來猜測是哪個jar,如果不行,你可以反編譯jars然後找出包含該類的jar
Once you find the extra dependency, let's say /system/framework/com.google.android.maps.jar (which is one that is commonly needed), the deodexerant command would be
(on linux/mac)
一旦你找到了該額外的附屬,我們就假設它是/system/framework/com.google.android.maps.jar
(這是普遍被需求的一個jar),那麼deodexrant命令就如下(linux和mac平臺)
adb shell BOOTCLASSPATH=\$BOOTCLASSPATH:/system/framework/com.google.android.maps.jar deodexerant blah.odex 1234 &

Windows平臺
adb shell BOOTCLASSPATH=$BOOTCLASSPATH:/system/framework/com.google.android.maps.jar deodexerant blah.odex 1234 &
________________________________________

另外的一件你可能遇到的事實堆溢出。錯誤提示類似“java.lang.OutOfMemoryError: Java heap space”。解決他的辦法是你可以增加java參數-Xmx512m來增加堆到512Mb。當然如果需要你也可以增加到更大。如果你正在使用類似“java -jar baksmali.jar”來運行baksmali,可以用如下指令來代替
java -Xmx512m -jar baksmali.jar -x :1234 blah.odex

如果你正在使用封裝腳本
baksmali -JXmx512m -x :1234 blah.odex
________________________________________

另外一件事是發生在一些平臺上(個人認爲尤其是windows平臺)的堆溢出。錯誤提示類似“java.lang.StackOverflowError”。錯誤的堆棧軌跡很可能是包含了類似"at org.jf.dexlib.Util.DeodexUtil$insn.propagateRegisters(DeodexUtil.java:1396)"的說明。
爲了修正這個錯誤,你可以用-Xss10m指令來增加堆空間
java -Xss10m -jar baksmali.jar -x :1234 blah.odex
or
baksmali -JXss10m -x :1234 blah.odex
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章