了解 Dalvik 代码的反汇编?
Posted
技术标签:
【中文标题】了解 Dalvik 代码的反汇编?【英文标题】:Understanding disassembly of Dalvik code? 【发布时间】:2011-06-16 18:11:01 【问题描述】:我在我编写的一个小型 Hello World android 应用程序上使用smali and baksmali。我的源代码是:
package com.hello;
import android.app.Activity;
import android.os.Bundle;
public class Main extends Activity
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
然后拆解成:
.class public Lcom/hello/Main;
.super Landroid/app/Activity;
.source "Main.java"
# direct methods
.method public constructor <init>()V
.locals 0
.prologue
.line 6
invoke-direct p0, Landroid/app/Activity;-><init>()V
return-void
.end method
# virtual methods
.method public onCreate(Landroid/os/Bundle;)V
.locals 1
.parameter "savedInstanceState"
.prologue
.line 10
invoke-super p0, p1, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)V
.line 11
const/high16 v0, 0x7f03
invoke-virtual p0, v0, Lcom/hello/Main;->setContentView(I)V
.line 12
return-void
.end method
我知道这是某种中间表示,但我不确定它是什么。据我了解,必须有一些关于如何理解这种表示的规范,但我无法弄清楚如何搜索它。所以给定一个apk文件,有人可以用外行的方式解释Dalvik opcode specification是如何用来达到这个表示的吗?我目前的理解是这样的:
给定一个 APK,我可以提取 二进制 XML 中的 AndroidManifest.xml 格式化并使用工具,例如 axml2xml.pl 获取“文本” 清单的版本不是 完成或者我可以使用 apktool 以获得更具可读性 形式。但我仍然不确定是什么 他们使用的规范 将二进制 XML 转换为文本。 该 反汇编程序以某种方式利用 Dalvil 操作码规范 读取 dex 文件并进行转换 进入上述表示。关于上述两个步骤的任何信息(可能带有一些简单的示例)都可以很好地帮助我正确理解这些概念。
更新 1(在 Chris 回复后发布):
所以本质上,我会执行以下操作来获得 Dalvik 字节码:
获取 apk 并将其解压缩以获取 classes.dex 文件。然后反汇编程序读取 classes.dex 文件并确定 apk 中存在的所有类。你能给我一些关于这是如何完成的信息吗?它是否以十六进制模式解析文件并查找 Dalvik 规范,然后适当地解析?还是发生了其他事情?例如,当我在 classes.dex 上使用 hexdump 时,它给了我这样的信息:
64 65 78 0a 30 33 ...
这些现在是否用于操作码查找?
假设该工具能够将传入的字节码分成单独的类,然后它会继续扫描 classes.dex 文件中的十六进制代码并使用 Davlik 规范从表中输出适当的操作码名称?实际上,简而言之,我很想知道所有这些“魔法”是如何完成的。例如,如果我要学习编写这个工具,我应该遵循的高级路线图是什么?
【问题讨论】:
【参考方案1】:您正在查看的是 davlik 字节码。 dx 工具将 Java 代码转换为 Dalvik 字节码。清单是一个单独的问题,我将在稍后讨论。实际上,当您编译 Android 应用程序时,dx 工具使用 256 个 dalvik 操作码将您的 Java 代码转换为字节码(与 javac 将 Java 转换为标准 JVM 应用程序的 Java 字节码的方式相同)。
例如,invoke-super
是一个操作码,它指示 dvm(dalvik 虚拟机)调用超类上的方法。同样,invoke-interface
指示 dvm 调用接口方法。
所以你可以看到
super.onCreate(savedInstanceState);
翻译成
invoke-super p0, p1, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)
在这种情况下,invoke-super
有两个参数,p0,p1
组和 Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)
参数,这是它在必要时用于查找和解析方法的方法规范。
然后是构造函数区域中的invoke-direct
调用。
invoke-direct p0, Landroid/app/Activity;-><init>()V
每个类都有一个init
方法,用于初始化类的数据成员,也称为构造函数。当你构造一个类时,虚拟机也必须调用超类的构造函数。这就解释了为什么您的类的构造函数调用Activity
构造函数。
关于清单,会发生什么(如果您查看源代码,这一切都在 Dalvik 规范中)是编译器(生成 apk 文件)将清单转换为更压缩的格式(二进制 xml)为了节省空间。清单与您发布的代码没有任何关系,它更多地指示dvm如何处理应用程序是关于Activities
、Services
等的一个整体。您发布的内容实际上是什么被执行。
这是对您问题的高级回答。如果您需要更多,请告诉我,我会尽力而为。
编辑你基本上是对的。反编译器将二进制数据作为字节流从 dex 文件中读取。它了解格式应该是什么,并且能够提取常量、类等信息。关于操作码,这正是它所做的。它了解每个操作码的字节值是什么(或它在 dex 文件中的表示方式),并且能够将其转换为人类可读的字符串。如果你要实现这一点,除了了解编译器的一般基础知识之外,我将从深入了解 dex 文件的结构开始。从那里,您需要构建一个将操作码值与人类可读字符串匹配的表。使用这些信息和一些关于字符串常量等的附加信息,您可以构建已编译类的文本文件表示。这有意义吗?
【讨论】:
+1 感谢您抽出宝贵时间。我在问题中发布的代码对我来说没有意义。看到您的回复后,我用我目前的理解更新了我的问题。你能看一下吗?作为关于 Manifest 文件的说明,是否可以从压缩形式中恢复原始 xml 文件?我的意思是,这些实际上是给我原始的 xml 文件吗?在这种特殊情况下,确实如此,但总是如此吗? @Legend,我已经更新了我的答案以反映您的更新。关于清单文件,我不确定。我几乎肯定它在功能上是一样的。也就是说,结果将等同于(就设备而言)原始结果,但它可能没有相同的空白字符等。 非常感谢您的详细解释。接受为答案。最后一点,您是否碰巧知道任何通过示例解释此概念的教程?它不必是特定于 Dalvik 的(也可以是与 Java 字节码相关的)。我只想看到在某些字节码上执行此操作,即从字节码到可读格式。 @Legend,老实说,这个过程与一般的编译过程非常相似。字节码实际上只是一种特定形式的机器语言。例如,您可以为 C++ 构建一个 VM,该 VM 可以读取 x86 机器语言并在其他系统甚至 x86 系统上执行它。首先,我建议您阅读有关编译器的一般信息,但我会看看是否可以找到特定于 java 的内容。或者,如果你真的很有野心,dx 工具是开源的,并且是 android 存储库的一部分...... 再次感谢您。当您找到一些时间时,任何特定于 Java 的参考都会很棒,但到目前为止,我要去获取 Android 源代码。我会闲逛一下:)【参考方案2】:操作码规范仅描述指令。 dex file format 不仅如此 - 它包含 Dalvik VM(和反汇编器)解释文件所需的所有元数据 - 字符串、类、类型、方法等。另请参阅official opcode spec,它比您链接的更完整和详细。
<plug>
BTW,下一版IDA Pro将支持.dex文件的反汇编</plug>
【讨论】:
这看起来像一个更完整的页面。谢谢! IDAPro 看起来很棒,但商业化 :( 看起来只有旧版本是免费的。 netmite.com 上没有任何内容是“官方的”。官方版本在 Android 源代码树中,例如android.git.kernel.org/?p=platform/… 。 (OTOH,netmite 副本比 git 存储库中的副本更易于阅读,因为存在 CSS 页面。)以上是关于了解 Dalvik 代码的反汇编?的主要内容,如果未能解决你的问题,请参考以下文章