2121import uwu .narumi .deobfuscator .api .helper .AsmHelper ;
2222import uwu .narumi .deobfuscator .api .transformer .Transformer ;
2323
24- import java .util .ArrayList ;
25- import java .util .HashMap ;
26- import java .util .List ;
27- import java .util .Map ;
24+ import java .util .*;
2825import java .util .concurrent .atomic .AtomicBoolean ;
2926
3027/**
@@ -78,7 +75,7 @@ protected void transform() throws Exception {
7875
7976 SandBox sandBox = new SandBox (context ());
8077 encryptedClassWrapper .forEach ((classWrapper , tmpClassWrapper ) -> {
81- AtomicBoolean isDecryptedFully = new AtomicBoolean (true );
78+ AtomicBoolean shouldCleanArray = new AtomicBoolean (true );
8279
8380 try {
8481 InstanceClass clazz = sandBox .getHelper ().loadClass ("tmp." + classWrapper .canonicalName ());
@@ -102,11 +99,12 @@ protected void transform() throws Exception {
10299 matchContext .removeAll ();
103100 markChange ();
104101 } catch (Exception e ) {
105- isDecryptedFully .set (false );
102+ shouldCleanArray .set (false );
106103 }
107104 });
108105 }
109106
107+ // TODO: Access directly array without getter
110108 SimpleArrayValue arrayValue = (SimpleArrayValue ) sandBox .getInvocationUtil ().invokeReference (
111109 clazz .getMethod ("getArr" , "()[Ljava/lang/String;" )
112110 );
@@ -155,7 +153,7 @@ else if (insn instanceof VarInsnNode varInsnNode &&
155153
156154 context ().removeCompiledClass (tmpClassWrapper );
157155
158- if (isDecryptedFully .get ())
156+ if (shouldCleanArray .get ())
159157 cleanUpFunction (classWrapper );
160158 });
161159 }
@@ -167,27 +165,19 @@ private void cleanUpFunction(ClassWrapper classWrapper) {
167165 MatchContext match = matches .get (matches .size () - 1 );
168166
169167 JumpInsnNode jumpInsnNode = match .captures ().get ("label" ).insn ().asJump ();
170- AbstractInsnNode currentInsn = jumpInsnNode .label ;
171168
172- List < AbstractInsnNode > removedInsns = new ArrayList <>();
173- LabelNode firstLabel = null ;
169+ Arrays . stream ( clinitMethod . instructions . toArray ()). filter ( insn -> insn instanceof LabelNode ). map ( insn -> ( LabelNode ) insn ). findFirst (). ifPresent ( firstLabel -> {
170+ AbstractInsnNode currentInsn = jumpInsnNode . label ;
174171
175- for ( AbstractInsnNode insn : clinitMethod . instructions . toArray ()) {
176- if ( insn instanceof LabelNode labelNode ) {
177- firstLabel = labelNode ;
178- break ;
172+ List < AbstractInsnNode > removedInsns = new ArrayList <>();
173+ while ( currentInsn != firstLabel ) {
174+ currentInsn = currentInsn . getPrevious () ;
175+ removedInsns . add ( currentInsn ) ;
179176 }
180- }
181-
182- if (firstLabel == null )
183- return ;
184177
185- while (currentInsn != firstLabel ) {
186- currentInsn = currentInsn .getPrevious ();
187- removedInsns .add (currentInsn );
188- }
178+ removedInsns .forEach (insn -> clinitMethod .instructions .remove (insn ));
179+ });
189180
190- removedInsns .forEach (insn -> clinitMethod .instructions .remove (insn ));
191181 classWrapper .methods ().removeIf (methodNode -> methodNode .desc .equals ("(II)Ljava/lang/String;" ));
192182 }
193183
@@ -205,6 +195,7 @@ private byte[] cloneClassWithClinit(ClassWrapper classWrapper, MethodNode clinit
205195 classNode .methods .add (clinit );
206196
207197 // create a tmp array for getting data
198+ // TODO: Can we find a way to access direcly variable without getter?
208199 classNode .fields .add (new FieldNode (ACC_PUBLIC | ACC_STATIC , "arr" , "[Ljava/lang/String;" , null , null ));
209200
210201 MethodNode getMethodNode = new MethodNode (ACC_PUBLIC | ACC_STATIC , "getArr" , "()[Ljava/lang/String;" , null , new String [0 ]);
@@ -229,7 +220,7 @@ private byte[] cloneClassWithClinit(ClassWrapper classWrapper, MethodNode clinit
229220 }
230221 }
231222
232- classWrapper .findMethod (methodNode -> methodNode . desc . equals ( "(II)Ljava/lang/String;" ) ).ifPresent (method -> {
223+ classWrapper .findMethod (this :: isDecryptMethod ).ifPresent (method -> {
233224 if (!classNode .methods .contains (method ))
234225 classNode .methods .add (method );
235226 });
@@ -238,6 +229,15 @@ private byte[] cloneClassWithClinit(ClassWrapper classWrapper, MethodNode clinit
238229 return cw .toByteArray ();
239230 }
240231
232+ private boolean isDecryptMethod (MethodNode methodNode ) {
233+ if (!methodNode .desc .equals ("(II)Ljava/lang/String;" ))
234+ return false ;
235+
236+ if ((methodNode .access & (ACC_PRIVATE | ACC_STATIC )) == 0 )
237+ return false ;
238+
239+ return Arrays .stream (methodNode .instructions .toArray ()).anyMatch (abstractInsnNode -> abstractInsnNode .getOpcode () == TABLESWITCH );
240+ }
241241
242242 private byte [] modifyByteCode (ClassWrapper classWrapper , byte [] classByte ) {
243243 ClassReader cr = new ClassReader (classByte );
@@ -273,9 +273,11 @@ private byte[] modifyByteCode(ClassWrapper classWrapper, byte[] classByte) {
273273 if (insn instanceof LabelNode )
274274 break ;
275275
276- if (insn .getOpcode () == Opcodes .INVOKESTATIC )
276+ if (insn .getOpcode () == Opcodes .INVOKESTATIC ) {
277277 clinitMethod .instructions .remove (insn );
278- else if (insn instanceof VarInsnNode varInsnNode &&
278+ } else if (insn instanceof TypeInsnNode typeInsnNode && typeInsnNode .getOpcode () == Opcodes .ANEWARRAY && !typeInsnNode .desc .equals ("java/lang/String" )) {
279+ typeInsnNode .desc = "java/lang/String" ;
280+ } else if (insn instanceof VarInsnNode varInsnNode &&
279281 insn .getPrevious () instanceof TypeInsnNode typeInsnNode && typeInsnNode .getOpcode () == Opcodes .ANEWARRAY && typeInsnNode .desc .equals ("java/lang/String" ) &&
280282 insn .getPrevious ().getPrevious () != null && insn .getPrevious ().getPrevious ().isInteger ()
281283 ) {
0 commit comments