android oat如何提取dex文件字节码,Android: 使用oatdump反编译oat文件

本文探讨了如何使用apktool将apk中的dex反编译为smali代码,以及尝试通过oatdump工具反编译oat文件。oat文件是一个包含dex代码和汇编实现的ELF可执行文件,它在Android系统中用于快速执行应用程序。通过oatdump,我们可以看到dex方法和对应的汇编代码,但不提供完整的源码级别分析。文章以一个简单的JNI和Java代码示例展示了dex2oat过程,并分析了生成的oat文件结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

网上经常看到有通过apktool将apk中的dex反编译成smali格式的文件,以便分析功能实现与破—解,确没怎么看到oat文件反通过oatdump反编译的,所以就写了一篇这样的文档。声明一下oat文件也是可以反编译的。本来想着通过oatdump处理之后,既可以看到dex代码又可以看到相应的汇编实现。反编译之后发现其实不然,难道是因为系统是eng版本的原因,有机会再验证看看。

先看一下这两个代码片段

1. JNI代码: jni/com_android_hello_HelloActivity.cpp

#include

#include

extern "C" void Java_com_android_hello_HelloActivity_sayHello(JNIEnv *, jobject)

{

__builtin_trap();

}

使APP出现native crash

2. Java代码: src/com/android/hello/HelloActivity.java

public class HelloActivity extends Activity {

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

sayHello();

}

static {

System.loadLibrary("hello-jni");

}

private static native void sayHello();

}

加载JNI库libhello-jni.so, 并且在app launch时调用JNI方法sayHello()。

APK安装时会执行dex2oat命令,生成oat文件:

03-11 23:06:38.748 11835 11902 D PackageManager: Renaming /data/app/vmdl111617587.tmp to /data/app/com.android.hello-1

03-11 23:06:38.774 11835 11902 I PackageManager: Running dexopt on: /data/app/com.android.hello-1/base.apk pkg=com.android.hello isa=arm vmSafeMode=false

03-11 23:06:38.800 18221 18221 I dex2oat : /system/bin/dex2oat --zip-fd=6 --zip-location=/data/app/com.android.hello-1/base.apk --oat-fd=7 --oat-location=/data/dalvik-cache/arm/data@app@com.android.hello-1@base.apk@classes.dex --instruction-set=arm --instruction-set-features=div --runtime-arg -Xms64m --runtime-arg -Xmx512m --compiler-filter=interpret-only --swap-fd=8

03-11 23:06:38.818 18221 18221 I dex2oat : Decided to run without swap.

03-11 23:06:38.838 18221 18221 I dex2oat : dex2oat took 38.211ms (threads: 4) arena alloc=0B java alloc=7KB native alloc=75KB free=32KB

oat文件是什么:

$ adb pull /data/dalvik-cache/arm/data@app@com.android.hello-1@base.apk@classes.dex

1236 KB/s (12720 bytes in 0.010s)

$ file data\@app\@com.android.hello-1\@base.apk\@classes.dex

data@app@com.android.hello-1@base.apk@classes.dex: ELF 32-bit LSB shared object, ARM, version 1 (GNU/Linux), dynamically linked, stripped

是一个ELF可执行文件。执行readelf/arm-linux-androideabi-readelf命令看看:

$ arm-linux-androideabi-readelf -a data\@app\@com.android.hello-1\@base.apk\@classes.dex

ELF Header:

Magic: 7f 45 4c 46 01 01 01 03 00 00 00 00 00 00 00 00

Class: ELF32

Data: 2's complement, little endian

Version: 1 (current)

OS/ABI: UNIX - GNU

ABI Version: 0

Type: DYN (Shared object file)

Machine: ARM

Version: 0x1

Entry point address: 0x0

Start of program headers: 52 (bytes into file)

Start of section headers: 12400 (bytes into file)

Flags: 0x5000000, Version5 EABI

Size of this header: 52 (bytes)

Size of program headers: 32 (bytes)

Number of program headers: 5

Size of section headers: 40 (bytes)

Number of section headers: 8

Section header string table index: 7

Section Headers:

[Nr] Name Type Addr Off Size ES Flg Lk Inf Al

[ 0] NULL 00000000 000000 000000 00 0 0 0

