了解Dalvik代码的反汇编?

Leg*_*end 5 java android reverse-engineering dalvik disassembly

我在我写的一个小的Hello World Android应用程序上玩了smali和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);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后被拆解为:

.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
Run Code Online (Sandbox Code Playgroud)

我知道这是某种中级代表,但我不确定它是什么.据我所知,必须有一些关于如何理解这种表示的规范,但我无法弄清楚如何搜索它.所以给定一个apk文件,有人可以用外行语来解释如何使用Dalvik操作码规范来达到这种表示吗?我目前的理解是这样的:

  • 给定一个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规范从表中输出相应的操作码名称?

实际上,简而言之,我有兴趣知道所有这些"神奇"是如何完成的.例如,如果我要学习编写这个工具,那么我应该遵循的高级路线图是什么?

Chr*_*son 14

您正在查看的是davlik字节码.Java代码由dx工具转换为Dalvik字节码.清单是一个单独的问题,我将在一分钟内完成.实际上,在编译Android应用程序时,dx工具使用256 dalvik操作码将Java代码转换为字节码(与javac将Java转换为标准JVM应用程序的Java字节码的方式相同).

例如,invoke-super是一个操作码,它指示dvm(dalvik虚拟机)调用超类上的方法.同样,invoke-interface指示dvm调用接口方法.

所以你可以看到

super.onCreate(savedInstanceState);
Run Code Online (Sandbox Code Playgroud)

翻译成

invoke-super {p0, p1}, Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,invoke-super需要两个参数,即{p0,p1组和Landroid/app/Activity;->onCreate(Landroid/os/Bundle;)参数,它是用于查找的方法规范,并在必要时解析方法.

然后invoke-direct是构造函数区域中的调用.

invoke-direct {p0}, Landroid/app/Activity;-><init>()V
Run Code Online (Sandbox Code Playgroud)

每个类都有一个init方法,用于初始化类的数据成员,也称为构造函数.构造类时,虚拟机还必须调用超类的构造函数.这解释了为什么类的Activity构造函数调用构造函数.

关于清单,发生的事情(如果您查看源代码,这在Dalvik规范中都是)编译器(生成apk文件)将清单转换为更加压缩的格式(二进制xml)用于此目的节省空间.该清单没有任何与您发布的代码,它更多的指示如何处理应用程序的DVM是一个整体与问候Activities,Services等什么你张贴实际上是被执行什么.

这是对你的问题的高级答案.如果您需要更多,请告诉我,我会尽力而为.

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