--- nfo/perl/scripts/fluscate/bin/fluscate.pl 2004/08/03 00:24:15 1.6 +++ nfo/perl/scripts/fluscate/bin/fluscate.pl 2004/08/03 02:36:05 1.7 @@ -2,8 +2,11 @@ # fluscate - The Flash Obfuscator -# $Id: fluscate.pl,v 1.6 2004/08/03 00:24:15 joko Exp $ +# $Id: fluscate.pl,v 1.7 2004/08/03 02:36:05 joko Exp $ # $Log: fluscate.pl,v $ +# Revision 1.7 2004/08/03 02:36:05 joko +# new features: Random, Undo, Interactive mode +# # Revision 1.6 2004/08/03 00:24:15 joko # restructured code (procedures) # command-line arguments @@ -59,9 +62,11 @@ =head2 Obfuscation See ASO Pro: http://www.genable.com/aso/preview.html - + fluscate implements a subset of these features plus some others. + +=head2 Symbols -=head2 Functions +=head3 Functions fluscate handles two different styles of function declarations: @@ -81,7 +86,24 @@ ls: dup trace - branchIfTrue ls" + branchIfTrue ls + + Needs testing! + +=head2 Random + + Instead of using '-1', '-2', '-3', etc., this option creates randomized numbers + as symbol replacements. + +=head2 Undo + + fluscate now has "undo"-functionality which can revert symbol replacements. + First, use "fluscate -m -s" (memorize+save switches) to store your metadata and + "fluscate -m -l -u" (memorize+load+undo switches) to make things undone. + +=head2 Interactive mode + + Can ask you about each symbol whether to replace it. Use "-i -f file.flm". =head1 Dependencies @@ -96,13 +118,15 @@ Please type "fluscate --help" to get more information about command-line parameters. -=head2 win32 +=head2 Semantic use: + +=head3 win32 #> flasm.exe -d puzzle.swf > puzzle.flm #> cat puzzle.flm | perl fluscate.pl > puzzle_fusc.flm #> flasm.exe -a puzzle_fusc.flm -=head2 *nix +=head3 *nix #> ./flasm -d puzzle.swf > puzzle.flm #> cat puzzle.flm | ./fluscate.pl > puzzle_fusc.flm @@ -114,17 +138,15 @@ =head2 Todo - provide list of flash event handler names to exclude from symbol replacement + - include list of ->keywords from: + http://www.macromedia.com/support/flash/action_scripts/actionscript_dictionary/ =head2 Wishlist - - komplexere verschlüsselung als "-1, -2 ..." z-b nicht in der numerischen reihenfolge sondern nach - zufallsprinip (-21,-3,-89)? (->random) - - evtl. constants nach abfrage ersetzen ? leider sehr aufwendig, bei vielen constants (->ask) - - rausgeben des arrays mit den "neuen" werten um evtl die obfuscation rückgängig zu machen (->undo) - what about other symbols beside "function"s? (e.g. variables) (->mode) - - include list of ->keywords from: - http://www.macromedia.com/support/flash/action_scripts/actionscript_dictionary/ - replace symbols in multiple files (->multifile) + - more symbol-replacement-modes: + normal, random, random-alphanumeric (e.g. ahjit, twobc, plodf), wordlist, etc. =head2 Notes @@ -202,6 +224,7 @@ use Getopt::Long; use Storable; use Data::Dumper; +use Term::ReadKey; my $VERSION = "0.10"; @@ -213,6 +236,7 @@ 'push' => 'push\s\'(.+?)\'', }; my @symbols; +my $symbols_table; my @lines; my $options; @@ -220,7 +244,14 @@ GetOptions( "pollute" => \$options->{pollute}, "help" => \$options->{help}, - "version" => \$options->{version} + "version" => \$options->{version}, + "random" => \$options->{random}, + "memorize" => \$options->{memorize}, + "load" => \$options->{load}, + "save" => \$options->{save}, + "undo" => \$options->{undo}, + "interactive" => \$options->{interactive}, + "file=s" => \$options->{file}, ); } @@ -274,7 +305,6 @@ # ... remember them $symbol = $1; - } elsif (m/$regex->{function_stacked}/) { if ($lines[$counter - 1] =~ m/$regex->{push}/) { $symbol = $1; @@ -291,38 +321,71 @@ } -#print join("\n", @symbols); exit; +sub scramble_symbols { + if ($options->{random}) { + #my $range = $#symbols; + #my $range = 7; + my $range = 10000; + my $rndmem = {}; + foreach (@symbols) { + shuffle: + my $rnd = -int(rand($range) + 1); + goto shuffle if ($rndmem->{$rnd}); + $symbols_table->{$_} = $rnd; + $rndmem->{$rnd}++; + } + } else { + my $symbol_counter = -1; + foreach (@symbols) { + $symbols_table->{$_} = $symbol_counter; + $symbol_counter--; + } + } +} + +sub select_symbols { + print STDERR "Please answer with y/n to select symbols for replacement:", "\n"; + ReadMode 3; + foreach (keys %$symbols_table) { + print STDERR $_, ": "; + getkey: + my $key = ReadKey(0) || ""; + goto getkey if ($key !~ m/[yn]/i); + print STDERR $key, "\n"; + delete $symbols_table->{$_} if ($key =~ m/n/i); + } + ReadMode 0; +} # 2. step through all symbols found and replace them sub obfuscate { # 1st stage: symbol replacement - my $symbol_counter = -1; - foreach my $symbol (@symbols) { + foreach my $symbol (keys %{$symbols_table}) { + my $symbol_new = $symbols_table->{$symbol}; my $line_counter = 0; foreach (@lines) { # function declarations; single quotes might not be there! if (m/$regex->{function}/) { - s/\s'*$symbol'*\s/ '$symbol_counter' /i; + s/\s'*$symbol'*\s/ '$symbol_new' /i; # "constants"-line at begin of each block; single quotes should already be there } elsif (m/$regex->{constants}/) { - s/'$symbol'/'$symbol_counter'/i; + s/'$symbol'/'$symbol_new'/i; # function calls; replace inside predecessor line of calling-lines } elsif (m/$regex->{call}/) { - $lines[$line_counter - 1] =~ s/'$symbol'/'$symbol_counter'/i; + $lines[$line_counter - 1] =~ s/'$symbol'/'$symbol_new'/i; # function declarations; name of function is pushed on stack one line before! } elsif (m/$regex->{function_stacked}/) { - $lines[$line_counter - 1] =~ s/'$symbol'/'$symbol_counter'/i; + $lines[$line_counter - 1] =~ s/'$symbol'/'$symbol_new'/i; } $line_counter++; } - $symbol_counter--; } # 2nd stage: pollute & Co. @@ -351,20 +414,67 @@ [-p|--pollute] Pollute code by inserting snippet making life harder for disassemblers [-h|--help] This text [-v|--version] Show version information only + [-m|--memorize] Enable "memorize"-mode: can load and save symbol replacement metadata + [-l|--load] Load symbol replacement table from file + [-s|--save] Save symbol replacement table to file + [-u|--undo] Replaces obfuscated symbols with original ones; valid only with "memorize" and "load" + [-f|--file] Specify path to file for interactive mode USAGE }; } sub main { + + # basic option handling read_options(); #print Dumper($options); if ($options->{help} || $options->{version}) { usage(); exit; } - # read flasm code from STDIN - @lines = ; - scan_symbols(); + if ($options->{interactive} and not -z STDIN) { + print "Can not switch to interactive mode while reading from STDIN, please specify file with '-f'.", "\n"; + exit; + } + + if ($options->{file}) { + # read flasm code from file + if (!open(FH, $options->{file})) { + print "Could not open file '$options->{file}'!", "\n"; + exit; + } + @lines = ; + close(FH); + } else { + # read flasm code from STDIN + @lines = ; + close(STDIN); + } + + # symbol stuff (build/load/save) + my $file = "fluscate.syms"; + if ($options->{memorize} and $options->{load}) { + # load + $symbols_table = retrieve($file); + if ($options->{undo}) { + %$symbols_table = reverse %$symbols_table; + } + } else { + # build + scan_symbols(); + scramble_symbols(); + # save + if ($options->{memorize} and $options->{save}) { + store($symbols_table, $file); + } + } + + if ($options->{interactive}) { + select_symbols(); + } + #print Dumper($symbols_table); exit; + + # replacements obfuscate(); # write all stuff to STDOUT print STDOUT @lines;