11package jadx .plugins .stringdecoder ;
22
3+ import java .util .Locale ;
4+
35import jadx .api .plugins .input .data .annotations .EncodedType ;
46import jadx .api .plugins .input .data .annotations .EncodedValue ;
57import jadx .api .plugins .input .data .attributes .JadxAttrType ;
810import jadx .api .plugins .pass .types .JadxDecompilePass ;
911import jadx .core .dex .attributes .AType ;
1012import jadx .core .dex .attributes .FieldInitInsnAttr ;
13+ import jadx .core .dex .info .MethodInfo ;
1114import jadx .core .dex .instructions .ConstStringNode ;
15+ import jadx .core .dex .instructions .InvokeNode ;
16+ import jadx .core .dex .instructions .args .InsnArg ;
17+ import jadx .core .dex .instructions .args .InsnWrapArg ;
18+ import jadx .core .dex .instructions .args .RegisterArg ;
1219import jadx .core .dex .nodes .ClassNode ;
1320import jadx .core .dex .nodes .FieldNode ;
1421import jadx .core .dex .nodes .InsnNode ;
@@ -49,7 +56,9 @@ private void processField(FieldNode field) {
4956 if (initAttr != null ) {
5057 InsnNode initInsn = initAttr .getInsn ();
5158 if (initInsn instanceof ConstStringNode ) {
52- annotateField (field , ((ConstStringNode ) initInsn ).getString ());
59+ annotateField (field , ((ConstStringNode ) initInsn ).getString (), false );
60+ } else {
61+ findAndAnnotateInArgTree (field , initInsn , 0 );
5362 }
5463 return ;
5564 }
@@ -59,16 +68,75 @@ private void processField(FieldNode field) {
5968 if (constVal != null && constVal .getType () == EncodedType .ENCODED_STRING ) {
6069 Object val = constVal .getValue ();
6170 if (val instanceof String ) {
62- annotateField (field , (String ) val );
71+ annotateField (field , (String ) val , false );
72+ }
73+ }
74+ }
75+
76+ /**
77+ * Recursively walks the instruction arg tree looking for a ConstStringNode.
78+ * When the ConstStringNode is a direct arg of a Base64.decode-like call, decodes
79+ * unconditionally (the call itself is strong evidence of intent).
80+ * Otherwise, applies normal false-positive checks via {@link B64Detector#detect}.
81+ */
82+ private boolean findAndAnnotateInArgTree (FieldNode field , InsnNode insn , int depth ) {
83+ if (insn == null || depth > 8 ) {
84+ return false ;
85+ }
86+ boolean isBase64Call = isBase64DecodeCall (insn );
87+ for (int i = 0 ; i < insn .getArgsCount (); i ++) {
88+ InsnArg arg = insn .getArg (i );
89+ InsnNode argInsn = resolveArgInsn (arg );
90+ if (argInsn == null ) {
91+ continue ;
6392 }
93+ if (argInsn instanceof ConstStringNode ) {
94+ String str = ((ConstStringNode ) argInsn ).getString ();
95+ if (annotateField (field , str , isBase64Call )) {
96+ return true ;
97+ }
98+ } else if (findAndAnnotateInArgTree (field , argInsn , depth + 1 )) {
99+ return true ;
100+ }
101+ }
102+ return false ;
103+ }
104+
105+ private static InsnNode resolveArgInsn (InsnArg arg ) {
106+ if (arg instanceof InsnWrapArg ) {
107+ return ((InsnWrapArg ) arg ).getWrapInsn ();
108+ }
109+ if (arg instanceof RegisterArg ) {
110+ return ((RegisterArg ) arg ).getAssignInsn ();
64111 }
112+ return null ;
65113 }
66114
67- private void annotateField (FieldNode field , String str ) {
68- String decoded = B64Detector .detect (str , options );
115+ /** Returns true if {@code insn} looks like a call to a Base64 decode method. */
116+ static boolean isBase64DecodeCall (InsnNode insn ) {
117+ if (!(insn instanceof InvokeNode )) {
118+ return false ;
119+ }
120+ MethodInfo mth = ((InvokeNode ) insn ).getCallMth ();
121+ String clsName = mth .getDeclClass ().getFullName ().toLowerCase (Locale .ROOT );
122+ String mthName = mth .getName ().toLowerCase (Locale .ROOT );
123+ return clsName .contains ("base64" ) && mthName .contains ("decode" );
124+ }
125+
126+ /**
127+ * Annotates the field if the string is valid Base64.
128+ * When {@code forced} is true, skips false-positive heuristics.
129+ * Returns true if a comment was added.
130+ */
131+ private boolean annotateField (FieldNode field , String str , boolean forced ) {
132+ String decoded = forced
133+ ? B64Detector .decodeForced (str , options .getMaxCommentLength ())
134+ : B64Detector .detect (str , options );
69135 if (decoded != null ) {
70136 field .addCodeComment ("b64: " + decoded );
137+ return true ;
71138 }
139+ return false ;
72140 }
73141
74142 @ Override
0 commit comments