Skip to content

Commit 52eb0ec

Browse files
committed
wip: virtualization
1 parent fd27d70 commit 52eb0ec

6 files changed

Lines changed: 577 additions & 40 deletions

File tree

dev.skidfuscator.obfuscator/src/main/java/dev/skidfuscator/obfuscator/transform/impl/string/StringTransformerV2.java

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import dev.skidfuscator.obfuscator.transform.impl.string.generator.v3.ByteBufferClinitV3EncryptionGenerator;
1515
import dev.skidfuscator.obfuscator.transform.impl.string.generator.v3.BytesClinitV3EncryptionGenerator;
1616
import dev.skidfuscator.obfuscator.transform.impl.string.generator.v3.BytesV3EncryptionGenerator;
17+
import dev.skidfuscator.obfuscator.transform.impl.string.generator.v3.VirtualizedStringEncryptionGenerator;
1718
import dev.skidfuscator.obfuscator.util.RandomUtil;
1819
import org.mapleir.asm.ClassNode;
1920
import org.mapleir.ir.cfg.ControlFlowGraph;
@@ -63,30 +64,34 @@ void handle(final RunMethodTransformEvent event) {
6364
EncryptionGeneratorV3 generator = keyMap.get(parentNode);
6465

6566
if (generator == null) {
66-
switch (RandomUtil.nextInt(3)) {
67-
case 0: {
68-
final int size = RandomUtil.nextInt(127) + 1;
69-
final byte[] keys = new byte[size];
70-
71-
for (int i = 0; i < size; i++) {
72-
keys[i] = (byte) (RandomUtil.nextInt(127) + 1);
67+
generator = new VirtualizedStringEncryptionGenerator();
68+
keyMap.put(parentNode, generator);
69+
if (false) {
70+
switch (RandomUtil.nextInt(3)) {
71+
case 0: {
72+
final int size = RandomUtil.nextInt(127) + 1;
73+
final byte[] keys = new byte[size];
74+
75+
for (int i = 0; i < size; i++) {
76+
keys[i] = (byte) (RandomUtil.nextInt(127) + 1);
77+
}
78+
keyMap.put(parentNode, (generator = new BytesV3EncryptionGenerator(keys)));
79+
break;
7380
}
74-
keyMap.put(parentNode, (generator = new BytesV3EncryptionGenerator(keys)));
75-
break;
76-
}
77-
case 1: {
78-
final int size = RandomUtil.nextInt(127) + 1;
79-
final byte[] keys = new byte[size];
80-
81-
for (int i = 0; i < size; i++) {
82-
keys[i] = (byte) (RandomUtil.nextInt(127) + 1);
81+
case 1: {
82+
final int size = RandomUtil.nextInt(127) + 1;
83+
final byte[] keys = new byte[size];
84+
85+
for (int i = 0; i < size; i++) {
86+
keys[i] = (byte) (RandomUtil.nextInt(127) + 1);
87+
}
88+
keyMap.put(parentNode, (generator = new BytesClinitV3EncryptionGenerator(keys)));
89+
break;
90+
}
91+
default: {
92+
keyMap.put(parentNode, (generator = new ByteBufferClinitV3EncryptionGenerator()));
93+
break;
8394
}
84-
keyMap.put(parentNode, (generator = new BytesClinitV3EncryptionGenerator(keys)));
85-
break;
86-
}
87-
default: {
88-
keyMap.put(parentNode, (generator = new ByteBufferClinitV3EncryptionGenerator()));
89-
break;
9095
}
9196
}
9297
}

dev.skidfuscator.obfuscator/src/main/java/dev/skidfuscator/obfuscator/transform/impl/string/generator/v3/AbstractEncryptionGeneratorV3.java

Lines changed: 140 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -136,13 +136,18 @@ public void visitPre(SkidClassNode node) {
136136
for (Method declaredMethod : this.getClass().getDeclaredMethods()) {
137137
declaredMethod.setAccessible(true);
138138

139+
System.out.println(declaredMethod.getName());
140+
System.out.println(declaredMethod.getAnnotation(InjectMethod.class));
141+
139142
/*
140143
* Skip methods that are not annotated with @Inject
141144
*/
142145
if (!declaredMethod.isAnnotationPresent(InjectMethod.class)) {
143146
continue;
144147
}
145148

149+
System.out.println("Injecting method " + declaredMethod.getName());
150+
146151
/*
147152
* Get the method node from the class node
148153
*/
@@ -220,6 +225,28 @@ public void visitPre(SkidClassNode node) {
220225
throw new IllegalStateException("Field remap not found for " + fieldInsnNode.name + fieldInsnNode.desc);
221226
}
222227
}
228+
} else if (insn instanceof org.objectweb.asm.tree.MethodInsnNode) {
229+
final org.objectweb.asm.tree.MethodInsnNode methodInsnNode = (org.objectweb.asm.tree.MethodInsnNode) insn;
230+
231+
/*
232+
* If the method owner is the same as the class node, then we need to remap it
233+
*/
234+
if (methodInsnNode.owner.equals(classNode.getName())) {
235+
methodInsnNode.owner = node.getName();
236+
}
237+
238+
/*
239+
* Remap the method name and description to their new values
240+
*/
241+
final String remappedMethodName = methodMapping.getMapping(methodInsnNode.name);
242+
243+
if (remappedMethodName != null) {
244+
methodInsnNode.name = remappedMethodName;
245+
} else {
246+
if (methodInsnNode.owner.equals(classNode.getName())) {
247+
throw new IllegalStateException("Method remap not found for " + methodInsnNode.name);
248+
}
249+
}
223250
}
224251
});
225252

@@ -284,28 +311,28 @@ protected Stmt storeInjectField(final SkidClassNode parent,
284311
);
285312
}
286313

287-
protected Expr generateByteArrayGenerator(final SkidClassNode node, final byte[] encrypted) {
314+
protected static <T> Expr generateArrayGenerator(final SkidClassNode node, final T[] array, final Type elementType) {
288315
final SkidMethodNode injector = new SkidMethodNodeBuilder(node.getSkidfuscator(), node)
289316
.access(Opcodes.ACC_STATIC | Opcodes.ACC_PRIVATE)
290317
.name(RandomUtil.randomAlphabeticalString(15))
291-
.desc("()[B")
318+
.desc("()[" + elementType.getDescriptor())
292319
.phantom(true)
293320
.build();
294321

295-
final Expr[] csts = new Expr[encrypted.length];
296-
for (int i = 0; i < encrypted.length; i++) {
297-
csts[i] = new ConstantExpr(encrypted[i], Type.BYTE_TYPE);
322+
final Expr[] constants = new Expr[array.length];
323+
for (int i = 0; i < array.length; i++) {
324+
constants[i] = new ConstantExpr(array[i], elementType);
298325
}
299326

300-
final NewArrayExpr encryptedExpr = new NewArrayExpr(
301-
new Expr[]{new ConstantExpr(encrypted.length, Type.INT_TYPE)},
302-
Type.getType(byte[].class),
303-
csts
327+
final NewArrayExpr arrayExpr = new NewArrayExpr(
328+
new Expr[]{new ConstantExpr(array.length, Type.INT_TYPE)},
329+
Type.getType(elementType.getDescriptor() + "[]"),
330+
constants
304331
);
305332

306333
injector.getCfg()
307334
.getEntry()
308-
.add(new ReturnStmt(Type.getType(byte[].class), encryptedExpr));
335+
.add(new ReturnStmt(Type.getType(elementType.getDescriptor() + "[]"), arrayExpr));
309336

310337
return new StaticInvocationExpr(
311338
node.isInterface() ? InvocationExpr.CallType.INTERFACE : InvocationExpr.CallType.STATIC,
@@ -316,6 +343,109 @@ protected Expr generateByteArrayGenerator(final SkidClassNode node, final byte[]
316343
);
317344
}
318345

346+
protected static Expr generateByteArrayGenerator(final SkidClassNode node, final byte[] array) {
347+
return generatePrimitiveArrayGenerator(node, array, Type.BYTE_TYPE);
348+
}
349+
350+
protected static Expr generateIntArrayGenerator(final SkidClassNode node, final int[] array) {
351+
return generatePrimitiveArrayGenerator(node, array, Type.INT_TYPE);
352+
}
353+
354+
private static Expr generatePrimitiveArrayGenerator(final SkidClassNode node, final Object array, final Type elementType) {
355+
// Validation
356+
if (!elementType.equals(Type.BYTE_TYPE) && !elementType.equals(Type.INT_TYPE)) {
357+
throw new IllegalArgumentException("Unsupported primitive type: " + elementType);
358+
}
359+
360+
// Check array
361+
if (array == null) {
362+
throw new IllegalArgumentException("Array cannot be null");
363+
}
364+
365+
// Check array type
366+
if (!array.getClass().isArray()) {
367+
throw new IllegalArgumentException("Object is not an array");
368+
}
369+
370+
// Check array length
371+
if (java.lang.reflect.Array.getLength(array) == 0) {
372+
throw new IllegalArgumentException("Array length is 0");
373+
}
374+
375+
// Check array element type
376+
if (!elementType.equals(Type.getType(array.getClass().getComponentType()))) {
377+
throw new IllegalArgumentException("Array element type does not match");
378+
}
379+
380+
final SkidMethodNode injector = new SkidMethodNodeBuilder(node.getSkidfuscator(), node)
381+
.access(Opcodes.ACC_STATIC | Opcodes.ACC_PRIVATE)
382+
.name(RandomUtil.randomAlphabeticalString(15))
383+
.desc("()[" + elementType.getDescriptor())
384+
.phantom(true)
385+
.build();
386+
387+
final int length = java.lang.reflect.Array.getLength(array);
388+
final Expr[] constants = new Expr[length];
389+
390+
for (int i = 0; i < length; i++) {
391+
Object value = java.lang.reflect.Array.get(array, i);
392+
constants[i] = new ConstantExpr(value, elementType);
393+
}
394+
395+
final NewArrayExpr arrayExpr = new NewArrayExpr(
396+
new Expr[]{new ConstantExpr(length, Type.INT_TYPE)},
397+
Type.getType("[" + elementType.getDescriptor()),
398+
constants
399+
);
400+
401+
injector.getCfg()
402+
.getEntry()
403+
.add(new ReturnStmt(Type.getType("[" + elementType.getDescriptor()), arrayExpr));
404+
405+
return new StaticInvocationExpr(
406+
node.isInterface() ? InvocationExpr.CallType.INTERFACE : InvocationExpr.CallType.STATIC,
407+
new Expr[0],
408+
node.getName(),
409+
injector.getName(),
410+
injector.getDesc()
411+
);
412+
}
413+
414+
// Convenience methods for Map conversion
415+
protected static Expr generateIntArrayFromMap(final SkidClassNode node, Map<Integer, Integer> map) {
416+
int[] array = new int[map.size() * 2];
417+
int i = 0;
418+
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
419+
array[i++] = entry.getKey();
420+
array[i++] = entry.getValue();
421+
}
422+
return generateIntArrayGenerator(node, array);
423+
}
424+
425+
protected static Expr generateByteArrayFromInts(final SkidClassNode node, final int[] array) {
426+
byte[] bytes = new byte[array.length * 4];
427+
for (int i = 0; i < array.length; i++) {
428+
int value = array[i];
429+
bytes[i * 4] = (byte) (value >>> 24);
430+
bytes[i * 4 + 1] = (byte) (value >>> 16);
431+
bytes[i * 4 + 2] = (byte) (value >>> 8);
432+
bytes[i * 4 + 3] = (byte) value;
433+
}
434+
return generateByteArrayGenerator(node, bytes);
435+
}
436+
437+
// Helper method to handle arrays of different types
438+
protected static Expr generateArray(final SkidClassNode node, final Object array) {
439+
if (array instanceof byte[]) {
440+
return generateByteArrayGenerator(node, (byte[]) array);
441+
} else if (array instanceof int[]) {
442+
return generateIntArrayGenerator(node, (int[]) array);
443+
} else if (array instanceof Map) {
444+
return generateIntArrayFromMap(node, (Map<Integer, Integer>) array);
445+
}
446+
throw new IllegalArgumentException("Unsupported array type: " + array.getClass());
447+
}
448+
319449
static class InjectMapping {
320450
private final Map<String, String> fieldMap = new HashMap<>();
321451

0 commit comments

Comments
 (0)