blog

jadxのソースコードを読み込む

GUIレベルでは、ファイルを選択した後、openメソッドに飛びますが、ファイルを開くには、.jadxのサフィックスと、apk, aar, jarなどのその他のタイプに分かれます。 次の具体的なコードは...

Aug 12, 2020 · 4 min. read
シェア

ここでは、メインラインのソースコードのみを分析します。

エントリ: MainWindow

ファイルを選択した後、GUIレベルは、MainWindowのオープンメソッドにジャンプしますファイルを開くには、2つのタイプに分かれて、1つは、.jadxの接尾辞であり、もう一つは、次のような他のタイプです:apk、aar、jarなど、そのうちのapkは最も複雑です。

private final transient JadxWrapper wrapper;
void open(Path path, Runnable onFinish) {
 backgroundExecutor.execute(NLS.str("progress.load"),
 () -> wrapper.openFile(path.toFile()),
 () -> {
 ......
 });
}

ファイルを開くには、次のように、JadxWrapperクラスのopenFileメソッドを利用します:

public void openFile(File file) {
 close();
 this.openFile = file;
 try {
 JadxArgs jadxArgs = settings.toJadxArgs();
 jadxArgs.setInputFile(file);
 this.decompiler = new JadxDecompiler(jadxArgs);
 this.decompiler.load();
 } catch (Exception e) {
 LOG.error("Jadx init error", e);
 close();
 }
}

JadxArgsは、入力ファイルと出力ファイル、出力フォルダ、デコンパイルスレッドプールのサイズなどのストレージを格納するだけでなく、エンティティクラスです。入力ファイルを設定した後、デコンパイル操作を実行するためにJadxDecompilerを使用し、そのロードメソッドを見て:sfsad

private JadxPluginManager pluginManager = new JadxPluginManager();
public void load() {
 ......
 loadInputFiles();
 root = new RootNode(args);
 root.loadClasses(loadedInputs);
 root.initClassPath();
 root.loadResources(getResources());
 root.initPasses();
 root.runPreDecompileStage();
}
private void loadInputFiles() {
 loadedInputs.clear();
 List<Path> inputPaths = Utils.collectionMap(args.getInputFiles(), File::toPath);
 for (JadxInputPlugin inputPlugin : pluginManager.getInputPlugins()) {
 loadedInputs.add(inputPlugin.loadFiles(inputPaths));
 }
}

JadxDecompilerは、クラス、メソッド、変数情報、ルートノード情報、リソースリスト、Javaクラスのリストを格納するConcurrentHashMap構造で、デコンパイルスレッドプールを維持する非常にコアな管理クラスです、マルチスレッドの使用は、デコンパイルの効率を向上させることができます;

非常に重要なメソッドに関連するコードを次に具体的に見てloadInputFilesは、デフォルトの入力ファイルは1であり、その後JadxPluginManagerは、ファイルの内容をロードするために、プロジェクトのプラグインに応じてロードされます。

JavaConvertPluginの説明

@Override
public JadxPluginInfo getPluginInfo() {
 return new JadxPluginInfo("java-convert", "JavaConvert", "Convert .jar and .class files to dex");
}
@Override
public ILoadResult loadFiles(List<Path> input) {
 ConvertResult result = JavaConvertLoader.process(input);
 if (result.isEmpty()) {
 result.deleteTemp();
 return EmptyLoadResult.INSTANCE;
 }
 List<DexReader> dexReaders = DexFileLoader.collectDexFiles(result.getConverted());
 return new DexLoadResult(dexReaders) {
 @Override
 public void close() throws IOException {
 super.close();
 result.deleteTemp();
 }
 };
}

次に、JavaConvertPluginのloadFilesメソッドを具体的に見て、JavaConvertLoaderは、ファイル処理を行います、主な機能は、それが.jarまたは.classファイルであるかどうかを判断することです、ファイルがapkの場合、結果の結果は空です。

DexInputPluginの説明

@Override
public JadxPluginInfo getPluginInfo() {
 return new JadxPluginInfo("dex-input", "DexInput", "Load .dex and .apk files");
}

DexInputPluginの主な機能は、.dexファイルとapkファイルをロードすることです。

@Override
public ILoadResult loadFiles(List<Path> input) {
 return new DexLoadResult(DexFileLoader.collectDexFiles(input));
}
private static List<DexReader> loadDexFromPath(Path path, int depth) {
 try (InputStream inputStream = Files.newInputStream(path, StandardOpenOption.READ)) {
 byte[] magic = new byte[DexConsts.MAX_MAGIC_SIZE];
 if (inputStream.read(magic) != magic.length) {
 return Collections.emptyList();
 }
 if (isStartWithBytes(magic, DexConsts.DEX_FILE_MAGIC)) {
 return Collections.singletonList(new DexReader(path));
 }
 if (depth == 0 && isStartWithBytes(magic, DexConsts.ZIP_FILE_MAGIC)) {
 return collectDexFromZip(path, depth);
 }
 } catch (Exception e) {
 LOG.error("File open error: {}", path, e);
 }
 return Collections.emptyList();
}
//Collections.singletonList()戻り値はイミュータブルなセットだが、セットの長さは1しかない

ここでは、ファイルが必要であるかどうかを判断するために4バイトを読み取る使用し、それがDEXまたはZIPであるかどうかを判断するために、ファイルの16進ヘッダによると、DEXファイルヘッダマジック値:0x64、0x65、0x78、0x0a 、ZIPファイルヘッダマジック値:0x50、0x4B、0x03、0x04、あなたはメモ帳を使用することができます。++ またはsublime hex pluginを使用して、これら2つのファイルのヘッダーを比較することができます。これらの2つの方法は、本質的にDexReaderメソッドを実行するので、直接DexReaderの内容を見て、この側。

public DexReader(Path path) throws IOException {
 this.path = path;
 this.buf = ByteBuffer.wrap(Files.readAllBytes(path));
 this.header = new DexHeader(new SectionReader(this, 0));
}

DexReaderはDexの全内容をByteBufferに読み込み、SectionReaderでバッファのコピーを作成します:

public DexHeader(SectionReader buf) {
 ......
 fieldIdsSize = buf.readInt();
 fieldIdsOff = buf.readInt();
 methodIdsSize = buf.readInt();
 methodIdsOff = buf.readInt();
 classDefsSize = buf.readInt();
 classDefsOff = buf.readInt();
 ......
}

SectionReaderのコア部分は、変数、メソッド、クラスなどの情報を読み込む役割を担っています。この時点で、DexInputPlugin load dexの一般的な処理が紹介されました。

このプロセス全体は、apkをzipファイルとして読み込むだけで、クラスを丸ごと読み出す方法など、具体的な読み込み操作には関与していません。

Read next

サーバーをレンタルする場合、どのシステムをインストールすればいいのかわからない?よく使われるOSを分析する

初めてレンタルサーバーを借りる方は、サーバーのシステムがよくわからず、どのようなシステムを導入するのが適切なのかわからないという方がほとんどです。 オペレーティングシステムは、サーバーのハードウェアとソフトウェアのリソースを管理するための基本的な手順であり、異なるオペレーティングシステムは、独自の長所と短所を持っており、さまざまな異なるアプリケーションに適しています。以下は、4つの一般的なオペレーティングシステムとそのアプリケーション環境の分析です:利点:Windows Serverシステムは、他のサービスと比較して...

Aug 12, 2020 · 2 min read