53
53
import org .objectweb .asm .tree .analysis .SourceInterpreter ;
54
54
import org .objectweb .asm .tree .analysis .SourceValue ;
55
55
56
- public class HideAccessObfuscationTransformer extends Transformer <TransformerConfig > {
56
+ @ TransformerConfig .ConfigOptions (configClass = HideAccessObfuscationTransformer .Config .class )
57
+ public class HideAccessObfuscationTransformer extends Transformer <HideAccessObfuscationTransformer .Config > {
57
58
private static final String [][] CLASS_TO_PRIMITIVE = {
58
59
{"java/lang/Byte" , "byte" },
59
60
{"java/lang/Short" , "short" },
@@ -142,7 +143,23 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
142
143
args .add (JavaValue .valueOf (((InvokeDynamicInsnNode ) insn ).name ));
143
144
args .add (new JavaObject (null , "java/lang/invoke/MethodType" ));
144
145
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
+ }
146
163
switch (result .type ) {
147
164
case "virtual" :
148
165
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
195
212
List <JavaValue > args = new ArrayList <>();
196
213
args .add (new JavaInteger (value ));
197
214
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
+ }
199
232
hideAccessMethod .instructions .remove (returnInsert );
200
233
//Remove the array of objects
201
234
while (insn .getPrevious () != null ) {
@@ -318,7 +351,23 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
318
351
MethodNode decryptMethod = classes .get (owner ).methods .stream ().filter (m -> m .desc .equals ("(I)Ljava/lang/reflect/Method;" )).findFirst ().orElse (null );
319
352
if (insn .getPrevious ().getOpcode () == Opcodes .SWAP ) {
320
353
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
+ }
322
371
//Remove the array of objects
323
372
while (insn .getPrevious () != null ) {
324
373
if (insn .getPrevious ().getOpcode () == Opcodes .ANEWARRAY ) {
@@ -363,8 +412,24 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
363
412
case "(I)Ljava/lang/Object;" : { // GETSTATIC
364
413
MethodNode decryptMethod = classes .get (owner ).methods .stream ().filter (m -> m .desc .equals ("(I)Ljava/lang/reflect/Field;" )).findFirst ().orElse (null );
365
414
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
+
368
433
if (insn .getNext ().getOpcode () == Opcodes .CHECKCAST && isUnboxingMethod ((TypeInsnNode )insn .getNext ())
369
434
&& Type .getType (result .getDesc ()).getClassName ().equals (getPrimitiveFromClass (((TypeInsnNode )insn .getNext ()).desc ))) {
370
435
methodNode .instructions .remove (insn .getNext ().getNext ());
@@ -379,7 +444,23 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
379
444
MethodNode decryptMethod = classes .get (owner ).methods .stream ().filter (m -> m .desc .equals ("(I)Ljava/lang/reflect/Field;" )).findFirst ().orElse (null );
380
445
if (insn .getPrevious ().getOpcode () == Opcodes .SWAP ) {
381
446
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
+ }
383
464
384
465
methodNode .instructions .remove (insn .getPrevious ().getPrevious ());
385
466
methodNode .instructions .remove (insn .getPrevious ());
@@ -395,7 +476,23 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
395
476
case "(Ljava/lang/Object;I)Ljava/lang/Object;" : { // GETFIELD
396
477
MethodNode decryptMethod = classes .get (owner ).methods .stream ().filter (m -> m .desc .equals ("(I)Ljava/lang/reflect/Field;" )).findFirst ().orElse (null );
397
478
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
+ }
399
496
400
497
if (insn .getNext ().getOpcode () == Opcodes .CHECKCAST && isUnboxingMethod ((TypeInsnNode )insn .getNext ())
401
498
&& Type .getType (result .getDesc ()).getClassName ().equals (getPrimitiveFromClass (((TypeInsnNode )insn .getNext ()).desc ))) {
@@ -412,7 +509,23 @@ public boolean canCheckEquality(JavaValue first, JavaValue second, Context conte
412
509
413
510
if (insn .getPrevious ().getOpcode () == Opcodes .SWAP ) {
414
511
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
+ }
416
529
417
530
methodNode .instructions .remove (insn .getPrevious ().getPrevious ());
418
531
methodNode .instructions .remove (insn .getPrevious ());
@@ -642,4 +755,28 @@ public BasicValue merge(final BasicValue v, final BasicValue w)
642
755
return v ;
643
756
}
644
757
}
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
+ }
645
782
}
0 commit comments