日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

015 Android之可执行文件dex

發布時間:2025/3/21 Android 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 015 Android之可执行文件dex 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 從一個hello world開始
    • Dex文件結構
      • 文件頭
      • 各種數據的數組
        • 字符串表
        • 類型表
        • 原型表
        • 字段表
        • 方法表
      • 類數據
      • 手工解析Smali代碼

從一個hello world開始

smali代碼和dex之間有著千絲萬縷的聯系,先從一個最簡單的dex文件hello world開始,學習整個dex文件的結構

.class public LHelloWorld; .super Ljava/lang/Object;.method public static main([Ljava/lang/String;)V.registers 2sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;const-string v1, "Hello World!"invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)Vreturn-void .end method

以上面這段smali代碼為例

D:\Android\tools>java -jar smali.jar -o classes.dex HelloWorld.smali

然后將smali代碼轉成dex文件,并打成壓縮包,命名為HelloWorld.zip

確保adb和模擬器連接成功

再將打包好的zip文件上傳到模擬器

接著執行dex文件,可以看到成功打印了Hello World

Dex文件結構

Dex文件主要可以分為三大塊:

  • Dex文件頭
  • 各種數據的數組,包括字符串 類型 方法原型 字段 方法
  • 類數據
  • 文件頭

    首先來看文件頭的部分

    總共占0x70個字節大小,比較重要的字段有四個

  • dex_magic:表示dex文件的文件標識,特征字符串
  • checksum:校驗和,對文件求了32位的哈希值(從字段3開始到文件末尾)
  • signature:表示sha1,對文件求哈希值(從字段4開始到文件末尾)
  • file_size:表示文件大小
  • 除了這四個字段以外,文件頭部還有其他一些字段

  • header_size:dex文件頭大小
  • endian_tag:數據排列方式–小端方式
  • 各種表的大小及偏移

  • string_ids_size和string_ids_off,字符串表的大小和偏移
  • type_ids_size和type_ids_off,類型表的大小和偏移
  • proto_ids_size和proto_ids_off,字段表的大小和偏移
  • class_defs_size和class_defs_off,類數據表的大小和偏移
  • 各種數據的數組

    dex文件第二部分是各種數據的數組,包括字符串 類型 方法原型 字段 方法

    字符串表

    字符串表項,是一個字符串數據的偏移,偏移指向的是一個string_data結構。string_data結構中有兩個字段

    字段1:字符串長度,數據類型是uleb128,安卓中特有的變長的數據類型

    字段2:存儲數據,字符串以0結尾

    類型表

    類型表,保存的是一個索引值,指向的是字符串表

    例如:索引值為3表示的是字符串表的下標為3的位置指向的是L/java/lang/Object這個字符串。

    原型表

    原型表中存儲的是函數原型的各部分描述信息。包括短類型(shorty_idx),返回類型(return_type_idx),參數的類型(parameters_off),最終還是一個指向字符串表的數組下標。

    注意:字段為返回類型(return_type_idx)的值,是類型表中的索引

    字段表

    存儲的是字段信息,包括字段所在類(class_idx),字段的類型(type_idx),字段的名稱(name_idx)。

    class_idx是類型表中的索引,type_idx是類型表中的索引,字段名稱的索引是字符串的數組下標

    方法表

    方法表中存儲的是方法的信息,包括方法所在的類(class_dex),方法的原型(proto_idx),方法的名稱(name_idx)。

    其中class_idx是類型表的索引,proto_idx是原型表的索引,方法名稱的索引(name_idx)是字符串表的數組下標

    類數據

    類數據也是一個數組,每一個元素就是一個類的相關信息。現在所分析的這個文件因為只有一個類,所以只有一個類的信息。

    在表項中的class_data中存儲的是類數據,包括類名索引,訪問屬性,父類索引,接口偏移,源碼索引,注解偏移,類數據偏移

    其中,整個類的數據在class_data_item這個結構中。

    method_list是類內所有方法的列表,因為當前這個文件只有一個Main方法,所以列表內只有一個結構體。結構體中有方法的基本信息,包括方法索引,訪問標志,代碼偏移,代碼信息

    其中code_item是整個代碼的信息,里面有兩個字段特別重要

    ins_size:指令長度

    ushort insns[8]:指令數組

    這個數組存放的就是被翻譯成smali代碼的虛擬機指令,也就是OpCode

    手工解析Smali代碼

    62 00 00 00 1A 01 00 00 6E 20 01 00 10 00 0E 00

    接下來復制這一段十六進制,手工將這段代碼解析成Smali代碼。

    這里還需要借助一個文檔《(中文)Dalvik操作碼》,里面有所有的Opcode和對應的操作碼以及示例。

    首先找到62,62代表的指令含義是根據字段ID讀取靜態對象引用字段到vx,接著,還需要看懂旁邊的示例

    6201 0C00

    解析為smali代碼是

    sget‐object v1, Test3.os1:Lja va/lang/Object; // field@000c

    讀取 Object 的靜態對象引用字段 os1(字段表#CH 條目)到 v1。

    也就說這條指令一共4個字節

    62 代表操作碼 sget‐object 01 代表的是序號為1的寄存器v1 000C 代表字段表索引為0xC的字段

    接著再來看我們要解析的Opcode

    62 00 00 00 1A 01 00 00 6E 20 01 00 10 00 0E 00

    先解析前四個字節

    62 00 00 00

    具體含義如下

    62 代表操作碼 sget‐object 00 代表的是序號為0的寄存器v0 0000 代表字段表索引為00的字段

    接下來在字段表中找到第0個字段

    java.io.PrintStream java.lang.System.out

    第0個字段就是out這個對象,將這個字段翻譯為smali代碼

    Ljava.lang.System;->out:java.io.PrintStream

    那么前四個字節

    62 00 00 00

    解析為smali代碼就是

    sget‐object v0, Ljava.lang.System;->out:java.io.PrintStream

    接著來看1A

    1A08 0000

    解析為

    const‐string v8, "" // string @0000

    存入 string@0000(字符串表#0 條目)的引用到 v 8

    需要解析的Opcode

    1A 01 00 00

    接著找到字符串表索引為0的字符串

    那么這條指令解析為Smali代碼就是

    const‐string v1, "Hello World!"

    接下來查找6E

    直接看例子

    6E53 0600 0421 ‐ invoke‐virtual { v4, v0, v1, v2, v3}, Test2.method5:(IIII)V // me thod@0006

    這條指令比較復雜,一共6個字節,其中

    6E---> invoke‐virtual 5---> 參數數量 3---> v3 0600--->method@0006 0421--->v4, v0, v1, v2

    調用參數表的編譯比較詭異,如果參數的數量大于4,第5個參數將編譯在指令字節的下一個字節的4個最低位

    那么我們要解析的Opcode

    6E 20 01 00 10 00

    就可以解析為

    6E---> invoke‐virtual 2---> 參數數量 01 00--->method@0001 10 00--->v1 v0

    翻譯出來就是

    invoke‐virtual {v0,v1},method@01

    找到函數表下標為1的方法

    void java.io.PrintStream.println(java.lang.String)

    轉為Smali代碼

    Ljava/io/PrintStream;->println(Ljava/lang/String;)V

    完整的smali代碼就是

    invoke‐virtual {v0,v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V

    最后看0E

    表示返回值為空

    62 00 00 00 1A 01 00 00 6E 20 01 00 10 00 0E 00

    解析出來完整的smali代碼就是

    sget‐object v0, Ljava.lang.System;->out:java.io.PrintStream;const‐string v1, "Hello World!"invoke‐virtual {v0,v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)Vreturn‐void

    和HelloWorld.smali的源碼沒有區別

    總結

    以上是生活随笔為你收集整理的015 Android之可执行文件dex的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。