This commit is contained in:
isPointer
2026-06-10 06:17:47 +06:00
committed by GitHub
parent a354b2ca67
commit d9450aa91f
16 changed files with 625 additions and 486 deletions
@@ -1,377 +0,0 @@
package com.antik;
import com.reandroid.apk.ApkModule;
import com.reandroid.archive.ByteInputSource;
import com.reandroid.archive.InputSource;
import org.jf.dexlib2.DexFileFactory;
import org.jf.dexlib2.Opcode;
import org.jf.dexlib2.Opcodes;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.DexFile;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.MethodImplementation;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.immutable.ImmutableClassDef;
import org.jf.dexlib2.immutable.ImmutableMethod;
import org.jf.dexlib2.immutable.ImmutableMethodImplementation;
import org.jf.dexlib2.immutable.instruction.ImmutableInstruction10x;
import org.jf.dexlib2.immutable.instruction.ImmutableInstruction11n;
import org.jf.dexlib2.immutable.instruction.ImmutableInstruction11x;
import org.jf.dexlib2.immutable.instruction.ImmutableInstruction21c;
import org.jf.dexlib2.immutable.instruction.ImmutableInstruction35c;
import org.jf.dexlib2.immutable.reference.ImmutableMethodReference;
import org.jf.dexlib2.immutable.reference.ImmutableTypeReference;
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.InputStream;
import java.nio.file.Files;
import java.util.*;
public class DexPatcher {
public static void patch(ApkModule m) throws Exception {
List<String> dx_ns = new ArrayList<String>();
for (InputSource s : m.getInputSources()) {
if (s.getName().endsWith(".dex")) {
dx_ns.add(s.getName());
}
}
List<ClassDef> l_cds = new ArrayList<ClassDef>();
Set<String> a_ts = new HashSet<String>();
String pkg = "unknown";
try {
pkg = m.getPackageName();
} catch (Exception ignored) {}
try (InputStream i = Main.class.getResourceAsStream("/log.dex")) {
if (i != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[8192];
int len;
while ((len = i.read(buf)) != -1) {
baos.write(buf, 0, len);
}
byte[] l_bs = baos.toByteArray();
File t_l_dx = File.createTempFile("log", ".dex");
Files.write(t_l_dx.toPath(), l_bs);
DexFile l_df = DexFileFactory.loadDexFile(t_l_dx, Opcodes.getDefault());
t_l_dx.delete();
for (ClassDef c : l_df.getClasses()) {
if ("Lcom/pairip/PairipLog;".equals(c.getType())) {
List<org.jf.dexlib2.iface.Field> s_fs = new ArrayList<org.jf.dexlib2.iface.Field>();
for (org.jf.dexlib2.iface.Field f : c.getStaticFields()) {
if ("DIR_PATH".equals(f.getName())) {
String n_v = "/data/data/" + pkg + "/dictionary";
s_fs.add(new org.jf.dexlib2.immutable.ImmutableField(
f.getDefiningClass(),
f.getName(),
f.getType(),
f.getAccessFlags(),
new org.jf.dexlib2.immutable.value.ImmutableStringEncodedValue(n_v),
f.getAnnotations(),
f.getHiddenApiRestrictions()));
} else {
s_fs.add(f);
}
}
l_cds.add(new ImmutableClassDef(
c.getType(), c.getAccessFlags(), c.getSuperclass(),
c.getInterfaces(), c.getSourceFile(), c.getAnnotations(),
s_fs, c.getInstanceFields(),
c.getDirectMethods(), c.getVirtualMethods()));
} else {
l_cds.add(c);
}
a_ts.add(c.getType());
}
System.out.println("[INFO] Added classes from log.dex (Package: " + pkg + ")");
}
}
List<String> j_ts = new ArrayList<String>();
for (String dn : dx_ns) {
InputSource s = m.getInputSource(dn);
if (s == null) continue;
byte[] d_bs;
try (InputStream i = s.openStream()) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[8192];
int len;
while ((len = i.read(buf)) != -1) {
baos.write(buf, 0, len);
}
d_bs = baos.toByteArray();
}
File t_dx = File.createTempFile("temp", ".dex");
Files.write(t_dx.toPath(), d_bs);
DexFile d_f = DexFileFactory.loadDexFile(t_dx, Opcodes.getDefault());
t_dx.delete();
for (ClassDef cd : d_f.getClasses()) {
if (cd.getMethods().iterator().hasNext()) continue;
if (!cd.getFields().iterator().hasNext()) continue;
if (!"Ljava/lang/Object;".equals(cd.getSuperclass())) continue;
if (cd.getAccessFlags() != 1) continue;
boolean o_t = true;
for (org.jf.dexlib2.iface.Field f : cd.getFields()) {
if (f.getAccessFlags() != 9) {
o_t = false;
break;
}
String t = f.getType();
if (!t.equals("Ljava/lang/String;") && !t.equals("Ljava/lang/reflect/Method;")) {
o_t = false;
break;
}
if (f.getInitialValue() != null) {
o_t = false;
break;
}
}
if (o_t) {
j_ts.add(cd.getType());
}
}
}
System.out.println("[INFO] Found " + j_ts.size() + " junk classes");
for (String dn : dx_ns) {
InputSource s = m.getInputSource(dn);
if (s == null) continue;
byte[] d_bs;
try (InputStream i = s.openStream()) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[8192];
int len;
while ((len = i.read(buf)) != -1) {
baos.write(buf, 0, len);
}
d_bs = baos.toByteArray();
}
File t_dx = File.createTempFile("temp", ".dex");
Files.write(t_dx.toPath(), d_bs);
DexFile d_f = DexFileFactory.loadDexFile(t_dx, Opcodes.getDefault());
t_dx.delete();
List<ClassDef> cds = new ArrayList<ClassDef>();
boolean mod = false;
for (ClassDef cd : d_f.getClasses()) {
if (a_ts.contains(cd.getType())) {
continue;
}
if ("Lcom/pairip/StartupLauncher;".equals(cd.getType())) {
mod = true;
cds.add(patchStartupLauncher(cd, j_ts));
} else if ("Lcom/pairip/SignatureCheck;".equals(cd.getType()) ||
"Lcom/pairip/licensecheck/LicenseClient;".equals(cd.getType()) ||
"Lcom/pairip/licensecheck3/LicenseClientV3;".equals(cd.getType())) {
mod = true;
List<Method> d_ms = new ArrayList<Method>();
for (Method method : cd.getDirectMethods()) {
d_ms.add(patchMethodIfTarget(method));
}
List<Method> v_ms = new ArrayList<Method>();
for (Method method : cd.getVirtualMethods()) {
v_ms.add(patchMethodIfTarget(method));
}
cds.add(new ImmutableClassDef(
cd.getType(), cd.getAccessFlags(), cd.getSuperclass(),
cd.getInterfaces(), cd.getSourceFile(), cd.getAnnotations(),
cd.getStaticFields(), cd.getInstanceFields(),
d_ms, v_ms));
} else {
cds.add(cd);
}
}
if (dn.equals("classes.dex")) {
if (!l_cds.isEmpty()) {
cds.addAll(l_cds);
mod = true;
}
}
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 " + dn);
}
}
}
private static Method patchMethodIfTarget(Method m) {
String n = m.getName();
if ("verifySignatureMatches".equals(n)) {
System.out.println("[INFO] Bypassing verifySignatureMatches");
List<Instruction> ins = Arrays.asList(
new ImmutableInstruction11n(Opcode.CONST_4, 0, 1),
new ImmutableInstruction11x(Opcode.RETURN, 0)
);
return new ImmutableMethod(
m.getDefiningClass(), n, m.getParameters(),
m.getReturnType(), m.getAccessFlags(),
m.getAnnotations(), m.getHiddenApiRestrictions(),
new ImmutableMethodImplementation(1, ins, null, null));
} else if ("verifyIntegrity".equals(n)) {
System.out.println("[INFO] Bypassing " + n);
String rt = m.getReturnType();
List<Instruction> ins;
if ("V".equals(rt)) {
ins = Collections.singletonList(new ImmutableInstruction10x(Opcode.RETURN_VOID));
} else if (rt.startsWith("L") || rt.startsWith("[")) {
ins = Arrays.asList(
new ImmutableInstruction11n(Opcode.CONST_4, 0, 0),
new ImmutableInstruction11x(Opcode.RETURN_OBJECT, 0)
);
} else {
ins = Arrays.asList(
new ImmutableInstruction11n(Opcode.CONST_4, 0, 1),
new ImmutableInstruction11x(Opcode.RETURN, 0)
);
}
return new ImmutableMethod(
m.getDefiningClass(), n, m.getParameters(),
rt, m.getAccessFlags(),
m.getAnnotations(), m.getHiddenApiRestrictions(),
new ImmutableMethodImplementation(1, ins, null, null));
}
return m;
}
private static ClassDef patchStartupLauncher(ClassDef cd, List<String> j_ts) {
System.out.println("[INFO] Patching StartupLauncher");
List<Method> d_ms = new ArrayList<Method>();
for (Method m : cd.getDirectMethods()) {
if ("launch".equals(m.getName())) {
d_ms.add(patchLaunchMethod(m));
} else if (!"pairip".equals(m.getName())) {
d_ms.add(m);
}
}
d_ms.add(createPairipMethod(cd.getType(), j_ts));
return new ImmutableClassDef(
cd.getType(), cd.getAccessFlags(), cd.getSuperclass(),
cd.getInterfaces(), cd.getSourceFile(), cd.getAnnotations(),
cd.getStaticFields(), cd.getInstanceFields(),
d_ms, cd.getVirtualMethods());
}
private static Method patchLaunchMethod(Method m) {
MethodImplementation im = m.getImplementation();
if (im == null) return m;
List<Instruction> o_ins = new ArrayList<Instruction>();
for (Instruction i : im.getInstructions()) {
o_ins.add(i);
}
List<Instruction> n_ins = new ArrayList<Instruction>();
int p_off = -1;
int c_off = 0;
for (int i = 0; i < o_ins.size(); i++) {
Instruction inst = o_ins.get(i);
n_ins.add(inst);
int u = inst.getCodeUnits();
if (inst instanceof ReferenceInstruction) {
ReferenceInstruction r_i = (ReferenceInstruction) inst;
if (r_i.getReference() instanceof MethodReference) {
MethodReference m_r = (MethodReference) r_i.getReference();
if ("Lcom/pairip/VMRunner;".equals(m_r.getDefiningClass()) && "invoke".equals(m_r.getName())) {
boolean a_p = false;
if (i + 1 < o_ins.size()) {
Instruction nx = o_ins.get(i + 1);
if (nx instanceof ReferenceInstruction) {
ReferenceInstruction n_r = (ReferenceInstruction) nx;
if (n_r.getReference() instanceof MethodReference) {
MethodReference n_m = (MethodReference) n_r.getReference();
if ("pairip".equals(n_m.getName())) {
a_p = true;
}
}
}
}
if (!a_p) {
p_off = c_off + u;
n_ins.add(new ImmutableInstruction35c(Opcode.INVOKE_STATIC, 0, 0, 0, 0, 0, 0,
new ImmutableMethodReference("Lcom/pairip/StartupLauncher;", "pairip", null, "V")));
}
}
}
}
c_off += u;
}
if (p_off == -1) return m;
List<? extends org.jf.dexlib2.iface.TryBlock<? extends org.jf.dexlib2.iface.ExceptionHandler>> o_tbs = im.getTryBlocks();
List<org.jf.dexlib2.immutable.ImmutableTryBlock> n_tbs = new ArrayList<org.jf.dexlib2.immutable.ImmutableTryBlock>();
for (org.jf.dexlib2.iface.TryBlock<? extends org.jf.dexlib2.iface.ExceptionHandler> t : o_tbs) {
int s = t.getStartCodeAddress();
int c = t.getCodeUnitCount();
int e = s + c;
List<org.jf.dexlib2.immutable.ImmutableExceptionHandler> h = new ArrayList<org.jf.dexlib2.immutable.ImmutableExceptionHandler>();
for (org.jf.dexlib2.iface.ExceptionHandler ha : t.getExceptionHandlers()) {
int h_a = ha.getHandlerCodeAddress();
if (h_a >= p_off) {
h.add(new org.jf.dexlib2.immutable.ImmutableExceptionHandler(ha.getExceptionType(), h_a + 3));
} else {
h.add(org.jf.dexlib2.immutable.ImmutableExceptionHandler.of(ha));
}
}
if (s < p_off && e >= p_off) {
n_tbs.add(new org.jf.dexlib2.immutable.ImmutableTryBlock(s, c + 3, h));
} else if (s >= p_off) {
n_tbs.add(new org.jf.dexlib2.immutable.ImmutableTryBlock(s + 3, c, h));
} else {
n_tbs.add(new org.jf.dexlib2.immutable.ImmutableTryBlock(s, c, h));
}
}
return new ImmutableMethod(
m.getDefiningClass(), m.getName(), m.getParameters(),
m.getReturnType(), m.getAccessFlags(),
m.getAnnotations(), m.getHiddenApiRestrictions(),
new ImmutableMethodImplementation(im.getRegisterCount(), n_ins, n_tbs, im.getDebugItems()));
}
private static Method createPairipMethod(String dc, List<String> j_ts) {
List<Instruction> ins = new ArrayList<Instruction>();
for (String t : j_ts) {
ins.add(new ImmutableInstruction21c(Opcode.CONST_CLASS, 0, new ImmutableTypeReference(t)));
ins.add(new ImmutableInstruction35c(Opcode.INVOKE_STATIC, 1, 0, 0, 0, 0, 0,
new ImmutableMethodReference("Lcom/pairip/PairipLog;", "put", Collections.singletonList("Ljava/lang/Class;"), "V")));
}
ins.add(new ImmutableInstruction10x(Opcode.RETURN_VOID));
return new ImmutableMethod(
dc, "pairip", null, "V", 0x08,
null, null,
new ImmutableMethodImplementation(1, ins, null, null));
}
}
@@ -0,0 +1,188 @@
package com.antik.DexPatcher;
import static com.antik.DexPatcher.MethodT.patchLauncher.patchStartupLauncher;
import com.antik.DexPatcher.MethodT.patchM;
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.iface.Method;
import org.jf.dexlib2.immutable.ImmutableClassDef;
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.InputStream;
import java.nio.file.Files;
import java.util.*;
public class DexPatcher {
public static void patch(ApkModule m) throws Exception {
List<String> dx_ns = new ArrayList<String>();
for (InputSource s : m.getInputSources()) {
if (s.getName().endsWith(".dex")) {
dx_ns.add(s.getName());
}
}
List<ClassDef> l_cds = new ArrayList<ClassDef>();
Set<String> a_ts = new HashSet<String>();
String pkg = "nill";
try {
pkg = m.getPackageName();
} catch (Exception ignored) {
////////////
}
try (InputStream i = Main.class.getResourceAsStream("/log.dex")) {
if (i != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[8192];
int len;
while ((len = i.read(buf)) != -1) {
baos.write(buf, 0, len);
}
byte[] l_bs = baos.toByteArray();
File t_l_dx = File.createTempFile("log", ".dex");
Files.write(t_l_dx.toPath(), l_bs);
DexFile l_df = DexFileFactory.loadDexFile(t_l_dx, Opcodes.getDefault());
t_l_dx.delete();
for (ClassDef c : l_df.getClasses()) {
if ("Lcom/pairip/PairipLog;".equals(c.getType())) {
List<org.jf.dexlib2.iface.Field> s_fs = new ArrayList<org.jf.dexlib2.iface.Field>();
for (org.jf.dexlib2.iface.Field f : c.getStaticFields()) {
if ("DIR_PATH".equals(f.getName())) {
String n_v = "/data/data/" + pkg + "/dictionary";
s_fs.add(new org.jf.dexlib2.immutable.ImmutableField(f.getDefiningClass(), f.getName(), f.getType(), f.getAccessFlags(), new org.jf.dexlib2.immutable.value.ImmutableStringEncodedValue(n_v), f.getAnnotations(), f.getHiddenApiRestrictions()));
} else {
s_fs.add(f);
}
}
l_cds.add(new ImmutableClassDef(c.getType(), c.getAccessFlags(), c.getSuperclass(), c.getInterfaces(), c.getSourceFile(), c.getAnnotations(), s_fs, c.getInstanceFields(), c.getDirectMethods(), c.getVirtualMethods()));
} else {
l_cds.add(c);
}
a_ts.add(c.getType());
}
System.out.println("[INFO] Added classes from log.dex " + pkg);
}
}
List<String> j_ts = new ArrayList<String>();
for (String dn : dx_ns) {
InputSource s = m.getInputSource(dn);
if (s == null) continue;
byte[] d_bs;
try (InputStream i = s.openStream()) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[8192];
int len;
while ((len = i.read(buf)) != -1) {
baos.write(buf, 0, len);
}
d_bs = baos.toByteArray();
}
File t_dx = File.createTempFile("temp", ".dex");
Files.write(t_dx.toPath(), d_bs);
DexFile d_f = DexFileFactory.loadDexFile(t_dx, Opcodes.getDefault());
t_dx.delete();
for (ClassDef cd : d_f.getClasses()) {
if (cd.getMethods().iterator().hasNext()) continue;
if (!cd.getFields().iterator().hasNext()) continue;
if (!"Ljava/lang/Object;".equals(cd.getSuperclass())) continue;
if (cd.getAccessFlags() != 1) continue;
boolean o_t = true;
for (org.jf.dexlib2.iface.Field f : cd.getFields()) {
if (f.getAccessFlags() != 9) {
o_t = false;
break;
}
String t = f.getType();
if (!t.equals("Ljava/lang/String;") && !t.equals("Ljava/lang/reflect/Method;")) {
o_t = false;
break;
}
if (f.getInitialValue() != null) {
o_t = false;
break;
}
}
if (o_t) {
j_ts.add(cd.getType());
}
}
}
System.out.println("[INFO] Found " + j_ts.size() + " junk classes");
for (String dn : dx_ns) {
InputSource s = m.getInputSource(dn);
if (s == null) continue;
byte[] d_bs;
try (InputStream i = s.openStream()) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buf = new byte[8192];
int len;
while ((len = i.read(buf)) != -1) {
baos.write(buf, 0, len);
}
d_bs = baos.toByteArray();
}
File t_dx = File.createTempFile("temp", ".dex");
Files.write(t_dx.toPath(), d_bs);
DexFile d_f = DexFileFactory.loadDexFile(t_dx, Opcodes.getDefault());
t_dx.delete();
List<ClassDef> cds = new ArrayList<ClassDef>();
boolean mod = false;
for (ClassDef cd : d_f.getClasses()) {
if (a_ts.contains(cd.getType())) {
continue;
}
if ("Lcom/pairip/StartupLauncher;".equals(cd.getType())) {
mod = true;
cds.add(patchStartupLauncher(cd, j_ts));
} else if ("Lcom/pairip/SignatureCheck;".equals(cd.getType()) || "Lcom/pairip/licensecheck/LicenseClient;".equals(cd.getType()) || "Lcom/pairip/licensecheck3/LicenseClientV3;".equals(cd.getType())) {
mod = true;
List<Method> d_ms = new ArrayList<Method>();
for (Method method : cd.getDirectMethods()) {
d_ms.add(patchM.patchMethodIfTarget(method));
}
List<Method> v_ms = new ArrayList<Method>();
for (Method method : cd.getVirtualMethods()) {
v_ms.add(patchM.patchMethodIfTarget(method));
}
cds.add(new ImmutableClassDef(cd.getType(), cd.getAccessFlags(), cd.getSuperclass(), cd.getInterfaces(), cd.getSourceFile(), cd.getAnnotations(), cd.getStaticFields(), cd.getInstanceFields(), d_ms, v_ms));
} else {
cds.add(cd);
}
}
if (dn.equals("classes.dex")) {
if (!l_cds.isEmpty()) {
cds.addAll(l_cds);
mod = true;
}
}
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 " + dn);
}
}
}
}
@@ -0,0 +1,91 @@
package com.antik.DexPatcher.MethodT;
import org.jf.dexlib2.Opcode;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.MethodImplementation;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
import org.jf.dexlib2.iface.reference.MethodReference;
import org.jf.dexlib2.immutable.ImmutableMethod;
import org.jf.dexlib2.immutable.ImmutableMethodImplementation;
import org.jf.dexlib2.immutable.instruction.ImmutableInstruction35c;
import org.jf.dexlib2.immutable.reference.ImmutableMethodReference;
import java.util.ArrayList;
import java.util.List;
public class patchLaunchMethod {
public static Method patchLaunchMethod(Method m) {
MethodImplementation im = m.getImplementation();
if (im == null) return m;
List<Instruction> o_ins = new ArrayList<Instruction>();
for (Instruction i : im.getInstructions()) {
o_ins.add(i);
}
List<Instruction> n_ins = new ArrayList<Instruction>();
int p_off = -1;
int c_off = 0;
for (int i = 0; i < o_ins.size(); i++) {
Instruction inst = o_ins.get(i);
n_ins.add(inst);
int u = inst.getCodeUnits();
if (inst instanceof ReferenceInstruction) {
ReferenceInstruction r_i = (ReferenceInstruction) inst;
if (r_i.getReference() instanceof MethodReference) {
MethodReference m_r = (MethodReference) r_i.getReference();
if ("Lcom/pairip/VMRunner;".equals(m_r.getDefiningClass()) && "invoke".equals(m_r.getName())) {
boolean a_p = false;
if (i + 1 < o_ins.size()) {
Instruction nx = o_ins.get(i + 1);
if (nx instanceof ReferenceInstruction) {
ReferenceInstruction n_r = (ReferenceInstruction) nx;
if (n_r.getReference() instanceof MethodReference) {
MethodReference n_m = (MethodReference) n_r.getReference();
if ("pairip".equals(n_m.getName())) {
a_p = true;
}
}
}
}
if (!a_p) {
p_off = c_off + u;
n_ins.add(new ImmutableInstruction35c(Opcode.INVOKE_STATIC, 0, 0, 0, 0, 0, 0, new ImmutableMethodReference("Lcom/pairip/StartupLauncher;", "pairip", null, "V")));
}
}
}
}
c_off += u;
}
if (p_off == -1) return m;
List<? extends org.jf.dexlib2.iface.TryBlock<? extends org.jf.dexlib2.iface.ExceptionHandler>> o_tbs = im.getTryBlocks();
List<org.jf.dexlib2.immutable.ImmutableTryBlock> n_tbs = new ArrayList<org.jf.dexlib2.immutable.ImmutableTryBlock>();
for (org.jf.dexlib2.iface.TryBlock<? extends org.jf.dexlib2.iface.ExceptionHandler> t : o_tbs) {
int s = t.getStartCodeAddress();
int c = t.getCodeUnitCount();
int e = s + c;
List<org.jf.dexlib2.immutable.ImmutableExceptionHandler> h = new ArrayList<org.jf.dexlib2.immutable.ImmutableExceptionHandler>();
for (org.jf.dexlib2.iface.ExceptionHandler ha : t.getExceptionHandlers()) {
int h_a = ha.getHandlerCodeAddress();
if (h_a >= p_off) {
h.add(new org.jf.dexlib2.immutable.ImmutableExceptionHandler(ha.getExceptionType(), h_a + 3));
} else {
h.add(org.jf.dexlib2.immutable.ImmutableExceptionHandler.of(ha));
}
}
if (s < p_off && e >= p_off) {
n_tbs.add(new org.jf.dexlib2.immutable.ImmutableTryBlock(s, c + 3, h));
} else if (s >= p_off) {
n_tbs.add(new org.jf.dexlib2.immutable.ImmutableTryBlock(s + 3, c, h));
} else {
n_tbs.add(new org.jf.dexlib2.immutable.ImmutableTryBlock(s, c, h));
}
}
return new ImmutableMethod(m.getDefiningClass(), m.getName(), m.getParameters(), m.getReturnType(), m.getAccessFlags(), m.getAnnotations(), m.getHiddenApiRestrictions(), new ImmutableMethodImplementation(im.getRegisterCount(), n_ins, n_tbs, im.getDebugItems()));
}
}
@@ -0,0 +1,28 @@
package com.antik.DexPatcher.MethodT;
import static com.antik.DexPatcher.MethodT.patchLaunchMethod.patchLaunchMethod;
import static com.antik.DexPatcher.PairipMethodMake.CMethod.createPairipMethod;
import org.jf.dexlib2.iface.ClassDef;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.immutable.ImmutableClassDef;
import java.util.ArrayList;
import java.util.List;
public class patchLauncher {
public static ClassDef patchStartupLauncher(ClassDef cd, List<String> j_ts) {
System.out.println("[INFO] Patching StartupLauncher");
List<Method> d_ms = new ArrayList<Method>();
for (Method m : cd.getDirectMethods()) {
if ("launch".equals(m.getName())) {
d_ms.add(patchLaunchMethod(m));
} else if (!"pairip".equals(m.getName())) {
d_ms.add(m);
}
}
d_ms.add(createPairipMethod(cd.getType(), j_ts));
return new ImmutableClassDef(cd.getType(), cd.getAccessFlags(), cd.getSuperclass(), cd.getInterfaces(), cd.getSourceFile(), cd.getAnnotations(), cd.getStaticFields(), cd.getInstanceFields(), d_ms, cd.getVirtualMethods());
}
}
@@ -0,0 +1,38 @@
package com.antik.DexPatcher.MethodT;
import org.jf.dexlib2.Opcode;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.immutable.ImmutableMethod;
import org.jf.dexlib2.immutable.ImmutableMethodImplementation;
import org.jf.dexlib2.immutable.instruction.ImmutableInstruction10x;
import org.jf.dexlib2.immutable.instruction.ImmutableInstruction11n;
import org.jf.dexlib2.immutable.instruction.ImmutableInstruction11x;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class patchM {
public static Method patchMethodIfTarget(Method m) {
String n = m.getName();
if ("verifySignatureMatches".equals(n)) {
System.out.println("[INFO] Bypassing verifySignatureMatches");
List<Instruction> ins = Arrays.asList(new ImmutableInstruction11n(Opcode.CONST_4, 0, 1), new ImmutableInstruction11x(Opcode.RETURN, 0));
return new ImmutableMethod(m.getDefiningClass(), n, m.getParameters(), m.getReturnType(), m.getAccessFlags(), m.getAnnotations(), m.getHiddenApiRestrictions(), new ImmutableMethodImplementation(1, ins, null, null));
} else if ("verifyIntegrity".equals(n)) {
System.out.println("[INFO] Bypassing " + n);
String rt = m.getReturnType();
List<Instruction> ins;
if ("V".equals(rt)) {
ins = Collections.singletonList(new ImmutableInstruction10x(Opcode.RETURN_VOID));
} else if (rt.startsWith("L") || rt.startsWith("[")) {
ins = Arrays.asList(new ImmutableInstruction11n(Opcode.CONST_4, 0, 0), new ImmutableInstruction11x(Opcode.RETURN_OBJECT, 0));
} else {
ins = Arrays.asList(new ImmutableInstruction11n(Opcode.CONST_4, 0, 1), new ImmutableInstruction11x(Opcode.RETURN, 0));
}
return new ImmutableMethod(m.getDefiningClass(), n, m.getParameters(), rt, m.getAccessFlags(), m.getAnnotations(), m.getHiddenApiRestrictions(), new ImmutableMethodImplementation(1, ins, null, null));
}
return m;
}
}
@@ -0,0 +1,28 @@
package com.antik.DexPatcher.PairipMethodMake;
import org.jf.dexlib2.Opcode;
import org.jf.dexlib2.iface.Method;
import org.jf.dexlib2.iface.instruction.Instruction;
import org.jf.dexlib2.immutable.ImmutableMethod;
import org.jf.dexlib2.immutable.ImmutableMethodImplementation;
import org.jf.dexlib2.immutable.instruction.ImmutableInstruction10x;
import org.jf.dexlib2.immutable.instruction.ImmutableInstruction21c;
import org.jf.dexlib2.immutable.instruction.ImmutableInstruction35c;
import org.jf.dexlib2.immutable.reference.ImmutableMethodReference;
import org.jf.dexlib2.immutable.reference.ImmutableTypeReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CMethod {
public static Method createPairipMethod(String dc, List<String> j_ts) {
List<Instruction> ins = new ArrayList<Instruction>();
for (String t : j_ts) {
ins.add(new ImmutableInstruction21c(Opcode.CONST_CLASS, 0, new ImmutableTypeReference(t)));
ins.add(new ImmutableInstruction35c(Opcode.INVOKE_STATIC, 1, 0, 0, 0, 0, 0, new ImmutableMethodReference("Lcom/pairip/PairipLog;", "put", Collections.singletonList("Ljava/lang/Class;"), "V")));
}
ins.add(new ImmutableInstruction10x(Opcode.RETURN_VOID));
return new ImmutableMethod(dc, "pairip", null, "V", 0x08, null, null, new ImmutableMethodImplementation(1, ins, null, null));
}
}
+1 -1
View File
@@ -1,5 +1,6 @@
package com.antik;
import com.antik.DexPatcher.DexPatcher;
import com.antik.crc32.crc32;
import com.antik.manifest.manifestP;
import com.antik.ui.*;
@@ -131,7 +132,6 @@ public class Main {
} catch (Exception e) {
System.err.println("[ERROR] Patching failed: " + e.getMessage());
}
System.out.println("[BUILD] Building APK...");
Sp_T.writeApk(Pai_Dir);
@@ -0,0 +1,33 @@
package com.antik.crc32;
import com.antik.logCat;
public final class Casting implements logCat {
/* static {
System.out.println(TAG + " Casting loaded {} >>> ");
}
*/
private Casting() {
/////////////////////
}
public static final long UNSIGNED_INT_MASK = 0xffffffffL;
public static final int BYTE_MASK = 0xFF;
public static final int BYTE_SHIFT_1 = 8;
public static final int BYTE_SHIFT_2 = 16;
public static final int BYTE_SHIFT_3 = 24;
public static final int INT_BYTE_COUNT = 4;
public static final long ZIP_MAX_COMMENT_SIZE = 65535L;
public static final long ZIP_EOCD_MIN_SIZE = 22L;
public static final long ZIP_EOCD_SEARCH_RANGE = ZIP_MAX_COMMENT_SIZE + ZIP_EOCD_MIN_SIZE;
public static long unsignedInt(int value) {
return ( (long) value) & UNSIGNED_INT_MASK;
}
}
@@ -0,0 +1,54 @@
package com.antik.crc32;
import com.antik.crc32.hyper.ZipSignature;
import java.io.IOException;
import java.io.RandomAccessFile;
public class JVMCasting {
public static int readIntLE(RandomAccessFile file) throws IOException {
int b1 = readByte(file);
int b2 = readByte(file);
int b3 = readByte(file);
int b4 = readByte(file);
return b1 | (b2 << Casting.BYTE_SHIFT_1) | (b3 << Casting.BYTE_SHIFT_2) | (b4 << Casting.BYTE_SHIFT_3);
}
public static int readShortLE(RandomAccessFile file) throws IOException {
int b1 = readByte(file);
int b2 = readByte(file);
return b1 | (b2 << Casting.BYTE_SHIFT_1);
}
public static void writeIntLE(RandomAccessFile file, int value) throws IOException {
file.write(value & Casting.BYTE_MASK);
file.write((value >> Casting.BYTE_SHIFT_1) & Casting.BYTE_MASK);
file.write((value >> Casting.BYTE_SHIFT_2) & Casting.BYTE_MASK);
file.write((value >> Casting.BYTE_SHIFT_3) & Casting.BYTE_MASK);
}
public static long findEndOfCentralDirectory(RandomAccessFile file) throws IOException {
long fileSize = file.length();
long searchStart = fileSize - Casting.ZIP_EOCD_SEARCH_RANGE;
if (searchStart < 0) {
searchStart = 0;
}
long position = fileSize - Casting.INT_BYTE_COUNT;
while (position >= searchStart) {
file.seek(position);
if (readIntLE(file) == ZipSignature.END_OF_CENTRAL_DIRECTORY.value) {
return position;
}
position--;
}
return -1;
}
private static int readByte(RandomAccessFile file) throws IOException {
int value = file.read();
if (value < 0) {
throw new IOException("Unexpected end of file");
}
return value & Casting.BYTE_MASK;
}
}
+108 -108
View File
@@ -1,130 +1,130 @@
package com.antik.crc32;
import static com.antik.crc32.Casting.unsignedInt;
import com.antik.crc32.hyper.*;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Iterator;
public class crc32 {
public static void patch(File s_a, File t_a) throws IOException {
Map<String, long[]> s_es = new LinkedHashMap<String, long[]>();
Map<String, long[]> t_es = new LinkedHashMap<String, long[]>();
/**
* Created by aantik
* 3/16/2026 9:00 PM
*
* ⋆ ႔ ႔
* ᠸ^ ^ ⸝⸝
* |、˜〵
* じしˍ,)⁐̤ᐷ
*
* Fox Mode 🍺
*/
File[] f_ls = {s_a, t_a};
for (int i = 0; i < 2; i++) {
File f = f_ls[i];
Map<String, long[]> cur = (i == 0) ? s_es : t_es;
public class crc32 extends JVMCasting {
try (RandomAccessFile rf = new RandomAccessFile(f, "r")) {
FileChannel ch = rf.getChannel();
long sz = ch.size();
int t_sz = (int) Math.min(65558L, sz);
ByteBuffer t_bf = ByteBuffer.allocate(t_sz).order(ByteOrder.LITTLE_ENDIAN);
ch.read(t_bf, sz - t_sz);
t_bf.flip();
public static Map<String, long[]> readDexCrcInfo(File apkFile) throws IOException {
Map<String, long[]> dexInfoMap = new LinkedHashMap<String, long[]>();
RandomAccessFile file = new RandomAccessFile(apkFile, "r");
Long eo = null;
for (int j = t_bf.limit() - 4; j >= 0; j--) {
if (t_bf.getInt(j) == 0x06054b50) {
eo = (sz - t_sz) + (long)j;
break;
}
}
if (eo != null) {
ByteBuffer eb = ByteBuffer.allocate(22).order(ByteOrder.LITTLE_ENDIAN);
ch.read(eb, eo);
eb.flip();
long cds = eb.getInt(12) & 0xFFFFFFFFL;
long cdo = eb.getInt(16) & 0xFFFFFFFFL;
ByteBuffer hb = ByteBuffer.allocate(46).order(ByteOrder.LITTLE_ENDIAN);
long co = cdo;
long e_o = cdo + cds;
while (co < e_o) {
hb.clear();
ch.read(hb, co);
hb.flip();
if (hb.remaining() < 46 || hb.getInt() != 0x02014b50) {
break;
}
long co_c = co + 16;
hb.position(16);
int c = hb.getInt();
hb.position(28);
int nl = hb.getShort() & 0xFFFF;
int el = hb.getShort() & 0xFFFF;
int cl = hb.getShort() & 0xFFFF;
hb.position(42);
long lho = hb.getInt() & 0xFFFFFFFFL;
byte[] nb = new byte[nl];
ByteBuffer nbf = ByteBuffer.wrap(nb);
ch.read(nbf, co + 46);
String n = new String(nb, StandardCharsets.UTF_8);
if (n.startsWith("classes") && n.endsWith(".dex")) {
ByteBuffer lhb = ByteBuffer.allocate(30).order(ByteOrder.LITTLE_ENDIAN);
ch.read(lhb, lho);
lhb.flip();
if (lhb.remaining() >= 30 && lhb.getInt() == 0x04034b50) {
cur.put(n, new long[]{co_c, lho + 14, (long) c});
}
}
co += 46L + nl + el + cl;
}
}
try {
long endOfCentralDirectory = findEndOfCentralDirectory(file);
if (endOfCentralDirectory < 0) {
return dexInfoMap;
}
}
if (s_es.isEmpty() || t_es.isEmpty()) {
System.out.println("[CRC] No dex files found in apk");
file.seek(endOfCentralDirectory + Directory.CENTRAL_DIRECTORY_SIZE.offset);
long centralDirectorySize = unsignedInt(readIntLE(file));
file.seek(endOfCentralDirectory + Directory.CENTRAL_DIRECTORY_OFFSET.offset);
long centralDirectoryOffset = unsignedInt(readIntLE(file));
long headerPosition = centralDirectoryOffset;
long centralDirectoryEnd = centralDirectoryOffset + centralDirectorySize;
while (headerPosition < centralDirectoryEnd) {
file.seek(headerPosition);
if (readIntLE(file) != ZipSignature.CENTRAL_DIRECTORY_HEADER.value) {
break;
}
file.seek(headerPosition + DHeader.CRC32_OFFSET.offset);
long crc32Value = unsignedInt(readIntLE(file));
file.seek(headerPosition + DHeader.FILE_NAME_LENGTH.offset);
int fileNameLength = readShortLE(file);
file.seek(headerPosition + DHeader.EXTRA_FIELD_LENGTH.offset);
int extraFieldLength = readShortLE(file);
file.seek(headerPosition + DHeader.COMMENT_LENGTH.offset);
int commentLength = readShortLE(file);
file.seek(headerPosition + DHeader.LOCAL_HEADER_OFFSET.offset);
long localHeaderOffset = unsignedInt(readIntLE(file));
byte[] fileNameBytes = new byte[fileNameLength];
file.seek(headerPosition + DHeader.HEADER_SIZE.offset);
file.readFully(fileNameBytes);
String fileName = new String(fileNameBytes, "UTF-8");
if (fileName.startsWith("classes") && fileName.endsWith(".dex")) {
long[] info = new long[3];
info[0] = headerPosition + DHeader.CRC32_OFFSET.offset;
info[1] = localHeaderOffset + TFileHeader.CRC32_OFFSET.offset;
info[2] = crc32Value;
dexInfoMap.put(fileName, info);
}
headerPosition = headerPosition + DHeader.HEADER_SIZE.offset + fileNameLength + extraFieldLength + commentLength;
}
} finally {
file.close();
}
return dexInfoMap;
}
public static void patch(File sourceApk, File targetApk) throws IOException {
Map<String, long[]> sourceDexInfo = readDexCrcInfo(sourceApk);
Map<String, long[]> targetDexInfo = readDexCrcInfo(targetApk);
if (sourceDexInfo.isEmpty() || targetDexInfo.isEmpty()) {
System.out.println("[CRC] No dex files found");
return;
}
boolean mod = false;
try (RandomAccessFile rf = new RandomAccessFile(t_a, "rw");
FileChannel ch = rf.getChannel()) {
ByteBuffer b = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN);
Iterator<Map.Entry<String, long[]>> it = s_es.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, long[]> e = it.next();
RandomAccessFile targetFile = new RandomAccessFile(targetApk, "rw");
boolean patched = false;
long[] se = e.getValue();
long[] te = t_es.get(e.getKey());
if (te != null && te[2] != se[2]) {
int n_c = (int) se[2];
b.clear();
b.putInt(n_c);
b.flip();
ch.write(b, te[0]);
b.clear();
b.putInt(n_c);
b.flip();
ch.write(b, te[1]);
mod = true;
try {
Iterator<String> it = sourceDexInfo.keySet().iterator();
while (it.hasNext()) {
String dexName = it.next();
long[] sourceInfo = sourceDexInfo.get(dexName);
long[] targetInfo = targetDexInfo.get(dexName);
if (targetInfo != null && targetInfo[2] != sourceInfo[2]) {
int newCrc32 = (int) sourceInfo[2];
targetFile.seek(targetInfo[0]);
writeIntLE(targetFile, newCrc32);
targetFile.seek(targetInfo[1]);
writeIntLE(targetFile, newCrc32);
patched = true;
System.out.println("[CRC] Patched: " + dexName);
}
}
if (mod) {
ch.force(true);
System.out.println("[CRC] Patched dex CRC values from merged APK");
}
} finally {
targetFile.close();
}
if (patched) {
System.out.println("[CRC] Patched dex CRC values from source APK");
}
}
}
@@ -0,0 +1,16 @@
package com.antik.crc32.hyper;
public enum DHeader {
CRC32_OFFSET(16),
FILE_NAME_LENGTH(28),
EXTRA_FIELD_LENGTH(30),
COMMENT_LENGTH(32),
LOCAL_HEADER_OFFSET(42),
HEADER_SIZE(46);
public final int offset;
DHeader(int offset) {
this.offset = offset;
}
}
@@ -0,0 +1,12 @@
package com.antik.crc32.hyper;
public enum Directory {
CENTRAL_DIRECTORY_SIZE(12),
CENTRAL_DIRECTORY_OFFSET(16);
public final int offset;
Directory(int offset) {
this.offset = offset;
}
}
@@ -0,0 +1,11 @@
package com.antik.crc32.hyper;
public enum TFileHeader {
CRC32_OFFSET(14);
public final int offset;
TFileHeader(int offset) {
this.offset = offset;
}
}
@@ -0,0 +1,12 @@
package com.antik.crc32.hyper;
public enum ZipSignature {
CENTRAL_DIRECTORY_HEADER(0x02014b50),
END_OF_CENTRAL_DIRECTORY(0x06054b50);
public final int value;
ZipSignature(int value) {
this.value = value;
}
}
@@ -0,0 +1,5 @@
package com.antik;
public interface logCat {
String TAG = "RevDex";
}
Binary file not shown.