android APK反編譯的方法

 由於學習Android編程的須要,有時咱們須要對網絡上發佈的應用項目進行學習,但是Android項目通常是經過APK文件進行發佈的,咱們看不到源代碼,嘿嘿,辦法總會有的,並且不止一個...

   ps:對於軟件開發人員來講,保護代碼安全也是比較重要的因素之一,不過目前來講Google Android平臺選擇了Java Dalvik VM的方式使其程序很容易破解和被修改,首先APK文件其實就是一個MIME爲ZIP的壓縮包,咱們修改ZIP後綴名方式能夠看到內部的文件結構,相似Sun JavaMe的Jar壓縮格式同樣,不過比較去別的是Android上的二進制代碼被編譯成爲Dex的字節碼,全部的Java文件最終會編譯進該文件中去,做爲託管代碼既然虛擬機能夠識別,那麼咱們就能夠很輕鬆的反編譯。全部的類調用、涉及到的方法都在裏面體現到,至於邏輯的執行能夠經過實時調試的方法來查看,固然這須要藉助一些咱們本身編寫的跟蹤程序。Google最然在Android Market上設置了權限保護app-private文件夾的安全,可是最終咱們使用修改定值的系統仍然能夠獲取到須要的文件。 java

1、dexdump方法 android

      dexdump是emulator自帶提供的查看dex文件的工具,可以使用相似這樣的命令將dex文件dump到txt文件中: 編程

      D:\Program Files\android-sdk-windows-1.6_r1\platforms\android-1.6\tools>dexdump.exe -d classes.dex > spk.dump.txt windows

     獲得的文件內容,描述了類的信息,但實在是很差讀啊~~~~ 安全

2、dex2jar + XJad 方法 網絡

     該方法是使用dex2jar.jar包,將classes.dex文件解包成jar,在經過XJad(或者其餘class反編譯工具)進行java反編譯。如: app

     一、dex2jar.bat d:\play\classes.dex 工具

          默認的輸出路徑同classes.dex,生成的文件名爲classes.dex.dex2jar.jar 學習

     二、使用XJad反編譯該jar包 調試

          以後的使用方法,你們都懂的:)

     該方法的好處在於,經過XJad反編譯後,你們可直接開到java源文件,缺點在於只能反編譯出開發時的java文件,而開發時使用的lib包不能反編譯出來。

3、AXMLPrinter2.jar + baksmali.jar + smali.jar 方法

      這個方法就強大了,AXMLPrinter2是還原AndroidManifest.xml和main.xml的工具,直接打開這兩個xml文件是亂碼,而經過還原以後,能夠很明白的看到裏面的內容(我猜想仍是使用了字節異或的方式加的密)。

      baksmali.jar是反解析dex的工具,smali.jar則是再還原成dex的工具

      操做方式以下:

     一、java -jar AXMLPrinter2.jar D:\play\AndroidManifest.xml > AndroidManifest.txt

     二、java -jar AXMLPrinter2.jar D:\play\res\layout\main.xml > main.txt

     三、java -jar baksmali-1.2.5.jar -o classout/ d:\play\classes.dex

      baksmali可解析(注意,是解析,不是反編譯)原java包以及引用的lib包,解析出的文件認真看仍是能看懂,好比如下片斷:

view plaincopy to clipboardprint?
.class Lcom/paul/test/a;  
.super Landroid/view/View;  
 
# static fields  
.field private static final a:Landroid/graphics/Typeface;  
 
# instance fields  
.field private b:I  
.field private c:I  
.field private d:Z  
.field private e:J  
.field private f:I  
.field private l:[Ljava/lang/String;  
 
# direct methods  
.method static constructor <clinit>()V  
    .registers 2 
    sget-object v0, Landroid/graphics/Typeface;->SANS_SERIF:Landroid/graphics/Typeface;  
    const/4 v1, 0x0 
    invoke-static {v0, v1}, Landroid/graphics/Typeface;->create(Landroid/graphics/Typeface;I)Landroid/graphics/Typeface;  
    move-result-object v0  
    sput-object v0, Lcom/wiyun/ad/a;->a:Landroid/graphics/Typeface;  
    return-void 
.end method  
#  
# other methods ..........  
#  
# virtual methods  
.method public onKeyUp(ILandroid/view/KeyEvent;)Z  
    .registers 4 
    const/16 v0, 0x42 
    if-eq p1, v0, :cond_8  
    const/16 v0, 0x17 
    if-ne p1, v0, :cond_b  
    :cond_8  
    invoke-direct {p0}, Lcom/paul/test/a;->d()V  
    :cond_b  
    const/4 v0, 0x0 
    invoke-virtual {p0, v0}, Lcom/paul/test/a;->setPressed(Z)V  
    invoke-super {p0, p1, p2}, Landroid/view/View;->onKeyUp(ILandroid/view/KeyEvent;)Z  
    move-result v0  
    return v0  
.end method 
.class Lcom/paul/test/a;
.super Landroid/view/View;

# static fields
.field private static final a:Landroid/graphics/Typeface;

# instance fields
.field private b:I
.field private c:I
.field private d:Z
.field private e:J
.field private f:I
.field private l:[Ljava/lang/String;

# direct methods
.method static constructor <clinit>()V
    .registers 2
    sget-object v0, Landroid/graphics/Typeface;->SANS_SERIF:Landroid/graphics/Typeface;
    const/4 v1, 0x0
    invoke-static {v0, v1}, Landroid/graphics/Typeface;->create(Landroid/graphics/Typeface;I)Landroid/graphics/Typeface;
    move-result-object v0
    sput-object v0, Lcom/wiyun/ad/a;->a:Landroid/graphics/Typeface;
    return-void
.end method
#
# other methods ..........
#
# virtual methods
.method public onKeyUp(ILandroid/view/KeyEvent;)Z
    .registers 4
    const/16 v0, 0x42
    if-eq p1, v0, :cond_8
    const/16 v0, 0x17
    if-ne p1, v0, :cond_b
    :cond_8
    invoke-direct {p0}, Lcom/paul/test/a;->d()V
    :cond_b
    const/4 v0, 0x0
    invoke-virtual {p0, v0}, Lcom/paul/test/a;->setPressed(Z)V
    invoke-super {p0, p1, p2}, Landroid/view/View;->onKeyUp(ILandroid/view/KeyEvent;)Z
    move-result v0
    return v0
.end method


認真一看,就知道:

# static fields             定義靜態變量的標記

# instance fields        定義實例變量的標記

# direct methods       定義靜態方法的標記

# virtual methods      定義非靜態方法的標記

 

以onKeyUp方法爲例,其中定義了處理邏輯,if-eq p1, v0, :cond_8 表示若是p1和v0相等,則執行cond_8的流程:

    :cond_8
    invoke-direct {p0}, Lcom/paul/test/a;->d()V

調用com.paul.test.a的d()方法

不相等: if-ne p1, v0, :cond_b 則執行cond_b的流程:

    :cond_b
    const/4 v0, 0x0

    invoke-virtual {p0, v0}, Lcom/paul/test/a;->setPressed(Z)V

    invoke-super {p0, p1, p2}, Landroid/view/View;->onKeyUp(ILandroid/view/KeyEvent;)Z

    move-result v0

 

大概意思就是調用com.paul.test.a的setPressed方法,而後再調用父類View的onKeyUp方法

最後 return v0

      該方法,能把外部引用的lib包類也解析出來,能開到包的全貌。缺點在於,解析出的smali文件並非反編譯出的java文件,可讀性下降了,但仔細研究也能看出大概。

相關文章
相關標籤/搜索