2011-01-27 132 views
4

我正在玩一个smali and baksmali在我写的一个小型Hello World Android应用程序上。我的源代码是:了解反汇编Dalvik代码?

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(贴从克里斯的答复后):

所以基本上,我会做以下以在Dalvik字节码到:

  • 采取的APK并提取它来获得classes.dex文件。
  • 然后反汇编器读取classes.dex文件并确定apk中存在的所有类。你能向我提供一些关于如何完成的信息吗?它是否以十六进制模式解析文件并查找Dalvik规范,然后进行适当的解析?或者是其他事情发生?举例来说,当我用classes.dex hexdump都可以,它给了我这样的事情:

    64 65 78 0A 30 33 ...

难道这些现在被用来操作码查找?

  • 假设工具是能够进入的字节码转换为单独的类分离,则它继续扫描从classes.dex文件中的十六进制代码,并使用Davlik规范输出来自表中的适当操作码的名字?

其实,总之,我很想知道所有这些“魔法”是如何完成的。例如,如果我要学习编写这个工具,我应该遵循什么样的高层路线图?

回答

14

什么你看是davlik字节码拆卸。 Java代码由dx工具转换为Dalvik字节码。清单是一个单独的问题,我将在一分钟内解决。实际上,当您编译Android应用程序时,dx工具会使用256个dalvik操作码将Java代码转换为字节码(与javac将标准JVM应用程序的Java字节码转换为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如何处理应用程序是整体关于ActivitiesServices等。您发布的内容是实际执行的内容。

这是您的问题的高级答案。如果你需要更多,让我知道,我会尽我所能。

编辑你基本上是对的。反编译器将二进制数据从dex文件读取为字节流。它了解格式应该是什么,并能够抽出像常量,类等信息。关于操作码,这正是它所做的。它理解每个操作码的字节值是什么(或者它是如何在dex文件中表示的)并且能够将其转换为可读的字符串。如果你打算实现这一点,除了理解编译器的一般基础知识外,我将首先深入理解一个dex文件的结构。从那里,你将需要构建一个表,匹配opcode值与人类可读的字符串。通过这些信息和一些关于字符串常量的附加信息,您可以构建编译类的文本文件表示。那有意义吗?

3

操作码规范只描述说明。 dex file format不止于此 - 它包含Dalvik VM(和反汇编程序)解释文件所需的所有元数据 - 字符串,类,类型,方法等。另请参阅official opcode spec,它比链接的更完整和详细。

<plug> BTW,的IDA Pro下一版本将支持.DEX文件</plug>

+0

这看起来像一个更完整的页面。谢谢! IDAPro似乎很棒,但商业化:(看起来只有旧版本免费提供) – Legend 2011-01-27 18:59:31

+0

netmite.com上的任何内容都不是“官方”的,官方版本位于Android源代码树中,例如http://android.git。 kernel.org/?p=platform/dalvik.git;a=tree;f=docs;h=7045c2e00b823918a8387187ca171d4c68936080;hb=HEAD。(OTOH,netmite副本比git存储库中的更容易阅读,因为CSS页面) – fadden 2011-01-29 01:23:59