--- nfo/perl/scripts/fluscate/bin/fluscate.pl 2004/07/26 13:51:54 1.4 +++ nfo/perl/scripts/fluscate/bin/fluscate.pl 2004/08/03 02:36:05 1.7 @@ -1,9 +1,22 @@ #!/usr/bin/perl -# fluscate.pl 0.03 - The Flash Obfuscator +# fluscate - The Flash Obfuscator -# $Id: fluscate.pl,v 1.4 2004/07/26 13:51:54 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 +# new feature: pollute +# +# Revision 1.5 2004/07/26 16:11:58 joko +# updated pod +# included more complete list of flash event-handlers +# fixed substitution regex #1: now using spaces around function names +# # Revision 1.4 2004/07/26 13:51:54 joko # updated pod # @@ -19,8 +32,10 @@ =pod + fluscate - The Flash Obfuscator + This software is Copyright (C) 2004 Andreas Motl - Ideas and future AppleScript integration by Holger Marseille. + Ideas and MacOS X Application by Holger Marseille This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -47,19 +62,49 @@ =head2 Obfuscation See ASO Pro: http://www.genable.com/aso/preview.html - + fluscate implements a subset of these features plus some others. -=head2 Functions +=head2 Symbols + +=head3 Functions fluscate handles two different styles of function declarations: - 1. "Normal" ones + 1. "Normal" ones, e.g. function mp3Player ('arg1', 'arg2') - 2. There may be "stacked" function declarations + 2. There may be "stacked" function declarations, e.g. push 'mp3Player' function () +=head2 Pollute + + Some flash-disassemblers might croak when inserting the following code + after a/each "constants"-declaration: + + push 0 + ls: + dup + trace + 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 @@ -69,13 +114,19 @@ =head1 Usage -=head2 win32 +=head2 General + + Please type "fluscate --help" to get more information about command-line parameters. + +=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 @@ -87,20 +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) - - " push 0 - ls: - dup - trace - branchIfTrue ls" - ... after each "constants" declaration (->pollute) - what about other symbols beside "function"s? (e.g. variables) (->mode) + - replace symbols in multiple files (->multifile) + - more symbol-replacement-modes: + normal, random, random-alphanumeric (e.g. ahjit, twobc, plodf), wordlist, etc. =head2 Notes @@ -149,13 +195,25 @@ Password Busting / SWF Protections: http://www.searchlores.org/cinix_fla.htm =head2 Off-Topic - + +=head3 XML + XPath for Actionscript and other stuff: http://www.xfactorstudio.com/Actionscript/ + XMLRPC Flash Libraries for ActionScript 2.0: http://xmlrpcflash.sourceforge.net/ + +=head3 Marshalling / AMF (Flash Remoting protocol) + + AMFPHP - Flash Remoting for PHP: http://www.amfphp.org/ + AMF::Perl - Flash Remoting in Perl and Python: http://simonf.com/amfperl/ SerializerClass: http://sourceforge.net/projects/serializerclass/ - AMF::Perl - Flash Remoting in Perl and Python - using Flash Remoting protocol (AMF): - http://simonf.com/amfperl/ + +=head3 Misc + PEAR::SWF - Read and write SWF head tag: http://www.sephiroth.it/test/php/SWF/ - AMFPHP - Flash Remoting for PHP: http://www.amfphp.org/ + Convert videos to flv: + http://ffmpeg.sourceforge.net/ + http://www.videohelp.com/tools?tool=263 + Flash-CMS: http://www.lachoseinteractive.net/fr/produits/alahup/ =cut @@ -163,6 +221,13 @@ use strict; use warnings; +use Getopt::Long; +use Storable; +use Data::Dumper; +use Term::ReadKey; + +my $VERSION = "0.10"; + my $regex = { 'function' => 'function(?:2|)\s(.+?)\s\(.*?\)', 'constants' => 'constants', @@ -170,69 +235,252 @@ 'function_stacked' => 'function(?:2|)\s\s\(.*?\)', 'push' => 'push\s\'(.+?)\'', }; -my @symbols_events = qw( onPress onReleaseOutside onRelease onMouseDown onEnterFrame ); my @symbols; +my $symbols_table; +my @lines; +my $options; + +sub read_options { + GetOptions( + "pollute" => \$options->{pollute}, + "help" => \$options->{help}, + "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}, + ); +} -# 1. read flasm code from STDIN -my @lines = ; - -my $counter = 0; -foreach (@lines) { - - # trim newlines - #chomp; - my $symbol; - - # check for all "function" / "function2" symbols and ... - if (m/$regex->{function}/) { - # ... remember them - $symbol = $1; +sub scan_symbols { + my @symbols_events = qw( + onDragOut + onDragOver + onKeyUp + onKeyDown + onKillFocus + onPress + onRelease + onReleaseOutside + onRollOut + onRollOver + onSetFocus + onActivity + onStatus + onSelect + onData + onLoad + allowDomain + allowInsecureDomain + onMouseDown + onMouseMove + onMouseUp + onMouseWheel + onEnterFrame + onUnload + onLoadComplete + onLoadError + onLoadInit + onLoadProgress + onLoadStart + onID3 + onSoundComplete + onResize + onChanged + onScroller + ); - - } elsif (m/$regex->{function_stacked}/) { - if ($lines[$counter - 1] =~ m/$regex->{push}/) { + my $counter = 0; + foreach (@lines) { + + # trim newlines + #chomp; + my $symbol; + + # check for all "function" / "function2" symbols and ... + if (m/$regex->{function}/) { + # ... remember them $symbol = $1; + + } elsif (m/$regex->{function_stacked}/) { + if ($lines[$counter - 1] =~ m/$regex->{push}/) { + $symbol = $1; + } } + + if ($symbol and not grep(/$symbol/, @symbols_events)) { + push @symbols, $symbol; + } + + $counter++; + } - if ($symbol and not grep(/$symbol/, @symbols_events)) { - push @symbols, $symbol; +} + +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--; + } } - - $counter++; - } -#print join("\n", @symbols); exit; +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 -my $symbol_counter = -1; -foreach my $symbol (@symbols) { - my $line_counter = 0; - foreach (@lines) { - - # function declarations; single quotes might not be there! - if (m/$regex->{function}/) { - s/'*$symbol'*/'$symbol_counter'/i; - - # "constants"-line at begin of each block; single quotes should already be there - } elsif (m/$regex->{constants}/) { - s/'$symbol'/'$symbol_counter'/i; - - # function calls; replace inside predecessor line of calling-lines - } elsif (m/$regex->{call}/) { - $lines[$line_counter - 1] =~ s/'$symbol'/'$symbol_counter'/i; +sub obfuscate { - # 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; + # 1st stage: symbol replacement + 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_new' /i; + + # "constants"-line at begin of each block; single quotes should already be there + } elsif (m/$regex->{constants}/) { + 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_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_new'/i; + } + + $line_counter++; + } + } - $line_counter++; - + # 2nd stage: pollute & Co. + if ($options->{pollute}) { + foreach (@lines) { + if (m/$regex->{constants}/) { + my $inject = qq( + push 0 + ls: + dup + trace + branchIfTrue ls + +); + $_ .= $inject; + } + } + } + +} + +sub usage { + print "fluscate - The Flash Obfuscator (v$VERSION)", "\n"; + if (not $options->{version}) { + print <{help} || $options->{version}) { + usage(); + exit; + } + 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(); } - $symbol_counter--; + #print Dumper($symbols_table); exit; + + # replacements + obfuscate(); + # write all stuff to STDOUT + print STDOUT @lines; } -# write all stuff to STDOUT -print STDOUT @lines; +main(); + +1; +__END__