From 603a7dce4909d98e9499891200d925b833456e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Wed, 2 Jul 2025 22:59:16 +0200 Subject: [PATCH] Added: Allow obfuscated DefineEditText variable identifiers --- CHANGELOG.md | 1 + libsrc/ffdec_lib/lexers/text.flex | 53 +++- .../flash/tags/DefineEditTextTag.java | 6 +- .../decompiler/flash/tags/text/TextLexer.java | 290 ++++++++++++------ 4 files changed, 241 insertions(+), 109 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d4feb176..eb5e1e25f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file. - AS2 detection of uninitialized class fields is cancellable, faster (parallel) and shows its progress - AS2 - show deobfuscated class/package names in the class tree +- Allow obfuscated DefineEditText variable identifiers ### Fixed - [#2474] Gotos incorrectly decompiled diff --git a/libsrc/ffdec_lib/lexers/text.flex b/libsrc/ffdec_lib/lexers/text.flex index f3ebcbd6a..ad655f36f 100644 --- a/libsrc/ffdec_lib/lexers/text.flex +++ b/libsrc/ffdec_lib/lexers/text.flex @@ -31,10 +31,12 @@ package com.jpexs.decompiler.flash.tags.text; %{ - boolean finish = false; - boolean parameter = false; + private boolean finish = false; + private boolean parameter = false; - StringBuilder string = null; + private StringBuilder string = null; + + private int repeatNum = 1; /** * Create an empty lexer, yyrset will be called later to reset and assign @@ -55,13 +57,16 @@ package com.jpexs.decompiler.flash.tags.text; %} Parameter = [a-z_][a-z0-9_]* -Value = [^ \r\n\]\"]+ +Value = [^ \r\n\]\"\u00A7]+ Divider = [ \r\n]+ HexDigit = [0-9a-fA-F] StringCharacter = [^\r\n\"\\] +OIdentifierCharacter = [^\r\n\u00A7\\] +DecIntegerLiteral = (0 | [1-9][0-9]*) [ui]? +LineTerminator = \r|\n|\r\n -%state PARAMETER,VALUE,STRING +%state PARAMETER,VALUE,OIDENTIFIER,STRING %% @@ -96,7 +101,7 @@ StringCharacter = [^\r\n\"\\] } { - {Divider} {} + {Divider} {} {Parameter} { yybegin(VALUE); return new ParsedSymbol(SymbolType.PARAMETER_IDENTIFIER, yytext()); @@ -115,6 +120,10 @@ StringCharacter = [^\r\n\"\\] yybegin(STRING); } + "\u00A7" { + string = new StringBuilder(); + yybegin(OIDENTIFIER); + } {Parameter} { return new ParsedSymbol(SymbolType.PARAMETER_IDENTIFIER, yytext()); } @@ -127,6 +136,38 @@ StringCharacter = [^\r\n\"\\] } } + { + "\u00A7" { + yybegin(VALUE); + repeatNum = 1; + // length also includes the trailing quote + String ret = string.toString(); + string = null; + return new ParsedSymbol(SymbolType.PARAMETER_VALUE, ret); + } + + {OIdentifierCharacter} { for(int r=0;r { \" { yybegin(VALUE); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java index 3d851792d..a577dbe14 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java @@ -16,6 +16,7 @@ */ package com.jpexs.decompiler.flash.tags; +import com.jpexs.decompiler.flash.IdentifiersDeobfuscation; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.SWFOutputStream; @@ -55,10 +56,12 @@ import com.jpexs.decompiler.flash.types.RGB; import com.jpexs.decompiler.flash.types.RGBA; import com.jpexs.decompiler.flash.types.TEXTRECORD; import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.DottedIdentifier; import com.jpexs.decompiler.flash.types.annotations.EnumValue; import com.jpexs.decompiler.flash.types.annotations.Multiline; import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.decompiler.flash.types.annotations.SWFVersion; +import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.helpers.ByteArrayRange; import com.jpexs.helpers.SerializableImage; import com.jpexs.helpers.utf8.Utf8Helper; @@ -175,6 +178,7 @@ public class DefineEditTextTag extends TextTag { @Conditional("hasLayout") public int leading; + @DottedIdentifier public String variableName; @Conditional("hasText") @@ -656,7 +660,7 @@ public class DefineEditTextTag extends TextTag { writer.append("leading ").append(leading).newLine(); } if (!variableName.isEmpty()) { - writer.append("variablename ").append(variableName).newLine(); + writer.append("variablename ").append(DottedChain.parseNoSuffix(variableName).toPrintableString(false)).newLine(); } writer.append("]"); if (hasText) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/text/TextLexer.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/text/TextLexer.java index 7af532509..c8b617db0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/text/TextLexer.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/text/TextLexer.java @@ -1,5 +1,7 @@ +/* The following code was generated by JFlex 1.6.0 */ + /* - * Copyright (C) 2010-2025 JPEXS, All rights reserved. + * Copyright (C) 2010-2016 JPEXS, All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -35,7 +37,8 @@ public final class TextLexer { public static final int YYINITIAL = 0; public static final int PARAMETER = 2; public static final int VALUE = 4; - public static final int STRING = 6; + public static final int OIDENTIFIER = 6; + public static final int STRING = 8; /** * ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l @@ -44,18 +47,18 @@ public final class TextLexer { * l is of the form l = 2*k, k a non negative integer */ private static final int ZZ_LEXSTATE[] = { - 0, 0, 1, 1, 2, 2, 3, 3 + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4 }; /** * Translates characters to character classes */ private static final String ZZ_CMAP_PACKED = - "\12\0\1\11\1\22\1\22\1\11\22\0\1\4\1\0\1\10\4\0"+ - "\1\20\10\0\12\2\7\0\6\5\24\0\1\12\1\7\1\3\1\0"+ - "\1\1\1\0\1\6\1\13\3\6\1\16\7\1\1\15\3\1\1\17"+ - "\1\1\1\14\1\23\2\1\1\21\2\1\12\0\1\22\u1fa2\0\1\22"+ - "\1\22\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\udfe6\0"; + "\12\0\1\11\1\26\1\26\1\15\22\0\1\4\1\0\1\10\4\0"+ + "\1\24\10\0\1\13\11\2\7\0\6\5\24\0\1\16\1\7\1\3"+ + "\1\0\1\1\1\0\1\6\1\17\3\6\1\22\2\1\1\14\4\1"+ + "\1\21\3\1\1\23\1\1\1\20\1\27\2\1\1\25\2\1\1\30"+ + "\1\0\1\31\7\0\1\26\41\0\1\12\u1f80\0\1\26\1\26\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\uffff\0\udfe6\0"; /** * Translates characters to character classes @@ -68,14 +71,16 @@ public final class TextLexer { private static final int [] ZZ_ACTION = zzUnpackAction(); private static final String ZZ_ACTION_PACKED_0 = - "\4\0\2\1\1\2\1\3\1\4\1\5\1\6\1\7"+ - "\1\10\1\11\1\12\1\2\1\13\1\14\1\15\1\16"+ - "\1\17\1\20\1\21\1\22\1\23\1\24\1\25\1\26"+ - "\1\14\1\27\1\30\1\31\1\32\1\33\1\34\1\35"+ - "\1\36\1\37\2\27\2\0\1\40\1\0"; + "\5\0\2\1\1\2\1\3\1\4\1\5\1\6\1\7"+ + "\1\10\1\11\1\12\1\13\1\2\1\14\1\15\1\14"+ + "\1\16\1\2\1\17\1\20\1\21\1\22\1\23\1\24"+ + "\1\25\1\26\1\27\1\30\1\31\1\32\1\20\1\33"+ + "\1\34\1\35\1\36\1\37\1\40\1\41\3\20\1\42"+ + "\1\43\1\44\1\45\1\46\1\47\1\50\1\51\1\52"+ + "\2\42\6\0\1\53\1\54\2\0\1\55\1\0"; private static int [] zzUnpackAction() { - int [] result = new int[44]; + int [] result = new int[69]; int offset = 0; offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); return result; @@ -100,15 +105,18 @@ public final class TextLexer { private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); private static final String ZZ_ROWMAP_PACKED_0 = - "\0\0\0\24\0\50\0\74\0\120\0\144\0\120\0\120"+ - "\0\170\0\120\0\214\0\240\0\264\0\120\0\310\0\334"+ - "\0\120\0\120\0\120\0\120\0\120\0\120\0\120\0\120"+ - "\0\120\0\120\0\120\0\120\0\360\0\120\0\120\0\120"+ - "\0\120\0\120\0\120\0\120\0\120\0\120\0\360\0\u0104"+ - "\0\u0118\0\u012c\0\120\0\360"; + "\0\0\0\32\0\64\0\116\0\150\0\202\0\234\0\202"+ + "\0\202\0\266\0\202\0\320\0\352\0\u0104\0\202\0\202"+ + "\0\202\0\u011e\0\202\0\202\0\u0138\0\u0152\0\u016c\0\202"+ + "\0\202\0\202\0\202\0\202\0\202\0\202\0\202\0\202"+ + "\0\202\0\202\0\202\0\u0186\0\202\0\202\0\202\0\202"+ + "\0\202\0\202\0\202\0\u01a0\0\u01ba\0\u01d4\0\202\0\202"+ + "\0\202\0\202\0\202\0\202\0\202\0\202\0\202\0\u0186"+ + "\0\u01ee\0\u0208\0\u0222\0\u023c\0\u0256\0\u0270\0\u028a\0\202"+ + "\0\202\0\u01a0\0\u02a4\0\202\0\u0186"; private static int [] zzUnpackRowMap() { - int [] result = new int[44]; + int [] result = new int[69]; int offset = 0; offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); return result; @@ -131,27 +139,43 @@ public final class TextLexer { private static final int [] ZZ_TRANS = zzUnpackTrans(); private static final String ZZ_TRANS_PACKED_0 = - "\7\5\1\6\1\5\1\7\1\10\7\5\1\7\1\5"+ - "\1\7\1\11\1\7\1\12\1\13\1\7\1\11\2\7"+ - "\1\13\1\7\5\11\1\7\1\11\1\7\1\11\1\14"+ - "\1\15\1\14\1\12\1\13\1\14\1\15\1\14\1\16"+ - "\1\13\1\14\5\15\1\14\1\15\1\14\1\15\7\17"+ - "\1\20\1\21\1\7\12\17\24\0\3\22\1\23\3\22"+ - "\1\24\1\25\1\0\1\26\1\27\1\30\1\31\1\32"+ - "\1\33\1\34\1\35\1\0\1\22\1\0\2\11\3\0"+ - "\1\11\4\0\5\11\1\0\1\11\1\0\1\11\4\0"+ - "\1\13\4\0\1\13\12\0\3\14\2\0\3\14\2\0"+ - "\13\14\2\15\2\0\1\14\1\15\1\14\2\0\1\14"+ - "\5\15\1\14\1\15\1\14\1\15\7\17\3\0\12\17"+ - "\7\36\1\37\1\40\1\0\1\36\1\41\1\42\1\43"+ - "\1\44\1\45\1\46\1\47\1\0\1\50\2\0\1\51"+ - "\2\0\2\51\4\0\1\51\2\0\1\51\7\0\1\52"+ - "\2\0\2\52\4\0\1\52\2\0\1\52\7\0\1\53"+ - "\2\0\2\53\4\0\1\53\2\0\1\53\7\0\1\54"+ - "\2\0\2\54\4\0\1\54\2\0\1\54\5\0"; + "\7\6\1\7\1\6\1\10\3\6\1\10\1\11\7\6"+ + "\1\10\3\6\1\10\1\12\1\10\1\13\1\14\1\10"+ + "\1\12\2\10\1\14\2\10\1\12\1\14\1\10\5\12"+ + "\1\10\1\12\1\10\1\12\2\10\1\15\1\16\1\15"+ + "\1\13\1\14\1\15\1\16\1\15\1\17\1\14\1\20"+ + "\1\15\1\16\1\14\1\15\5\16\1\15\1\16\1\15"+ + "\1\16\2\15\7\21\1\22\1\21\1\23\1\24\2\21"+ + "\1\25\14\21\7\26\1\27\1\30\1\10\3\26\1\10"+ + "\14\26\32\0\3\31\1\32\3\31\1\33\1\34\1\0"+ + "\3\31\1\0\1\35\1\36\1\37\1\40\1\41\1\42"+ + "\1\43\1\44\1\0\3\31\1\0\2\12\3\0\1\12"+ + "\4\0\2\12\2\0\5\12\1\0\1\12\1\0\1\12"+ + "\6\0\1\14\4\0\1\14\3\0\1\14\14\0\3\15"+ + "\2\0\3\15\3\0\2\15\1\0\15\15\2\16\2\0"+ + "\1\15\1\16\1\15\3\0\2\16\1\0\1\15\5\16"+ + "\1\15\1\16\1\15\1\16\2\15\7\31\1\45\1\31"+ + "\1\0\1\46\2\31\1\0\1\31\1\47\1\50\1\51"+ + "\1\52\1\53\1\31\1\54\1\0\1\55\1\56\1\31"+ + "\11\0\1\23\20\0\7\26\3\0\3\26\1\0\14\26"+ + "\7\57\1\60\1\61\1\0\3\57\1\0\1\57\1\62"+ + "\1\63\1\64\1\65\1\66\1\67\1\70\1\0\1\71"+ + "\2\57\2\0\1\72\2\0\2\72\4\0\1\72\3\0"+ + "\1\72\2\0\1\72\11\0\1\73\2\0\2\73\4\0"+ + "\1\73\3\0\1\73\2\0\1\73\11\0\1\74\2\0"+ + "\2\74\4\0\1\74\3\0\1\74\2\0\1\74\11\0"+ + "\1\75\10\0\1\76\20\0\1\77\2\0\2\77\4\0"+ + "\1\77\3\0\1\77\2\0\1\77\11\0\1\100\2\0"+ + "\2\100\4\0\1\100\3\0\1\100\2\0\1\100\11\0"+ + "\1\101\2\0\2\101\4\0\1\101\3\0\1\101\2\0"+ + "\1\101\11\0\1\102\2\0\2\102\4\0\1\102\3\0"+ + "\1\102\2\0\1\102\11\0\1\75\10\0\1\75\1\103"+ + "\12\0\1\103\1\0\1\104\14\0\1\103\12\0\1\103"+ + "\1\0\1\104\2\0\1\105\2\0\2\105\4\0\1\105"+ + "\3\0\1\105\2\0\1\105\40\0\1\104"; private static int [] zzUnpackTrans() { - int [] result = new int[320]; + int [] result = new int[702]; int offset = 0; offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); return result; @@ -189,11 +213,12 @@ public final class TextLexer { private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); private static final String ZZ_ATTRIBUTE_PACKED_0 = - "\4\0\1\11\1\1\2\11\1\1\1\11\3\1\1\11"+ - "\2\1\14\11\1\1\11\11\2\1\2\0\1\11\1\0"; + "\5\0\1\11\1\1\2\11\1\1\1\11\3\1\3\11"+ + "\1\1\2\11\3\1\14\11\1\1\7\11\3\1\11\11"+ + "\2\1\6\0\2\11\2\0\1\11\1\0"; private static int [] zzUnpackAttribute() { - int [] result = new int[44]; + int [] result = new int[69]; int offset = 0; offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); return result; @@ -270,10 +295,12 @@ public final class TextLexer { /* user code: */ - boolean finish = false; - boolean parameter = false; + private boolean finish = false; + private boolean parameter = false; - StringBuilder string = null; + private StringBuilder string = null; + + private int repeatNum = 1; /** * Create an empty lexer, yyrset will be called later to reset and assign @@ -313,7 +340,7 @@ public final class TextLexer { char [] map = new char[0x110000]; int i = 0; /* index in packed string */ int j = 0; /* index in unpacked array */ - while (i < 116) { + while (i < 132) { int count = packed.charAt(i++); char value = packed.charAt(i++); do map[j++] = value; while (--count > 0); @@ -662,11 +689,11 @@ public final class TextLexer { case 1: { if (string == null) string = new StringBuilder(); string.append(yytext()); } - case 33: break; + case 46: break; case 2: { if (!parameter) { if (string == null) string = new StringBuilder(); string.append(yytext()); } } - case 34: break; + case 47: break; case 3: { parameter = true; yybegin(PARAMETER); @@ -676,131 +703,190 @@ public final class TextLexer { return new ParsedSymbol(SymbolType.TEXT, ret); } } - case 35: break; + case 48: break; case 4: { yybegin(VALUE); return new ParsedSymbol(SymbolType.PARAMETER_IDENTIFIER, yytext()); } - case 36: break; + case 49: break; case 5: { yybegin(YYINITIAL); parameter = false; } - case 37: break; + case 50: break; case 6: { } - case 38: break; + case 51: break; case 7: { return new ParsedSymbol(SymbolType.PARAMETER_VALUE, yytext()); } - case 39: break; + case 52: break; case 8: { return new ParsedSymbol(SymbolType.PARAMETER_IDENTIFIER, yytext()); } - case 40: break; + case 53: break; case 9: { string = new StringBuilder(); yybegin(STRING); } - case 41: break; + case 54: break; case 10: + { string = new StringBuilder(); + yybegin(OIDENTIFIER); + } + case 55: break; + case 11: + { for(int r=0;r