Skip to content

Commit e91b6e2

Browse files
authored
HideAccess "Skip Failures" Option
1 parent 8154d1a commit e91b6e2

File tree

1 file changed

+146
-9
lines changed

1 file changed

+146
-9
lines changed

src/main/java/com/javadeobfuscator/deobfuscator/transformers/stringer/HideAccessObfuscationTransformer.java

Lines changed: 146 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@
5353
import org.objectweb.asm.tree.analysis.SourceInterpreter;
5454
import org.objectweb.asm.tree.analysis.SourceValue;
5555

56-
public class HideAccessObfuscationTransformer extends Transformer<TransformerConfig> {
56+
@TransformerConfig.ConfigOptions(configClass = HideAccessObfuscationTransformer.Config.class)
57+
public class HideAccessObfuscationTransformer extends Transformer<HideAccessObfuscationTransformer.Config> {
5758
private static final String[][] CLASS_TO_PRIMITIVE = {
5859
{"java/lang/Byte", "byte"},
5960
{"java/lang/Short", "short"},
@@ -142,7 +143,23 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
142143
args.add(JavaValue.valueOf(((InvokeDynamicInsnNode) insn).name));
143144
args.add(new JavaObject(null, "java/lang/invoke/MethodType"));
144145

145-
JavaMethodHandle result = MethodExecutor.execute(classNode, bootstrapMethod, args, null, context);
146+
JavaMethodHandle result;
147+
try
148+
{
149+
result = MethodExecutor.execute(classNode, bootstrapMethod, args, null, context);
150+
if(result == null)
151+
throw new NullPointerException("Null result returned");
152+
}catch(Exception e)
153+
{
154+
if(getConfig().shouldIgnoreFailures())
155+
{
156+
System.out.println("Failed to decrypt invokedynamic call at class " + classNode.name
157+
+ " method " + methodNode.name + methodNode.desc);
158+
System.out.println(e.toString() + " @ " + e.getStackTrace()[0].toString());
159+
continue;
160+
}else
161+
throw e;
162+
}
146163
switch (result.type) {
147164
case "virtual":
148165
methodNode.instructions.set(insn, new MethodInsnNode(Opcodes.INVOKEVIRTUAL, result.clazz, result.name, result.desc, false));
@@ -195,7 +212,23 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
195212
List<JavaValue> args = new ArrayList<>();
196213
args.add(new JavaInteger(value));
197214
args.add(new JavaObject(null, "java/lang/Object"));
198-
JavaConstructor result = MethodExecutor.execute(classes.get(owner), hideAccessMethod, Collections.singletonList(new JavaInteger(value)), null, context);
215+
JavaConstructor result;
216+
try
217+
{
218+
result = MethodExecutor.execute(classes.get(owner), hideAccessMethod, Collections.singletonList(new JavaInteger(value)), null, context);
219+
if(result == null)
220+
throw new NullPointerException("Null result returned");
221+
}catch(Exception e)
222+
{
223+
if(getConfig().shouldIgnoreFailures())
224+
{
225+
System.out.println("Failed to decrypt invokespecial call at class " + classNode.name
226+
+ " method " + methodNode.name + methodNode.desc);
227+
System.out.println(e.toString() + " @ " + e.getStackTrace()[0].toString());
228+
continue;
229+
}else
230+
throw e;
231+
}
199232
hideAccessMethod.instructions.remove(returnInsert);
200233
//Remove the array of objects
201234
while (insn.getPrevious() != null) {
@@ -318,7 +351,23 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
318351
MethodNode decryptMethod = classes.get(owner).methods.stream().filter(m -> m.desc.equals("(I)Ljava/lang/reflect/Method;")).findFirst().orElse(null);
319352
if (insn.getPrevious().getOpcode() == Opcodes.SWAP) {
320353
Integer value = (Integer) ((LdcInsnNode) insn.getPrevious().getPrevious()).cst;
321-
JavaMethod result = MethodExecutor.execute(classes.get(owner), decryptMethod, Collections.singletonList(new JavaInteger(value)), null, context);
354+
JavaMethod result;
355+
try
356+
{
357+
result = MethodExecutor.execute(classes.get(owner), decryptMethod, Collections.singletonList(new JavaInteger(value)), null, context);
358+
if(result == null)
359+
throw new NullPointerException("Null result returned");
360+
}catch(Exception e)
361+
{
362+
if(getConfig().shouldIgnoreFailures())
363+
{
364+
System.out.println("Failed to decrypt encrypted method call at class " + classNode.name
365+
+ " method " + methodNode.name + methodNode.desc);
366+
System.out.println(e.toString() + " @ " + e.getStackTrace()[0].toString());
367+
continue;
368+
}else
369+
throw e;
370+
}
322371
//Remove the array of objects
323372
while (insn.getPrevious() != null) {
324373
if (insn.getPrevious().getOpcode() == Opcodes.ANEWARRAY) {
@@ -363,8 +412,24 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
363412
case "(I)Ljava/lang/Object;": { // GETSTATIC
364413
MethodNode decryptMethod = classes.get(owner).methods.stream().filter(m -> m.desc.equals("(I)Ljava/lang/reflect/Field;")).findFirst().orElse(null);
365414
Integer value = (Integer) ((LdcInsnNode) insn.getPrevious()).cst;
366-
JavaField result = MethodExecutor.execute(classes.get(owner), decryptMethod, Collections.singletonList(new JavaInteger(value)), null, context);
367-
415+
JavaField result;
416+
try
417+
{
418+
result = MethodExecutor.execute(classes.get(owner), decryptMethod, Collections.singletonList(new JavaInteger(value)), null, context);
419+
if(result == null)
420+
throw new NullPointerException("Null result returned");
421+
}catch(Exception e)
422+
{
423+
if(getConfig().shouldIgnoreFailures())
424+
{
425+
System.out.println("Failed to decrypt getstatic call at class " + classNode.name
426+
+ " method " + methodNode.name + methodNode.desc);
427+
System.out.println(e.toString() + " @ " + e.getStackTrace()[0].toString());
428+
continue;
429+
}else
430+
throw e;
431+
}
432+
368433
if (insn.getNext().getOpcode() == Opcodes.CHECKCAST && isUnboxingMethod((TypeInsnNode)insn.getNext())
369434
&& Type.getType(result.getDesc()).getClassName().equals(getPrimitiveFromClass(((TypeInsnNode)insn.getNext()).desc))) {
370435
methodNode.instructions.remove(insn.getNext().getNext());
@@ -379,7 +444,23 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
379444
MethodNode decryptMethod = classes.get(owner).methods.stream().filter(m -> m.desc.equals("(I)Ljava/lang/reflect/Field;")).findFirst().orElse(null);
380445
if (insn.getPrevious().getOpcode() == Opcodes.SWAP) {
381446
Integer value = (Integer) ((LdcInsnNode) insn.getPrevious().getPrevious()).cst;
382-
JavaField result = MethodExecutor.execute(classes.get(owner), decryptMethod, Collections.singletonList(new JavaInteger(value)), null, context);
447+
JavaField result;
448+
try
449+
{
450+
result = MethodExecutor.execute(classes.get(owner), decryptMethod, Collections.singletonList(new JavaInteger(value)), null, context);
451+
if(result == null)
452+
throw new NullPointerException("Null result returned");
453+
}catch(Exception e)
454+
{
455+
if(getConfig().shouldIgnoreFailures())
456+
{
457+
System.out.println("Failed to decrypt putstatic call at class " + classNode.name
458+
+ " method " + methodNode.name + methodNode.desc);
459+
System.out.println(e.toString() + " @ " + e.getStackTrace()[0].toString());
460+
continue;
461+
}else
462+
throw e;
463+
}
383464

384465
methodNode.instructions.remove(insn.getPrevious().getPrevious());
385466
methodNode.instructions.remove(insn.getPrevious());
@@ -395,7 +476,23 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
395476
case "(Ljava/lang/Object;I)Ljava/lang/Object;": { // GETFIELD
396477
MethodNode decryptMethod = classes.get(owner).methods.stream().filter(m -> m.desc.equals("(I)Ljava/lang/reflect/Field;")).findFirst().orElse(null);
397478
Integer value = (Integer) ((LdcInsnNode) insn.getPrevious()).cst;
398-
JavaField result = MethodExecutor.execute(classes.get(owner), decryptMethod, Collections.singletonList(new JavaInteger(value)), null, context);
479+
JavaField result;
480+
try
481+
{
482+
result = MethodExecutor.execute(classes.get(owner), decryptMethod, Collections.singletonList(new JavaInteger(value)), null, context);
483+
if(result == null)
484+
throw new NullPointerException("Null result returned");
485+
}catch(Exception e)
486+
{
487+
if(getConfig().shouldIgnoreFailures())
488+
{
489+
System.out.println("Failed to decrypt getfield call at class " + classNode.name
490+
+ " method " + methodNode.name + methodNode.desc);
491+
System.out.println(e.toString() + " @ " + e.getStackTrace()[0].toString());
492+
continue;
493+
}else
494+
throw e;
495+
}
399496

400497
if (insn.getNext().getOpcode() == Opcodes.CHECKCAST && isUnboxingMethod((TypeInsnNode)insn.getNext())
401498
&& Type.getType(result.getDesc()).getClassName().equals(getPrimitiveFromClass(((TypeInsnNode)insn.getNext()).desc))) {
@@ -412,7 +509,23 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
412509

413510
if (insn.getPrevious().getOpcode() == Opcodes.SWAP) {
414511
Integer value = (Integer) ((LdcInsnNode) insn.getPrevious().getPrevious()).cst;
415-
JavaField result = MethodExecutor.execute(classes.get(owner), decryptMethod, Collections.singletonList(new JavaInteger(value)), null, context);
512+
JavaField result;
513+
try
514+
{
515+
result = MethodExecutor.execute(classes.get(owner), decryptMethod, Collections.singletonList(new JavaInteger(value)), null, context);
516+
if(result == null)
517+
throw new NullPointerException("Null result returned");
518+
}catch(Exception e)
519+
{
520+
if(getConfig().shouldIgnoreFailures())
521+
{
522+
System.out.println("Failed to decrypt putfield call at class " + classNode.name
523+
+ " method " + methodNode.name + methodNode.desc);
524+
System.out.println(e.toString() + " @ " + e.getStackTrace()[0].toString());
525+
continue;
526+
}else
527+
throw e;
528+
}
416529

417530
methodNode.instructions.remove(insn.getPrevious().getPrevious());
418531
methodNode.instructions.remove(insn.getPrevious());
@@ -642,4 +755,28 @@ public BasicValue merge(final BasicValue v, final BasicValue w)
642755
return v;
643756
}
644757
}
758+
759+
public static class Config extends TransformerConfig
760+
{
761+
/**
762+
* Should we skip calls that fail to decrypt? This is useful if there are
763+
* a few encrypted calls that cannot be resolved by adding libraries.
764+
*/
765+
private boolean ignoreFailures = false;
766+
767+
public Config()
768+
{
769+
super(HideAccessObfuscationTransformer.class);
770+
}
771+
772+
public boolean shouldIgnoreFailures()
773+
{
774+
return ignoreFailures;
775+
}
776+
777+
public void setIgnoreFailures(boolean ignoreFailures)
778+
{
779+
this.ignoreFailures = ignoreFailures;
780+
}
781+
}
645782
}

0 commit comments

Comments
 (0)