[ 1] .dynsym DYNSYM 000000d4 0000d4 000040 10 A 2 0 4

[ 2] .dynstr STRTAB 00000114 000114 00004f 01 A 0 0 1

[ 3] .hash HASH 00000164 000164 000020 04 A 1 0 4

[ 4] .rodata PROGBITS 00001000 001000 001000 00 A 0 0 4096

[ 5] .text PROGBITS 00002000 002000 000094 00 AX 0 0 4096

[ 6] .dynamic DYNAMIC 00003000 003000 000038 08 A 1 0 4096

[ 7] .shstrtab STRTAB 00000000 003038 000038 01 0 0 1

Key to Flags:

W (write), A (alloc), X (execute), M (merge), S (strings)

I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)

O (extra OS processing required) o (OS specific), p (processor specific)

There are no section groups in this file.

Program Headers:

Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align

PHDR 0x000034 0x00000034 0x00000034 0x000a0 0x000a0 R 0x4

LOAD 0x000000 0x00000000 0x00000000 0x02000 0x02000 R 0x1000

LOAD 0x002000 0x00002000 0x00002000 0x00094 0x00094 R E 0x1000

LOAD 0x003000 0x00003000 0x00003000 0x00038 0x00038 RW 0x1000

DYNAMIC 0x003000 0x00003000 0x00003000 0x00038 0x00038 RW 0x1000

Section to Segment mapping:

Segment Sections...

00

01 .dynsym .dynstr .hash .rodata

02 .text

03 .dynamic

04 .dynamic

Dynamic section at offset 0x3000 contains 7 entries:

Tag Type Name/Value

0x00000004 (HASH) 0x164

0x00000005 (STRTAB) 0x114

0x00000006 (SYMTAB) 0xd4

0x0000000b (SYMENT) 16 (bytes)

0x0000000a (STRSZ) 79 (bytes)

0x0000000e (SONAME) Library soname: [data@app@com.android.hello-1@base.apk@classes.dex]

0x00000000 (NULL) 0x0

There are no relocations in this file.

There are no unwind sections in this file.

Symbol table '.dynsym' contains 4 entries:

Num: Value Size Type Bind Vis Ndx Name

0: 00000000 0 NOTYPE LOCAL DEFAULT UND

1: 00001000 4096 OBJECT GLOBAL DEFAULT 4 oatdata

2: 00002000 148 OBJECT GLOBAL DEFAULT 5 oatexec

3: 00002090 4 OBJECT GLOBAL DEFAULT 5 oatlastword

Histogram for bucket list length (total of 2 buckets):

Length Number % of total Coverage

0 0 ( 0.0%)

1 1 ( 50.0%) 33.3%

2 1 ( 50.0%) 100.0%

No version information found in this file.

能使用objdump/arm-linux-androideabi-objdum反编译吗:

$ arm-linux-androideabi-objdump -d data\@app\@com.android.hello-1\@base.apk\@classes.dex

data@app@com.android.hello-1@base.apk@classes.dex: file format elf32-littlearm

Disassembly of section .text:

00002000 :

...

200c:30 00 00 00 e0 4d 00 00 00 00 00 00 78 00 00 00 0....M......x...

201c:2d e9 e0 4d ad f2 14 0d 00 90 4f f0 01 0c cd f8 -..M......O.....

202c:08 c0 d9 f8 c8 c0 cd f8 04 c0 0d f2 04 0c c9 f8 ................

203c:c8 c0 d0 f8 08 c0 cd f8 0c c0 c9 f8 8c d0 4f f0 ..............O.

204c:00 0c c9 f8 90 c0 48 46 d0 f8 94 c1 e0 47 04 90 ......HF.....G..

