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; |