Skip to content

Commit

Permalink
[BETA] Rebuild apk fully with new resource id generation
Browse files Browse the repository at this point in the history
  • Loading branch information
REAndroid committed May 31, 2024
1 parent 9bd2ede commit eca3c9a
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 5 deletions.
58 changes: 58 additions & 0 deletions src/main/java/com/reandroid/apkeditor/decompile/Decompiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,19 @@
package com.reandroid.apkeditor.decompile;

import com.reandroid.apk.*;
import com.reandroid.apkeditor.APKEditor;
import com.reandroid.apkeditor.BaseCommand;
import com.reandroid.apkeditor.Util;
import com.reandroid.apkeditor.smali.SmaliDecompiler;
import com.reandroid.archive.ArchiveFile;
import com.reandroid.archive.block.ApkSignatureBlock;
import com.reandroid.arsc.chunk.TableBlock;
import com.reandroid.arsc.coder.xml.XmlCoder;
import com.reandroid.common.DiagnosticMessage;
import com.reandroid.common.DiagnosticsReporter;
import com.reandroid.commons.command.ARGException;
import com.reandroid.dex.model.DexDirectory;
import com.reandroid.graph.ApkBuilder;

import java.io.File;
import java.io.IOException;
Expand Down Expand Up @@ -58,10 +63,63 @@ public void run() throws IOException {
apkModule.validateResourcesDir();
}
logMessage("Decompiling to " + options.type + " ...");

runFullApkRebuildExperimental(apkModule);

ApkModuleDecoder decoder = getApkModuleDecoder(apkModule);
decoder.decode(options.outputFile);
logMessage("Saved to: "+options.outputFile);
}
private void runFullApkRebuildExperimental(ApkModule apkModule) throws IOException {
if(!APKEditor.isExperimental()) {
return;
}
if(!canLoadFullDex(apkModule)) {
return;
}
DexDirectory directory = DexDirectory.fromZip(apkModule.getZipEntryMap());
DiagnosticsReporter reporter = new DiagnosticsReporter() {
@Override
public void report(DiagnosticMessage diagnosticMessage) {
logMessage(diagnosticMessage.toString());
}
@Override
public boolean isVerboseEnabled() {
return false;
}
@Override
public boolean isDebugEnabled() {
return false;
}
};
logMessage("Rebuilding apk with new resource id generation ...");
ApkBuilder builder = new ApkBuilder(apkModule, directory);
builder.setReporter(reporter);
builder.build();
logMessage("Refreshing and merging ...");
directory.refresh();

// Cleans duplicate strings, codes, section entries ...
directory.shrink();

// Combines dex files to minimum possible number
directory.merge();

directory.refreshFull();
directory.save();
apkModule.putTag(DexDirectory.class, directory);
}
private boolean canLoadFullDex(ApkModule apkModule) {
int CLASSES_LIMIT = 5;
int size = apkModule.listDexFiles().size();
logMessage("Total dex files: " + size);
if(size > CLASSES_LIMIT) {
logMessage("Huge classes your memory might not handle it, decoding separately without advanced features." +
" You can disable this restrictions by increasing \"CLASSES_LIMIT\" variable here on source code");
return false;
}
return true;
}
private ApkModuleDecoder getApkModuleDecoder(ApkModule apkModule){

DecompileOptions options = getOptions();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ private InputSource buildExperimental(String progress, File classesDir, File dex
dexFile.setVersion(version);
dexFile.clearEmptySections();
dexFile.sortSection(SectionType.getR8Order());
dexFile.shrink();
dexFile.refreshFull();
dexFile.write(dexCacheFile);
dexFile.close();
Expand Down
35 changes: 30 additions & 5 deletions src/main/java/com/reandroid/apkeditor/smali/SmaliDecompiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,22 @@
import com.reandroid.apkeditor.APKEditor;
import com.reandroid.apkeditor.decompile.DecompileOptions;
import com.reandroid.arsc.chunk.TableBlock;
import com.reandroid.common.DiagnosticsReporter;
import com.reandroid.dex.common.AnnotationVisibility;
import com.reandroid.dex.data.AnnotationItem;
import com.reandroid.dex.key.MethodKey;
import com.reandroid.dex.key.TypeKey;
import com.reandroid.dex.model.DexClass;
import com.reandroid.dex.model.DexClassRepository;
import com.reandroid.dex.model.DexDirectory;
import com.reandroid.dex.model.DexFile;
import com.reandroid.dex.refactor.RenameTypes;
import com.reandroid.dex.sections.SectionType;
import com.reandroid.dex.smali.SmaliWriter;
import com.reandroid.dex.smali.SmaliWriterSetting;
import com.reandroid.graph.ApkBuilder;
import com.reandroid.utils.CompareUtil;
import com.reandroid.utils.StringsUtil;
import com.reandroid.utils.collection.ArrayCollection;
import org.jf.baksmali.Baksmali;
import org.jf.baksmali.BaksmaliOptions;
Expand Down Expand Up @@ -71,18 +77,26 @@ public void decodeDex(DexFileInputSource inputSource, File mainDir) throws IOExc
}
@Override
public void decodeDex(ApkModule apkModule, File mainDirectory) throws IOException {
if(!canLoadFullDex(apkModule) || !APKEditor.isExperimental()) {
if(!APKEditor.isExperimental()) {
DexDecoder.super.decodeDex(apkModule, mainDirectory);
return;
}
logMessage("Loading full dex ...");
DexDirectory directory = DexDirectory.fromZip(apkModule.getZipEntryMap());
DexDirectory directory = (DexDirectory) apkModule.getTag(DexDirectory.class);
if(directory == null) {
if(!canLoadFullDex(apkModule)) {
DexDecoder.super.decodeDex(apkModule, mainDirectory);
return;
}
logMessage("Loading full dex ...");
directory = DexDirectory.fromZip(apkModule.getZipEntryMap());
}
if(decompileOptions.noDexDebug) {
logMessage("Clean debug info ...");
clearDebug_DirtyMethod(directory);
directory.refresh();
}
directory.refresh();

logMessage("Dumping smali ...");
File smali = toSmaliRoot(mainDirectory);
SmaliWriterSetting setting = new SmaliWriterSetting();
setting.setResourceIdComment(tableBlock.pickOne());
Expand All @@ -100,7 +114,15 @@ public void decodeDex(ApkModule apkModule, File mainDirectory) throws IOExceptio
}
}
private boolean canLoadFullDex(ApkModule apkModule) {
return apkModule.listDexFiles().size() < 5;
int CLASSES_LIMIT = 5;
int size = apkModule.listDexFiles().size();
logMessage("Total dex files: " + size);
if(size > CLASSES_LIMIT) {
logMessage("Huge classes your memory might not handle it, decoding separately without advanced features." +
" You can disable this restrictions by increasing \"CLASSES_LIMIT\" variable here on source code");
return false;
}
return true;
}

private void disassembleJesusFreke(DexFileInputSource inputSource, File mainDir) throws IOException {
Expand Down Expand Up @@ -162,6 +184,9 @@ private boolean removeAnnotation(TypeKey typeKey) {
if(name.startsWith("Ljavax/")) {
return true;
}
if(name.contains("SourceDebugExtension")) {
return true;
}
return name.contains("Null");
}
private void writeDexCache(DexFileInputSource inputSource, File mainDir) throws IOException {
Expand Down

0 comments on commit eca3c9a

Please sign in to comment.