205c:0d f2 0c 01 d9 f8 98 00 dd f8 00 c0 dc f8 28 c0 ..............(.

206c:e0 47 04 98 49 46 d1 f8 9c c1 e0 47 d9 f8 7c c0 .G..IF.....G..|.

207c:bc f1 00 0f 03 d1 0d f2 14 0d bd e8 e0 8d 60 46 ..............`F

208c:d9 f8 34 c2 ..4.

00002090 :

2090:e0 47 00 be .G..

没什么内容。

最后,我们用oatdump命令查看一下:

$ oatdump --oat-file=data\@app\@com.android.hello-1\@base.apk\@classes.dex

MAGIC:

oat

045

CHECKSUM:

0x864eeade

INSTRUCTION SET:

Thumb2

INSTRUCTION SET FEATURES:

div

DEX FILE COUNT:

1

EXECUTABLE OFFSET:

0x00001000

INTERPRETER TO INTERPRETER BRIDGE OFFSET:

0x00000000

INTERPRETER TO COMPILED CODE BRIDGE OFFSET:

0x00000000

JNI DLSYM LOOKUP OFFSET:

0x00000000

PORTABLE IMT CONFLICT TRAMPOLINE OFFSET:

0x00000000

PORTABLE RESOLUTION TRAMPOLINE OFFSET:

0x00000000

PORTABLE TO INTERPRETER BRIDGE OFFSET:

0x00000000

QUICK GENERIC JNI TRAMPOLINE OFFSET:

0x00000000

QUICK IMT CONFLICT TRAMPOLINE OFFSET:

0x00000000

QUICK RESOLUTION TRAMPOLINE OFFSET:

0x00000000

QUICK TO INTERPRETER BRIDGE OFFSET:

0x00000000

IMAGE PATCH DELTA:

0 (0x00000000)

IMAGE FILE LOCATION OAT CHECKSUM:

0x8223fe58

IMAGE FILE LOCATION OAT BEGIN:

0x70dd0000

KEY VALUE STORE:

dex2oat-cmdline = --zip-fd=6 --zip-location=/data/app/com.android.hello-1/base.apk --oat-fd=7 --oat-location=/data/dalvik-cache/arm/data@app@com.android.hello-1@base.apk@classes.dex --instruction-set=arm --instruction-set-features=div --runtime-arg -Xms64m --runtime-arg -Xmx512m --compiler-filter=interpret-only --swap-fd=8

dex2oat-host = Arm

image-location = /data/dalvik-cache/arm/system@framework@boot.art

pic = false

SIZE:

4244

OatDexFile:

location: /data/app/com.android.hello-1/base.apk

checksum: 0x2e3d006c

0: Lcom/android/hello/HelloActivity; (offset=0x00000578) (type_idx=2) (StatusVerified) (OatClassSomeCompiled)

0: void com.android.hello.HelloActivity.() (dex_method_idx=2)

DEX CODE:

0x0000: const-string v0, "hello-jni" // string@10

0x0002: invoke-static {v0}, void java.lang.System.loadLibrary(java.lang.String) // method@6

0x0005: return-void

OatMethodOffsets (offset=0x00000000)

code_offset: 0x00000000

gc_map: (offset=0x00000000)

OatQuickMethodHeader (offset=0x00000000)

mapping_table: (offset=0x00000000)

vmap_table: (offset=0x00000000)

QuickMethodFrameInfo

frame_size_in_bytes: 0

core_spill_mask: 0x00000000

fp_spill_mask: 0x00000000

CODE: (code_offset=0x00000000 size_offset=0x00000000 size=0)

NO CODE!

1: void com.android.hello.HelloActivity.() (dex_method_idx=3)

DEX CODE:

0x0000: invoke-direct {v0}, void android.app.Activity.() // method@0

0x0003: return-void

OatMethodOffsets (offset=0x00000000)

code_offset: 0x00000000

gc_map: (offset=0x00000000)

OatQuickMethodHeader (offset=0x00000000)

mapping_table: (offset=0x00000000)

vmap_table: (offset=0x00000000)

QuickMethodFrameInfo

frame_size_in_bytes: 0

core_spill_mask: 0x00000000

fp_spill_mask: 0x00000000

CODE: (code_offset=0x00000000 size_offset=0x00000000 size=0)

NO CODE!

2: void com.android.hello.HelloActivity.sayHello() (dex_method_idx=5)

DEX CODE:

OatMethodOffsets (offset=0x00000584)

code_offset: 0x0000101d

gc_map: (offset=0x00000000)

OatQuickMethodHeader (offset=0x00001000)

mapping_table: (offset=0x00000000)

vmap_table: (offset=0x00000000)

QuickMethodFrameInfo

frame_size_in_bytes: 48

core_spill_mask: 0x00004de0 (r5, r6, r7, r8, r10, r11, r14)

fp_spill_mask: 0x00000000

CODE: (code_offset=0x0000101d size_offset=0x00001018 size=120)...

0x0000101c: e92d4de0push {r5, r6, r7, r8, r10, r11, lr}

0x00001020: f2ad0d14subw sp, sp, #20

0x00001024: 9000 str r0, [sp, #0]

0x00001026: f04f0c01mov.w r12, #1

0x0000102a: f8cdc008str.w r12, [sp, #8]

0x0000102e: f8d9c0c8ldr.w r12, [r9, #200] ; top_handle_scope

0x00001032: f8cdc004str.w r12, [sp, #4]

0x00001036: f20d0c04addw r12, sp, #4

0x0000103a: f8c9c0c8str.w r12, [r9, #200]

0x0000103e: f8d0c008ldr.w r12, [r0, #8]

0x00001042: f8cdc00cstr.w r12, [sp, #12]

0x00001046: f8c9d08cstr.w sp, [r9, #140]

0x0000104a: f04f0c00mov.w r12, #0

0x0000104e: f8c9c090str.w r12, [r9, #144]

0x00001052: 4648 mov r0, r9

0x00001054: f8d0c194ldr.w r12, [r0, #404]

0x00001058: 47e0 blx r12

0x0000105a: 9004 str r0, [sp, #16]

0x0000105c: f20d010caddw r1, sp, #12

0x00001060: f8d90098ldr.w r0, [r9, #152] ; jni_env

0x00001064: f8ddc000ldr.w r12, [sp, #0]

0x00001068: f8dcc028ldr.w r12, [r12, #40]

0x0000106c: 47e0 blx r12

0x0000106e: 9804 ldr r0, [sp, #16]

0x00001070: 4649 mov r1, r9

0x00001072: f8d1c19cldr.w r12, [r1, #412]

0x00001076: 47e0 blx r12

0x00001078: f8d9c07cldr.w r12, [r9, #124] ; exception

0x0000107c: f1bc0f00cmp.w r12, #0

0x00001080: d103 bne +6 (0x0000108a)

0x00001082: f20d0d14addw sp, sp, #20

0x00001086: e8bd8de0pop {r5, r6, r7, r8, r10, r11, pc}

0x0000108a: 4660 mov r0, r12

0x0000108c: f8d9c234ldr.w r12, [r9, #564] ; pDeliverException

0x00001090: 47e0 blx r12

0x00001092: be00

3: void com.android.hello.HelloActivity.onCreate(android.os.Bundle) (dex_method_idx=4)

DEX CODE:

0x0000: invoke-super {v0, v1}, void android.app.Activity.onCreate(android.os.Bundle) // method@1

0x0003: invoke-static {}, void com.android.hello.HelloActivity.sayHello() // method@5

0x0006: return-void

OatMethodOffsets (offset=0x00000000)

code_offset: 0x00000000

gc_map: (offset=0x00000000)

OatQuickMethodHeader (offset=0x00000000)

mapping_table: (offset=0x00000000)

vmap_table: (offset=0x00000000)

QuickMethodFrameInfo

frame_size_in_bytes: 0

core_spill_mask: 0x00000000

fp_spill_mask: 0x00000000

CODE: (code_offset=0x00000000 size_offset=0x00000000 size=0)

NO CODE!

看来oat文件中既包含dex代码,又包启汇编代码,不知道是不是因为我手机是eng版本的。相关系统属性如下(Nexus4 android-5.1.1_r17(lmy48t):

[dalvik.vm.dex2oat-Xms]: [64m]

[dalvik.vm.dex2oat-Xmx]: [512m]

[dalvik.vm.dex2oat-filter]: [interpret-only]

[dalvik.vm.dexopt-flags]: [m=y]

[dalvik.vm.image-dex2oat-Xms]: [64m]

[dalvik.vm.image-dex2oat-Xmx]: [64m]

[dalvik.vm.image-dex2oat-filter]: [verify-none]

相关的参考文档,ART and Dalvik: https://source.android.com/devices/tech/dalvik/index.html

1. Bytecode Format: https://source.android.com/devices/tech/dalvik/dalvik-bytecode.html

2. .Dex Format: https://source.android.com/devices/tech/dalvik/dex-format.html

3. Instruction Formats: https://source.android.com/devices/tech/dalvik/instruction-formats.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值