@@ -50,7 +50,7 @@ public void b64DecodableNotEncodedTest() throws Exception {
5050
5151 @ Test
5252 public void fieldB64Test () throws Exception {
53- // Base64 string assigned to a static field in <clinit>
53+ // Base64 string in a const-string in a regular method body (instance field via iput-object)
5454 String code = decompileSmali ("b64/field_b64.smali" );
5555 System .out .println (code );
5656 assertThat (code ).contains ("b64: Hello, World!" );
@@ -205,14 +205,6 @@ public void multilineFieldB64Test() throws Exception {
205205 assertThat (code ).contains ("b64(mime): Hello, World!" );
206206 }
207207
208- @ Test
209- public void pemB64FieldTest () throws Exception {
210- // PEM Base64 String CONSTANT_VALUE + byte[] field via Base64.decode — both should get b64(mime): comment
211- String code = decompileSmali ("b64/pem_b64_field.smali" );
212- System .out .println (code );
213- assertThat (code ).contains ("b64(mime):" );
214- }
215-
216208 @ Test
217209 public void antifridas8kTest () throws Exception {
218210 // Real-world anti-frida/xposed detection class (s8.k) with filled-new-array/range.
@@ -283,17 +275,6 @@ public void camelCaseNotFlaggedTest() throws Exception {
283275 assertThat (code ).doesNotContain ("b64:" );
284276 }
285277
286- @ Test
287- public void camelCaseSkipDisabledTest () throws Exception {
288- // with skipCamelCase=false, "getContext" is no longer suppressed by the camelCase filter;
289- // other filters (printable ratio, alnum ratio) will still apply
290- String code = decompileSmali ("b64/camelcase_b64.smali" ,
291- Map .of (opt ("skipCamelCase" ), "false" ));
292- System .out .println (code );
293- // "getContext" decodes to non-UTF-8 bytes so no comment expected even without the filter
294- assertThat (code ).doesNotContain ("b64:" );
295- }
296-
297278 @ Test
298279 public void allCapsNotFlaggedTest () throws Exception {
299280 // "CURSOR" is all-uppercase and decodes to "\tDR9" — suppressed by skipSnakeCase (default true)
@@ -302,16 +283,6 @@ public void allCapsNotFlaggedTest() throws Exception {
302283 assertThat (code ).doesNotContain ("b64:" );
303284 }
304285
305- @ Test
306- public void allCapsSkipDisabledTest () throws Exception {
307- // With skipSnakeCase=false, "CURSOR" is no longer suppressed by the pattern filter;
308- // it decodes to "\tDR9" (75% printable), which fails the 90% default printable threshold
309- String code = decompileSmali ("b64/allcaps_b64.smali" ,
310- Map .of (opt ("skipSnakeCase" ), "false" ));
311- System .out .println (code );
312- assertThat (code ).doesNotContain ("b64:" );
313- }
314-
315286 @ Test
316287 public void allLowerNotFlaggedTest () throws Exception {
317288 // "closed" is all-lowercase and decodes to "rZ,y" — suppressed by skipSnakeCase (default true)
@@ -341,16 +312,6 @@ public void dictionaryWordNotFlaggedTest() throws Exception {
341312 assertThat (code ).doesNotContain ("b64:" );
342313 }
343314
344- @ Test
345- public void dictionarySkipDisabledTest () throws Exception {
346- // Disabling skipDictionaryWords must not crash; "callback" is still rejected by the
347- // UTF-8 decode step so no b64: comment is expected
348- String code = decompileSmali ("b64/dict_word_b64.smali" ,
349- Map .of (opt ("skipDictionaryWords" ), "false" ));
350- System .out .println (code );
351- assertThat (code ).doesNotContain ("b64:" );
352- }
353-
354315 @ Test
355316 public void pascalCaseNotFlaggedTest () throws Exception {
356317 // "FileUtil" matches PascalCase — suppressed by skipPascalCase (default true)
@@ -360,13 +321,16 @@ public void pascalCaseNotFlaggedTest() throws Exception {
360321 }
361322
362323 @ Test
363- public void pascalCaseSkipDisabledTest () throws Exception {
364- // With skipPascalCase=false, "FileUtil" is no longer suppressed by the pattern filter;
365- // it decodes to bytes that are ~60% printable, failing the 90% default threshold
366- String code = decompileSmali ("b64/pascalcase_b64.smali" ,
324+ public void pascalCaseSkipDisabledDecodesTest () throws Exception {
325+ // "SiteWith" is PascalCase and decodes to "J+^Z+a" (100% printable, 50% alnum).
326+ // With the filter on (default) it is suppressed; with it off it should be annotated.
327+ String codeDefault = decompileSmali ("b64/pascalcase_decodable_b64.smali" );
328+ assertThat (codeDefault ).doesNotContain ("b64:" );
329+
330+ String codeDisabled = decompileSmali ("b64/pascalcase_decodable_b64.smali" ,
367331 Map .of (opt ("skipPascalCase" ), "false" ));
368- System .out .println (code );
369- assertThat (code ). doesNotContain ("b64:" );
332+ System .out .println (codeDisabled );
333+ assertThat (codeDisabled ). contains ("b64: J+^Z+a " );
370334 }
371335
372336 @ Test
@@ -419,4 +383,46 @@ public void b64InTryCatchTest() throws Exception {
419383 assertThat (code ).contains ("b64: getPackageInfo" );
420384 }
421385
386+ @ Test
387+ public void b64ConditionalTryCatchTest () throws Exception {
388+ // Real-world pattern: cache==null branch initialises via two Base64.decode reflection
389+ // strings; an sdk>=33 conditional selects a delegate path; else branch uses a third
390+ // Base64.decode string. All three must be annotated despite the branching structure.
391+ String code = decompileSmali ("b64/b64_conditional_trycatch.smali" );
392+ System .out .println (code );
393+ assertThat (code ).contains ("b64[0]: android.app.ActivityThread" );
394+ assertThat (code ).contains ("b64[1]: getPackageManager" );
395+ assertThat (code ).contains ("b64: getPackageInfo" );
396+ }
397+
398+ @ Test
399+ public void b64DecodePassDisabledTest () throws Exception {
400+ // enableB64DecodePass=false must suppress all b64: comments from the main detection pass
401+ String code = decompileSmali ("b64/hello.smali" ,
402+ Map .of (opt ("enableB64DecodePass" ), "false" ));
403+ System .out .println (code );
404+ assertThat (code ).doesNotContain ("b64:" );
405+ }
406+
407+ @ Test
408+ public void b64DecodePassDisabledAlsoDisablesFieldInitPassTest () throws Exception {
409+ // enableB64DecodePass=false gates all three passes, including B64FieldInitPass.
410+ // A static field initialised with a Base64 string must not be annotated.
411+ String code = decompileSmali ("b64/static_field_b64.smali" ,
412+ Map .of (opt ("enableB64DecodePass" ), "false" ));
413+ System .out .println (code );
414+ assertThat (code ).doesNotContain ("b64:" );
415+ }
416+
417+ @ Test
418+ public void filledArrayNoAnchorNotAnnotatedTest () throws Exception {
419+ // String[] where every element ("aGVs") decodes to valid Base64+UTF-8 ("hel", 3 chars)
420+ // but fails full heuristic detection (decoded length 3 < default minDecodedLength=4).
421+ // hasAnchor=false so neither b64: nor b64[N]: comments are emitted.
422+ String code = decompileSmali ("b64/filled_array_no_anchor.smali" );
423+ System .out .println (code );
424+ assertThat (code ).doesNotContain ("b64:" );
425+ assertThat (code ).doesNotContain ("b64[" );
426+ }
427+
422428}
0 commit comments