Flasm is a free command line assembler/disassembler of Flash ActionScript bytecode. It lets you make changes to any SWF. Flasm fully supports SWFs produced by Macromedia Flash 8 and earlier Flash versions.
About
Flasm disassembles your entire SWF including all the timelines and events. Looking at disassembly, you learn how the Flash compiler works, which improves your ActionScript skills. You can also do some optimizations on the disassembled code by hand or adjust the code as you wish. Flasm then applies your changes to the original SWF, replacing original actions.It's also possible to embed Flasm actions in your ActionScript, making optimizing of large projects more comfortable.Flasm is not a decompiler. What you get is the human readable representation of SWF bytecodes, not ActionScript source. If you're looking for a decompiler,Flare may suit your needs. However, Flare can't alter the SWF.
Page too long? You don't have to read it all. First, make yourself familiar with usage. Then read flash virtual machine topic to understand the concept of registers and stack. Disassemble some of your SWFs, starting with simpler ones, to see the inner workings of the Flash compiler. The rest of this page tries to address questions you may have at this point.
Download
Most recent Flasm version is 1.62.Windows binary: flasm16win.zipMac OS X binary: flasm16mac.tgz
Linux x86 binary: flasm16linux.tgz
There is no installation procedure. Just create a folder named
flasm
somewhere and unpack the archive there. To uninstall, delete the folder and you're done. Flasm doesn't touch your system files or registry.Third-party distributions and translations
FreeBSD port is maintained by Jun Kuriyama, Redhat RPMs are built by Daichi Shinozaki. They may be some versions behind the current and are not tested by me. If something goes wrong, please contact the maintainers. Jaco has translated Flasm manual into Italian.
Want to compile from sources?
Source code, platform independent: flasm16src.zip
You will need gcc or cc compiler with
flex
, bison
, gperf
, zlib
and zlib-devel
packages installed. It should compile well without any changes. Tested on Windows 2000 (Cygwin), Mac OS X, and Linux. For Cygwin, please install mingw
, mingw-runtime
and mingw-zlib
packages too. On Windows, Usage
Flasm is a command line tool. To use it, you have to open DOS window first (Windows). On Mac OS X, open terminal window:Applications/Utilities/Terminal
. Then go to the Flasm folder with cd c:\Flasm
cd /flasm
flasm
(Windows) or ./flasm
(Mac/Linux). Called without arguments, Flasm will show you the list of possible commands described below.flasm command filename
command
-d
Disassemble SWF file to the console-a
Assemble Flasm project-u
Update SWF file, replace Flasm macros-b
Assemble actions to __bytecode__()
instruction or byte sequence-z
Compress SWF with zlib-x
Decompress SWF-d foo.swf
Disassemble
foo.swf
to the console. To see action offsets in disassembly set showoffset
and hexoffset
options in flasm.ini
.-d foo.swf > foo.flm
Disassemble
foo.swf
, redirect the output to foo.flm
. Calling Flasm without a command on a .swf
file has the same effect.-a foo.flm
Assemble
foo.flm
and update the SWF defined inside. Calling Flasm without a command on a .flm
file has the same effect.The backup of original SWF is created with
.$wf
extension.-u foo.swf
Disassemble
foo.swf
to the temporary file.Execute Flasm macros embedded in SWF.
Make trivial optimizations automatically: remove double nots, replace
0.0
with 0
, rebuild constant pools, clear register arguments.Create
.$wf
backup, update the original SWF.It's a good idea to update the final version of SWF with
flasm -u
.-b foo.txt
produce
__bytecode__
instruction or byte sequence, depending on boutput
setting in flasm.ini
. Takes as input a simple action list without any movie
or frame
declarations. Output is sent to console. Redirect it to file if you wish: flasm -b foo.txt > foo.as
boutput
is set to 1
, Flasm produces binary output — probably of use for inserting raw action chunks into swf files build by other tools on server.-x foo.swf
Decompress
foo.swf
, create .$wf
backup.-z foo.swf
Compress
foo.swf
, create .$wf
backup. Source SWF doesn't have to be Flash MX file. However, only Flash MX and later players will be able to play the resulting compressed file.Flasm settings are read from the configuration file
flasm.ini
. Available options are commented in flasm.ini
and explained at appropriate places in the documentation. flasm.ini
is searched for in the working directory and, if not found, in the directory where the Flasm binary resides.All errors and warnings go to the console. If you want to log them in a file instead, uncomment
logto
option in flasm.ini
and enter the desired log file name there. Set logmode
option to 0
(default) to append new messages to the log file. If logmode
is set to 1
the log file will be overwritten each time you run Flasm.If you like Flasm and use it often, you may want to add it to Windows right-click context menu for SWF files. The explanation is for Windows 2000, but it should work with minor changes for any Windows version.
Start Windows Explorer. Select
View, Folder Options,
click the File Types
tab, and choose Flash player movie
(or similar) type, which stands for SWF file extension. Click Edit
button, then click New
button. In the Action
field enter Disassemble
. Click the Browse
button, navigate to the Flasm's folder, and double-click on flasm.exe
. No parameters are needed. Click OK, Close,
and Close
again. Now right click on any SWF and choose Disassemble
. The disassembly of somename.swf
will be stored in file somename.flm
in SWF's folder. Further automating is possible, adding flasm -u
flasm -a
If you don't want to do that, look at WinFlasm — simple windows GUI wrapper for Flasm. Note WinFlasm is old and does not support all Flasm commands.
Flash virtual machine
StackConstant pool
Global registers
Local registers
Every ActionScript statement is compiled by Flash into a couple of simple bytecode actions. For example,
a=b*b;
is transformed intoconstants 'a', 'b'
push 'a', 'b'
getVariable
push 'b'
getVariable
multiply
setVariable
The bytecodes are stored in SWF in binary form. They are interpreted by the virtual machine of the Flash Player. The code above is the visual representation of the bytecodes, created by Flasm.
I'll call actions inside of a frame or event action blocks. Flash executes action blocks one after another, so the execution flow inside of a block is neverinterrupted, neither by event nor by
gotoAndPlay()
or similar actions. Real parallel execution would be nicer? I'm sure it would dramatically affect player stability, which is great now, considering all things going on in a complex movie.Stack
Flash virtual machine is stack based, you can not refer to the particular memory location. The stack is a place in memory where data can be stored so that the last entered (pushed) value will be extracted (popped) first from the stack. Every command reads (and pops) operands from stack and pushes the result (if any) onto the stack.
The stack may contain elements of arbitrary type — integers, strings, floats and some others. If needed, type conversion happens during execution — like in ActionScript. Often there's no difference between the string
'10'
, integer 10
or double 10.0
.Further stack explanation by Robert Penner:
If you're familiar withTheArray.push
andArray.pop
, those commands are similar to stack manipulations. The stack is like an array of values, except you can only access the value on top, push another value onto the top, or swap the top two values.
For instance, to add two numbers, you have to push both of them onto the stack, then calladd
. Theadd
command will pop the top two values off the stack, add them together, and push the value onto the stack.
pop
action leads to no errors if the stack is empty. The special UNDEF
value is popped then, that corresponds to the ActionScript's undefined
.These two actions give you additional functionality for stack handling:
dup
and swap
. dup
duplicates the value on top of the stack, swap
swaps the two topmost values. Currently Flash doesn't use dup
and swap
very often as you'll see in disassembly, but they are of great importance for optimization.Every ActionScript statement, regardless of its complexity, leaves the stack empty after execution. In Flash IDE you don't see the bytecodes and don't have to worry about it. Making changes to bytecodes with Flasm, however, you should always count what's on stack. Improper stack manipulation often doesn't lead to any errors in Flash player. You will not see the 10.000 dead stack entries your loop produced, but the execution will slow down and the SWF probably runs out of memory at some point.
The stack was global in Flash 5. If the value was pushed in frame 1, frame 5 could trace it successfully. It was accessible in movie clips too. With Flash MX the situation changed: Flash Players 6 and 7 flush stack contents after every action block.
Constant pool
At the beginning of every action block where variables, methods or strings are used more than once, Flash creates so called constant pool. In fact, if at least one variable is used twice, the pool is created for all strings in the block. Here is an example:
constants 'bottom', 'paused', 'aliensleft', 'fire'
Constant pool can hold up to 65535 strings (in theory). These can be addressed later in your actions with 1 byte (first 256 strings in the pool) or 2 byte (the rest of the pool) reference. Commonly no more than 256 strings are stored, so you rarely meet 2 byte references in SWF. Practically the number of strings is limited by overall size of
constants
action, which can't exceed 65535 bytes like any other action.Flasm disassembler abstracts constant references away by default. They are showed as strings. To see actual references in disassembly, set
literalconstants
option in flasm.ini
to 0
. The difference between strings and constant pool members will be obvious then.Writing
push c:1
after the above constants
definition means push second constant from the pool (counting from 0). Writing push 'paused'
will in turn have the same effect, because Flasm finds the constant in the pool automatically and substitutes string with reference during assembly.If no previous constant pool declaration is found in the same action block, however, the string
'paused'
will be pushed as is. The difference is in code size only, not in execution speed — naturally, the string 'paused'
takes five bytes more than one-byte reference. Don't forget to add your strings to the constant pool.In update mode
flasm -u foo.swf
)The constant pool defined at the start of the frame is valid for every function in this frame. I've never seen constants defined in functions in disassembly. Every event has its own constant pool though.
Although Flash itself never redefines constant pool in the middle of the action block, theoretically you're allowed to do this. Flasm disassembler versions < 1.52 couldn't really deal with multiple constant pools. Flasm 1.52 will show constant references in
c:xx
form. To always show strings (resembles Flasm < 1.52 behavior, may be inaccurate) set literalconstants
to 2
.Global registers
Flash virtual machine has 4 global registers that are addressed
r:0, r:1, r:2, r:3
. Accessing variables is much slower than accessing registers, so you should store your most used variables there. Flash versions before MX 2004 only used r:0
, so there was enough room for optimization. Flash MX 2004's compiler, however, may substitute local variables with other registers — a very good reason to use local variables in ActionScript.To store something in a register, you should first put this something onto the stack and then execute
setRegister
command:push 'paused'
getVariable
setRegister r:1
Now the value of variable
paused
is stored in r:1
. Instead of asking for paused
next time, use push r:1
.Note: Unlike most other commands,
setRegister
does not pop the top value from stack! If you don't need the value stored in register to be on stack, you should manually pop
it.The value of global register, defined in a particular frame on
_root
, is available to all functions in this frame. If some function is defined or movie clip happens here, it can access or overwrite the register too. It looks like after the showFrame
tag occurs in SWF, registers disappear. Generally you don't know what happens to the global register. Of course, calling function A from the middle of function B should leave registers untouched. Flash MX 2004's compiler takes care of it — at the start of the function registers are saved on stack, at the end original values are restored. You should pay some attention here, too.Local registers
Inside of
function2
(Flash Player 6.0.65 and above), and only there, up to 255 local registers exist — from r:0
to r:254
. Why not 256? In the function2
header, the number of local registers used in this function is stored in a byte. At the start of function2
the place for local registers is allocated somewhere in memory. The highest possible value for a byte is 255.Generally, you don't have to care about the number of allocated registers — Flasm calculates this number automatically, and it's not shown in disassembly. Please take consequent registers numbers — using
r:1
and r:254
only forces Flasm and Flash Player to allocate 255 registers, which may have impact on memory.Since local registers are addressed by the same bytecodes as global registers —
setRegister
and push r:something
, function2
has no access to the global registers. Even more confusing is the scope — imagine you have frame A
, function2 B
inside of A
, and function C
inside of B
. Now function2 B
nicely has its own set of registers, and is totally unaware of global registers. That's OK. But function C
will share four global registers with frame A
!Besides of all that, local registers function just like global ones. There's no speed difference, too. To summarize: in SWF7 there are still four global registers everywhere outside
function2
, but any function2
may allocate a set of 255 local registers.Assembler syntax
Data types and pushControl flow
Button events
Play head control
setTarget/setTargetExpr
function2
try/catch/finally
protect/enableDebugger
scriptLimits
Unknown actionsFor details on SWF file format, read Macromedia's description and Alexis' SWF Reference. Macromedia has updated the docs for Flash 7 file format in November 2003. For historical reasons Flasm has its own names for some actions, slightly different from Macromedia's names. Important differences and abstractions are described here. If in doubt, look into
action.h
from Flasm's source distribution.Every Flasm project must start with
movie 'moviename.swf'
. The moviename.swf
is the name of your SWF origin. Don't forget to include the file name in quotes. At assembling time Flasm first looks here and then tries to overwrite the file. The backup of target SWF is created with .$wf
extension. If update fails for whatever reason, however, the original file will not be destroyed and no backup will be created.If
compressed
attribute is found just after movie name movie 'moviename.swf' compressed
),compressed
keyword decides about compression of updated SWF.Flasm is case insensitive (excluding string values that may be case sensitive). If you must use a single quote in your strings, escape it like this:
'it\'s beautiful'
"it's beautiful"
Comments look exactly like in ActionScript:
// calculating distance
or multi-line comment:
/* calculating
distance */
Flasm implements
#include
macro. #include 'loop.flm'
will be substituted with the contents of loop.flm
. Nested and multiple includes are allowed too: foo.flm
includes routine.flm
, which includes loop.flm
and calc.flm
. Maximum nesting depth is 10.I introduced some extra constructs in order to match the SWF structure. These serve as containers for Flash actions:
frame
, defineButton
, defineMovieClip
,initMovieClip
, movie
, on
, onClipEvent
, placeMovieClip
.Other supported tags:
enableDebugger
, enableDebugger2
, exportAssets
, fileAttributes
. importAssets
, importAssets2
, metadata
, protect
, scriptLimits
.Please don't alter the SWF structure! It means don't delete, replace or add action block containers! Well, you may add or delete an extra event without causing any damage. But if you remove a frame or change the movie clip id, Flasm will be no more able to find the pendant to it and any subsequent statements at assembling time.
Data types and push
Well,
push
is the core action in SWF and we'll go a bit more into detail here. Since you can push all kinds of values onto the stack, the push
action has an internal type attribute in SWF. While you don't see and can't access the push type from within Flasm, Flasm decides what type to use based on how your data is formatted.Push type | Number of bytes | What it means | Example |
0 | string length + 1 | string | push 'Hello' |
1 | 4 | float | push Y_PROPERTY |
2 | 0 | null | push NULL |
3 | 0 | undefined | push UNDEF |
4 | 1 | register | push r:2 |
5 | 1 | boolean | push TRUE |
6 | 8 | double | push 3.1415926 |
7 | 4 | integer | push 25 |
8 | 1 | constant (0-255) | push 'Hello' |
9 | 2 | constant (256-65534) | push 'Hello' |
Strings must be included in single or double quotes and may contain escape characters:
\b, \f, \n, \r, \t
and \\
. No line break is allowed inside of a string. If Flasm founds push 'Hello'
statement, it first looks into the constant pool for the current action block. If the string is defined there, 1- or 2-byte reference is pushed (push type 8
or 9
); if not, the string itself (type 0
).Integers are recognized in decimal and hexadecimal notation (
0xF0F0
). Doubles are decimal: -3.1415926
. The notation 9.4e-10
is supported too. In addition, constants _NAN
, POSITIVE_INFINITY
and NEGATIVE_INFINITY
are defined as double values.0.0
is considered double; 0
is an integer. Flash compiler itself always stores 0
as double 0.0
. In update mode Flasm will automatically replace all 0.0
occurrences with 0
, saving 4 bytes per each replace.Push type
1
is only used by Flash to store property values. Flash 4 stored all number values as strings (push type 0
), Flash 5+ utilizes push type 7
for integers and push type 6
for floats.However, Flash is not the only program creating SWFs. I know now of at least one third-party program (3D-Flash Animator), which uses type
1
for actually storing numbers. So while Flasm will disassemble type 1
to property constant if possible, all values that couldn't be resolved to any constant will be shown as floats: -3.1415926f
or 100.0f
. You can use this notation in your Flasm projects too, saving 4 bytes per number. Any floating point value which ends with f
will be treated as single-precision float and stored with push type 1
(beware of limited precision). The constants _NANF
, POSITIVE_INFINITYF
and NEGATIVE_INFINITYF
are defined too.One
push
statement can handle multiple values of different types: push 'Hello', 3.141, XSCALE_PROPERTY
. It's not just a shortcut in Flasm for 3 single push
actions, but a shorter and faster way.Control flow
Jumps inside of the action block are implemented with
branch
and branchIfTrue
actions. Every high level ActionScript construct like if (..) then .. else ..
while (..) do ..
branch/branchIfTrue
pattern. branch
simply jumps to the specified label. For example, the translation of if .. then .. else
branch
after its then
part, which skips the else
part and jumps forward to the end of if
. Backward jumps are allowed too, loops always contain them. branchIfTrue
takes the condition from stack.Internally relative numerical branch offsets are stored in SWF after every branch instruction. During disassembling Flasm creates unique label for every offset with the name
label1 .. labelN
, which hides the branch offset from your eyes and makes the disassembly more readable. The syntax is branch label4
orbranchIfTrue label6
. Somewhere in the same action block the label (identifier followed by colon) must be present. You are by no means forced to use identifiers like label5:
. Choose meaningful names (LoopStart:
, SearchComplete:
etc.) instead.Let's take an example: the really fast countdown loop, which can't be made with Flash (and can't be decompiled to any valid ActionScript).
push 0,1,2,3,4,5,6,7,8,9,10
loopstart:
dup
trace
branchIfTrue loopstart
First 10 values are pushed onto the stack. Note the last pushed value (
10
) will be on top of the stack. We have to duplicate the value in loop with dup
, because we need it two times: trace
pops the first value, branchIfTrue
gets the second as loop condition. Since branchIfTrue
converts condition to boolean, loop executes until 0
is found, which evaluates to false and stops the loop.Button events
Every single button event
on
contains one or multiple of the following:idleToOverUp | overUpToIdle | overUpToOverDown |
overDownToOverUp | overDownToOutDown | outDownToOverDown |
outDownToIdle | idleToOverDown | overDownToIdle |
keyPress |
There's no one-to-one relation of ActionScript button events and events stored in SWF. Some ActionScript events actually set multiple SWF events. That's why the names are different.
keyPress
is used in the form keyPress 'char'
keyPpress const
,keyPress 'a'
or keyPress _SPACE
. All constants correspond to those in Flash authoring:_BACKSPACE
, _DELETE
, _DOWN
, _END
, _ENTER
, _ESCAPE
, _HOME
, _INSERT
, _LEFT
, _PAGEDOWN
, _PAGEUP
, _RIGHT
, _SPACE
, _TAB
, _UP
.You are free to change button event conditions in Flasm code.
Play head control
The SWF file format describes three actions for this task:
gotoFrame
(frame number as operand), gotoFrame2
(takes the frame number from stack) and gotoLabel
(frame label as operand). While Flasm's gotoFrame
and gotoLabel
actions are named exactly like their SWF format pendants, gotoFrame2
action is not present. For your convenience gotoFrame2
is showed as gotoAndPlay
/gotoAndStop
. In SWF gotoFrame2
is a sole action with a byte flag for play/stop.Additionally, if you have multiple scenes, Flash puts yet another argument here — the total number of frames in all scenes before the one you're jumping to. These frames will be skipped by Flash player — in other words, added to the expression on stack. This allows for using
gotoAndPlay
/gotoAndStop
with a frame number inside of current scene instead of absolute frame number which starts from the beginning of SWF. Remember, scenes do not exist in SWF. In this case Flasm will show you something like gotoAndStop skip 10
. Note you're in trouble if your expression represents label string instead of integer frame number. Flash player doesn't care and will add frames to skip here too — and play head jumps to the false frame. Try using _root.gotoAndStop()
. Here movie clip method will be used instead of single instruction. It does no corrections and will work properly for labels.Higher Flash versions tend to use
gotoAndPlay/gotoAndStop
methods of the movie clip object (passing them as strings) to control movie clips.gotoLabel
is rarely seen in disassembly, because Flash replaces it with frame-based actions exporting SWF. Only if Flash can't resolve the frame number (the label is not on the same timeline), gotoLabel
will be left as is. Labels, however, are still present in SWF and may be accessed from javascript or whatever hosts the SWF, even if jumps to these labels were eliminated.setTarget and setTargetExpr
setTarget
action corresponds to tellTarget
in ActionScript. If target is an expression, setTargetExpr
is used, which pops the target string from stack. Flasm shows it likesetTarget '/defender' | or | setTargetExpr |
The
end
statement does not exist in bytecode; Flash uses setTarget ''
to mark the end of “targeted” statements.setTarget '/defender' | or | setTargetExpr |
Since every
setTarget
is handled by Flash this way, I decided to make it look more readable. Nesting of setTarget
blocks is not allowed.function2
Flash MX 2004 introduced new
function2
bytecode, which works in Flash Player 6.0.65 and above. function2
is an extended version of function
. In disassembly, it looks like this:function2 test (r:3='arg1', 'arg2', r:4='arg3') (r:1='this', r:2='_root')
In first parenthesis function arguments are shown. These arguments may be stored in local registers. Each
function2
has its own set of local registers. If register is absent, the corresponding argument isn't stored in register and behaves just like normal function argument. If register is present, the corresponding argument is stored there before function2
executes.You can't access arguments stored in registers by name (with
getVariable
), only by r:something
(something
being numerical or literal, see below). That means their names are effectively useless in SWF. If clearregisterargs
is set to 1
in flasm.ini
, flasm -u
arg1, arg2, ...,
because actual parameter names will be lost. To the best of my knowledge it doesn't affect code execution in any way.Second parenthesis contains “automatic” parameters. Their values are calculated and stored in local registers before function executes, like function arguments. Currently (in SWF7) there are six possible values:
'this'
, 'arguments'
, 'super'
, '_root'
, '_parent'
and '_global'
. Internally in SWF the corresponding bits in an unsigned integer value are set to indicate the presence of such value. For the sake of understandability Flasm shows them in literal form, however you can't add your own particular value here or affect register allocation. Registers are allocated by Flash Player in the above order, i.e the value of 'this'
goes to r:1
, the value of 'arguments'
to r:2
etc. If 'this'
is absent, 'arguments'
goes to r:1
. If you accidentally tell Flasm to store automatic values in wrong registers, Flasm will report an error.So the use of local registers in
function2
is threefold: arguments, “automatic” values and local variables are stored there.If
literalregisters
flag is set to 1
in flasm.ini
, Flasm will disassemble function2
like this:function2 isSpace (r:1='char')
push r:char
...
end // of function isSpace
instead of
function2 isSpace (r:1='char')
push r:1
...
end // of function isSpace
I.e. all
function2
arguments and automatic values like 'this'
will be shown with their literal names after r:
. Of course, you're free to write your own code using literal registers. r:char
in the example above means exactly the same as r:1
, and you may use numerical and literal notations together without any problems. However, you can't name other registers (local variables or like).You can safely store your own values in local registers, Flasm automatically adjusts the number of registers to allocate for any
function2
. This number, although stored in SWF, is invisible in disassembly. A small side-effect: for whatever reason Flash compiler often allocates more registers than needed. Flasm will allocate the minimal possible number.An edge case:
this
, arguments
and super
automatic parameters will be suppressed by Flash player if they don't appear in second parenthesis. They will neither be stored in registers nor accessible by name inside of function2
. Normally, you don't care: if you need one of these, allocate a register for it. In the very special case where you don't want to do it, but still want to access the parameter by name, you can list it without register given. Listing '_root'
, '_parent'
and '_global'
makes no difference. They are always available by name anyway. Nice, what?The try/catch/finally block
There is a new
try-catch-finally
construct in Flash MX 2004. In SWF all catch
blocks are merged into one, and exception condition checking is done with normal control flow there. In disassembly, the variable that holds the actual exception will be shown after try
keyword, not catch
. Like this:try 'e'
push 'x'
getVariable
throw
branch label1
catch
push 5
trace
label1:
end // of try
Alternatively, condition may be held in a register:
try r:2
or try r:something
(literal register). Data type exceptions, for example, are always transferred through register, usually r:0
. Other registers are used if error variable is declared local inside of try
block (thanks to Alex Bradley for finding this out), or given as parameter to function2
that contains the try/catch/finally
block.The
throw
action stores condition in a variable or register given after the try
keyword automatically, you don't have to do it explicitly. The condition is then available at the start of catch
block.protect, enableDebugger and enableDebugger2 tags
protect
was meant by Macromedia as a hint for authoring program, saying that the author of particular SWF doesn't wish it to be opened in Flash IDE. protect
is not actually protecting anything, any program that deals with SWF can simply ignore it. In Flasm, protect
will be shown, and can be added/deleted. You can place it anywhere in SWF, albeit usual location is somewhere near to the beginning. Note protect
is not an action, so it has to be outside of action blocks. Passwords are encoded by Flash compiler into a 28 characters long string, consisting of these parts (Paul Cannon):TheFlasm will show the encoded string, but not the password.$1$
at the start does signify an encryption scheme; it's the traditional way to indicate a crypt-MD5 password. Everything between the second and third$
is the salt, and everything after the last$
is the hashed password, in a sort of base-64 representation.
enableDebugger
is another attempt to secure the content of SWF. Always protected by password (Flasm will show the encoded string), this tag gives you the ability to “remote debug” the SWF. If you don't know the password, debugger will not let you in. If you delete the password, debugger will not let you in. But if you change enableDebugger
parameter to '$1$.e$7cXTDev5MooPv3voVnOMX1'
, empty password will be accepted.To say it clear one more time: above tags, including encrypted passwords, give you no protection and can be safely deleted or altered.
Flash MX allows debugging on source code level, so there is a new tag
enableDebugger2
, which is used instead of enableDebugger
. It makes no difference at all. However, Flasm will not show another tag (63) or contents of external file used by debugger, don't know anything about their format.scriptLimits tag
Introduced with Flash Player 7, scriptLimits tag gives you control about the maximum recursion depth and the maximum time before the famous "Script causes the movie to run slowly.." message appears. So far I know, these settings can not be changed in Flash IDE. The following syntax is used:
scriptLimits recursion 2000 timeout 10
While increasing recursion depth (256 by default) is surely useful in some situations, you may actually want to decrease the time-out for ActionScript for testing purposes. Instead of standard 15 or 20 seconds, setting the value to 1 or 2 will immediately show you where the bottlenecks are.
Unknown actions support
Flasm 1.6 knows every Flash action, including Flash 8 actions. Only subset of possible bytecodes, however, is currently used by Flash. Part of bytecodes space is reserved for third-party applications. For example, Apple's QuickTime added tag
0xAA
for QuickTime actions. Flasm is able to disassemble/assemble actions it doesn't know. The disassembly line looks likeswfAction 0x02 // Unknown action!
If the action has additional data,
hexdata
part is present:swfAction 0xAA hexdata 0x43,0x12,0x18 // Unknown action!
The data is shown as comma separated list of hex bytes. If you define your own actions for some proprietary application, there is no need to include tag length in
hexdata
field — the length is calculated and added automatically if hexdata
keyword is found. Don't forget, only bytecodes 0x80
Embedding Flasm code in ActionScript
If invoked with-u
command flasm -u foo.swf
),"push 'Hello world!'"
"push myTextField"
"setVariable"
The above has the same effect as
myTextField = "Hello world!";
ActionScript statement. Semicolons are not required, but will do no harm. Flasm code strings are allowed everywhere in your scripts, so don't worry about the right placement. Any restrictions? Sure. Don't define frames or movie clips in embedded Flasm. If you embed, you are already inside of some frame or event definition. Make sure the stack is empty after your embedded code executes. It's not a restriction, but you probably don't want to cause memory leaks.All Flasm actions behave as expected, there is only one important difference to consider — if you use
constants
declaration in embedded scripts, Flasm will add them to the main pool in the action block instead of redefining it. The same goes for constants
inside of any included file. Using #include
as part of the embedded string, please take care of slashes. Use normal slashes and not backslashes in file path. Latter will be escaped, if not deleted by Flash.While Flasm works just fine with compression enabled in Flash MX, update process will require two additional steps: decompressing and compressing. If your computer is slow, you may consider disabling compression in Flash publish settings. You can always compress SWF with
flasm -z
Testing embedded actions from within Flash IDE
Of course you can export the SWF, update it with Flasm, and check for errors then. Testing directly from Flash IDE would be nicer. Since Flash IDE has no post processing interface, it's rather tricky.
Flash 8 and Flash MX 2004
I've written a dll and a JSFL script which manages to preview your SWF in internal player. Here we go.
- Copy
flasmhelper.dll
fromhelper
directory of Flasm distribution toExternal Libraries
directory inside of your Flash configuration folder.
On windows 2000 and XP Flash 8 configuration is located here:C:\Documents and Settings\username\Local Settings\Application Data\Macromedia\Flash 8\en\Configuration
. The path will vary for non-English Windows and/or Flash. - Copy
Update with Flasm and Preview.jsfl
toCommands
directory inside Flash configuration folder. - Edit the first line of JSFL script and adjust path to the Flasm executable.
- Start Flash 8/MX 2004. "Update with Flasm and Preview" should be now available under "Commands". If you wish, associate a shortcut with it.
- You are all set. Execute the command to preview embedded Flasm actions. You have to write some first :) If unsure, re-read previous section.
flasm.exe
, no command.com
or such. It should be enough to prevent simple abusing it from malicious JSFL scripts. The dll is tested under Windows 2000 and XP. Please tell me if it works for you on Windows 98/ME — or if it doesn't.It shouldn't be too hard to port the library to Mac. To a pity, I don't own a Mac and can't do it myself. If you have interest in porting, drop me a line, I'll make the source available on request. To make sure you have all the prerequisites, try compiling the Mac sample from Macromedia.
Flash 5 or MX
There was no JSFL. Sven Kรถnig has found a way, and I've implemented it in Flasm. We'll make Flash believe Flasm is a browser. While proper installation requires some tweaking, it will work like a charm once you got it. I'll describe the procedure for Windows, but something similar should work on Mac too.
- Copy
flasm.exe
andflasm.ini
into theBrowser
subdirectory of Flash.
For Flash 5, theBrowser
subdirectory is inside of your Flash install folder.
Flash MX, stores settings elsewhere. IfBrowser
subdirectory does not exist, create it.
Windows 2000 or XP:C:\Documents and Settings\username\Application Data\Macromedia\Flash MX\Configuration\Browser
Windows 98 or ME:C:\Windows\Application Data\Macromedia\Flash MX\Configuration\Browser
Windows NT:[Windows directory]\profiles\[username]\Application Data\Macromedia\Flash MX\Configuration\Browser
Mac OS X:Hard Drive/Users/Library/Application Support/Macromedia/FlashMX/Configuration/Browser
Embedding on Mac is untested, please drop me a line if you get it to work. - Rename
flasm.exe
toiexplore.exe
- Create shortcut to your new
iexplore.exe
in the same subdirectory. Don't worry, it doesn't affect the real browser. - Open
flasm.ini
in a text editor. Changeflaplayer
andflabrowser
values to contain your Flash player and internet browser path, respectively. Long file names are not supported in dos, you should first discover what the corresponding short names look like:"C:\PROGRA~1\INTERN~1\IEXPLORE.EXE"
or similar. Even if you're on Win 2000, please use short names. Set the value offlatest
to “flaplayer
” if you want to test your files in player, and to “flabrowser
”, if you'll test in browser. You can changeflatest
value later while testing without restarting machine or Flash. or Flash IDE. - Done. Now open your file in Flash, insert Flasm code, make sure
HTML
and “Use Default Names
” boxes are checked in Flash publish settings, and pressF12
(Publish Preview).
iexplore.exe
) is ok, give the HTML file name to Flasm. After calculating the real SWF name Flasm will update the SWF and invoke browser or player to show it. The DOS box appears for the short time, but will only stay open if there are error messages to report. I guess (based on my experience) the most popular error would be “Could not start: c:\...\...\foo.exe
”, because the path in flaplayer
orflabrowser
is wrong. Correct it and try again.Doesn't work? Have you tried it with Flash MX 2004 by chance? MX 2004 doesn't seem to support default browser mechanism any more, use the first dll/JSFL method.Sometimes Flash just doesn't start Flasm. Enter something in actions window. Or uncheck HTML in export settings, publish, check it again, publish. Or delete iexplore shortcut from browser directory, publish, restore shortcut.
#include
may fail in Flash IDE if you haven't exported the SWF to the right location before. Check publish settings.In Resources you'll find links to the small debugger by Pavils Jurjans and profiler by Ben Schleimer.
Optimization techniques
MeasurementActionScript optimizations
Flasm optimizations
Double nots
ThanksHuge bitmaps, not optimized vectors, false frame rates, animating many movie clips at the same time, loading large XML files, dealing with tons of editable text, streaming high quality sound, or simply viewing SWF on mac — in 95% of all cases, bad SWF performance has nothing to do with ActionScript. Flasm, although being “yet another cool tool”, is no solution for above problems. Optimizing with Flasm makes sense for games, 3D engines, path finding, actually converting large amounts of data — computing things in general. Flash MX 2004 and Flash 8 made things much better here, too — at least for newer Flash Players.
If you're unsure where is the bottle neck: slow drawing or slow calculating, there is a simple trick: make the player or browser window very small and switch aliasing off in the Flash Player. If performance increases significantly, you probably should optimize your graphics or movie clip structure first.
Measurement
Don't try to optimize every single line of your code — you'll just make it unreadable, probably omit some important places, and nobody will ever notice 10.000 hours of your hard work. The key to any optimization is measurement. Bottle necks are very hard to guess. I used to have plenty of tips here, well tested for Flash 5 and Flash 4, but it just can't work this way because of the current diversity of possible environments. Now we have Flash Player 8, 7, 6, 5 and (still) 4 out there, stand-alone applications, mobile devices, not to mention Windows, Mac and Linux. These all are entirely different species. It means only some general strategies still work everywhere, and you have to measure your particular application on your target environment yourself. But how?
Optimize and test for your target environment. Tests in Flash IDE are very rough estimates at best.
You should differentiate between ActionScript code in FLA and compiled code in SWF. For example, if “
Omit Trace Actions
” is checked during publishing, traces simply do not make it into SWF. They do not exist there. The same goes for commented code. #include
d files are in effect exactly the same as inlined code, since they are first included, then compiled — nothing to test here, too. There are no classes in SWF — just functions. Flash compiler optimizes library function calls with constant arguments too. Calls like f = Math.sin(0.25)
or f = Math.max(3,5)
are never saved in SWF, the calculated values go here. Neither will if
parts with condition that always evaluates to false
be stored. Some local variables are stored in registers by the compiler, which makes a huge difference. And so on. Before you test, take a look at disassembly.Compiled bytecodes for Flash Player 7 are, err, context-dependant. Code inside of function2 benefits from local registers. The same code in a frame will not.
In a standard procedural programming language, most of the program time is spent in loops and functions or methods called from those loops. In Flash, frame loops and often or parallel called events should be investigated too.
Ben Schleimer's Flasm Profiler (or is it Flash Profiler?) and David Chang's ASProf are attempts to solve the main problem — what to optimize. I don't know how good they work, because I've not used them in a real-world project yet — they are relatively new. The profiler basically tells you execution times and number of calls for every function.
After you've found what's critical, find better algorithm first, or change your approach in general. Although you could improve the code in small, optimization should be the last resort.
Do all tests in a defined computer state — fresh booted, no virus scans or internet connection in background, all other programs closed. Don't move or resize widows during the test, don't do anything. Don't move your mouse, and let your mouse stay over flash movie. It does make a huge difference. That's not voodoo — OS manages your mouse, and Flash isn't the only running process.
Think about graphics. A script is never interrupted, so it's relatively easy to measure. If, however, you start to measure in the first frame, and end in tenth, you measure everything in between and simply don't know what you measure. The result largely depends on player's mood and takes generally much longer, making your ActionScript test irrelevant. Network requests,
gotoAndPlay
actions and many other things related to screen refresh are executed asynchronously. Get them out of measured code parts.Beware of loop overhead. Short test times are not reliable, since the loop itself takes most of the time. Calculate time for an empty loop, function, etc. and subtract it from your results. Use big loops, so that remaining times are bigger then, say, 1000 ms. Computers aren't that exact in ms. Generally, try to isolate the code in question from anything else and measure that code only. Of course, try to get other factors out of consideration first — network bandwidth, graphics etc. Otherwise you results can't be compared because of hidden overhead.
Mac Flash Player is slow compared to PC. Test on Macs early.
Don't execute different tests together. If you try to compare optimization 1 with optimization 2, give them the same environment. One run — one test. If you put both tests in the same frame, you start to deal with caching.
ActionScript optimizations
Flash Player 7 and 8 are much faster with ActionScript. Because of player improvements, and because of compiler improvements in Flash MX 2004/Flash 8. The latter are only noticeable if you compile for Flash Player 6 or higher though. If that's your target audience, you mostly can do now without Flasm optimizations, because the compiler will use registers anyway. You will still be able to achieve better performance with Flasm, but your first step should be getting Flash 8 IDE for critical applications.
I used to elaborate on so called “deprecated Flash 4 actions” here, which are much faster in Flash Player 5 or 6. The worst example:
myMC.gotoAndStop()
was25 times slower than tellTarget("myMC") gotoAndStop()
.Action blocks are always executed from the start to the end, no event or
gotoAndPlay()
will interrupt execution of other code. That's the reason why any large for
loop will hang the player, no screen updates are made.Define local variables in functions with
var
keyword. Local variables are faster, generally a good practice, and may be replaced with registers automatically, if compiled with Flash MX 2004/Flash 8.eval
is something special compared to, say, this
or any other ActionScript keyword. In fact, eval
is kind of macro — it doesn't have a bytecode, but simply writes its argument onto the stack — at compile time. No doubt it's faster than any method call. Starting with Flash MX, you're no longer allowed to use eval
on the left side of assignment. Use set
instead.Unfortunately, identifier length still matters, even in Flash 8, so choose short names for variables. This can be extended to built-in functions too. Creating the function
t = Math.tan
Math.tan
occurrences with t
will serve 2 purposes: no additional lookup is made for object Math
, then for method tan
; and the name itself is shorter. It works only for Flash 5+ methods and functions; Flash 4 functions will slow down. Of course, names of local variables don't matter if they are stored in registers.The old trick with replacing
b = a*4
b = a«2
Flash tries to precalculate constant parts of your expressions. The calculation order results from operator precedence. As Robert Penner noticed,
rad = Math.PI/180
rad = c*Math.PI/180
rad = c*(Math.PI/180)
in this case).for
and while
loops show no speed difference. It depends on how you write them. The most optimized ActionScript examples of both, looping down to 0
, produce the same bytecode: for(var i = 10; i--;) {}
i = 10; while (i--) {}
for
loop, absent in my example, is actually in the body of loop, so you can't compare it with a normal while
.Avoid multiple parallel
hitTest()
functions in events — often seen in games. If the player is killed after any touch with an enemy, and you have 100 duplicated enemy clips, don't include any code in the enemy clip enterFrame
event. Create the new movie clip and insert the enemy clip here. Then duplicate inside of this parent clip. Now you can check with only one hitTest()
if the collision takes place. If you need to, use some custom math then to calculate what enemy was hit. Since most of the time no collision occurs, you'll make a really big improvement in fps.I mostly do not say “3.45 times slower”, because comparisons are very context dependant, exact values will vary. My “slower” just means “noticeably slower, no situation ever makes it faster”.
The list is by no means complete, and will never be. Technology may render some points incorrect, again. Please make your own tests.
Flasm optimizations
After you're done in ActionScript, and the code is still slow, you can start to optimize with Flasm. Basically only two meaningful low-level features are not accessible from ActionScript and therefore subject of Flasm work: stack and registers.
Let's optimize a simple loop using stack. Our ActionScript is
for (var n=0; n<1000; n++) {
someFunction(n);
}
Flash compiles this loop to the following bytecodes:
constants 'n', 'someFunction' | // Store all variables in constant pool |
What we immediately see, the
n
variable is evaluated many times here. getVariable
action is slow compared to stack operations, and the n
is only used as local counter. Why not discard n
, keep the counter on stack and use it over and over, thus eliminating all getVariable
calls? We also don't need the constant pool declaration, since n
will disappear, and someFunction
name will be only used once. The number of jumps can be reduces to one, too. We know we have to callsomeFunction(0)
, so there is no need to check for the condition on the top of the loop. Look at optimized version:push 0 | // No need for double 0.0, integer 0 will do it |
We can go even further. If our function, say, fills an array with some calculated values, it makes no difference to do it from
0
to 999
or from 999
“down to” 0
. We can eliminate lessThan
action in this case, because branchIfTrue
is kind enough to convert 0
to false, and all other numbers to true for us.push 1000 |
We moved
decrement
to the top of the loop, because otherwise branchIfTrue
would immediately exit loop if the counter value is 0
and not let us executesomeFunction(0)
.As you see, we end with a pretty clear loop version, which will be much faster than the original Flash. How much, depends on what
someFunction()
does. As the next step you would go there and optimize it.The best way to learn how to use registers is to compile the same code in Flash MX 2004 for Flash 5, Flash 6, Flash 7, and look at the disassembly. Flash 5 version will use
r:0
only, Flash 6 will utilize all four global registers, and Flash 7/8 will add local function2
registers.Now if your target is Flash 5, you'll see from Flash 6' code what can be done. For higher targets, the room for further optimization is smaller. But there are still many places where the code could be improved — basically by eliminating useless
pop
s, push
es and branch
es.push
statements may push multiple values, not just one. Try to merge single push
es into one. That's way faster. You'll have to slightly re-arrange the code to do that.Registers are faster than variables, but still slower than stack. Why not keep all the values on stack so they go to the top just in the moment you need them? The problem is, if you're doing this with 2 or more variables, your algorithm may want to access them in a different order than they're stored. If some value is only required, say, at the start and at the end of your routine — no problem, it happily lives somewhere at the bottom, waiting for its time coming, and lets you work with other values on top. But for often needed values it doesn't work. While we have
swap
action to exchange two top values on stack, we can't directly access the third. Even if you find some illusionistic approach to access many variables, you'll just slow the execution with big amounts of swap
commands.Double nots
In certain cases Flash writes double
not
s in your code. Consider ActionScript code if (a<=b) { ... } else { ... }
Two inversions are created here by Flash compiler:push 'b'
getVariable
push 'a'
getVariable
lessThan
// a>b?not
// now inverted: a<=b?not
// prepare for branch to the else condition: again a>b?branchIfTrue elseCondition
As you see, Flash is not very flexible compiling your statements and does not change the order of operands in expression or use another pattern for
if
statement. It doesn't really make sense. The only purpose here could be an attempt to force type conversion to boolean. The next action you always see in the code, however, is branchIfTrue
. And this action does type conversion itself.So Flasm will automatically remove those
not
s in update mode.Thanks
My very special thanks go to the people on flashcoders list, whose ideas helped me to the better understanding of optimization and flowed into above examples:
Rasheed Abdal-Aziz, Ralf Bokelberg, Robin Debreuil, Zeh Fernando, Gary Fixler, Branden Hall, Dave Hayden, Damien Morton, Amos Olson, Robert Penner, Casper Schuirink.
__bytecode__
__bytecode__
function, first mentioned (1. post, 2. post) by Robin Debreuil is a way to inject bytecodes directly into swf without using Flasm (compare embedding). It takes a string filled with hexadecimal numbers as parameter. Since __bytecode__
is evaluated at compile time, it is not possible to give it a variable parameter. While it's convenient to not rely on Flasm updating the swf, __bytecode__
also offers an excellent way to shoot yourself in the foot. No checks are made by compiler here. You better make sure values are correct. Well, using Flasm in -b
mode to produce __bytecode__
parameter (or any other tool) at least guarantees proper instruction layout. Some caveats remain though.__bytecode__
is a function and as such returns a value. So single pop
action is added by Flash IDE if the result is unused. You may also assign the return value to variable, then it will be something else than pop
. Normally, an extra pop
is harmless.There are possible complications here with constant pools. Defining your own inside of
__bytecode__
will disable the pool automatically produced by compiler. Not defining makes the swf bigger. Define your own pool when needed and let __bytecode__
reside in a place where there is no other ActionScript — don't mix.File size difference
After assembling Flasm source or updating SWF with Flasm you'll often see your SWF having few less bytes even if you haven't changed anything in the bytecode. Besides of trivial optimizations Flasm does in update mode, there is one more reason for it. Flash may save block lengthes in the SWF as 2 or 6 byte records. 6 bytes are only needed if the block is larger than 62 bytes. Flash, however, often uses 6 bytes where 2 bytes will do. Although Flasm does this too in certain cases, most blocks are optimized during assembling. So I get 400 less bytes on the file of 90kB length without optimizing anything. I don't know of any disadvantages, enjoy this unexpected Flasm bonus. Side note: ironically, there are places where long lengthes are required because of Flash player bugs, but Flasm is aware of this and will let them untouched.Huge scripts
While it's good practice to keep scripts smaller than 64k (compiled) per frame, it's possible to get larger. But the sole action record —constants, push, function
and other is limited to 64k because of 2 bytes length field size.Since Flash attempts to create the constant pool for all variables and methods, and never creates multiple constant pools, what does it do in such cases? Flash 5 compiler would silently write an overflowed value to the length field without errors or warnings. Later Flash versions are smarter: they would put so many strings as possible into constant pool, other strings just remain in place. Flash MX 2004 will even warn you about classes being too big. However, the compiler doesn't check other places where overflow may occur. Function length (ActionScript 1), for example, isn't verified and will be broken for very big functions.
If you try to execute this kind of SWF, Flash player crashes or actions are omitted. Disassembly will be incomplete and/or wrong. In most cases, Flasm will show an error message.
Quirks, bugs and crashes
Flasm may not be able to disassemble protected SWFs. The protection is usually achieved by inserting some kind of junk into SWF. Generally, such SWFs work in Flash Player, but break the SWF file format spec. Flasm, however, aims to support the spec, not to mimic essentially undefined behavior of some particular Flash Player version. What's my point here? Don't ask me to disassemble something you've downloaded somewhere. Neither will I tune Flasm to overcome any protections. They are not even interesting, and easy to fix with a hex editor.Windows version of Flasm can't open unicode file names. It seems to be a Cygwin limitation.When saving flm files in Windows Notepad/Editor, choose ANSI as encoding. In UTF-8 mode Notepad inserts so called byte order mark (BOM) at the start of the file, which irritates Flasm (and many other programs). If you work with UTF-8, please choose another editor, most of them don't add the BOM.
You can't compile something like
function 0123รค()
in Flash because of parser limitations, the SWF format doesn't impose any restrictions on function names. Since Flasm deals with SWF directly, it should support such names, too. When assembling an SWF, you have to manually place quotes around problematic function names. Note: some of these (unicode names, for example, or Flasm keywords) are perfectly ok with Flash IDE, but interfere with Flasm parser.An edge case: nested
tellTargets
don't work if one of them is inside of a function.Don't know of any other bugs at the moment. If you find a nontrivial bug, fell free to send me your file. Please try to produce a minimal sample where the bug still occurs. The relevant part of source code or FLA is also welcome.
To make it clear: provided the SWF is valid, it must run properly after disassembling and assembling back without changes. The update mode must work too. There are absolutely no voodoo behaviors or unsupported features in Flasm. If you encounter problems, there must be a serious bug in my implementation and your report is highly appreciated.
History
Dave Hayden released Flasm in cooperation with Damien Morton in April 2001. The first version was able to disassemble the main timeline of the SWF and assemble to the first frame only. Flasm was quite useful already. I was very excited to discover Flasm back then, and soon started to play with source code. I've expanded Flasm's functionality and fixed some bugs. Dave then started the project on sourceforge.net. From 2002 until now I'm the only person developing and maintaining Flasm. Recently, Wang Zhen from Genable Labs has greatly contributed to Flasm 1.6.Project state
After five years of development Flasm is stable enough to be used in real-life projects and to my best knowledge fully supports all quirks of SWF format. I'm happy that during these time Flasm's source code has helped to develop some third-party software. My special thanks go to all the people who reported problems and suggested improvements. Now I'm busy with other projects and will not be able to implement exciting new features. Please send me your bug reports though, bug fixes will continue to happen.It's unlikely I'll ever add support for Flash 9. As you may know, Flash Player 9 contains the new virtual machine, which is nothing like the old one. I see it as a natural end of Flasm's life cycle — supporting that would in fact mean writing another Flasm from scratch.
Resources
This page can always be found at http://www.nowrap.de/flasm.html. The mirror at flasm.sourceforge.net is updated from time to time.The source is available here or may be downloaded from SourceForge's CVS. Project page is http://sourceforge.net/projects/flasm.
Take a look at my another project: Flare, the free ActionScript decompiler.
On the original Flasm page resides the first version and the useful explanation of Flash 5 bytecodes by Dave.
Compare tree animations made by Amos Olson: standard ActionScript version and the optimized one.
Look at path finding swf made with Flasm by Casper Schuirink. Here is the source.
MTASC, an open source ActionScript II compiler.
ActionScript problems are discussed on the highly frequented flashcoders mailing list, maintained by Branden Hall.
Alexis' SWF Reference
Macromedia's SWF File Format description
At the prototype site you'll find some Flash functions redefined for speed or flexibility, and also many new and useful ones. Often it's better to start Flasm optimizing from one of them.
Extendflash mailing list deals mostly with JSAPI, which allows customizing Flash MX 2004 and Flash 8 IDEs. Some posts about SWF internals.
KineticFusion by Kinesis Software converts your complete SWF to XML and back. Pricey.
Ben Schleimer's Flasm Profiler shows you what to optimize in the first place.
Pavils Jurjans has written the little debugger for Flasm, useful while embedding Flasm code in ActionScript. The debugger shows stack and register contents.
Jon Bott's has written an obfuscator, based on Flasm.
For people who don't like to work with command line, and don't like to register Flasm as SWF handler in Windows Explorer either, there is a WinFlasm bySharriff Aina, simple Windows interface to Flasm.
Albert Chosky has created Flasm 1.32 syntax files for EditPlus.
The older Flasm syntax file for UltraEdit, submitted by anonymous Russian flasmer.
Terms of use
Copyright © 2001 Opaque Industries, © 2002-2007 Igor Kogan, © 2005 Wang ZhenAll rights reserved.
Flasm is completely free. It's provided “as is” and without any warranties. Please read the license included in the distribution for details.
Macromedia and Flash are registered trademarks of Adobe Systems Inc.
Adobe does not sponsor, affiliate, or endorse this product.
0 comments :
Post a Comment