| 4 |
|
|
| 5 |
# $Id$ |
# $Id$ |
| 6 |
# $Log$ |
# $Log$ |
| 7 |
|
# Revision 1.7 2004/08/03 02:36:05 joko |
| 8 |
|
# new features: Random, Undo, Interactive mode |
| 9 |
|
# |
| 10 |
# Revision 1.6 2004/08/03 00:24:15 joko |
# Revision 1.6 2004/08/03 00:24:15 joko |
| 11 |
# restructured code (procedures) |
# restructured code (procedures) |
| 12 |
# command-line arguments |
# command-line arguments |
| 62 |
=head2 Obfuscation |
=head2 Obfuscation |
| 63 |
|
|
| 64 |
See ASO Pro: http://www.genable.com/aso/preview.html |
See ASO Pro: http://www.genable.com/aso/preview.html |
| 65 |
|
fluscate implements a subset of these features plus some others. |
| 66 |
|
|
| 67 |
|
=head2 Symbols |
| 68 |
|
|
| 69 |
=head2 Functions |
=head3 Functions |
| 70 |
|
|
| 71 |
fluscate handles two different styles of function declarations: |
fluscate handles two different styles of function declarations: |
| 72 |
|
|
| 86 |
ls: |
ls: |
| 87 |
dup |
dup |
| 88 |
trace |
trace |
| 89 |
branchIfTrue ls" |
branchIfTrue ls |
| 90 |
|
|
| 91 |
|
Needs testing! |
| 92 |
|
|
| 93 |
|
=head2 Random |
| 94 |
|
|
| 95 |
|
Instead of using '-1', '-2', '-3', etc., this option creates randomized numbers |
| 96 |
|
as symbol replacements. |
| 97 |
|
|
| 98 |
|
=head2 Undo |
| 99 |
|
|
| 100 |
|
fluscate now has "undo"-functionality which can revert symbol replacements. |
| 101 |
|
First, use "fluscate -m -s" (memorize+save switches) to store your metadata and |
| 102 |
|
"fluscate -m -l -u" (memorize+load+undo switches) to make things undone. |
| 103 |
|
|
| 104 |
|
=head2 Interactive mode |
| 105 |
|
|
| 106 |
|
Can ask you about each symbol whether to replace it. Use "-i -f file.flm". |
| 107 |
|
|
| 108 |
|
|
| 109 |
=head1 Dependencies |
=head1 Dependencies |
| 118 |
|
|
| 119 |
Please type "fluscate --help" to get more information about command-line parameters. |
Please type "fluscate --help" to get more information about command-line parameters. |
| 120 |
|
|
| 121 |
=head2 win32 |
=head2 Semantic use: |
| 122 |
|
|
| 123 |
|
=head3 win32 |
| 124 |
|
|
| 125 |
#> flasm.exe -d puzzle.swf > puzzle.flm |
#> flasm.exe -d puzzle.swf > puzzle.flm |
| 126 |
#> cat puzzle.flm | perl fluscate.pl > puzzle_fusc.flm |
#> cat puzzle.flm | perl fluscate.pl > puzzle_fusc.flm |
| 127 |
#> flasm.exe -a puzzle_fusc.flm |
#> flasm.exe -a puzzle_fusc.flm |
| 128 |
|
|
| 129 |
=head2 *nix |
=head3 *nix |
| 130 |
|
|
| 131 |
#> ./flasm -d puzzle.swf > puzzle.flm |
#> ./flasm -d puzzle.swf > puzzle.flm |
| 132 |
#> cat puzzle.flm | ./fluscate.pl > puzzle_fusc.flm |
#> cat puzzle.flm | ./fluscate.pl > puzzle_fusc.flm |
| 138 |
=head2 Todo |
=head2 Todo |
| 139 |
|
|
| 140 |
- provide list of flash event handler names to exclude from symbol replacement |
- provide list of flash event handler names to exclude from symbol replacement |
| 141 |
|
- include list of ->keywords from: |
| 142 |
|
http://www.macromedia.com/support/flash/action_scripts/actionscript_dictionary/ |
| 143 |
|
|
| 144 |
=head2 Wishlist |
=head2 Wishlist |
| 145 |
|
|
|
- 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) |
|
| 146 |
- what about other symbols beside "function"s? (e.g. variables) (->mode) |
- 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/ |
|
| 147 |
- replace symbols in multiple files (->multifile) |
- replace symbols in multiple files (->multifile) |
| 148 |
|
- more symbol-replacement-modes: |
| 149 |
|
normal, random, random-alphanumeric (e.g. ahjit, twobc, plodf), wordlist, etc. |
| 150 |
|
|
| 151 |
=head2 Notes |
=head2 Notes |
| 152 |
|
|
| 224 |
use Getopt::Long; |
use Getopt::Long; |
| 225 |
use Storable; |
use Storable; |
| 226 |
use Data::Dumper; |
use Data::Dumper; |
| 227 |
|
use Term::ReadKey; |
| 228 |
|
|
| 229 |
my $VERSION = "0.10"; |
my $VERSION = "0.10"; |
| 230 |
|
|
| 236 |
'push' => 'push\s\'(.+?)\'', |
'push' => 'push\s\'(.+?)\'', |
| 237 |
}; |
}; |
| 238 |
my @symbols; |
my @symbols; |
| 239 |
|
my $symbols_table; |
| 240 |
my @lines; |
my @lines; |
| 241 |
my $options; |
my $options; |
| 242 |
|
|
| 244 |
GetOptions( |
GetOptions( |
| 245 |
"pollute" => \$options->{pollute}, |
"pollute" => \$options->{pollute}, |
| 246 |
"help" => \$options->{help}, |
"help" => \$options->{help}, |
| 247 |
"version" => \$options->{version} |
"version" => \$options->{version}, |
| 248 |
|
"random" => \$options->{random}, |
| 249 |
|
"memorize" => \$options->{memorize}, |
| 250 |
|
"load" => \$options->{load}, |
| 251 |
|
"save" => \$options->{save}, |
| 252 |
|
"undo" => \$options->{undo}, |
| 253 |
|
"interactive" => \$options->{interactive}, |
| 254 |
|
"file=s" => \$options->{file}, |
| 255 |
); |
); |
| 256 |
} |
} |
| 257 |
|
|
| 305 |
# ... remember them |
# ... remember them |
| 306 |
$symbol = $1; |
$symbol = $1; |
| 307 |
|
|
|
|
|
| 308 |
} elsif (m/$regex->{function_stacked}/) { |
} elsif (m/$regex->{function_stacked}/) { |
| 309 |
if ($lines[$counter - 1] =~ m/$regex->{push}/) { |
if ($lines[$counter - 1] =~ m/$regex->{push}/) { |
| 310 |
$symbol = $1; |
$symbol = $1; |
| 321 |
|
|
| 322 |
} |
} |
| 323 |
|
|
| 324 |
#print join("\n", @symbols); exit; |
sub scramble_symbols { |
| 325 |
|
if ($options->{random}) { |
| 326 |
|
#my $range = $#symbols; |
| 327 |
|
#my $range = 7; |
| 328 |
|
my $range = 10000; |
| 329 |
|
my $rndmem = {}; |
| 330 |
|
foreach (@symbols) { |
| 331 |
|
shuffle: |
| 332 |
|
my $rnd = -int(rand($range) + 1); |
| 333 |
|
goto shuffle if ($rndmem->{$rnd}); |
| 334 |
|
$symbols_table->{$_} = $rnd; |
| 335 |
|
$rndmem->{$rnd}++; |
| 336 |
|
} |
| 337 |
|
} else { |
| 338 |
|
my $symbol_counter = -1; |
| 339 |
|
foreach (@symbols) { |
| 340 |
|
$symbols_table->{$_} = $symbol_counter; |
| 341 |
|
$symbol_counter--; |
| 342 |
|
} |
| 343 |
|
} |
| 344 |
|
} |
| 345 |
|
|
| 346 |
|
sub select_symbols { |
| 347 |
|
print STDERR "Please answer with y/n to select symbols for replacement:", "\n"; |
| 348 |
|
ReadMode 3; |
| 349 |
|
foreach (keys %$symbols_table) { |
| 350 |
|
print STDERR $_, ": "; |
| 351 |
|
getkey: |
| 352 |
|
my $key = ReadKey(0) || ""; |
| 353 |
|
goto getkey if ($key !~ m/[yn]/i); |
| 354 |
|
print STDERR $key, "\n"; |
| 355 |
|
delete $symbols_table->{$_} if ($key =~ m/n/i); |
| 356 |
|
} |
| 357 |
|
ReadMode 0; |
| 358 |
|
} |
| 359 |
|
|
| 360 |
# 2. step through all symbols found and replace them |
# 2. step through all symbols found and replace them |
| 361 |
sub obfuscate { |
sub obfuscate { |
| 362 |
|
|
| 363 |
# 1st stage: symbol replacement |
# 1st stage: symbol replacement |
| 364 |
my $symbol_counter = -1; |
foreach my $symbol (keys %{$symbols_table}) { |
| 365 |
foreach my $symbol (@symbols) { |
my $symbol_new = $symbols_table->{$symbol}; |
| 366 |
my $line_counter = 0; |
my $line_counter = 0; |
| 367 |
foreach (@lines) { |
foreach (@lines) { |
| 368 |
|
|
| 369 |
# function declarations; single quotes might not be there! |
# function declarations; single quotes might not be there! |
| 370 |
if (m/$regex->{function}/) { |
if (m/$regex->{function}/) { |
| 371 |
s/\s'*$symbol'*\s/ '$symbol_counter' /i; |
s/\s'*$symbol'*\s/ '$symbol_new' /i; |
| 372 |
|
|
| 373 |
# "constants"-line at begin of each block; single quotes should already be there |
# "constants"-line at begin of each block; single quotes should already be there |
| 374 |
} elsif (m/$regex->{constants}/) { |
} elsif (m/$regex->{constants}/) { |
| 375 |
s/'$symbol'/'$symbol_counter'/i; |
s/'$symbol'/'$symbol_new'/i; |
| 376 |
|
|
| 377 |
# function calls; replace inside predecessor line of calling-lines |
# function calls; replace inside predecessor line of calling-lines |
| 378 |
} elsif (m/$regex->{call}/) { |
} elsif (m/$regex->{call}/) { |
| 379 |
$lines[$line_counter - 1] =~ s/'$symbol'/'$symbol_counter'/i; |
$lines[$line_counter - 1] =~ s/'$symbol'/'$symbol_new'/i; |
| 380 |
|
|
| 381 |
# function declarations; name of function is pushed on stack one line before! |
# function declarations; name of function is pushed on stack one line before! |
| 382 |
} elsif (m/$regex->{function_stacked}/) { |
} elsif (m/$regex->{function_stacked}/) { |
| 383 |
$lines[$line_counter - 1] =~ s/'$symbol'/'$symbol_counter'/i; |
$lines[$line_counter - 1] =~ s/'$symbol'/'$symbol_new'/i; |
| 384 |
} |
} |
| 385 |
|
|
| 386 |
$line_counter++; |
$line_counter++; |
| 387 |
|
|
| 388 |
} |
} |
|
$symbol_counter--; |
|
| 389 |
} |
} |
| 390 |
|
|
| 391 |
# 2nd stage: pollute & Co. |
# 2nd stage: pollute & Co. |
| 414 |
[-p|--pollute] Pollute code by inserting snippet making life harder for disassemblers |
[-p|--pollute] Pollute code by inserting snippet making life harder for disassemblers |
| 415 |
[-h|--help] This text |
[-h|--help] This text |
| 416 |
[-v|--version] Show version information only |
[-v|--version] Show version information only |
| 417 |
|
[-m|--memorize] Enable "memorize"-mode: can load and save symbol replacement metadata |
| 418 |
|
[-l|--load] Load symbol replacement table from file |
| 419 |
|
[-s|--save] Save symbol replacement table to file |
| 420 |
|
[-u|--undo] Replaces obfuscated symbols with original ones; valid only with "memorize" and "load" |
| 421 |
|
[-f|--file] Specify path to file for interactive mode |
| 422 |
USAGE |
USAGE |
| 423 |
}; |
}; |
| 424 |
} |
} |
| 425 |
|
|
| 426 |
sub main { |
sub main { |
| 427 |
|
|
| 428 |
|
# basic option handling |
| 429 |
read_options(); |
read_options(); |
| 430 |
#print Dumper($options); |
#print Dumper($options); |
| 431 |
if ($options->{help} || $options->{version}) { |
if ($options->{help} || $options->{version}) { |
| 432 |
usage(); |
usage(); |
| 433 |
exit; |
exit; |
| 434 |
} |
} |
| 435 |
# read flasm code from STDIN |
if ($options->{interactive} and not -z STDIN) { |
| 436 |
@lines = <STDIN>; |
print "Can not switch to interactive mode while reading from STDIN, please specify file with '-f'.", "\n"; |
| 437 |
scan_symbols(); |
exit; |
| 438 |
|
} |
| 439 |
|
|
| 440 |
|
if ($options->{file}) { |
| 441 |
|
# read flasm code from file |
| 442 |
|
if (!open(FH, $options->{file})) { |
| 443 |
|
print "Could not open file '$options->{file}'!", "\n"; |
| 444 |
|
exit; |
| 445 |
|
} |
| 446 |
|
@lines = <FH>; |
| 447 |
|
close(FH); |
| 448 |
|
} else { |
| 449 |
|
# read flasm code from STDIN |
| 450 |
|
@lines = <STDIN>; |
| 451 |
|
close(STDIN); |
| 452 |
|
} |
| 453 |
|
|
| 454 |
|
# symbol stuff (build/load/save) |
| 455 |
|
my $file = "fluscate.syms"; |
| 456 |
|
if ($options->{memorize} and $options->{load}) { |
| 457 |
|
# load |
| 458 |
|
$symbols_table = retrieve($file); |
| 459 |
|
if ($options->{undo}) { |
| 460 |
|
%$symbols_table = reverse %$symbols_table; |
| 461 |
|
} |
| 462 |
|
} else { |
| 463 |
|
# build |
| 464 |
|
scan_symbols(); |
| 465 |
|
scramble_symbols(); |
| 466 |
|
# save |
| 467 |
|
if ($options->{memorize} and $options->{save}) { |
| 468 |
|
store($symbols_table, $file); |
| 469 |
|
} |
| 470 |
|
} |
| 471 |
|
|
| 472 |
|
if ($options->{interactive}) { |
| 473 |
|
select_symbols(); |
| 474 |
|
} |
| 475 |
|
#print Dumper($symbols_table); exit; |
| 476 |
|
|
| 477 |
|
# replacements |
| 478 |
obfuscate(); |
obfuscate(); |
| 479 |
# write all stuff to STDOUT |
# write all stuff to STDOUT |
| 480 |
print STDOUT @lines; |
print STDOUT @lines; |