ここでは、メインラインのソースコードのみを分析します。
エントリ: 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ファイルとして読み込むだけで、クラスを丸ごと読み出す方法など、具体的な読み込み操作には関与していません。




