VOOZH about

URL: https://qiita.com/chibi929/items/940623d33d9f6eb3877f

⇱ AndroidのAPKを逆コンパイルする #Android - Qiita


👁 Image
184

Go to list of users who liked

182

Share on X(Twitter)

Share on Facebook

Add to Hatena Bookmark

More than 5 years have passed since last update.

@chibi929in👁 Image
マッシュ&ルーム

AndroidのAPKを逆コンパイルする

184
Posted at

2年ほど前に知ってて当たり前のように教えていただきました。
最近、再び逆コンパイル(デコンパイル)する機会がございましたので、Qiita記事としてメモを投稿しておこうと思います。

手順

  1. apkファイル から dexファイル を取り出す
  2. dexファイルjarファイル に変換する
  3. jarファイル から classファイル を取り出す
  4. classファイルjavaファイル に変換する

だいたいこんな感じです。

必要なツール

逆コンパイルする

まずは、サンプル用のapkを用意します。
せっかくなので以下の記事で使用したサンプルアプリのapkを逆コンパイルしてみようと思います。
ActivityとFragmentのライフサイクルと罠

GitHubへのリンクは↓ですね。
https://github.com/chibi929/AndroidLifeCycle

プロジェクト構成はこんな感じです。
👁 20150930220520.png

apkファイル から dexファイル を取り出す

apkファイルはzipなので unzip で解凍ができます。

解凍前の状況がこちら

$ ls
app-debug.apk

unzipコマンドの様子がこちら

$ unzip app-debug.apk 
Archive: app-debug.apk
 inflating: AndroidManifest.xml 
 inflating: res/anim/abc_fade_in.xml 
 ~略~

unzipで解凍後の状況がこちら

$ ls
AndroidManifest.xml classes.dex META-INF res resources.arsc

classes.dex が取り出せました。

dexファイル を jarファイル に変換する

ここで dex2jarの出番です。
今回は記事投稿時点で最新版だった dex2jar-2.0 を使います。

dex2jarのスクリプトファイルに実行権限がなかったので付けました。

$ chmod +x -R dex2jar-2.0

dex2jar実行の様子がこちら

$ ~/tool/dex2jar-2.0/d2j-dex2jar.sh classes.dex 
dex2jar classes.dex -> ./classes-dex2jar.jar

dex2jar実行後の状況がこちら

$ ls
AndroidManifest.xml app-debug.apk classes.dex classes-dex2jar.jar META-INF res resources.arsc

classes-dex2jar.jar が増えています。

jarファイル から classファイル を取り出す

jarファイルはご存知の通りzipですので、apkファイル同様unzipをします。

unzipコマンドの様子がこちら

$ unzip classes-dex2jar.jar 
Archive: classes-dex2jar.jar
 creating: android/
 creating: android/support/
 ~略~

unzipで解凍後の状況がこちら

$ ls
android AndroidManifest.xml app-debug.apk chibi classes.dex classes-dex2jar.jar META-INF res resources.arsc

androidディレクトリchibiディレクトリ が生まれています。
chibiディレクトリ は以下のような構成になっております。

chibi/jp/lifecycle
│ AppActivity.class
│ AppFragment.class
│ BuildConfig.class
│ MainActivity$1.class
│ MainActivity$2.class
│ MainActivity.class
│ R$anim.class
│ R$attr.class
│ R$bool.class
│ R$color.class
│ R$dimen.class
│ R$drawable.class
│ R$id.class
│ R$integer.class
│ R$layout.class
│ R$menu.class
│ R$mipmap.class
│ R$string.class
│ R$style.class
│ R$styleable.class
│ R.class
│ V4AppActivity.class
│ V4AppFragment.class
│
└─base
 LifeCycleActivity.class
 LifeCycleFragment.class
 LifeCycleFragmentActivity.class
 LifeCycleV4Fragment.class

一番最初に載せたプロジェクト構成の画像とほぼ同じですね。

classファイル を javaファイル に変換する

最後に Java Decompiler の出番です。

$ ~/tool/jad -o -r -sjava -ddecomp chibi/**/*.class
Parsing chibi/jp/lifecycle/BuildConfig.class...The class file version is 50.0 (only 45.3, 46.0 and 47.0 are supported)
 Generating decomp/chibi/jp/lifecycle/BuildConfig.java
Parsing chibi/jp/lifecycle/R.class...The class file version is 50.0 (only 45.3, 46.0 and 47.0 are supported)
~略~

コマンドは Java Decompiler の Readme.txt に書いてあったものをそのまま・・・。
それでは decompディレクトリ のディレクトリ構成を確認します。

decomp
└─chibi
 └─jp
 └─lifecycle
 │ AppActivity.java
 │ AppFragment.java
 │ BuildConfig.java
 │ MainActivity.java
 │ R.java
 │ V4AppActivity.java
 │ V4AppFragment.java
 │
 └─base
 LifeCycleActivity.java
 LifeCycleFragment.java
 LifeCycleFragmentActivity.java
 LifeCycleV4Fragment.java

もう、ほぼ元通りです。

最後に

本物のjavaファイル逆コンパイル後のjavaファイル を見てみます。

本物のMainActivity.java
package chibi.jp.lifecycle;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

 findViewById(R.id.appFragmentButton).setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View v) {
 Intent i = new Intent(getApplicationContext(), AppActivity.class);
 startActivity(i);
 }
 });

 findViewById(R.id.v4AppFragmentButton).setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View v) {
 Intent i = new Intent(getApplicationContext(), V4AppActivity.class);
 startActivity(i);
 }
 });
 }
}
逆コンパイル後のMainActivity.java
// Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.geocities.com/kpdus/jad.html
// Decompiler options: packimports(3) 

package chibi.jp.lifecycle;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

// Referenced classes of package chibi.jp.lifecycle:
// AppActivity, V4AppActivity

public class MainActivity extends AppCompatActivity
{

 public MainActivity()
 {
 }

 protected void onCreate(Bundle bundle)
 {
 super.onCreate(bundle);
 setContentView(0x7f04001a);
 findViewById(0x7f0c0050).setOnClickListener(new android.view.View.OnClickListener() {

 public void onClick(View view)
 {
 view = new Intent(getApplicationContext(), chibi/jp/lifecycle/AppActivity);
 startActivity(view);
 }

 final MainActivity this$0;

 
 {
 this$0 = MainActivity.this;
 super();
 }
 });
 findViewById(0x7f0c0051).setOnClickListener(new android.view.View.OnClickListener() {

 public void onClick(View view)
 {
 view = new Intent(getApplicationContext(), chibi/jp/lifecycle/V4AppActivity);
 startActivity(view);
 }

 final MainActivity this$0;

 
 {
 this$0 = MainActivity.this;
 super();
 }
 });
 }
}

MainActivity.javaにはif文が無かったのですが、
if文があると逆コンパイル後のjavaファイルにはgoto文になっていたりします。

以上。メモがてらの逆コンパイルでした。

184

Go to list of users who liked

182
0

Go to list of comments

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
184

Go to list of users who liked

182