This commit is contained in:
isPointer
2026-06-10 02:49:27 +06:00
committed by GitHub
parent fc0fb351d2
commit 8359a6b737
19 changed files with 1333 additions and 0 deletions
+15
View File
@@ -0,0 +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
+31
View File
@@ -0,0 +1,31 @@
plugins {
java
alias(libs.plugins.shadow)
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
tasks.jar {
enabled = false
}
tasks.shadowJar {
archiveFileName.set("RePairip.jar")
manifest {
attributes["Main-Class"] = "com.antik.Main"
}
}
// Make the 'build' and 'assemble' tasks produce the shadow jar
tasks.assemble {
dependsOn(tasks.shadowJar)
}
dependencies {
implementation(libs.dexlib2)
implementation(libs.reandroid.arsclib)
implementation(libs.guava)
}
@@ -0,0 +1,89 @@
package com.antik;
import java.io.*;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class AntikUtils {
public static String get_out(File i, String n) {
File p = i.getParentFile();
if (p == null) {
return n;
}
return new File(p, n).getPath();
}
public static void ex_apks(File zf, File dd) throws Exception {
try (ZipFile z = new ZipFile(zf)) {
Enumeration<? extends ZipEntry> es = z.entries();
while (es.hasMoreElements()) {
ZipEntry e = es.nextElement();
if (e.getName().endsWith(".apk")) {
File of = new File(dd, new File(e.getName()).getName());
try (InputStream i = z.getInputStream(e);
FileOutputStream fo = new FileOutputStream(of)) {
byte[] b = new byte[8192];
int l;
while ((l = i.read(b)) > 0) {
fo.write(b, 0, l);
}
}
}
}
}
}
public static void del_dir(File d) {
File[] fs = d.listFiles();
if (fs != null) {
for (File f : fs) {
if (f.isDirectory()) {
del_dir(f);
} else {
f.delete();
}
}
}
d.delete();
}
public static void banner() {
System.out.println("░░░░░█▀▄░█▀▀░█░█░█▀▄░█▀▀░█░█░░░░░");
System.out.println("░░░░░█▀▄░█▀▀░▀▄▀░█░█░█▀▀░▄▀▄░░░░░");
System.out.println("░░░░░▀░▀░▀▀▀░░▀░░▀▀░░▀▀▀░▀░▀░░░░░");
System.out.println("░█▀▄░█▀▀░█▀█░█▀█░▀█▀░█▀▄░▀█▀░█▀█░");
System.out.println("░█▀▄░█▀▀░█▀▀░█▀█░░█░░█▀▄░░█░░█▀▀░");
System.out.println("░▀░▀░▀▀▀░▀░░░▀░▀░▀▀▀░▀░▀░▀▀▀░▀░░░");
System.out.println("Version : 1.3.10");
System.out.println("--------------------------------------");
System.out.println("Dev : Antik (Fox)");
System.out.println("Channel : https://t.me/RevDex");
System.out.println("GitHub : https://github.com/ispointer/RePairip");
System.out.println("--------------------------------------");
}
public static void help() {
System.out.println("java -jar antik.jar -i <input.apks>");
}
public static void progress(int c, int t) {
if (t <= 0) t = 1;
int w = 30;
float p = (float) c / t;
if (p > 1.0f) p = 1.0f;
int f = (int) (p * w);
StringBuilder s = new StringBuilder("\r[");
for (int i = 0; i < f; i++) {
s.append("#");
}
for (int i = f; i < w; i++) {
s.append("-");
}
s.append("] ");
s.append(String.format("%d%%", (int) (p * 100)));
System.out.print(s.toString());
System.out.flush();
}
}
@@ -0,0 +1,130 @@
package com.antik;
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;
public class CrcPatcher {
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[]>();
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;
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();
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;
}
}
}
}
if (s_es.isEmpty() || t_es.isEmpty()) {
System.out.println("[CRC] No dex files found in apk");
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();
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;
}
}
if (mod) {
ch.force(true);
System.out.println("[CRC] Patched dex CRC values from merged APK");
}
}
}
}
@@ -0,0 +1,377 @@
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));
}
}
+153
View File
@@ -0,0 +1,153 @@
package com.antik;
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) {
if (a.length < 2 || !"-i".equals(a[0]))
{
AntikUtils.help();
return;
}
String P_ta = a[1];
File I_pa = new File(P_ta);
if (!I_pa.exists()) {
System.err.println("Input file not found : " + P_ta);
return;
}
AntikUtils.banner();
File T_Dir = null;
try {
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 {
ManifestPatcher.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";
} else {
o = o + "_merged.apk";
}
File o_f = new File(AntikUtils.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]++;
AntikUtils.progress(c[0], T_l);
}
});
AntikUtils.progress(T_l, T_l);
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(AntikUtils.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] Building APK...");
Sp_T.writeApk(Pai_Dir);
CrcPatcher.patch(o_f, Pai_Dir);
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());
} finally {
if (T_Dir != null) {
AntikUtils.del_dir(T_Dir);
}
}
}
}
@@ -0,0 +1,108 @@
package com.antik;
import com.reandroid.apk.ApkModule;
import com.reandroid.arsc.chunk.xml.AndroidManifestBlock;
import com.reandroid.arsc.chunk.xml.ResXmlElement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
@SuppressWarnings({"unchecked", "rawtypes"})
public class ManifestPatcher {
@SuppressWarnings({"unchecked", "rawtypes"})
public static void patch(ApkModule m) throws Exception {
AndroidManifestBlock mf = m.getAndroidManifest();
if (mf == null)
{
return;
}
Boolean e = mf.isExtractNativeLibs();
if (e != null && e.booleanValue() == false) {
mf.setExtractNativeLibs(true);
}
ResXmlElement m_e = mf.getManifestElement();
if (m_e != null)
{
m_e.removeAttributesWithName("requiredSplitTypes");
m_e.removeAttributesWithName("splitTypes");
}
List md_r = Arrays.asList(new String[]{"com.android.stamp.source", "com.android.stamp.type", "com.android.vending.splits", "com.android.vending.derived.apk.id", "com.android.dynamic.apk.fused.modules", "com.android.vending.splits.required"});
List act_r = Arrays.asList(new String[]{"com.pairip.licensecheck.LicenseActivity"});
List pv_r = Arrays.asList(new String[]{"com.pairip.licensecheck.LicenseContentProvider"});
Iterator i = mf.getApplicationElementsByTag("meta-data");
List rm_ls = new ArrayList();
while (i.hasNext()) {
ResXmlElement el = (ResXmlElement) i.next();
String n = AndroidManifestBlock.getAndroidNameValue(el);
if (md_r.contains(n)) {
rm_ls.add(el);
}
}
int x = 0;
for (; x < rm_ls.size(); x = x + 1) {
ResXmlElement el = (ResXmlElement) rm_ls.get(x);
el.removeSelf();
}
rm_ls.clear();
i = mf.getApplicationElementsByTag("activity");
while (i.hasNext()) {
ResXmlElement el = (ResXmlElement) i.next();
String n = AndroidManifestBlock.getAndroidNameValue(el);
if (act_r.contains(n)) {
rm_ls.add(el);
}
}
for (x = 0; x < rm_ls.size(); x = x + 1) {
ResXmlElement el = (ResXmlElement) rm_ls.get(x);
el.removeSelf();
}
rm_ls.clear();
i = mf.getApplicationElementsByTag("provider");
while (i.hasNext()) {
ResXmlElement el = (ResXmlElement) i.next();
String n = AndroidManifestBlock.getAndroidNameValue(el);
if (pv_r.contains(n)) {
rm_ls.add(el);
}
}
for (x = 0; x < rm_ls.size(); x++) {
ResXmlElement el = (ResXmlElement) rm_ls.get(x);
el.removeSelf();
}
m.setManifest(mf);
}
}
+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.
+2
View File
@@ -0,0 +1,2 @@
plugins {
}
+17
View File
@@ -0,0 +1,17 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. For more details, visit
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
# org.gradle.parallel=true
# When enabled, the Configuration Cache allows Gradle to skip the configuration
# phase entirely if nothing that affects the build configuration (such as build scripts)
# has changed. Additionally, Gradle applies performance optimizations to task execution.
org.gradle.configuration-cache=true
+12
View File
@@ -0,0 +1,12 @@
#This file is generated by updateDaemonJvm
toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect
toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect
toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect
toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect
toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/73bcfb608d1fde9fb62e462f834a3299/redirect
toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/846ee0d876d26a26f37aa1ce8de73224/redirect
toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/ec7520a1e057cd116f9544c42142a16b/redirect
toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/4c4f879899012ff0a8b2e2117df03b0e/redirect
toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/9482ddec596298c84656d31d16652665/redirect
toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/39701d92e1756bb2f141eb67cd4c660e/redirect
toolchainVersion=21
+15
View File
@@ -0,0 +1,15 @@
[versions]
junit = "4.13.2"
dexlib2 = "2.5.2"
reandroid-arsclib = "V1.3.8"
guava = "33.2.1-jre"
shadow = "8.3.5"
[libraries]
junit = { group = "junit", name = "junit", version.ref = "junit" }
dexlib2 = { group = "org.smali", name = "dexlib2", version.ref = "dexlib2" }
reandroid-arsclib = { group = "com.github.REAndroid", name = "ARSCLib", version.ref = "reandroid-arsclib" }
guava = { group = "com.google.guava", name = "guava", version.ref = "guava" }
[plugins]
shadow = { id = "com.gradleup.shadow", version.ref = "shadow" }
Binary file not shown.
+8
View File
@@ -0,0 +1,8 @@
#Tue Jun 09 03:26:12 BDT 2026
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+251
View File
@@ -0,0 +1,251 @@
#!/bin/sh
#
# Copyright © 2015 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
warn () {
echo "$*"
} >&2
die () {
echo
echo "$*"
echo
exit 1
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
Vendored
+94
View File
@@ -0,0 +1,94 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the command line
set CLASSPATH=
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
+28
View File
@@ -0,0 +1,28 @@
pluginManagement {
repositories {
google {
content {
includeGroupByRegex("com\\.android.*")
includeGroupByRegex("com\\.google.*")
includeGroupByRegex("androidx.*")
}
}
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}
rootProject.name = "RePairip"
include(":antik")