28 Commits
Author SHA1 Message Date
isPointer 19a8b07717 librarySurgery 2026-09-07 18:47:15 +06:00
isPointer 978a4b12ce librarySurgery 2026-09-07 18:47:07 +06:00
isPointerandGitHub 5f9c833473 Update help.java 2026-06-24 09:10:52 +06:00
isPointerandGitHub e80e6193ed #r_mod 2026-06-24 09:07:29 +06:00
isPointerandGitHub 2983f474ed Update README.md 2026-06-15 00:20:57 +06:00
isPointerandGitHub 200a33e250 Update README.md 2026-06-14 01:20:35 +06:00
isPointerandGitHub 2c0edca6be Update README.md 2026-06-14 01:19:06 +06:00
isPointerandGitHub 75a2f7d0c1 Update README.md 2026-06-14 01:18:23 +06:00
isPointerandGitHub 920c19047a Update README.md 2026-06-14 00:54:48 +06:00
isPointerandGitHub e3eab2393a Update README.md 2026-06-14 00:54:14 +06:00
isPointerandGitHub bb4f41abd4 Add files via upload 2026-06-14 00:53:39 +06:00
isPointerandGitHub bb20f079a0 Update README.md 2026-06-14 00:22:34 +06:00
isPointerandGitHub 2cc06244a7 Update README.md 2026-06-14 00:21:33 +06:00
isPointerandGitHub 0de666f273 Update README.md 2026-06-12 02:16:51 +06:00
isPointerandGitHub 6844956c06 Update README.md 2026-06-12 02:15:02 +06:00
isPointerandGitHub c855539ef7 Update README.md 2026-06-12 02:10:13 +06:00
isPointerandGitHub 3004c4543b Update README.md 2026-06-12 02:00:54 +06:00
isPointerandGitHub dc38d1dabf Update README.md 2026-06-12 01:55:56 +06:00
isPointerandGitHub 433ad5e6fb 🎀 2026-06-12 01:55:22 +06:00
isPointerandGitHub 05dc8da620 Update README.md 2026-06-12 01:53:39 +06:00
isPointerandGitHub 343394df95 🤔 2026-06-11 09:33:10 +06:00
isPointerandGitHub aa16c29c6f 🤔 2026-06-11 09:29:00 +06:00
isPointerandGitHub 0b6ca5b3db Update banner.java 2026-06-11 09:28:34 +06:00
isPointerandGitHub f28c927a63 🤔 2026-06-11 09:28:23 +06:00
isPointerandGitHub 7c7387d032 🤔 2026-06-11 09:28:03 +06:00
isPointerandGitHub 2856eca66b 🤔 2026-06-11 09:27:45 +06:00
isPointerandGitHub e627596cff coffee 2026-06-10 23:32:12 +06:00
isPointerandGitHub cd81deb4ae :( 2026-06-10 06:20:42 +06:00
119 changed files with 2914 additions and 471 deletions
+15 -15
View File
@@ -1,15 +1,15 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties
+3
View File
@@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AndroidProjectSystem">
<option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
</component>
</project>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="17" />
</component>
</project>
+17
View File
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/antik" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MarkdownSettings">
<option name="previewPanelProviderInfo">
<ProviderInfo name="Compose (experimental)" className="com.intellij.markdown.compose.preview.ComposePanelProvider" />
</option>
</component>
</project>
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="temurin-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>
+17
View File
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
</set>
</option>
</component>
</project>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+40
View File
@@ -0,0 +1,40 @@
<p align="center">
<img src="preview/re.png" width="100" height="100" alt="RePairip logo"/>
</p>
<h1 align="center">RePairip</h1>
<p align="center">
RePairip is a Google加固 reverse engineering tool that can dump all VMRunner snapshots and fully repack Android applications, removing protection layers completely
</p>
<p align="center">
<b>Current version:</b> 1.4.14 &nbsp;|&nbsp;
<b>Language:</b> Java 17 &nbsp;|&nbsp;
<b>Build:</b> Gradle + Shadow Jar
</p>
## Tutorial
[Watch Video on RevDex.Re](https://revdex.re/input.mp4)
[Watch Video on Telegram](https://t.me/RevDex/557)
| App UI | Dump Style |
| --- | --- |
| ![App UI](preview/a1.jpg) | ![Dump Style](preview/a2.jpg) |
## License
This project is distributed under the Apache License 2.0.
```text
Apache License
Version 2.0, January 2004
https://www.apache.org/licenses/
```
Copyright (C) 2026 HighCapable
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+3
View File
@@ -0,0 +1,3 @@
This is a resource file for the antik project.
Project: RePairip
Subproject: antik
Binary file not shown.
Binary file not shown.
+3
View File
@@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: com.antik.Main
@@ -0,0 +1,137 @@
package com.antik.DexPatcher.Translation.MethodT;
import com.antik.DexPatcher.Translation.TranslationData;
import com.antik.DexPatcher.Translation.antik.PairipClass;
import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.Opcode;
import org.jf.dexlib2.builder.Label;
import org.jf.dexlib2.builder.MethodImplementationBuilder;
import org.jf.dexlib2.builder.instruction.*;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.immutable.ImmutableMethod;
import org.jf.dexlib2.immutable.reference.ImmutableFieldReference;
import org.jf.dexlib2.immutable.reference.ImmutableMethodReference;
import org.jf.dexlib2.immutable.reference.ImmutableStringReference;
import org.jf.dexlib2.immutable.reference.ImmutableTypeReference;
import java.util.Collections;
import java.util.Map;
public class MethodMaker {
public static ImmutableMethod createCleanConstructor(Method method, String superclass) {
MethodImplementationBuilder builder = new MethodImplementationBuilder(method.getParameters().size() + 1);
builder.addInstruction(new BuilderInstruction35c(Opcode.INVOKE_DIRECT, 1, 0, 0, 0, 0, 0, new ImmutableMethodReference(superclass, "<init>", null, "V")));
builder.addInstruction(new BuilderInstruction10x(Opcode.RETURN_VOID));
return new ImmutableMethod(method.getDefiningClass(), method.getName(), method.getParameters(), method.getReturnType(), method.getAccessFlags(), method.getAnnotations(), method.getHiddenApiRestrictions(), builder.getMethodImplementation());
}
public static ImmutableMethod createPrivateConstructor(String className, String superclass) {
MethodImplementationBuilder builder = new MethodImplementationBuilder(1);
builder.addInstruction(new BuilderInstruction35c(Opcode.INVOKE_DIRECT, 1, 0, 0, 0, 0, 0, new ImmutableMethodReference(superclass, "<init>", null, "V")));
builder.addInstruction(new BuilderInstruction10x(Opcode.RETURN_VOID));
return new ImmutableMethod(className, "<init>", null, "V", AccessFlags.PRIVATE.getValue() | AccessFlags.CONSTRUCTOR.getValue(), null, null, builder.getMethodImplementation());
}
public static ImmutableMethod createReturnNull(Method method) {
MethodImplementationBuilder builder = new MethodImplementationBuilder(2);
builder.addInstruction(new BuilderInstruction11n(Opcode.CONST_4, 0, 0));
builder.addInstruction(new BuilderInstruction11x(Opcode.RETURN_OBJECT, 0));
return new ImmutableMethod(method.getDefiningClass(), method.getName(), method.getParameters(), method.getReturnType(), method.getAccessFlags(), method.getAnnotations(), method.getHiddenApiRestrictions(), builder.getMethodImplementation());
}
public static ImmutableMethod createReturnVoid(Method method) {
MethodImplementationBuilder builder = new MethodImplementationBuilder(2);
builder.addInstruction(new BuilderInstruction10x(Opcode.RETURN_VOID));
return new ImmutableMethod(method.getDefiningClass(), method.getName(), method.getParameters(), method.getReturnType(), method.getAccessFlags(), method.getAnnotations(), method.getHiddenApiRestrictions(), builder.getMethodImplementation());
}
public static ImmutableMethod createLaunch(boolean hasMethods) {
MethodImplementationBuilder builder = new MethodImplementationBuilder(3);
String startupLauncher = PairipClass.STARTUP_LAUNCHER.type;
builder.addInstruction(new BuilderInstruction21c(Opcode.CONST_CLASS, 0, new ImmutableTypeReference(startupLauncher)));
builder.addInstruction(new BuilderInstruction11x(Opcode.MONITOR_ENTER, 0));
Label tryStart = builder.addLabel("try_start");
builder.addInstruction(new BuilderInstruction21c(Opcode.SGET_BOOLEAN, 1, new ImmutableFieldReference(startupLauncher, "launchCalled", "Z")));
Label tryEnd = builder.addLabel("try_end");
builder.addInstruction(new BuilderInstruction21t(Opcode.IF_EQZ, 1, builder.getLabel("cond_false")));
builder.addInstruction(new BuilderInstruction11x(Opcode.MONITOR_EXIT, 0));
builder.addInstruction(new BuilderInstruction10x(Opcode.RETURN_VOID));
builder.addLabel("cond_false");
builder.addInstruction(new BuilderInstruction11n(Opcode.CONST_4, 1, 1));
Label tryStart2 = builder.addLabel("try_start_2");
builder.addInstruction(new BuilderInstruction21c(Opcode.SPUT_BOOLEAN, 1, new ImmutableFieldReference(startupLauncher, "launchCalled", "Z")));
builder.addInstruction(new BuilderInstruction35c(Opcode.INVOKE_STATIC, 0, 0, 0, 0, 0, 0, new ImmutableMethodReference(startupLauncher, "restoreString", null, "V")));
if (hasMethods) {
builder.addInstruction(new BuilderInstruction35c(Opcode.INVOKE_STATIC, 0, 0, 0, 0, 0, 0, new ImmutableMethodReference(startupLauncher, "restoreMethod", null, "V")));
}
Label tryEnd2 = builder.addLabel("try_end_2");
builder.addInstruction(new BuilderInstruction11x(Opcode.MONITOR_EXIT, 0));
builder.addInstruction(new BuilderInstruction10x(Opcode.RETURN_VOID));
Label catchAll = builder.addLabel("catchall");
builder.addInstruction(new BuilderInstruction11x(Opcode.MOVE_EXCEPTION, 1));
Label tryStart3 = builder.addLabel("try_start_3");
builder.addInstruction(new BuilderInstruction11x(Opcode.MONITOR_EXIT, 0));
Label tryEnd3 = builder.addLabel("try_end_3");
builder.addInstruction(new BuilderInstruction11x(Opcode.THROW, 1));
builder.addCatch(tryStart, tryEnd, catchAll);
builder.addCatch(tryStart2, tryEnd2, catchAll);
builder.addCatch(tryStart3, tryEnd3, catchAll);
return new ImmutableMethod(startupLauncher, "launch", null, "V", AccessFlags.STATIC.getValue() | AccessFlags.PUBLIC.getValue() | AccessFlags.DECLARED_SYNCHRONIZED.getValue(), null, null, builder.getMethodImplementation());
}
public static ImmutableMethod createRestoreString(TranslationData data) {
MethodImplementationBuilder builder = new MethodImplementationBuilder(1);
String startupLauncher = PairipClass.STARTUP_LAUNCHER.type;
for (Map.Entry<String, TranslationData.Entry> entry : data.entries.entrySet()) {
if ("java.lang.String".equals(entry.getValue().type)) {
String targetClass = TranslationData.normalizeClassName(entry.getKey());
for (Map.Entry<String, String> field : entry.getValue().fields.entrySet()) {
builder.addInstruction(new BuilderInstruction21c(Opcode.CONST_STRING, 0, new ImmutableStringReference(field.getValue())));
builder.addInstruction(new BuilderInstruction21c(Opcode.SPUT_OBJECT, 0, new ImmutableFieldReference(targetClass, field.getKey(), "Ljava/lang/String;")));
}
}
}
builder.addInstruction(new BuilderInstruction10x(Opcode.RETURN_VOID));
return new ImmutableMethod(startupLauncher, "restoreString", null, "V", AccessFlags.STATIC.getValue() | AccessFlags.PRIVATE.getValue(), null, null, builder.getMethodImplementation());
}
public static ImmutableMethod createRestoreMethod(TranslationData data) {
MethodImplementationBuilder builder = new MethodImplementationBuilder(1);
String startupLauncher = PairipClass.STARTUP_LAUNCHER.type;
for (Map.Entry<String, TranslationData.Entry> entry : data.entries.entrySet()) {
if ("java.lang.reflect.Method".equals(entry.getValue().type)) {
String targetClass = TranslationData.normalizeClassName(entry.getKey());
for (Map.Entry<String, String> field : entry.getValue().fields.entrySet()) {
builder.addInstruction(new BuilderInstruction21c(Opcode.CONST_STRING, 0, new ImmutableStringReference(field.getValue())));
builder.addInstruction(new BuilderInstruction35c(Opcode.INVOKE_STATIC, 1, 0, 0, 0, 0, 0, new ImmutableMethodReference("Lcom/pairip/RestoreMethod;", "get", Collections.singletonList("Ljava/lang/String;"), "Ljava/lang/reflect/Method;")));
builder.addInstruction(new BuilderInstruction11x(Opcode.MOVE_RESULT_OBJECT, 0));
builder.addInstruction(new BuilderInstruction21c(Opcode.SPUT_OBJECT, 0, new ImmutableFieldReference(targetClass, field.getKey(), "Ljava/lang/reflect/Method;")));
}
}
}
builder.addInstruction(new BuilderInstruction10x(Opcode.RETURN_VOID));
return new ImmutableMethod(startupLauncher, "restoreMethod", null, "V", AccessFlags.STATIC.getValue() | AccessFlags.PRIVATE.getValue(), null, null, builder.getMethodImplementation());
}
public static ImmutableMethod createClinit() {
MethodImplementationBuilder builder = new MethodImplementationBuilder(1);
builder.addInstruction(new BuilderInstruction21c(Opcode.CONST_STRING, 0, new ImmutableStringReference("RePatcher v1.6.30")));
builder.addInstruction(new BuilderInstruction35c(Opcode.INVOKE_STATIC, 0, 0, 0, 0, 0, 0, new ImmutableMethodReference(PairipClass.STARTUP_LAUNCHER.type, "launch", null, "V")));
builder.addInstruction(new BuilderInstruction10x(Opcode.RETURN_VOID));
return new ImmutableMethod(PairipClass.APPLICATION.type, "<clinit>", null, "V", AccessFlags.STATIC.getValue() | AccessFlags.CONSTRUCTOR.getValue(), null, null, builder.getMethodImplementation());
}
}
@@ -0,0 +1,43 @@
package com.antik.DexPatcher.Translation.MethodT;
import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.Opcode;
import org.jf.dexlib2.builder.MethodImplementationBuilder;
import org.jf.dexlib2.builder.instruction.*;
import org.jf.dexlib2.immutable.ImmutableClassDef;
import org.jf.dexlib2.immutable.ImmutableMethod;
import org.jf.dexlib2.immutable.ImmutableMethodParameter;
import java.util.Collections;
public class RestoreMethodMaker {
public static ImmutableClassDef createRestoreMethodClass() {
String type = "Lcom/pairip/RestoreMethod;";
MethodImplementationBuilder builder = new MethodImplementationBuilder(3);
builder.addInstruction(new BuilderInstruction11n(Opcode.CONST_4, 0, 0));
builder.addInstruction(new BuilderInstruction11x(Opcode.RETURN_OBJECT, 0));
ImmutableMethod getMethod = new ImmutableMethod(
type,
"get",
Collections.singletonList(new ImmutableMethodParameter("Ljava/lang/String;", null, null)),
"Ljava/lang/reflect/Method;",
AccessFlags.PUBLIC.getValue() | AccessFlags.STATIC.getValue(),
null,
null,
builder.getMethodImplementation());
return new ImmutableClassDef(
type,
AccessFlags.PUBLIC.getValue(),
"Ljava/lang/Object;",
null,
null,
null,
null,
null,
Collections.singletonList(getMethod),
null);
}
}
@@ -0,0 +1,65 @@
package com.antik.DexPatcher.Translation;
import com.reandroid.json.JSONObject;
import java.io.File;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
public class TranslationData {
public static class Entry {
public final String type;
public final Map<String, String> fields;
public Entry(String type, Map<String, String> fields) {
this.type = type;
this.fields = fields;
}
}
public final Map<String, Entry> entries = new HashMap<>();
public boolean hasMethods = false;
public TranslationData(File jsonFile) throws Exception {
String content = new String(Files.readAllBytes(jsonFile.toPath()));
JSONObject json = new JSONObject(content);
for (String className : json.keySet()) {
String rawClassName = className.trim();
JSONObject classObj = json.getJSONObject(className);
String type = normalizeFieldType(classObj.getString("type"));
if ("java.lang.reflect.Method".equals(type)) {
hasMethods = true;
}
JSONObject fieldsObj = classObj.getJSONObject("fields");
Map<String, String> fields = new HashMap<>();
for (String fieldName : fieldsObj.keySet()) {
fields.put(fieldName, fieldsObj.getString(fieldName));
}
entries.put(rawClassName, new Entry(type, fields));
}
}
public static String normalizeClassName(String className) {
String normalized = className.trim();
if (normalized.isEmpty()) {
return normalized;
}
if (normalized.startsWith("L") && normalized.endsWith(";")) {
return "L" + normalized.substring(1, normalized.length() - 1).replace('.', '/').replace('\\', '/') + ";";
}
if (normalized.startsWith("[")) {
return normalized.replace('.', '/').replace('\\', '/');
}
return "L" + normalized.replace('.', '/').replace('\\', '/') + ";";
}
private static String normalizeFieldType(String type) {
if ("Ljava/lang/String;".equals(type)) {
return "java.lang.String";
}
if ("Ljava/lang/reflect/Method;".equals(type)) {
return "java.lang.reflect.Method";
}
return type;
}
}
@@ -0,0 +1,343 @@
package com.antik.DexPatcher.Translation;
import com.antik.DexPatcher.Translation.antik.PairipClass;
import com.antik.Main;
import com.reandroid.apk.ApkModule;
import com.reandroid.archive.ByteInputSource;
import com.reandroid.archive.InputSource;
import org.jf.dexlib2.DexFileFactory;
import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.DexFile;
import org.jf.dexlib2.writer.io.MemoryDataStore;
import org.jf.dexlib2.writer.pool.DexPool;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class TranslationPatcher {
private static final byte[] DEX_MAGIC = new byte[]{0x64, 0x65, 0x78, 0x0A};
private static final byte[] PAIRIP_ASSET_HEADER = new byte[]{0x00, 0x49, 0x41, 0x50, 0x02};
public static void patch(ApkModule m, File jsonFile) throws Exception {
System.out.println("[INFO] Loading translation file: " + jsonFile.getName());
TranslationData data = new TranslationData(jsonFile);
TranslationRewriter rewriter = new TranslationRewriter(data);
List<String> dexNames = new ArrayList<>();
for (InputSource s : m.getInputSources()) {
if (s.getName().endsWith(".dex")) {
dexNames.add(s.getName());
}
}
Set<String> existingDexNames = new HashSet<>(dexNames);
Set<String> existingClassTypes = new HashSet<>();
for (String dn : dexNames) {
InputSource s = m.getInputSource(dn);
if (s == null) continue;
try (InputStream input = s.openStream()) {
DexFile dexFile = loadDexFile(readAllBytes(input), "trans_scan");
for (ClassDef classDef : dexFile.getClasses()) {
existingClassTypes.add(classDef.getType());
}
}
}
List<PendingDex> extraDexes = new ArrayList<>();
if (data.hasMethods) {
extraDexes.addAll(collectEmbeddedAssetDexes(m, existingClassTypes));
PendingDex restoreMethodDex = loadRestoreMethodDex(existingClassTypes);
if (restoreMethodDex != null) {
extraDexes.add(restoreMethodDex);
}
}
for (String dn : dexNames) {
InputSource s = m.getInputSource(dn);
if (s == null) continue;
byte[] d_bs;
try (InputStream i = s.openStream()) {
d_bs = readAllBytes(i);
}
DexFile d_f = loadDexFile(d_bs, "trans");
List<ClassDef> cds = new ArrayList<>();
boolean mod = false;
for (ClassDef cd : d_f.getClasses()) {
String type = cd.getType();
if (type.startsWith("Lcom/pairip/")) {
if (PairipClass.contains(type)) {
System.out.println("[INFO] Patching " + type + " in " + dn);
cds.add(rewriter.rewrite(cd));
mod = true;
} else if (!type.equals("Lcom/pairip/PairipLog;") && !type.equals("Lcom/pairip/RestoreMethod;")) {
System.out.println("[INFO] Removing class: " + type);
mod = true;
} else {
cds.add(cd);
}
} else {
cds.add(cd);
}
}
if (mod) {
MemoryDataStore ds = new MemoryDataStore();
DexPool dp = new DexPool(Opcodes.getDefault());
for (ClassDef c : cds) {
dp.internClass(c);
}
dp.writeTo(ds);
byte[] r_bs = Arrays.copyOf(ds.getData(), ds.getSize());
m.add(new ByteInputSource(r_bs, dn));
System.out.println("[BUILD] Patched translation in " + dn);
}
}
int nextDexNumber = nextDexNumber(existingDexNames);
for (PendingDex pendingDex : extraDexes) {
if (!pendingDex.canAddAgainst(existingClassTypes)) {
if (!pendingDex.isFullyPresentIn(existingClassTypes)) {
System.err.println("[WARN] Skipping " + pendingDex.sourceName + " due to partial class overlap");
}
continue;
}
String dexEntryName = nextDexEntryName(existingDexNames, nextDexNumber);
nextDexNumber = dexNumberOf(dexEntryName) + 1;
m.add(new ByteInputSource(pendingDex.dexBytes, dexEntryName));
existingDexNames.add(dexEntryName);
existingClassTypes.addAll(pendingDex.classTypes);
System.out.println("[INFO] Added " + dexEntryName + " from " + pendingDex.sourceName);
}
List<String> libFiles = new ArrayList<>();
for (InputSource source : m.getInputSources()) {
if (source.getName().contains("libpairipcore.so")) {
libFiles.add(source.getName());
}
}
for (String libFile : libFiles) {
try {
m.getZipEntryMap().remove(libFile);
System.out.println("[INFO] Removing lib: " + libFile);
} catch (Exception e) {
System.err.println("[WARN] Could not remove lib: " + libFile);
}
}
}
private static byte[] readAllBytes(InputStream input) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[8192];
int len;
while ((len = input.read(buf)) != -1) {
baos.write(buf, 0, len);
}
return baos.toByteArray();
}
private static DexFile loadDexFile(byte[] dexBytes, String prefix) throws Exception {
File tempDex = File.createTempFile(prefix, ".dex");
try {
Files.write(tempDex.toPath(), dexBytes);
return DexFileFactory.loadDexFile(tempDex, Opcodes.getDefault());
} finally {
tempDex.delete();
}
}
private static List<PendingDex> collectEmbeddedAssetDexes(ApkModule module, Set<String> existingClassTypes) throws Exception {
List<PendingDex> pendingDexes = new ArrayList<>();
for (InputSource source : module.getInputSources()) {
if (!isTopLevelAsset(source.getName())) {
continue;
}
byte[] assetBytes;
try (InputStream input = source.openStream()) {
assetBytes = readAllBytes(input);
}
if (!startsWith(assetBytes, PAIRIP_ASSET_HEADER)) {
continue;
}
int dexStart = findEmbeddedDexStart(assetBytes);
if (dexStart < 0) {
continue;
}
try {
byte[] dexBytes = extractEmbeddedDex(assetBytes, dexStart);
PendingDex pendingDex = pendingDexFromBytes(source.getName(), dexBytes, "asset_dex");
if (!pendingDex.isFullyPresentIn(existingClassTypes)) {
pendingDexes.add(pendingDex);
}
} catch (Exception ignored) {
}
}
pendingDexes.sort((left, right) -> {
int bySize = Integer.compare(right.classTypes.size(), left.classTypes.size());
if (bySize != 0) {
return bySize;
}
return left.sourceName.compareTo(right.sourceName);
});
return pendingDexes;
}
private static PendingDex loadRestoreMethodDex(Set<String> existingClassTypes) throws Exception {
try (InputStream input = Main.class.getResourceAsStream("/restoreMethod.dex")) {
if (input == null) {
throw new FileNotFoundException("Missing resource: /restoreMethod.dex");
}
PendingDex pendingDex = pendingDexFromBytes("restoreMethod.dex", readAllBytes(input), "restore_method");
System.out.println("[INFO] Loaded classes from restoreMethod.dex");
return pendingDex.isFullyPresentIn(existingClassTypes) ? null : pendingDex;
}
}
private static PendingDex pendingDexFromBytes(String sourceName, byte[] dexBytes, String prefix) throws Exception {
DexFile dexFile = loadDexFile(dexBytes, prefix);
Set<String> classTypes = new HashSet<>();
for (ClassDef classDef : dexFile.getClasses()) {
classTypes.add(classDef.getType());
}
return new PendingDex(sourceName, dexBytes, classTypes);
}
private static boolean isTopLevelAsset(String entryName) {
if (!entryName.startsWith("assets/")) {
return false;
}
return entryName.indexOf('/', "assets/".length()) < 0;
}
private static boolean startsWith(byte[] bytes, byte[] prefix) {
if (bytes.length < prefix.length) {
return false;
}
for (int i = 0; i < prefix.length; i++) {
if (bytes[i] != prefix[i]) {
return false;
}
}
return true;
}
private static int findEmbeddedDexStart(byte[] bytes) {
for (int i = 0; i <= bytes.length - DEX_MAGIC.length; i++) {
boolean matches = true;
for (int j = 0; j < DEX_MAGIC.length; j++) {
if (bytes[i + j] != DEX_MAGIC[j]) {
matches = false;
break;
}
}
if (matches) {
return i;
}
}
return -1;
}
private static byte[] extractEmbeddedDex(byte[] assetBytes, int dexStart) {
int headerOffset = dexStart + 0x20;
if (headerOffset + 4 > assetBytes.length) {
throw new IllegalArgumentException("Embedded dex header truncated");
}
int declaredFileSize = readLittleEndianInt(assetBytes, headerOffset);
if (declaredFileSize <= 0) {
throw new IllegalArgumentException("Embedded dex declared invalid file size: " + declaredFileSize);
}
int dexEnd = dexStart + declaredFileSize;
if (dexEnd > assetBytes.length) {
throw new IllegalArgumentException("Embedded dex declared size exceeds asset bounds: " + declaredFileSize);
}
return Arrays.copyOfRange(assetBytes, dexStart, dexEnd);
}
private static int readLittleEndianInt(byte[] bytes, int offset) {
return (bytes[offset] & 0xFF) | ((bytes[offset + 1] & 0xFF) << 8) | ((bytes[offset + 2] & 0xFF) << 16) | ((bytes[offset + 3] & 0xFF) << 24);
}
private static int nextDexNumber(Set<String> dexEntryNames) {
int next = 1;
for (String name : dexEntryNames) {
next = Math.max(next, dexNumberOf(name) + 1);
}
return next;
}
private static int dexNumberOf(String dexEntryName) {
if ("classes.dex".equals(dexEntryName)) {
return 1;
}
if (!dexEntryName.startsWith("classes") || !dexEntryName.endsWith(".dex")) {
return -1;
}
String middle = dexEntryName.substring("classes".length(), dexEntryName.length() - ".dex".length());
if (middle.isEmpty()) {
return 1;
}
try {
return Integer.parseInt(middle);
} catch (NumberFormatException ignored) {
return -1;
}
}
private static String nextDexEntryName(Set<String> dexEntryNames, int startNumber) {
int number = Math.max(startNumber, 1);
while (true) {
String candidate = number == 1 ? "classes.dex" : "classes" + number + ".dex";
if (!dexEntryNames.contains(candidate)) {
return candidate;
}
number++;
}
}
private static final class PendingDex {
private final String sourceName;
private final byte[] dexBytes;
private final Set<String> classTypes;
private PendingDex(String sourceName, byte[] dexBytes, Set<String> classTypes) {
this.sourceName = sourceName;
this.dexBytes = dexBytes;
this.classTypes = classTypes;
}
private boolean isFullyPresentIn(Set<String> existingClassTypes) {
return existingClassTypes.containsAll(classTypes);
}
private boolean canAddAgainst(Set<String> existingClassTypes) {
for (String classType : classTypes) {
if (existingClassTypes.contains(classType)) {
return false;
}
}
return true;
}
}
}
@@ -0,0 +1,92 @@
package com.antik.DexPatcher.Translation;
import com.antik.DexPatcher.Translation.MethodT.MethodMaker;
import com.antik.DexPatcher.Translation.antik.PairipClass;
import org.jf.dexlib2.AccessFlags;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.immutable.ImmutableClassDef;
import org.jf.dexlib2.immutable.ImmutableField;
import org.jf.dexlib2.immutable.value.ImmutableBooleanEncodedValue;
import java.util.ArrayList;
import java.util.List;
public class TranslationRewriter {
private final TranslationData data;
public TranslationRewriter(TranslationData data) {
this.data = data;
}
public ClassDef rewrite(ClassDef cd) {
String type = cd.getType();
if (PairipClass.APPLICATION.type.equals(type)) {
return patchApplication(cd);
} else if (PairipClass.STARTUP_LAUNCHER.type.equals(type)) {
return patchStartupLauncher(cd);
} else if (PairipClass.VM_RUNNER.type.equals(type)) {
return patchVMRunner(cd);
} else if (PairipClass.LICENSE_CLIENT_V3.type.equals(type)) {
return patchLicenseClient(cd);
}
return cd;
}
private ClassDef patchApplication(ClassDef cd) {
List<Method> methods = new ArrayList<>();
for (Method m : cd.getMethods()) {
if ("<init>".equals(m.getName())) {
methods.add(MethodMaker.createCleanConstructor(m, cd.getSuperclass()));
}
}
methods.add(MethodMaker.createClinit());
return new ImmutableClassDef(cd.getType(), cd.getAccessFlags(), cd.getSuperclass(), cd.getInterfaces(), cd.getSourceFile(), cd.getAnnotations(), cd.getStaticFields(), cd.getInstanceFields(), methods, null);
}
private ClassDef patchVMRunner(ClassDef cd) {
List<Method> methods = new ArrayList<>();
methods.add(MethodMaker.createPrivateConstructor(cd.getType(), cd.getSuperclass()));
for (Method m : cd.getMethods()) {
if ("invoke".equals(m.getName())) {
methods.add(MethodMaker.createReturnNull(m));
}
}
return new ImmutableClassDef(cd.getType(), AccessFlags.PUBLIC.getValue(), cd.getSuperclass(), cd.getInterfaces(), cd.getSourceFile(), null, null, null, methods, null);
}
private ClassDef patchLicenseClient(ClassDef cd) {
List<Method> methods = new ArrayList<>();
for (Method m : cd.getMethods()) {
if ("<init>".equals(m.getName())) {
methods.add(MethodMaker.createCleanConstructor(m, cd.getSuperclass()));
} else if ("onActivityCreate".equals(m.getName())) {
methods.add(MethodMaker.createReturnVoid(m));
}
}
return new ImmutableClassDef(cd.getType(), cd.getAccessFlags(), cd.getSuperclass(), cd.getInterfaces(), cd.getSourceFile(), cd.getAnnotations(), cd.getStaticFields(), cd.getInstanceFields(), methods, null);
}
private ClassDef patchStartupLauncher(ClassDef cd) {
List<Method> methods = new ArrayList<>();
for (Method m : cd.getMethods()) {
if ("<init>".equals(m.getName())) {
methods.add(m);
}
}
methods.add(MethodMaker.createLaunch(data.hasMethods));
methods.add(MethodMaker.createRestoreString(data));
if (data.hasMethods) {
methods.add(MethodMaker.createRestoreMethod(data));
}
List<ImmutableField> fields = new ArrayList<>();
fields.add(new ImmutableField(cd.getType(), "launchCalled", "Z", AccessFlags.STATIC.getValue() | AccessFlags.PRIVATE.getValue(), ImmutableBooleanEncodedValue.FALSE_VALUE, null, null));
return new ImmutableClassDef(cd.getType(), cd.getAccessFlags(), cd.getSuperclass(), cd.getInterfaces(), cd.getSourceFile(), cd.getAnnotations(), fields, cd.getInstanceFields(), methods, null);
}
}
@@ -0,0 +1,21 @@
package com.antik.DexPatcher.Translation.antik;
public enum PairipClass {
VM_RUNNER("Lcom/pairip/VMRunner;"),
APPLICATION("Lcom/pairip/application/Application;"),
STARTUP_LAUNCHER("Lcom/pairip/StartupLauncher;"),
LICENSE_CLIENT_V3("Lcom/pairip/licensecheck3/LicenseClientV3;");
public final String type;
PairipClass(String type) {
this.type = type;
}
public static boolean contains(String type) {
for (PairipClass pc : values()) {
if (pc.type.equals(type)) return true;
}
return false;
}
}
+142 -113
View File
@@ -1,156 +1,185 @@
package com.antik;
import com.antik.DexPatcher.DexPatcher;
import com.antik.DexPatcher.Translation.TranslationPatcher;
import com.antik.crc32.crc32;
import com.antik.manifest.manifestP;
import com.antik.root.*;
import com.antik.root.PackageM.Installer;
import com.antik.root.PackageM.uninstaller;
import com.antik.ui.*;
import com.antik.utils.*;
import com.reandroid.apk.ApkBundle;
import com.reandroid.apk.ApkModule;
import java.io.*;
import java.nio.file.Files;
/*
* Created by aantik
* 3/20/2026 6:20 PM
*
* ⋆ ႔ ႔
* ᠸ^ ^ ⸝⸝
* |、˜〵
* じしˍ,)⁐̤ᐷ
*
* Fox Mode 🍺
*/
/**
*
* @life is butterfly flyfly
* I am a professional Android Developer
*
*/
public class Main {
public static void main(String[] a) {
public static void main(String[] args) {
if (a.length < 2 || !"-i".equals(a[0]))
{
for (String arg : args) {
if ("-p".equals(arg) || "--package".equals(arg)) {
com.antik.librarySurgery.LibSurgery.main(args);
return;
}
}
if (args.length < 2) {
help.help();
return;
}
String P_ta = a[1];
File I_pa = new File(P_ta);
String inputPath = null;
String translatePath = null;
boolean R_mod = false;
if (!I_pa.exists()) {
System.err.println("Input file not found : " + P_ta);
for (int i = 0; i < args.length; i++) {
if ("-i".equals(args[i]) && i + 1 < args.length) {
inputPath = args[i + 1];
} else if ("-t".equals(args[i]) && i + 1 < args.length) {
translatePath = args[i + 1];
} else if ("-r".equals(args[i])) {
R_mod = true;
}
}
if (inputPath == null) {
help.help();
return;
}
File inputApk = new File(inputPath);
if (!inputApk.exists()) {
System.err.println("Input file not found : " + inputPath);
return;
}
banner.banner();
File T_Dir = null;
File T_dIR = null;
try {
ApkModule module;
File mergedApkFile;
T_Dir = Files.createTempDirectory("antik_merge").toFile();
System.out.println("[MERGE] Extracting APKs...");
AntikUtils.ex_apks(I_pa, T_Dir);
System.out.println("[MERGE] Merging APK...");
ApkBundle bd = new ApkBundle();
bd.loadApkDirectory(T_Dir);
ApkModule Sp_T = bd.mergeModules();
System.out.println("[INFO] Patching AndroidManifest.xml");
try {
manifestP.patch(Sp_T);
} catch (Exception e) {
System.err.println("[ERROR] Manifest patching failed: " + e.getMessage());
e.printStackTrace();
}
String o = I_pa.getName();
int d = o.lastIndexOf('.');
if (d > 0) {
o = o.substring(0, d) + "_merged.apk";
if (inputPath.endsWith(".apk")) {
System.out.println("[INFO] Loading APK ");
module = ApkModule.loadApkFile(inputApk);
mergedApkFile = inputApk;
} else {
o = o + "_merged.apk";
}
T_dIR = Files.createTempDirectory("antik_merge").toFile();
System.out.println("[MERGE] Extracting APKS ");
AntikUtils.ex_apks(inputApk, T_dIR);
System.out.println("[MERGE] Merging APK ");
ApkBundle bundle = new ApkBundle();
bundle.loadApkDirectory(T_dIR);
module = bundle.mergeModules();
File o_f = new File(output.get_out(I_pa, o));
int T_tl = Sp_T.getZipEntryMap().size();
if (Sp_T.hasTableBlock()) {
T_tl = T_tl - 1;
}
int[] c = {0};
final int T_l = T_tl;
Sp_T.writeApk(o_f, new com.reandroid.archive.WriteProgress() {
@Override
public void onCompressFile(String p, int m, long w) {
c[0]++;
loading.progress(c[0], T_l);
System.out.println("[INFO] Patching AndroidManifest.xml");
try {
manifestP.patch(module);
} catch (Exception e) {
System.err.println("[ERROR] Manifest patching failed : " + e.getMessage());
}
});
loading.progress(T_l, T_l);
String name = inputApk.getName();
int dot = name.lastIndexOf('.');
name = (dot > 0 ? name.substring(0, dot) : name) + "_merged.apk";
mergedApkFile = new File(output.get_out(inputApk, name));
System.out.println();
System.out.println("[MERGE] APK merged successfully..");
String pkg = "unknown";
try {
pkg = Sp_T.getPackageName();
System.out.println("[INFO] Package Name: " + pkg);
} catch (Exception ignored) {}
String p_n = I_pa.getName();
int d2 = p_n.lastIndexOf('.');
if (d2 > 0) {
p_n = p_n.substring(0, d2) + "_pairip.apk";
} else {
p_n = p_n + "_pairip.apk";
}
File Pai_Dir = new File(output.get_out(I_pa, p_n));
System.out.println("[INFO] Patching classes.dex");
try {
DexPatcher.patch(Sp_T);
} catch (Exception e) {
System.err.println("[ERROR] Patching failed: " + e.getMessage());
System.out.println("[BUILD] Writing merged APK ");
loading.progress(module, mergedApkFile);
System.out.println("[MERGE] APK merged successfully: " + mergedApkFile.getAbsolutePath());
}
System.out.println("[BUILD] Building APK...");
Sp_T.writeApk(Pai_Dir);
crc32.patch(o_f, Pai_Dir);
if (translatePath != null) {
File jsonFile = new File(translatePath);
if (jsonFile.exists()) {
System.out.println("[INFO] Starting Translation Patch ");
TranslationPatcher.patch(module, jsonFile);
String tn = mergedApkFile.getName();
int td = tn.lastIndexOf('.');
tn = (td > 0 ? tn.substring(0, td) : tn) + "_translated.apk";
File transFile = new File(output.get_out(inputApk, tn));
System.out.println("[BUILD] Building Translated APK ");
output.write(module, transFile);
System.out.println("[BUILD] Translated APK built at : " + transFile.getAbsolutePath());
} else {
System.err.println("[ERROR] Translation file not found : " + translatePath);
}
} else if (!inputPath.endsWith(".apk")) {
System.out.println("[INFO] Patching classes.dex for logging ");
try {
DexPatcher.patch(module);
} catch (Exception e) {
System.err.println("[ERROR] Patching failed : " + e.getMessage());
}
String pn = mergedApkFile.getName();
int pd = pn.lastIndexOf('.');
pn = (pd > 0 ? pn.substring(0, pd) : pn) + "_pairip.apk";
File paiFile = new File(output.get_out(inputApk, pn));
System.out.println("[BUILD] Building Logging APK ");
output.write(module, paiFile);
crc32.patch(mergedApkFile, paiFile);
System.out.println("[BUILD] Logging APK built at : " + paiFile.getAbsolutePath());
if (R_mod) {
String pkg = module.getPackageName();
System.out.println("[ROOT] Starting Root Mode for package : " + pkg);
uninstaller.uninstall(pkg);
Installer.install(paiFile);
if (T_dIR != null) {
File originalBase = new File(T_dIR, "base.apk");
if (originalBase.exists()) {
Base.replaceBase(pkg, originalBase);
launchApp.launchApp(pkg);
File pulledJson = new File(output.get_out(inputApk, "pairip.json"));
if (Pull.waitForFileAndPull(pkg, "dictionary/pairip.json", pulledJson)) {
System.out.println("[ROOT] pairip.json captured!");
Runtime.getRuntime().exec(new String[]{"su", "-c", "am force-stop " + pkg}).waitFor();
uninstaller.uninstall(pkg);
System.out.println("[INFO] Reloading clean merged APK for final patching ");
module = ApkModule.loadApkFile(mergedApkFile);
System.out.println("[INFO] Starting Translation Patch with captured JSON ");
TranslationPatcher.patch(module, pulledJson);
String tn = mergedApkFile.getName();
int td = tn.lastIndexOf('.');
tn = (td > 0 ? tn.substring(0, td) : tn) + "_translated.apk";
File transFile = new File(output.get_out(inputApk, tn));
System.out.println("[BUILD] Building Final Translated APK ");
output.write(module, transFile);
System.out.println("[BUILD] Final APK built at : " + transFile.getAbsolutePath());
}
} else {
System.err.println("[ERROR] Original base.apk not found in APKS for root replacement");
}
} else {
System.out.println("[ROOT] Root mode replacement skipped (Input was not an APKS file)");
}
}
}
System.out.println("[BUILD] APK built successfully at " + Pai_Dir.getAbsolutePath());
System.out.println("[BUILD] Process completed");
System.out.println("--------------------------------------");
System.out.println("⚠️ DO NOT use the pairip app (" + Pai_Dir.getAbsolutePath() + ") for translation.");
System.out.println("It is incomplete and intended for logging only.");
System.out.println("Please use the merged app instead (" + o_f.getAbsolutePath() + ").");
System.out.println("--------------------------------------");
} catch (Exception e) {
System.err.println("[ERROR] Merge failed: " + e.getMessage());
System.err.println("[ERROR] Process failed : " + e.getMessage());
e.printStackTrace();
} finally {
if (T_Dir != null) {
deleteDir.del_dir(T_Dir);
if (T_dIR != null) {
deleteDir.del_dir(T_dIR);
}
}
}
+289
View File
@@ -0,0 +1,289 @@
package com.antik;
import com.google.common.collect.ImmutableRangeMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Range;
import com.google.common.collect.RangeMap;
import org.jf.dexlib2.Format;
import org.jf.dexlib2.ReferenceType;
import javax.annotation.Nonnull;
import java.util.List;
public enum Opcode {
/* NOP(0x00, "nop", ReferenceType.NONE, Format.Format10x, org.jf.dexlib2.Opcode.CAN_CONTINUE),
MOVE(0x01, "move", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
MOVE_FROM16(0x02, "move/from16", ReferenceType.NONE, Format.Format22x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
MOVE_16(0x03, "move/16", ReferenceType.NONE, Format.Format32x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
MOVE_WIDE(0x04, "move-wide", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
MOVE_WIDE_FROM16(0x05, "move-wide/from16", ReferenceType.NONE, Format.Format22x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
MOVE_WIDE_16(0x06, "move-wide/16", ReferenceType.NONE, Format.Format32x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
MOVE_OBJECT(0x07, "move-object", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
MOVE_OBJECT_FROM16(0x08, "move-object/from16", ReferenceType.NONE, Format.Format22x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
MOVE_OBJECT_16(0x09, "move-object/16", ReferenceType.NONE, Format.Format32x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
MOVE_RESULT(0x0a, "move-result", ReferenceType.NONE, Format.Format11x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
MOVE_RESULT_WIDE(0x0b, "move-result-wide", ReferenceType.NONE, Format.Format11x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
MOVE_RESULT_OBJECT(0x0c, "move-result-object", ReferenceType.NONE, Format.Format11x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
MOVE_EXCEPTION(0x0d, "move-exception", ReferenceType.NONE, Format.Format11x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
RETURN_VOID(0x0e, "return-void", ReferenceType.NONE, Format.Format10x),
RETURN(0x0f, "return", ReferenceType.NONE, Format.Format11x),
RETURN_WIDE(0x10, "return-wide", ReferenceType.NONE, Format.Format11x),
RETURN_OBJECT(0x11, "return-object", ReferenceType.NONE, Format.Format11x),
CONST_4(0x12, "const/4", ReferenceType.NONE, Format.Format11n, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
CONST_16(0x13, "const/16", ReferenceType.NONE, Format.Format21s, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
CONST(0x14, "const", ReferenceType.NONE, Format.Format31i, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
CONST_HIGH16(0x15, "const/high16", ReferenceType.NONE, Format.Format21ih, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
CONST_WIDE_16(0x16, "const-wide/16", ReferenceType.NONE, Format.Format21s, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
CONST_WIDE_32(0x17, "const-wide/32", ReferenceType.NONE, Format.Format31i, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
CONST_WIDE(0x18, "const-wide", ReferenceType.NONE, Format.Format51l, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
CONST_WIDE_HIGH16(0x19, "const-wide/high16", ReferenceType.NONE, Format.Format21lh, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
CONST_STRING(0x1a, "const-string", ReferenceType.STRING, Format.Format21c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
CONST_STRING_JUMBO(0x1b, "const-string/jumbo", ReferenceType.STRING, Format.Format31c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
CONST_CLASS(0x1c, "const-class", ReferenceType.TYPE, Format.Format21c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
MONITOR_ENTER(0x1d, "monitor-enter", ReferenceType.NONE, Format.Format11x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
MONITOR_EXIT(0x1e, "monitor-exit", ReferenceType.NONE, Format.Format11x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
CHECK_CAST(0x1f, "check-cast", ReferenceType.TYPE, Format.Format21c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
INSTANCE_OF(0x20, "instance-of", ReferenceType.TYPE, Format.Format22c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
ARRAY_LENGTH(0x21, "array-length", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
NEW_INSTANCE(0x22, "new-instance", ReferenceType.TYPE, Format.Format21c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
NEW_ARRAY(0x23, "new-array", ReferenceType.TYPE, Format.Format22c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
FILLED_NEW_ARRAY(0x24, "filled-new-array", ReferenceType.TYPE, Format.Format35c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT),
FILLED_NEW_ARRAY_RANGE(0x25, "filled-new-array/range", ReferenceType.TYPE, Format.Format3rc, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT),
FILL_ARRAY_DATA(0x26, "fill-array-data", ReferenceType.NONE, Format.Format31t, org.jf.dexlib2.Opcode.CAN_CONTINUE),
THROW(0x27, "throw", ReferenceType.NONE, Format.Format11x, org.jf.dexlib2.Opcode.CAN_THROW),
GOTO(0x28, "goto", ReferenceType.NONE, Format.Format10t),
GOTO_16(0x29, "goto/16", ReferenceType.NONE, Format.Format20t),
GOTO_32(0x2a, "goto/32", ReferenceType.NONE, Format.Format30t),
PACKED_SWITCH(0x2b, "packed-switch", ReferenceType.NONE, Format.Format31t, org.jf.dexlib2.Opcode.CAN_CONTINUE),
SPARSE_SWITCH(0x2c, "sparse-switch", ReferenceType.NONE, Format.Format31t, org.jf.dexlib2.Opcode.CAN_CONTINUE),
CMPL_FLOAT(0x2d, "cmpl-float", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
CMPG_FLOAT(0x2e, "cmpg-float", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
CMPL_DOUBLE(0x2f, "cmpl-double", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
CMPG_DOUBLE(0x30, "cmpg-double", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
CMP_LONG(0x31, "cmp-long", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
IF_EQ(0x32, "if-eq", ReferenceType.NONE, Format.Format22t, org.jf.dexlib2.Opcode.CAN_CONTINUE),
IF_NE(0x33, "if-ne", ReferenceType.NONE, Format.Format22t, org.jf.dexlib2.Opcode.CAN_CONTINUE),
IF_LT(0x34, "if-lt", ReferenceType.NONE, Format.Format22t, org.jf.dexlib2.Opcode.CAN_CONTINUE),
IF_GE(0x35, "if-ge", ReferenceType.NONE, Format.Format22t, org.jf.dexlib2.Opcode.CAN_CONTINUE),
IF_GT(0x36, "if-gt", ReferenceType.NONE, Format.Format22t, org.jf.dexlib2.Opcode.CAN_CONTINUE),
IF_LE(0x37, "if-le", ReferenceType.NONE, Format.Format22t, org.jf.dexlib2.Opcode.CAN_CONTINUE),
IF_EQZ(0x38, "if-eqz", ReferenceType.NONE, Format.Format21t, org.jf.dexlib2.Opcode.CAN_CONTINUE),
IF_NEZ(0x39, "if-nez", ReferenceType.NONE, Format.Format21t, org.jf.dexlib2.Opcode.CAN_CONTINUE),
IF_LTZ(0x3a, "if-ltz", ReferenceType.NONE, Format.Format21t, org.jf.dexlib2.Opcode.CAN_CONTINUE),
IF_GEZ(0x3b, "if-gez", ReferenceType.NONE, Format.Format21t, org.jf.dexlib2.Opcode.CAN_CONTINUE),
IF_GTZ(0x3c, "if-gtz", ReferenceType.NONE, Format.Format21t, org.jf.dexlib2.Opcode.CAN_CONTINUE),
IF_LEZ(0x3d, "if-lez", ReferenceType.NONE, Format.Format21t, org.jf.dexlib2.Opcode.CAN_CONTINUE),
AGET(0x44, "aget", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
AGET_WIDE(0x45, "aget-wide", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
AGET_OBJECT(0x46, "aget-object", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
AGET_BOOLEAN(0x47, "aget-boolean", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
AGET_BYTE(0x48, "aget-byte", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
AGET_CHAR(0x49, "aget-char", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
AGET_SHORT(0x4a, "aget-short", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
APUT(0x4b, "aput", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
APUT_WIDE(0x4c, "aput-wide", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
APUT_OBJECT(0x4d, "aput-object", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
APUT_BOOLEAN(0x4e, "aput-boolean", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
APUT_BYTE(0x4f, "aput-byte", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
APUT_CHAR(0x50, "aput-char", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
APUT_SHORT(0x51, "aput-short", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
IGET(0x52, "iget", ReferenceType.FIELD, Format.Format22c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
IGET_WIDE(0x53, "iget-wide", ReferenceType.FIELD, Format.Format22c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
IGET_OBJECT(0x54, "iget-object", ReferenceType.FIELD, Format.Format22c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
IGET_BOOLEAN(0x55, "iget-boolean", ReferenceType.FIELD, Format.Format22c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
IGET_BYTE(0x56, "iget-byte", ReferenceType.FIELD, Format.Format22c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
IGET_CHAR(0x57, "iget-char", ReferenceType.FIELD, Format.Format22c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
IGET_SHORT(0x58, "iget-short", ReferenceType.FIELD, Format.Format22c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
IPUT(0x59, "iput", ReferenceType.FIELD, Format.Format22c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
IPUT_WIDE(0x5a, "iput-wide", ReferenceType.FIELD, Format.Format22c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
IPUT_OBJECT(0x5b, "iput-object", ReferenceType.FIELD, Format.Format22c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
IPUT_BOOLEAN(0x5c, "iput-boolean", ReferenceType.FIELD, Format.Format22c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
IPUT_BYTE(0x5d, "iput-byte", ReferenceType.FIELD, Format.Format22c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
IPUT_CHAR(0x5e, "iput-char", ReferenceType.FIELD, Format.Format22c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
IPUT_SHORT(0x5f, "iput-short", ReferenceType.FIELD, Format.Format22c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
SGET(0x60, "sget", ReferenceType.FIELD, Format.Format21c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.STATIC_FIELD_ACCESSOR),
SGET_WIDE(0x61, "sget-wide", ReferenceType.FIELD, Format.Format21c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER | org.jf.dexlib2.Opcode.STATIC_FIELD_ACCESSOR),
SGET_OBJECT(0x62, "sget-object", ReferenceType.FIELD, Format.Format21c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.STATIC_FIELD_ACCESSOR),
SGET_BOOLEAN(0x63, "sget-boolean", ReferenceType.FIELD, Format.Format21c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.STATIC_FIELD_ACCESSOR),
SGET_BYTE(0x64, "sget-byte", ReferenceType.FIELD, Format.Format21c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.STATIC_FIELD_ACCESSOR),
SGET_CHAR(0x65, "sget-char", ReferenceType.FIELD, Format.Format21c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.STATIC_FIELD_ACCESSOR),
SGET_SHORT(0x66, "sget-short", ReferenceType.FIELD, Format.Format21c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.STATIC_FIELD_ACCESSOR),
SPUT(0x67, "sput", ReferenceType.FIELD, Format.Format21c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.STATIC_FIELD_ACCESSOR),
SPUT_WIDE(0x68, "sput-wide", ReferenceType.FIELD, Format.Format21c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.STATIC_FIELD_ACCESSOR),
SPUT_OBJECT(0x69, "sput-object", ReferenceType.FIELD, Format.Format21c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.STATIC_FIELD_ACCESSOR),
SPUT_BOOLEAN(0x6a, "sput-boolean", ReferenceType.FIELD, Format.Format21c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.STATIC_FIELD_ACCESSOR),
SPUT_BYTE(0x6b, "sput-byte", ReferenceType.FIELD, Format.Format21c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.STATIC_FIELD_ACCESSOR),
SPUT_CHAR(0x6c, "sput-char", ReferenceType.FIELD, Format.Format21c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.STATIC_FIELD_ACCESSOR),
SPUT_SHORT(0x6d, "sput-short", ReferenceType.FIELD, Format.Format21c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.STATIC_FIELD_ACCESSOR),
INVOKE_VIRTUAL(0x6e, "invoke-virtual", ReferenceType.METHOD, Format.Format35c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT),
INVOKE_SUPER(0x6f, "invoke-super", ReferenceType.METHOD, Format.Format35c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT),
INVOKE_DIRECT(0x70, "invoke-direct", ReferenceType.METHOD, Format.Format35c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT | org.jf.dexlib2.Opcode.CAN_INITIALIZE_REFERENCE),
INVOKE_STATIC(0x71, "invoke-static", ReferenceType.METHOD, Format.Format35c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT),
INVOKE_INTERFACE(0x72, "invoke-interface", ReferenceType.METHOD, Format.Format35c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT),
INVOKE_VIRTUAL_RANGE(0x74, "invoke-virtual/range", ReferenceType.METHOD, Format.Format3rc, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT),
INVOKE_SUPER_RANGE(0x75, "invoke-super/range", ReferenceType.METHOD, Format.Format3rc, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT),
INVOKE_DIRECT_RANGE(0x76, "invoke-direct/range", ReferenceType.METHOD, Format.Format3rc, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT | org.jf.dexlib2.Opcode.CAN_INITIALIZE_REFERENCE),
INVOKE_STATIC_RANGE(0x77, "invoke-static/range", ReferenceType.METHOD, Format.Format3rc, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT),
INVOKE_INTERFACE_RANGE(0x78, "invoke-interface/range", ReferenceType.METHOD, Format.Format3rc, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT),
NEG_INT(0x7b, "neg-int", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
NOT_INT(0x7c, "not-int", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
NEG_LONG(0x7d, "neg-long", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
NOT_LONG(0x7e, "not-long", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
NEG_FLOAT(0x7f, "neg-float", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
NEG_DOUBLE(0x80, "neg-double", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
INT_TO_LONG(0x81, "int-to-long", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
INT_TO_FLOAT(0x82, "int-to-float", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
INT_TO_DOUBLE(0x83, "int-to-double", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
LONG_TO_INT(0x84, "long-to-int", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
LONG_TO_FLOAT(0x85, "long-to-float", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
LONG_TO_DOUBLE(0x86, "long-to-double", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
FLOAT_TO_INT(0x87, "float-to-int", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
FLOAT_TO_LONG(0x88, "float-to-long", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
FLOAT_TO_DOUBLE(0x89, "float-to-double", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
DOUBLE_TO_INT(0x8a, "double-to-int", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
DOUBLE_TO_LONG(0x8b, "double-to-long", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
DOUBLE_TO_FLOAT(0x8c, "double-to-float", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
INT_TO_BYTE(0x8d, "int-to-byte", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
INT_TO_CHAR(0x8e, "int-to-char", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
INT_TO_SHORT(0x8f, "int-to-short", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
ADD_INT(0x90, "add-int", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
SUB_INT(0x91, "sub-int", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
MUL_INT(0x92, "mul-int", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
DIV_INT(0x93, "div-int", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
REM_INT(0x94, "rem-int", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
AND_INT(0x95, "and-int", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
OR_INT(0x96, "or-int", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
XOR_INT(0x97, "xor-int", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
SHL_INT(0x98, "shl-int", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
SHR_INT(0x99, "shr-int", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
USHR_INT(0x9a, "ushr-int", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
ADD_LONG(0x9b, "add-long", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
SUB_LONG(0x9c, "sub-long", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
MUL_LONG(0x9d, "mul-long", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
DIV_LONG(0x9e, "div-long", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
REM_LONG(0x9f, "rem-long", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
AND_LONG(0xa0, "and-long", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
OR_LONG(0xa1, "or-long", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
XOR_LONG(0xa2, "xor-long", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
SHL_LONG(0xa3, "shl-long", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
SHR_LONG(0xa4, "shr-long", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
USHR_LONG(0xa5, "ushr-long", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
ADD_FLOAT(0xa6, "add-float", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
SUB_FLOAT(0xa7, "sub-float", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
MUL_FLOAT(0xa8, "mul-float", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
DIV_FLOAT(0xa9, "div-float", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
REM_FLOAT(0xaa, "rem-float", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
ADD_DOUBLE(0xab, "add-double", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
SUB_DOUBLE(0xac, "sub-double", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
MUL_DOUBLE(0xad, "mul-double", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
DIV_DOUBLE(0xae, "div-double", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
REM_DOUBLE(0xaf, "rem-double", ReferenceType.NONE, Format.Format23x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
ADD_INT_2ADDR(0xb0, "add-int/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
SUB_INT_2ADDR(0xb1, "sub-int/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
MUL_INT_2ADDR(0xb2, "mul-int/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
DIV_INT_2ADDR(0xb3, "div-int/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
REM_INT_2ADDR(0xb4, "rem-int/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
AND_INT_2ADDR(0xb5, "and-int/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
OR_INT_2ADDR(0xb6, "or-int/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
XOR_INT_2ADDR(0xb7, "xor-int/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
SHL_INT_2ADDR(0xb8, "shl-int/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
SHR_INT_2ADDR(0xb9, "shr-int/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
USHR_INT_2ADDR(0xba, "ushr-int/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
ADD_LONG_2ADDR(0xbb, "add-long/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
SUB_LONG_2ADDR(0xbc, "sub-long/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
MUL_LONG_2ADDR(0xbd, "mul-long/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
DIV_LONG_2ADDR(0xbe, "div-long/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
REM_LONG_2ADDR(0xbf, "rem-long/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
AND_LONG_2ADDR(0xc0, "and-long/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
OR_LONG_2ADDR(0xc1, "or-long/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
XOR_LONG_2ADDR(0xc2, "xor-long/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
SHL_LONG_2ADDR(0xc3, "shl-long/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
SHR_LONG_2ADDR(0xc4, "shr-long/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
USHR_LONG_2ADDR(0xc5, "ushr-long/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
ADD_FLOAT_2ADDR(0xc6, "add-float/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
SUB_FLOAT_2ADDR(0xc7, "sub-float/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
MUL_FLOAT_2ADDR(0xc8, "mul-float/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
DIV_FLOAT_2ADDR(0xc9, "div-float/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
REM_FLOAT_2ADDR(0xca, "rem-float/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
ADD_DOUBLE_2ADDR(0xcb, "add-double/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
SUB_DOUBLE_2ADDR(0xcc, "sub-double/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
MUL_DOUBLE_2ADDR(0xcd, "mul-double/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
DIV_DOUBLE_2ADDR(0xce, "div-double/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
REM_DOUBLE_2ADDR(0xcf, "rem-double/2addr", ReferenceType.NONE, Format.Format12x, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
ADD_INT_LIT16(0xd0, "add-int/lit16", ReferenceType.NONE, Format.Format22s, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
RSUB_INT(0xd1, "rsub-int", ReferenceType.NONE, Format.Format22s, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
MUL_INT_LIT16(0xd2, "mul-int/lit16", ReferenceType.NONE, Format.Format22s, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
DIV_INT_LIT16(0xd3, "div-int/lit16", ReferenceType.NONE, Format.Format22s, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
REM_INT_LIT16(0xd4, "rem-int/lit16", ReferenceType.NONE, Format.Format22s, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
AND_INT_LIT16(0xd5, "and-int/lit16", ReferenceType.NONE, Format.Format22s, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
OR_INT_LIT16(0xd6, "or-int/lit16", ReferenceType.NONE, Format.Format22s, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
XOR_INT_LIT16(0xd7, "xor-int/lit16", ReferenceType.NONE, Format.Format22s, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
ADD_INT_LIT8(0xd8, "add-int/lit8", ReferenceType.NONE, Format.Format22b, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
RSUB_INT_LIT8(0xd9, "rsub-int/lit8", ReferenceType.NONE, Format.Format22b, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
MUL_INT_LIT8(0xda, "mul-int/lit8", ReferenceType.NONE, Format.Format22b, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
DIV_INT_LIT8(0xdb, "div-int/lit8", ReferenceType.NONE, Format.Format22b, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
REM_INT_LIT8(0xdc, "rem-int/lit8", ReferenceType.NONE, Format.Format22b, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
AND_INT_LIT8(0xdd, "and-int/lit8", ReferenceType.NONE, Format.Format22b, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
OR_INT_LIT8(0xde, "or-int/lit8", ReferenceType.NONE, Format.Format22b, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
XOR_INT_LIT8(0xdf, "xor-int/lit8", ReferenceType.NONE, Format.Format22b, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
SHL_INT_LIT8(0xe0, "shl-int/lit8", ReferenceType.NONE, Format.Format22b, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
SHR_INT_LIT8(0xe1, "shr-int/lit8", ReferenceType.NONE, Format.Format22b, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
USHR_INT_LIT8(0xe2, "ushr-int/lit8", ReferenceType.NONE, Format.Format22b, org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
IGET_VOLATILE(firstApi(0xe3, 9), "iget-volatile", ReferenceType.FIELD, Format.Format22c, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.VOLATILE_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
IPUT_VOLATILE(firstApi(0xe4, 9), "iput-volatile", ReferenceType.FIELD, Format.Format22c, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.VOLATILE_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
SGET_VOLATILE(firstApi(0xe5, 9), "sget-volatile", ReferenceType.FIELD, Format.Format21c, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.VOLATILE_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.STATIC_FIELD_ACCESSOR),
SPUT_VOLATILE(firstApi(0xe6, 9), "sput-volatile", ReferenceType.FIELD, Format.Format21c, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.VOLATILE_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.STATIC_FIELD_ACCESSOR),
IGET_OBJECT_VOLATILE(firstApi(0xe7, 9), "iget-object-volatile", ReferenceType.FIELD, Format.Format22c, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.VOLATILE_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
IGET_WIDE_VOLATILE(firstApi(0xe8, 9), "iget-wide-volatile", ReferenceType.FIELD, Format.Format22c, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.VOLATILE_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
IPUT_WIDE_VOLATILE(firstApi(0xe9, 9), "iput-wide-volatile", ReferenceType.FIELD, Format.Format22c, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.VOLATILE_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
SGET_WIDE_VOLATILE(firstApi(0xea, 9), "sget-wide-volatile", ReferenceType.FIELD, Format.Format21c, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.VOLATILE_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER | org.jf.dexlib2.Opcode.STATIC_FIELD_ACCESSOR),
SPUT_WIDE_VOLATILE(firstApi(0xeb, 9), "sput-wide-volatile", ReferenceType.FIELD, Format.Format21c, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.VOLATILE_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.STATIC_FIELD_ACCESSOR),
THROW_VERIFICATION_ERROR(firstApi(0xed, 5), "throw-verification-error", ReferenceType.NONE, Format.Format20bc, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.CAN_THROW),
EXECUTE_INLINE(allApis(0xee), "execute-inline", ReferenceType.NONE, Format.Format35mi, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT),
EXECUTE_INLINE_RANGE(firstApi(0xef, 8), "execute-inline/range", ReferenceType.NONE, Format.Format3rmi, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT),
INVOKE_DIRECT_EMPTY(lastApi(0xf0, 13), "invoke-direct-empty", ReferenceType.METHOD, Format.Format35c, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT | org.jf.dexlib2.Opcode.CAN_INITIALIZE_REFERENCE),
INVOKE_OBJECT_INIT_RANGE(firstApi(0xf0, 14), "invoke-object-init/range", ReferenceType.METHOD, Format.Format3rc, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT | org.jf.dexlib2.Opcode.CAN_INITIALIZE_REFERENCE),
RETURN_VOID_BARRIER(combine(firstApi(0xf1, 11), lastArtVersion(0x73, 59)), "return-void-barrier", ReferenceType.NONE, Format.Format10x, org.jf.dexlib2.Opcode.ODEX_ONLY),
RETURN_VOID_NO_BARRIER(firstArtVersion(0x73, 60), "return-void-no-barrier", ReferenceType.NONE, Format.Format10x, org.jf.dexlib2.Opcode.ODEX_ONLY),
IGET_QUICK(combine(allApis(0xf2), allArtVersions(0xe3)), "iget-quick", ReferenceType.NONE, Format.Format22cs, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.QUICK_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
IGET_WIDE_QUICK(combine(allApis(0xf3), allArtVersions(0xe4)), "iget-wide-quick", ReferenceType.NONE, Format.Format22cs, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.QUICK_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.SETS_WIDE_REGISTER),
IGET_OBJECT_QUICK(combine(allApis(0xf4), allArtVersions(0xe5)), "iget-object-quick", ReferenceType.NONE, Format.Format22cs, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.QUICK_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
IPUT_QUICK(combine(allApis(0xf5), allArtVersions(0xe6)), "iput-quick", ReferenceType.NONE, Format.Format22cs, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.QUICK_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
IPUT_WIDE_QUICK(combine(allApis(0xf6), allArtVersions(0xe7)), "iput-wide-quick", ReferenceType.NONE, Format.Format22cs, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.QUICK_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
IPUT_OBJECT_QUICK(combine(allApis(0xf7), allArtVersions(0xe8)), "iput-object-quick", ReferenceType.NONE, Format.Format22cs, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.QUICK_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
IPUT_BOOLEAN_QUICK(allArtVersions(0xeb), "iput-boolean-quick", ReferenceType.NONE, Format.Format22cs, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.QUICK_FIELD_ACCESSOR),
IPUT_BYTE_QUICK(allArtVersions(0xec), "iput-byte-quick", ReferenceType.NONE, Format.Format22cs, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.QUICK_FIELD_ACCESSOR),
IPUT_CHAR_QUICK(allArtVersions(0xed), "iput-char-quick", ReferenceType.NONE, Format.Format22cs, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.QUICK_FIELD_ACCESSOR),
IPUT_SHORT_QUICK(allArtVersions(0xee), "iput-short-quick", ReferenceType.NONE, Format.Format22cs, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.QUICK_FIELD_ACCESSOR),
IGET_BOOLEAN_QUICK(allArtVersions(0xef), "iget-boolean-quick", ReferenceType.NONE, Format.Format22cs, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.QUICK_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
IGET_BYTE_QUICK(allArtVersions(0xf0), "iget-byte-quick", ReferenceType.NONE, Format.Format22cs, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.QUICK_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
IGET_CHAR_QUICK(allArtVersions(0xf1), "iget-char-quick", ReferenceType.NONE, Format.Format22cs, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.QUICK_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
IGET_SHORT_QUICK(allArtVersions(0xf2), "iget-short-quick", ReferenceType.NONE, Format.Format22cs, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.QUICK_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
INVOKE_VIRTUAL_QUICK(combine(allApis(0xf8), allArtVersions(0xe9)), "invoke-virtual-quick", ReferenceType.NONE, Format.Format35ms, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT),
INVOKE_VIRTUAL_QUICK_RANGE(combine(allApis(0xf9), allArtVersions(0xea)), "invoke-virtual-quick/range", ReferenceType.NONE, Format.Format3rms, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT),
INVOKE_SUPER_QUICK(lastApi(0xfa, 25), "invoke-super-quick", ReferenceType.NONE, Format.Format35ms, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT),
INVOKE_SUPER_QUICK_RANGE(lastApi(0xfb, 25), "invoke-super-quick/range", ReferenceType.NONE, Format.Format3rms, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT),
IPUT_OBJECT_VOLATILE(firstApi(0xfc, 9), "iput-object-volatile", ReferenceType.FIELD, Format.Format22c, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.VOLATILE_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE),
SGET_OBJECT_VOLATILE(firstApi(0xfd, 9), "sget-object-volatile", ReferenceType.FIELD, Format.Format21c, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.VOLATILE_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER | org.jf.dexlib2.Opcode.STATIC_FIELD_ACCESSOR),
SPUT_OBJECT_VOLATILE(betweenApi(0xfe, 9, 19), "sput-object-volatile", ReferenceType.FIELD, Format.Format21c, org.jf.dexlib2.Opcode.ODEX_ONLY | org.jf.dexlib2.Opcode.VOLATILE_FIELD_ACCESSOR | org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.STATIC_FIELD_ACCESSOR),
PACKED_SWITCH_PAYLOAD(0x100, "packed-switch-payload", ReferenceType.NONE, Format.PackedSwitchPayload, 0),
SPARSE_SWITCH_PAYLOAD(0x200, "sparse-switch-payload", ReferenceType.NONE, Format.SparseSwitchPayload, 0),
ARRAY_PAYLOAD(0x300, "array-payload", ReferenceType.NONE, Format.ArrayPayload, 0),
INVOKE_POLYMORPHIC(firstArtVersion(0xfa, 87), "invoke-polymorphic", ReferenceType.METHOD, ReferenceType.METHOD_PROTO, Format.Format45cc, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT),
INVOKE_POLYMORPHIC_RANGE(firstArtVersion(0xfb, 87), "invoke-polymorphic/range", ReferenceType.METHOD, ReferenceType.METHOD_PROTO, Format.Format4rcc, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT),
INVOKE_CUSTOM(firstArtVersion(0xfc, 111), "invoke-custom", ReferenceType.CALL_SITE, Format.Format35c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT),
INVOKE_CUSTOM_RANGE(firstArtVersion(0xfd, 111), "invoke-custom/range", ReferenceType.CALL_SITE, Format.Format3rc, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_RESULT),
CONST_METHOD_HANDLE(firstArtVersion(0xfe, 134), "const-method-handle", ReferenceType.METHOD_HANDLE, Format.Format21c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER),
CONST_METHOD_TYPE(firstArtVersion(0xff, 134), "const-method-type", ReferenceType.METHOD_PROTO, Format.Format21c, org.jf.dexlib2.Opcode.CAN_THROW | org.jf.dexlib2.Opcode.CAN_CONTINUE | org.jf.dexlib2.Opcode.SETS_REGISTER);
}*/
}
@@ -0,0 +1,26 @@
package com.antik.librarySurgery;
import java.io.File;
public class FileUtils {
public static void deleteDirectory(File dir) {
if (dir == null || !dir.exists()) return;
File[] files = dir.listFiles();
if (files != null) {
for (File f : files) {
if (f.isDirectory()) {
deleteDirectory(f);
} else {
if (!f.delete()) {
f.deleteOnExit();
}
}
}
}
boolean deleted = dir.delete();
if (!deleted) {
dir.deleteOnExit();
}
}
}
@@ -0,0 +1,97 @@
package com.antik.librarySurgery;
import com.antik.librarySurgery.memory.Memory;
import com.antik.librarySurgery.memory.MemoryRegion;
import com.antik.librarySurgery.process.ProcessFinder;
import com.antik.ui.banner;
import java.io.File;
import java.nio.file.Files;
import java.util.List;
import java.util.Map;
public class LibSurgery {
public static void process(String packageName, String outDirStr) {
banner.banner();
File outDir = new File(outDirStr);
if (!outDir.exists()) {
boolean created = outDir.mkdirs();
if (!created && !outDir.exists()) {
System.err.println("[ERROR] Could not create output directory : " + outDirStr);
}
}
File tmpDir = null;
try {
tmpDir = Files.createTempDirectory("pairip_surgery_").toFile();
List<File> apks = LibraryExtractor.getInstalledApks(packageName);
Map<String, File> extractedLibs = LibraryExtractor.extractArm64Libs(apks, tmpDir);
String pid = ProcessFinder.waitForProcess(packageName);
MemoryRegion<Long> rxRegion = Memory.findRxRegion(pid);
String rxAddr = rxRegion != null ? Long.toHexString(rxRegion.getStartAddress()) : null;
String dumpedPath = rxRegion != null ? rxRegion.getPathname() : "";
String dumpedLibName = !dumpedPath.isEmpty() ? new File(dumpedPath).getName() : "";
byte[] memDumpData = Memory.dumpMemory(pid, rxAddr);
int patchedCount = 0;
for (Map.Entry<String, File> entry : extractedLibs.entrySet()) {
String libName = entry.getKey();
File libPath = entry.getValue();
if ("libpairipcore.so".equals(libName)) {
continue;
}
byte[] data = Files.readAllBytes(libPath.toPath());
byte[] dumpToUse = (dumpedLibName.isEmpty() || libName.equalsIgnoreCase(dumpedLibName) || dumpedLibName.contains(libName))
? memDumpData : null;
PatchResult res = LibraryPatcher.patchSingleLib(data, dumpToUse);
if (res.success()) {
String outName = libName.replace(".so", "") + "_patched.so";
File outPath = new File(outDir, outName);
Files.write(outPath.toPath(), data);
System.out.println("[BUILD] " + libName + " -> Saved " + outName + " (" + data.length + " bytes)");
patchedCount++;
} else {
System.out.println("[SKIP] " + libName + " : " + res.message());
}
}
System.out.println("[BUILD] Process completed (" + patchedCount + " libraries patched)");
} catch (Exception e) {
System.err.println("[ERROR] Process failed : " + e.getMessage());
} finally {
if (tmpDir != null) {
FileUtils.deleteDirectory(tmpDir);
}
}
}
public static void main(String[] args) {
String packageName = null;
String outDir = null;
for (int i = 0; i < args.length; i++) {
if (("-p".equals(args[i]) || "--package".equals(args[i])) && i + 1 < args.length) {
packageName = args[++i];
} else if (("-o".equals(args[i]) || "--outdir".equals(args[i])) && i + 1 < args.length) {
outDir = args[++i];
}
}
if (packageName == null || outDir == null) {
System.out.println("Usage: java -jar RePairip.jar -p <package_name> -o <out_dir>");
System.exit(1);
}
process(packageName, outDir);
}
}
@@ -0,0 +1,76 @@
package com.antik.librarySurgery;
import com.antik.librarySurgery.shell.Shell;
import com.antik.librarySurgery.shell.ShellResult;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class LibraryExtractor {
public static List<File> getInstalledApks(String packageName) {
ShellResult result = Shell.runRootCmd("pm path " + packageName);
List<File> apks = new ArrayList<>();
if (result.isSuccess() && !result.getStdout().isEmpty()) {
for (String line : result.getStdout().split("\r?\n")) {
String trimmed = line.trim();
if (trimmed.startsWith("package:")) {
String apkPath = trimmed.replace("package:", "").trim();
File f = new File(apkPath);
if (f.exists()) {
apks.add(f);
} else {
File tmpCopy = new File("/data/local/tmp/temp_base.apk");
Shell.runRootCmd("cp " + apkPath + " " + tmpCopy.getAbsolutePath() + " && chmod 666 " + tmpCopy.getAbsolutePath());
if (tmpCopy.exists()) {
apks.add(tmpCopy);
}
}
}
}
}
if (apks.isEmpty()) {
System.err.println("[ERROR] Package not installed or APK paths unavailable : " + packageName);
System.exit(1);
}
System.out.println("[INFO] Found " + apks.size() + " APK path(s) for package : " + packageName);
return apks;
}
public static Map<String, File> extractArm64Libs(List<File> apks, File tmpDir) {
Map<String, File> extractedLibs = new HashMap<>();
for (File apkFile : apks) {
try (ZipFile zip = new ZipFile(apkFile)) {
Enumeration<? extends ZipEntry> entries = zip.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
String fname = entry.getName();
if (fname.endsWith(".so") && fname.contains("arm64")) {
String libName = new File(fname).getName();
if (!extractedLibs.containsKey(libName)) {
File extPath = new File(tmpDir, libName);
try (InputStream is = zip.getInputStream(entry);
OutputStream os = new FileOutputStream(extPath)) {
is.transferTo(os);
}
extractedLibs.put(libName, extPath);
}
}
}
} catch (Exception e) {
System.err.println("[ERROR] Extracting native libs failed : " + e.getMessage());
}
}
System.out.println("[INFO] Extracted " + extractedLibs.size() + " ARM64 native library/libraries");
return extractedLibs;
}
}
@@ -0,0 +1,129 @@
package com.antik.librarySurgery;
import com.antik.librarySurgery.elf.DynamicEntry;
import com.antik.librarySurgery.elf.Elf;
import com.antik.librarySurgery.elf.ElfConstants;
import com.antik.librarySurgery.elf.ProgramHeader;
import com.antik.librarySurgery.io.ByteReader;
import com.antik.librarySurgery.io.ByteWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class LibraryPatcher {
public static PatchResult patchSingleLib(byte[] data, byte[] memDump) {
Elf elf = new Elf(data);
if (!elf.getHeader().isValid()) {
return new PatchResult(false, "Invalid ELF header");
}
ProgramHeader dynamicHeader = elf.getDynamicHeader();
if (dynamicHeader == null) {
return new PatchResult(false, "No PT_DYNAMIC header found");
}
ByteReader reader = elf.getReader();
ByteWriter writer = new ByteWriter(data);
int dynOff = (int) dynamicHeader.getPOffset();
int dynSz = (int) dynamicHeader.getPFileSz();
Long initVa = null;
Long initArrayVa = null;
Long initArraySz = null;
List<DynamicEntry> newEntries = new ArrayList<>();
boolean hasPairip = false;
for (int j = 0; j < dynSz; j += 16) {
int entryPos = dynOff + j;
if (entryPos + 16 > reader.length()) break;
long tag = reader.readUInt64(entryPos);
long val = reader.readUInt64(entryPos + 8);
if (tag == ElfConstants.DT_NULL) {
break;
}
if (tag == ElfConstants.DT_INIT) {
initVa = val;
continue;
}
if (tag == ElfConstants.DT_INIT_ARRAY) {
initArrayVa = val;
continue;
}
if (tag == ElfConstants.DT_INIT_ARRAYSZ) {
initArraySz = val;
continue;
}
if (tag == ElfConstants.DT_NEEDED) {
String name = elf.readStringFromStrtab(val);
if (name.toLowerCase().contains("pairip")) {
hasPairip = true;
continue;
}
}
newEntries.add(new DynamicEntry(tag, val));
}
int posStr = reader.indexOf(ElfConstants.OLD_EXECUTE_PROGRAM);
boolean isPairipProtected = hasPairip || posStr != -1;
if (!isPairipProtected) {
return new PatchResult(false, "Not protected by PairIP");
}
newEntries.add(new DynamicEntry(ElfConstants.DT_NULL, 0L));
for (int k = 0; k < newEntries.size(); k++) {
int pos = dynOff + k * 16;
if (pos + 16 <= reader.length()) {
writer.writeUInt64(pos, newEntries.get(k).getTag());
writer.writeUInt64(pos + 8, newEntries.get(k).getVal());
}
}
writer.zeroRange(dynOff + newEntries.size() * 16, dynOff + dynSz);
if (initVa != null) {
for (ProgramHeader ph : elf.getProgramHeaders()) {
if (ph.getPType() == ElfConstants.PT_LOAD && ph.getPVaddr() <= initVa && initVa < ph.getPVaddr() + ph.getPMemSz()) {
writer.writeUInt32(ph.getHeaderOffset(), ElfConstants.PT_NULL);
}
}
}
if (initArrayVa != null && initArraySz != null) {
Long initArrayOff = elf.vaddrToOffset(initArrayVa);
if (initArrayOff != null) {
int arrayPos = initArrayOff.intValue();
int arraySize = initArraySz.intValue();
if (arrayPos >= 0 && arrayPos + arraySize <= reader.length()) {
writer.zeroRange(arrayPos, arrayPos + arraySize);
}
}
}
if (posStr != -1) {
writer.writeBytes(posStr, ElfConstants.NEW_MEMSET);
}
Long jniOnLoadOffset = elf.findSymbolAddress("JNI_OnLoad");
if (jniOnLoadOffset != null) {
int stubPos = jniOnLoadOffset.intValue();
if (stubPos >= 0 && stubPos + ElfConstants.ARM64_STUB_BYTES.length <= reader.length()) {
writer.writeBytes(stubPos, ElfConstants.ARM64_STUB_BYTES);
}
} else {
System.out.println("[INFO] JNI_OnLoad symbol not found in ELF, skipping stub patch safely.");
}
if (memDump != null && memDump.length > 0) {
int copyLen = Math.min(reader.length(), memDump.length);
writer.writeBytes(0, Arrays.copyOf(memDump, copyLen));
}
return new PatchResult(true, "Successfully patched");
}
}
@@ -0,0 +1,3 @@
package com.antik.librarySurgery;
public record PatchResult(boolean success, String message) {}
@@ -0,0 +1,20 @@
package com.antik.librarySurgery.elf;
public class DynamicEntry {
private final long tag;
private final long val;
public DynamicEntry(long tag, long val) {
this.tag = tag;
this.val = val;
}
public long getTag() {
return tag;
}
public long getVal() {
return val;
}
}
@@ -0,0 +1,120 @@
package com.antik.librarySurgery.elf;
import com.antik.librarySurgery.io.ByteReader;
import java.util.ArrayList;
import java.util.List;
public class Elf {
private final ByteReader reader;
private final ElfHeader header;
private final List<ProgramHeader> programHeaders = new ArrayList<>();
private ProgramHeader dynamicHeader = null;
private Long strtabVa = null;
private Long strtabOff = null;
private Long symtabVa = null;
private Long symtabOff = null;
public Elf(byte[] data) {
this.reader = new ByteReader(data);
this.header = new ElfHeader(reader);
if (header.isValid()) {
parseProgramHeaders();
parseDynamicSection();
}
}
private void parseProgramHeaders() {
long phOff = header.getPhOff();
int phNum = header.getPhNum();
for (int i = 0; i < phNum; i++) {
int offset = (int) (phOff + i * 56L);
if (offset + 56 > reader.length()) break;
ProgramHeader ph = new ProgramHeader(reader, offset);
programHeaders.add(ph);
if (ph.getPType() == ElfConstants.PT_DYNAMIC) {
this.dynamicHeader = ph;
}
}
}
private void parseDynamicSection() {
if (dynamicHeader == null) return;
int dynOff = (int) dynamicHeader.getPOffset();
int dynSz = (int) dynamicHeader.getPFileSz();
for (int j = 0; j < dynSz; j += 16) {
int pos = dynOff + j;
if (pos + 16 > reader.length()) break;
long tag = reader.readUInt64(pos);
long val = reader.readUInt64(pos + 8);
if (tag == ElfConstants.DT_STRTAB) {
this.strtabVa = val;
} else if (tag == ElfConstants.DT_SYMTAB) {
this.symtabVa = val;
}
}
if (strtabVa != null) {
this.strtabOff = vaddrToOffset(strtabVa);
}
if (symtabVa != null) {
this.symtabOff = vaddrToOffset(symtabVa);
}
}
public Long vaddrToOffset(long vaddr) {
for (ProgramHeader ph : programHeaders) {
if (ph.getPType() == ElfConstants.PT_LOAD && ph.getPVaddr() <= vaddr && vaddr < ph.getPVaddr() + ph.getPMemSz()) {
return ph.getPOffset() + (vaddr - ph.getPVaddr());
}
}
return null;
}
public Long findSymbolAddress(String symbolName) {
if (symtabOff == null || strtabOff == null) return null;
int symOff = symtabOff.intValue();
int maxSyms = 3000;
for (int i = 0; i < maxSyms; i++) {
int entryPos = symOff + i * 24;
if (entryPos + 24 > reader.length()) break;
long nameIdx = reader.readUInt32(entryPos);
long value = reader.readUInt64(entryPos + 8);
if (nameIdx > 0) {
String name = reader.readNullTerminatedString((int) (strtabOff + nameIdx));
if (symbolName.equals(name)) {
return vaddrToOffset(value);
}
}
}
return null;
}
public ByteReader getReader() {
return reader;
}
public ElfHeader getHeader() {
return header;
}
public List<ProgramHeader> getProgramHeaders() {
return programHeaders;
}
public ProgramHeader getDynamicHeader() {
return dynamicHeader;
}
public Long getStrtabOff() {
return strtabOff;
}
public String readStringFromStrtab(long offsetVal) {
if (strtabOff == null) return "";
return reader.readNullTerminatedString((int) (strtabOff + offsetVal));
}
}
@@ -0,0 +1,27 @@
package com.antik.librarySurgery.elf;
public class ElfConstants {
public static final byte[] ELF_MAGIC = new byte[]{(byte) 0x7f, 'E', 'L', 'F'};
public static final int PT_NULL = 0;
public static final int PT_LOAD = 1;
public static final int PT_DYNAMIC = 2;
public static final long DT_NULL = 0L;
public static final long DT_NEEDED = 1L;
public static final long DT_STRTAB = 5L;
public static final long DT_SYMTAB = 6L;
public static final long DT_INIT = 12L;
public static final long DT_INIT_ARRAY = 25L;
public static final long DT_INIT_ARRAYSZ = 27L;
public static final byte[] OLD_EXECUTE_PROGRAM = "ExecuteProgram\0".getBytes(java.nio.charset.StandardCharsets.US_ASCII);
public static final byte[] NEW_MEMSET = "memset\0\0\0\0\0\0\0\0\0".getBytes(java.nio.charset.StandardCharsets.US_ASCII);
public static final byte[] ARM64_STUB_BYTES = new byte[]{
(byte) 0xc0, 0x00, (byte) 0x80, 0x52, // mov w0, #0
0x20, 0x00, (byte) 0xa0, 0x72, // movk w0, #0x10, lsl #16 (JNI_VERSION_1_6 = 0x00010000)
(byte) 0xc0, 0x03, 0x5f, (byte) 0xd6 // ret
};
}
@@ -0,0 +1,34 @@
package com.antik.librarySurgery.elf;
import com.antik.librarySurgery.io.ByteReader;
public class ElfHeader {
private final long phOff;
private final int phNum;
private final boolean valid;
public ElfHeader(ByteReader reader) {
if (!reader.checkMagic(ElfConstants.ELF_MAGIC)) {
this.valid = false;
this.phOff = 0L;
this.phNum = 0;
return;
}
this.phOff = reader.readUInt64(0x20);
this.phNum = reader.readUInt16(0x38);
this.valid = true;
}
public boolean isValid() {
return valid;
}
public long getPhOff() {
return phOff;
}
public int getPhNum() {
return phNum;
}
}
@@ -0,0 +1,46 @@
package com.antik.librarySurgery.elf;
import com.antik.librarySurgery.io.ByteReader;
public class ProgramHeader {
private final int headerOffset;
private final int pType;
private final long pOffset;
private final long pVaddr;
private final long pFileSz;
private final long pMemSz;
public ProgramHeader(ByteReader reader, int headerOffset) {
this.headerOffset = headerOffset;
this.pType = (int) reader.readUInt32(headerOffset);
this.pOffset = reader.readUInt64(headerOffset + 8);
this.pVaddr = reader.readUInt64(headerOffset + 16);
this.pFileSz = reader.readUInt64(headerOffset + 32);
this.pMemSz = reader.readUInt64(headerOffset + 40);
}
public int getHeaderOffset() {
return headerOffset;
}
public int getPType() {
return pType;
}
public long getPOffset() {
return pOffset;
}
public long getPVaddr() {
return pVaddr;
}
public long getPFileSz() {
return pFileSz;
}
public long getPMemSz() {
return pMemSz;
}
}
@@ -0,0 +1,70 @@
package com.antik.librarySurgery.io;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
public class ByteReader {
private final byte[] buffer;
private final ByteBuffer byteBuffer;
public ByteReader(byte[] buffer) {
this.buffer = buffer;
this.byteBuffer = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN);
}
public byte[] getBuffer() {
return buffer;
}
public int length() {
return buffer.length;
}
public int readUInt16(int offset) {
if (offset < 0 || offset + 2 > buffer.length) return 0;
return byteBuffer.getShort(offset) & 0xFFFF;
}
public long readUInt32(int offset) {
if (offset < 0 || offset + 4 > buffer.length) return 0L;
return byteBuffer.getInt(offset) & 0xFFFFFFFFL;
}
public long readUInt64(int offset) {
if (offset < 0 || offset + 8 > buffer.length) return 0L;
return byteBuffer.getLong(offset);
}
public String readNullTerminatedString(int offset) {
if (offset < 0 || offset >= buffer.length) return "";
int end = offset;
while (end < buffer.length && buffer[end] != 0) {
end++;
}
return new String(buffer, offset, end - offset, StandardCharsets.US_ASCII);
}
public int indexOf(byte[] target) {
if (target == null || target.length == 0) return -1;
outer:
for (int i = 0; i <= buffer.length - target.length; i++) {
for (int j = 0; j < target.length; j++) {
if (buffer[i + j] != target[j]) {
continue outer;
}
}
return i;
}
return -1;
}
public boolean checkMagic(byte[] magic) {
if (magic == null || buffer.length < magic.length) return false;
for (int i = 0; i < magic.length; i++) {
if (buffer[i] != magic[i]) return false;
}
return true;
}
}
@@ -0,0 +1,51 @@
package com.antik.librarySurgery.io;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class ByteWriter {
private final byte[] buffer;
private final ByteBuffer byteBuffer;
public ByteWriter(byte[] buffer) {
this.buffer = buffer;
this.byteBuffer = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN);
}
public byte[] getBuffer() {
return buffer;
}
public void writeUInt16(int offset, int value) {
if (offset >= 0 && offset + 2 <= buffer.length) {
byteBuffer.putShort(offset, (short) value);
}
}
public void writeUInt32(int offset, long value) {
if (offset >= 0 && offset + 4 <= buffer.length) {
byteBuffer.putInt(offset, (int) value);
}
}
public void writeUInt64(int offset, long value) {
if (offset >= 0 && offset + 8 <= buffer.length) {
byteBuffer.putLong(offset, value);
}
}
public void writeBytes(int offset, byte[] data) {
if (data != null && offset >= 0 && offset + data.length <= buffer.length) {
System.arraycopy(data, 0, buffer, offset, data.length);
}
}
public void zeroRange(int startOffset, int endOffset) {
if (startOffset >= 0 && endOffset <= buffer.length && startOffset < endOffset) {
for (int i = startOffset; i < endOffset; i++) {
buffer[i] = 0;
}
}
}
}
@@ -0,0 +1,36 @@
package com.antik.librarySurgery.memory;
import com.antik.librarySurgery.shell.Shell;
import java.io.File;
import java.nio.file.Files;
public class Memory {
public static MemoryRegion<Long> findRxRegion(String pid) {
MemoryMap map = MemoryMap.parseFromProcess(pid);
return map.findRxRegion();
}
public static byte[] dumpMemory(String pid, String rxAddr) {
if (rxAddr == null || rxAddr.isEmpty()) {
return null;
}
String dumpPath = "/data/local/tmp/pairip_dump.bin";
System.out.println("[ROOT] Dumping decrypted .text memory from RAM (Address 0x" + rxAddr + ")");
Shell.runRootCmd("dd if=/proc/" + pid + "/mem of=" + dumpPath + " bs=1024 count=576 skip=$((0x" + rxAddr + "/1024))");
File dumpFile = new File(dumpPath);
byte[] data = null;
if (dumpFile.exists() && dumpFile.length() > 0) {
try {
data = Files.readAllBytes(dumpFile.toPath());
System.out.println("[ROOT] Captured " + data.length + " bytes decrypted memory dump");
} catch (Exception e) {
System.err.println("[ERROR] Reading memory dump failed : " + e.getMessage());
}
}
Shell.runRootCmd("rm -f " + dumpPath);
return data;
}
}
@@ -0,0 +1,58 @@
package com.antik.librarySurgery.memory;
import com.antik.librarySurgery.shell.Shell;
import com.antik.librarySurgery.shell.ShellResult;
import java.util.ArrayList;
import java.util.List;
public class MemoryMap {
private final List<MemoryRegion<Long>> regions = new ArrayList<>();
public static MemoryMap parseFromProcess(String pid) {
MemoryMap map = new MemoryMap();
ShellResult result = Shell.runRootCmd("grep 'r-xp' /proc/" + pid + "/maps");
if (!result.getStdout().isEmpty()) {
for (String line : result.getStdout().split("\r?\n")) {
String trimmed = line.trim();
String[] parts = trimmed.split("\\s+");
if (parts.length >= 1) {
String[] addrs = parts[0].split("-");
if (addrs.length == 2) {
try {
long start = Long.parseUnsignedLong(addrs[0], 16);
long end = Long.parseUnsignedLong(addrs[1], 16);
String perms = parts.length > 1 ? parts[1] : "";
String path = parts.length > 5 ? parts[5] : "";
map.regions.add(new MemoryRegion<>(start, end, perms, path));
} catch (NumberFormatException ignored) {}
}
}
}
}
return map;
}
public List<MemoryRegion<Long>> getRegions() {
return regions;
}
public MemoryRegion<Long> findRxRegion() {
for (MemoryRegion<Long> region : regions) {
String path = region.getPathname();
if (region.isExecutable() && (path.contains("apk") || path.contains("lib"))) {
return region;
}
}
return null;
}
public String findRxAddressString() {
MemoryRegion<Long> region = findRxRegion();
if (region != null) {
return Long.toHexString(region.getStartAddress());
}
return null;
}
}
@@ -0,0 +1,40 @@
package com.antik.librarySurgery.memory;
public class MemoryRegion<T extends Number> {
private final T startAddress;
private final T endAddress;
private final String permissions;
private final String pathname;
public MemoryRegion(T startAddress, T endAddress, String permissions, String pathname) {
this.startAddress = startAddress;
this.endAddress = endAddress;
this.permissions = permissions;
this.pathname = pathname;
}
public T getStartAddress() {
return startAddress;
}
public T getEndAddress() {
return endAddress;
}
public String getPermissions() {
return permissions;
}
public String getPathname() {
return pathname;
}
public boolean isExecutable() {
return permissions != null && permissions.contains("x");
}
public boolean isReadable() {
return permissions != null && permissions.contains("r");
}
}
@@ -0,0 +1,46 @@
package com.antik.librarySurgery.process;
import com.antik.librarySurgery.shell.Shell;
import com.antik.librarySurgery.shell.ShellResult;
public class ProcessFinder {
public static String getPidForPackage(String packageName) {
ShellResult result = Shell.runRootCmd("ps -A | grep " + packageName);
if (!result.isSuccess() || result.getStdout().isEmpty()) {
result = Shell.runRootCmd("pidof " + packageName);
if (result.isSuccess() && !result.getStdout().isEmpty()) {
String[] pids = result.getStdout().trim().split("\\s+");
return pids[0];
}
return null;
}
for (String line : result.getStdout().split("\r?\n")) {
String trimmed = line.trim();
if (trimmed.contains(packageName)) {
String[] parts = trimmed.split("\\s+");
if (parts.length >= 2) {
return parts[1];
}
}
}
return null;
}
public static String waitForProcess(String packageName) {
System.out.println("[INFO] Waiting for package : " + packageName);
System.out.println("[INFO] Please launch the app on your device ");
while (true) {
String pid = getPidForPackage(packageName);
if (pid != null && !pid.isEmpty()) {
System.out.println("[ROOT] App process detected with PID : " + pid);
return pid;
}
try {
Thread.sleep(1500);
} catch (InterruptedException ignored) {}
}
}
}
@@ -0,0 +1,45 @@
package com.antik.librarySurgery.shell;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Shell {
public static ShellResult runRootCmd(String command) {
try {
Process process = Runtime.getRuntime().exec(new String[]{"su", "-c", command});
BufferedReader outReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
BufferedReader errReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
StringBuilder outSb = new StringBuilder();
for (String line = outReader.readLine(); line != null; line = outReader.readLine()) {
outSb.append(line).append("\n");
}
StringBuilder errSb = new StringBuilder();
for (String line = errReader.readLine(); line != null; line = errReader.readLine()) {
errSb.append(line).append("\n");
}
int exitCode = process.waitFor();
return new ShellResult(exitCode, outSb.toString(), errSb.toString());
} catch (Exception e) {
return new ShellResult(-1, "", e.getMessage());
}
}
public static ShellResult runCmd(String command) {
try {
Process process = Runtime.getRuntime().exec(new String[]{"sh", "-c", command});
BufferedReader outReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder outSb = new StringBuilder();
for (String line = outReader.readLine(); line != null; line = outReader.readLine()) {
outSb.append(line).append("\n");
}
int exitCode = process.waitFor();
return new ShellResult(exitCode, outSb.toString(), "");
} catch (Exception e) {
return runRootCmd(command);
}
}
}
@@ -0,0 +1,30 @@
package com.antik.librarySurgery.shell;
public class ShellResult {
private final int exitCode;
private final String stdout;
private final String stderr;
public ShellResult(int exitCode, String stdout, String stderr) {
this.exitCode = exitCode;
this.stdout = stdout != null ? stdout.trim() : "";
this.stderr = stderr != null ? stderr.trim() : "";
}
public int getExitCode() {
return exitCode;
}
public String getStdout() {
return stdout;
}
public String getStderr() {
return stderr;
}
public boolean isSuccess() {
return exitCode == 0;
}
}

Some files were not shown because too many files have changed in this diff Show More