http://osflash.org/flex2cpp
http://flex2cpp.sourceforge.net/
I made some horrifying discoveries with ‘abcdump’: even the names of some local variables and constants (ones initialized when declared) and function parameters (ones with default values) were preserved in the output, so the obfuscator renames local variables as well.
Thinking about all those evil people (like me) who occasionally use a Flash decompiler, I made an automatic function/variable finder and renamer for my preprocessor-based builds.
Original
/**
* Do the complete flood Fill starting at {dx,dy}, disregarding any meaning for values that aren't blocked or 'unfilled'
* You wind up with a trail from sx,sy to dx,dy of decreasing values for Path()
* @param pathmap Bitmap already filled with the map template
* @param dx,dy The target
**/
static public function FillBasic( pathmap : BitmapData, dx:int, dy:int ) : void
{
pathmap.lock();
FIFO_DECL(stack); // Stack for values searched
var curr:Object;
var newvalue:uint;
var currx:int;
var curry:int;
var tx:int;
var ty:int;
var value:uint;
value = pathmap.getPixel( dx, dy );
if( FILLED(value) )
return;
FIFO_FIRST(stack,dx,dy);
pathmap.setPixel( dx, dy, TARGET_VALUE );
while( null != (curr = FIFO_EARLIEST(stack)) )
{
currx = curr.x;
curry = curr.y;
value = pathmap.getPixel( x, y )+1;
#define trydir(dirx,diry) \
tx = currx dirx;\
ty = curry diry;\
newvalue = pathmap.getPixel( tx, ty );\
if( UNFILLED(newvalue) )\
{\
pathmap.setPixel( tx, ty, value );\
FIFO_PUSH( stack, tx, ty )\
}
trydir(+1,ppNULL)
trydir(ppNULL,+1)
trydir(-1,ppNULL)
trydir(ppNULL,-1)
FIFO_POP_DISCARD(stack);
#undef trydir
}
pathmap.unlock();
}
Preprocessed (and pretty-printed) debug build
/**
* Do the complete flood Fill starting at {dx,dy}, disregarding any meaning for values that aren't blocked or 'unfilled'
* You wind up with a trail from sx,sy to dx,dy of decreasing values for Path()
* @param pathmap Bitmap already filled with the map template
* @param dx,dy The target
**/
static public function FillBasic( pathmap:BitmapData, dx:int, dy:int ):void
{
pathmap.lock();
var headstack:Object = null;
var tailstack:Object = null;; // Stack for values searched
var curr:Object;
var newvalue:uint;
var currx:int;
var curry:int;
var tx:int;
var ty:int;
var value:uint;
value = pathmap.getPixel( dx, dy );
if ( ( ( value ) <= 0x00ff0000 ) )
return;
{
tailstack = headstack =
{
x: dx, y: dy, next:null};
};
pathmap.setPixel( dx, dy, 0x01000000 );
while ( null != ( curr = headstack ) )
{
currx = curr.x;
curry = curr.y;
value = pathmap.getPixel( x, y ) + 1;
tx = currx + 1;
ty = curry;
newvalue = pathmap.getPixel( tx, ty );
if ( ( ( newvalue ) > 0x00ff0000 ) )
{
pathmap.setPixel( tx, ty, value );
{
tailstack = tailstack.next =
{
x: tx, y: ty, next:null};
}
}
tx = currx;
ty = curry + 1;
newvalue = pathmap.getPixel( tx, ty );
if ( ( ( newvalue ) > 0x00ff0000 ) )
{
pathmap.setPixel( tx, ty, value );
{
tailstack = tailstack.next =
{
x: tx, y: ty, next:null};
}
}
tx = currx - 1;
ty = curry;
newvalue = pathmap.getPixel( tx, ty );
if ( ( ( newvalue ) > 0x00ff0000 ) )
{
pathmap.setPixel( tx, ty, value );
{
tailstack = tailstack.next =
{
x: tx, y: ty, next:null};
}
}
tx = currx;
ty = curry - 1;
newvalue = pathmap.getPixel( tx, ty );
if ( ( ( newvalue ) > 0x00ff0000 ) )
{
pathmap.setPixel( tx, ty, value );
{
tailstack = tailstack.next =
{
x: tx, y: ty, next:null};
}
}
{
headstack = headstack.next;
};
}
pathmap.unlock();
}
Preprocessed, Obfuscated( and pretty-printed) release-mode build
/**
* Do the complete flood Fill starting at {dx,dy}, disregarding any meaning for values that aren't blocked or 'unfilled'
* You wind up with a trail from sx,sy to dx,dy of decreasing values for Path()
* @param _355 Bitmap already filled with the map template
* @param dx,dy The target
**/
static public function _160( _355:BitmapData, _118:int, _119:int ):void
{
_355.lock();
var _45:Object = null;
var _304:Object = null;; // Stack for values searched
var _91:Object;
var _286:uint;
var _93:int;
var _94:int;
var _421:int;
var _422:int;
var _428:uint;
_428 = _355.getPixel( _118, _119 );
if ( ( ( _428 ) <= 0x00ff0000 ) )
return;
{
_304 = _45 =
{
x: _118, y: _119, _290:null};
};
_355.setPixel( _118, _119, 0x01000000 );
while ( null != ( _91 = _45 ) )
{
_93 = _91.x;
_94 = _91.y;
_428 = _355.getPixel( x, y ) + 1;
_421 = _93 + 1;
_422 = _94;
_286 = _355.getPixel( _421, _422 );
if ( ( ( _286 ) > 0x00ff0000 ) )
{
_355.setPixel( _421, _422, _428 );
{
_304 = _304._290 =
{
x: _421, y: _422, _290:null};
}
}
_421 = _93;
_422 = _94 + 1;
_286 = _355.getPixel( _421, _422 );
if ( ( ( _286 ) > 0x00ff0000 ) )
{
_355.setPixel( _421, _422, _428 );
{
_304 = _304._290 =
{
x: _421, y: _422, _290:null};
}
}
_421 = _93 - 1;
_422 = _94;
_286 = _355.getPixel( _421, _422 );
if ( ( ( _286 ) > 0x00ff0000 ) )
{
_355.setPixel( _421, _422, _428 );
{
_304 = _304._290 =
{
x: _421, y: _422, _290:null};
}
}
_421 = _93;
_422 = _94 - 1;
_286 = _355.getPixel( _421, _422 );
if ( ( ( _286 ) > 0x00ff0000 ) )
{
_355.setPixel( _421, _422, _428 );
{
_304 = _304._290 =
{
x: _421, y: _422, _290:null};
}
}
{
_45 = _45._290;
};
}
_355.unlock();
}
The Makefile script
##################################
#
# Make a list of classes, functions
# and class member variables.
#
symbols:
@find src -name "*.as3" -exec sed -n \
-e "s/^.*function \(.*\)(.*$$/\1/p"\
-e "s/^.*\b\(public\|protected\|private\|internal\)\b.*\b\(var\|const\)\b[ ]*\(.*\):.*$$/\3/p" \
{} ;
##################################
#
# Make a list of symbols (except constructors),
# sort them, remove duplicates, remove extra
# whitespace, #define them to _1, _2, _3...
# In other words, auto-generate an obfuscate.h
# to turn release-mode code into spaghetti drool.
#
obfuscate:
@find src -name "*.as3" -exec sed -n \
-e "s/^.*function \(.*\)(.*).*:.*$$/\1/p" \
-e "s/^.*\b\(var\|const\)\b[ ]*\([A-Za-z0-9_]*\).*:.*$$/\2/p" \
{} ;\
|sort|sed "$!N; /^\(.*\)
\1$$/!P; D"\
|sed -e "s/[ ]*$$//" -e "s/^/#define /" \
|sed -n -e "/.*/ p;=" |sed -e "N;s/
/ _/"
It’s just the first pass. What it really needs to do is generate the obfuscate.h based on the already-preprocessed code and then rebuild, so all of the symbols are discovered, including the preprocessor-generated ones.
The major caveat is that YOUR code can’t contain any names from the Actionscript libraries (i.e. mask, x, y, bitmapData, etc.) because it’s a simple sed script that doesn’t compare to a big list of exceptions. I might spend more time on it, but it only took a couple of hours of edit/compile/curse to wring all the little devils out of my code, and it would take a day or two to write a dedicated obfuscation tool.
It also doesn’t rename classes, because it would need to rename the files, too.
You can also make your own obfuscation entries in your include file to eliminate local classes and things that the obfuscate-a-tronic doohicky doesn’t notice.
Here’s a recommended ‘obfuscate.h’ pattern…
#ifndef OBFUSCATE_H
#define OBFUSCATE_H
#ifndef DEBUG
// Define things the search doesn't spot
#define MyLocalClass _o
#define MyOtherLocalClass _0
// Include the auto-generated definitions
#include "auto-obfuscate.h"
#endif // DEBUG
#endif // OBFUSCATE_H