55 Commits
Author SHA1 Message Date
Vladimir Panteleev 352456d257 Update Changelog 2011-07-06 14:25:14 +03:00
Vladimir Panteleev d6544ae7cb Documentation: add link to FiddlerAutoCapture 2011-06-23 01:31:17 +03:00
Vladimir Panteleev 37cd4b415b disassembler: fixed handling of orphan methods with multiple references 2011-06-16 13:02:59 +03:00
Vladimir Panteleev 62d0756dbc asprogram: treat out-of-bounds namespace/multiname indices as null 2011-06-16 01:00:36 +03:00
Vladimir Panteleev 48b221535f disassembler: apply "blank line" change for si32-like instructions as well 2011-06-14 15:23:32 +03:00
Vladimir Panteleev beb7229bf8 Update Changelog 2011-06-14 15:15:21 +03:00
Vladimir Panteleev 296196ff71 Add support for out-of-bounds class/method indices 2011-06-12 18:57:01 +03:00
Vladimir Panteleev 170e7d6a8b Revert "abcfile: validate constant indices when reading bytecode"
This reverts commit 51536e4add.
2011-06-12 18:14:37 +03:00
Vladimir Panteleev 2c63eb592a disassembler: track private namespaces referenced only at script level 2011-06-12 18:09:19 +03:00
Vladimir Panteleev 16a5f649de disassembler: add support for orphan private namespaces 2011-06-12 18:08:45 +03:00
Vladimir Panteleev 111cd75eb4 disassembler: fix handling of null multinames 2011-06-12 16:35:45 +03:00
Vladimir Panteleev e103048af6 abcfile: Fix handling of exception info in corrupted method bodies 2011-06-12 16:21:06 +03:00
Vladimir Panteleev 61df70dd0e autodata: use to!string instead of format in AutoToString, for enum names 2011-06-12 14:43:52 +03:00
Vladimir Panteleev 51536e4add abcfile: validate constant indices when reading bytecode 2011-06-12 10:57:09 +03:00
Vladimir Panteleev fb5c03ada5 Update documentation 2011-06-12 10:40:15 +03:00
Vladimir Panteleev 2226b0059f disassembler: improve double shortest representation code 2011-06-12 10:32:05 +03:00
Vladimir Panteleev 69cf64b85c abcexport: delimit base file name and index with a dash 2011-06-10 18:51:33 +03:00
Vladimir Panteleev 2b49e77267 Fix handling of null namespaces 2011-06-10 18:44:10 +03:00
Vladimir Panteleev fab198a648 disassembler: add newlines after si32 as well 2011-06-10 14:21:32 +03:00
Vladimir Panteleev 4e4fd2b56d disassembler: externalize script-level methods, too 2011-06-10 13:24:57 +03:00
Vladimir Panteleev 7e4f7f5bac disassembler: dump classes to own file, use second-level extensions 2011-06-10 13:15:20 +03:00
Vladimir Panteleev 7a92e9fe81 asprogram: fix compiler warning 2011-06-10 12:36:25 +03:00
Vladimir Panteleev 41002f7085 Disassembler: fix handling of malformed UTF-8 2011-06-09 17:32:24 +03:00
Vladimir Panteleev 3b131fa932 Documentation: add a note about swfbinexport and swfbinreplace usage 2011-06-09 14:55:44 +03:00
Vladimir Panteleev 34316bd4c9 Documentation: fix typos 2011-05-26 15:39:01 +03:00
Vladimir Panteleev e49a6b3fec Update Changelog 2011-05-13 03:20:57 +03:00
Vladimir Panteleev bfa02943c6 disassembler: escape % too (the escape character) 2011-05-13 03:08:40 +03:00
Vladimir Panteleev cf8835b87d disassember: Escape space characters in filenames too (Windows forbids leading/trailing spaces) 2011-05-12 13:59:32 +03:00
Vladimir Panteleev 4c411ac1f2 Minor changes 2011-05-12 13:58:56 +03:00
Vladimir Panteleev 76cadf30cf Add swfbinexport and swfbinreplace utilities 2011-05-12 08:33:51 +03:00
Vladimir Panteleev 2498673231 Update copyright notices 2011-05-12 08:07:57 +03:00
Vladimir Panteleev a1b9ea05c0 Add a simple build tool 2011-05-12 07:59:26 +03:00
Vladimir Panteleev a766cf5919 Emit commented-out method body with raw hex bytes 2011-05-11 04:24:43 +03:00
Vladimir Panteleev e6f54db4c1 disassembler: Handle infinities in double shortening 2011-05-11 03:59:40 +03:00
Vladimir Panteleev 51e82bf985 Update Changelog 2011-05-11 03:45:39 +03:00
Vladimir Panteleev 282e8cbfc1 asprogram: Remove enum compiler hack 2011-05-11 01:06:09 +03:00
Vladimir Panteleev 4f53b789ee disassembler: aggressively try to shorten double literals 2011-04-17 22:46:12 +03:00
Vladimir Panteleev 0c5cbde348 disassembler: refuse to overwrite files 2011-04-17 08:29:03 +03:00
Vladimir Panteleev ff799d002f disassembler: place the contents of an entire script in one file 2011-04-17 08:11:35 +03:00
Vladimir Panteleev 1bf7a9a593 disassembler: handle private namespaces only referenced in initalizers 2011-04-16 20:53:50 +03:00
Vladimir Panteleev 1167b14471 disassembler: place script initializers in files near the rest of the script content 2011-04-16 20:09:39 +03:00
Vladimir Panteleev d3e8e47d54 disassembler: better refids and location for orphan classes and methods
This also changes the way classes are written (in a backwards-compatible
way).
2011-04-16 08:32:25 +03:00
Vladimir Panteleev 3f9be2b192 Whitespace 2011-04-16 08:25:39 +03:00
Vladimir Panteleev a690c82b7d disassembler: write exact context of private namespaces as a comment in the .privatens.asasm file 2011-04-16 07:15:49 +03:00
Vladimir Panteleev 2d7886bb0b disassembler: relax rootContext 2011-04-15 18:22:50 +03:00
Vladimir Panteleev 4cb179a1c6 disassembler: allow named private namespaces (ignore the name) 2011-04-15 18:21:45 +03:00
Vladimir Panteleev 0031be1f75 disassembler: improve context abbreviation for some cases 2011-04-15 17:58:06 +03:00
Vladimir Panteleev c7b7a5bce8 disassembler: Sort #privatens directives alphabetically 2011-04-15 17:46:29 +03:00
Vladimir Panteleev ac5d4b5e74 disassembler: rewrite the way refids/private namespace names are generated.
This will also place nested classes correctly in the directory structure.
2011-04-15 17:37:46 +03:00
Vladimir Panteleev eb07838668 Documentation: v1.1 change did not in fact break backwards compatibility 2011-04-15 07:15:45 +03:00
Vladimir Panteleev b80fe48bee Failing to decode a method body is now not a fatal error
Some obfuscators seem to append an orphan method to the end of the file
filled with junk. The disassembly will contain an empty body with a comment
describing the error message.
2011-04-14 13:26:17 +03:00
Vladimir Panteleev a083ed265f disassembler: always disassemble to the same location as the source file
Previously, rabcdasm would always create the disassembly directory in the
current directory.
2011-04-14 12:26:34 +03:00
Vladimir Panteleev 986ea47d03 Use "final switch" for opcode types 2011-04-14 11:50:31 +03:00
Vladimir Panteleev 3520d34cc2 Output correct opcode error location 2011-04-14 11:40:03 +03:00
Vladimir Panteleev 58ab6e3bf0 Documentation updates 2011-04-14 05:50:17 +03:00
18 changed files with 1019 additions and 390 deletions
+102 -54
View File
@@ -1,54 +1,102 @@
RABCDAsm Changelog
==================
RABCDAsm v1.5 (2011.04.14)
--------------------------
* Fixed v1.4 constant pool regression
* Added support for memory-access and sign-extend opcodes
* Speed optimizations
* Documentation updates
RABCDAsm v1.4 (2011.03.07)
--------------------------
* Source code ported to D2
* Add support for forward-references for TypeName-kind Multinames
* Correctly order classes by dependencies (extends/implements) and reference
count
* Finish Metadata support
* Documentation updates
RABCDAsm v1.3 (2010.11.11)
--------------------------
* Fixed double precision problem
* This also fixes problems with illegal default values for function
parameters (default values for integer parameters are stored as doubles,
which might become out-of-range due to inadequate double precision)
* Added Changelog
* Documentation markdown fixes
RABCDAsm v1.2 (2010.11.06)
--------------------------
* Fixed ref generation for orphan objects which were only referenced
by other orphans
* Better error handling in `abcexport`; warn when no DoABC tags found
* Documentation updates
RABCDAsm v1.1 (2010.06.30)
--------------------------
* Private namespaces are now referenced by auto-generated names
* Use `:` to delimit namespace and name in QNames for consistency
* Warning: this breaks compatibility with v1.0 disassemblies
* Fixed relative include paths
* Add optional byte offsets to labels, which allows lossless representation
of jumps inside instructions and outside the function bounds
* Documentation updates
RABCDAsm v1.0 (2010.05.05)
--------------------------
* Initial release.
RABCDAsm Changelog
==================
RABCDAsm v1.8 (2011.07.06)
--------------------------
* Fixed handling of orphan methods with multiple references
* Treat out-of-bounds namespace/multiname indices as null
* Documentation updates
RABCDAsm v1.7 (2011.06.14)
--------------------------
* Fixed handling of invalid UTF-8 in strings
* Fixed handling of null namespaces and multinames
* Fixed handling of exception info in corrupted method bodies
* Fixed handling of orphan private namespaces
* Fixed handling of out-of-bounds class/method indices
* Disassembler now creates one file per class and script-level method
* Disassembler now outputs blank lines after `si32` etc. instructions as well
* `abcexport` now delimits the index with a dash in output filenames
* Improved shortening of `double` literals
* Documentation updates
RABCDAsm v1.6 (2011.05.13)
--------------------------
* Overhaul of the structure of disassembler-generated files
* Private namespace names and `refid`s for nested classes are now generated
from their referenced contexts
* This also fixes problems caused by private namespaces being referenced
in multiple distinct contexts
* One `#include`d file per script instead of per class
* Nested classes, script initializers and other script traits are now in
the same file as their main class
* Inline methods are now in separate files, placed according to their usage
context
* Private namespaces are sorted by their autogenerated names in the
`.privatens.asasm` file
* No syntax changes, output is backwards-compatible
* Improved escaping of file names
* Output correct opcode error locations
* Disassembler will now refuse to overwrite files
* `rabcdasm` will now always generate output in the same directory as the
input file
* Failure to decode a method body is now not a fatal error
* Aggressively try to shorten double literals to their shortest representation
* Added the `swfbinexport` and `swfbinreplace` utilities, to aid in manipulating
contents of `DefineBinaryData` tags
* The package can now be built using a simple, dedicated build tool
* Documentation updates
RABCDAsm v1.5 (2011.04.14)
--------------------------
* Fixed v1.4 constant pool regression
* Added support for memory-access and sign-extend opcodes
* Speed optimizations
* Documentation updates
RABCDAsm v1.4 (2011.03.07)
--------------------------
* Source code ported to D2
* Add support for forward-references for TypeName-kind Multinames
* Correctly order classes by dependencies (extends/implements) and reference
count
* Finish Metadata support
* Documentation updates
RABCDAsm v1.3 (2010.11.11)
--------------------------
* Fixed double precision problem
* This also fixes problems with illegal default values for function
parameters (default values for integer parameters are stored as doubles,
which might become out-of-range due to inadequate double precision)
* Added Changelog
* Documentation markdown fixes
RABCDAsm v1.2 (2010.11.06)
--------------------------
* Fixed ref generation for orphan objects which were only referenced
by other orphans
* Better error handling in `abcexport`; warn when no DoABC tags found
* Documentation updates
RABCDAsm v1.1 (2010.06.30)
--------------------------
* Private namespaces are now referenced by auto-generated names
* Use `:` to delimit namespace and name in QNames for consistency
* Fixed relative include paths
* Add optional byte offsets to labels, which allows lossless representation
of jumps inside instructions and outside the function bounds
* Documentation updates
RABCDAsm v1.0 (2010.05.05)
--------------------------
* Initial release.
+48 -35
View File
@@ -11,16 +11,21 @@ These are:
* `abcreplace` - replaces ABC in SWF files
* `swfdecompress` - decompresses zlib-compressed SWF files
* `swf7zcompress` - (re-)compress the contents of a SWF using 7-Zip
* `swfbinexport` / `swfbinreplace` - extract/replace contents of binary
data tags from SWF files
`abcexport` and `abcreplace` are reimplementations of similar utilities from
my [swfutilsex][] Java package, however these work faster as they do not parse
the SWF files as deeply.
`swfdecompress` is ancilliary and is only useful for debugging and studying of
`swfdecompress` is ancillary and is only useful for debugging and studying of
the SWF file format, and not required for ABC manipulation. It is functionally
equivalent to [flasm][]'s `-x` option.
`swf7zcompress` is an utility to further reduce the size of SWF files. It uses
[7-Zip][] to compress the data better than the standard zlib library would. It
requires that the `7z` command-line program be installed and in `PATH`.
`swfbinexport` and `swfbinreplace` aid in the manipulation of
`DefineBinaryData` tags in SWF files (some files may contain nested SWF files
stored in these tags).
[RABCDAsm]: http://github.com/CyberShadow/RABCDAsm
[swfutilsex]: http://github.com/CyberShadow/swfutilsex
@@ -50,20 +55,20 @@ Compiling from source
RABCDAsm is written in the [D programming language, version 2][d2].
Assuming you have [dmd][] and [git][] installed, compiling should be as
straight-forward as:
Assuming you have [git][] and a D2 compiler, such as [dmd][] or [gdc][]
installed, compiling should be as straight-forward as:
git clone git://github.com/CyberShadow/RABCDAsm.git
cd RABCDAsm
dmd -O -inline rabcdasm abcfile asprogram disassembler autodata murmurhash2a
dmd -O -inline rabcasm abcfile asprogram assembler autodata murmurhash2a
dmd -O -inline abcexport swffile zlibx
dmd -O -inline abcreplace swffile zlibx
dmd -O -inline swfdecompress swffile zlibx
dmd -O -inline swf7zcompress swffile zlibx
dmd -run build_rabcdasm
Substitute `dmd` with `gdmd` if you're using gdc. You can use the `DC` and
`DCFLAGS` environment variables to override the detected compiler and default
compilation flags (`-O -inline`).
[d2]: http://www.digitalmars.com/d/2.0/
[dmd]: http://www.digitalmars.com/d/download.html
[gdc]: http://bitbucket.org/goshawk/gdc/
[git]: http://git-scm.com/
Pre-compiled binaries
@@ -82,25 +87,29 @@ To begin hacking on a SWF file:
abcexport file.swf
This will create `file0.abc` ... `fileN.abc` (often just `file0.abc`). Each
This will create `file-0.abc` ... `file-N.abc` (often just `file-0.abc`). Each
file corresponds to an ABC block inside the SWF file.
To disassemble one of the `.abc` files:
rabcdasm file0.abc
rabcdasm file-0.abc
This will create a `file0` directory, which will contain `file0.main.asasm`
(the main program file), `file0.privatens.asasm` (private namespace alias
definitions) and a file per ActionScript class.
This will create a `file-0` directory, which will contain `file-0.main.asasm`
(the main program file), `file-0.privatens.asasm` (private namespace alias
definitions), and files for ActionScript scripts, classes, and orphan and
script-level methods.
To assemble the `.asasm` files back, and update the SWF file:
rabcasm file0/file0.main.asasm
abcreplace file0.swf 0 file0/file0.main.abc
rabcasm file-0/file-0.main.asasm
abcreplace file-0.swf 0 file-0/file-0.main.abc
The second `abcreplace` argument represents the index of the ABC block in the
SWF file, and corresponds to the number in the filename created by `abcexport`.
`swfbinexport` and `swfbinreplace` are used in the same manner as `abcexport`
and `abcreplace`.
Syntax
======
@@ -242,7 +251,7 @@ namespace. Internally (the ABC file format), private namespaces are
distinguished by a numerical index - `rabcdasm` will attempt to give them
descriptive names based on their context. Aliases can be defined using the
`#privatens` directive. `rabcdasm` will create a separate file containing the
aliases (`file0.privatens.asasm`).
aliases (`file-0.privatens.asasm`).
Strings have a syntax similar to C string literals. Strings start and end with
a `"`. Supported escape sequences (a backslash followed by a letter) are `\n`
@@ -296,9 +305,9 @@ be instantiated in two ways:
although variables are defined using a string syntax, they are not
inserted as a string using this syntax. Thus, the code:
#set str "Hello, world!"
...
pushstring $str
#set str "Hello, world!"
...
pushstring $str
will expand to `pushstring Hello, world!`, which will result in an error.
To correct the problem, add escaped quotes around the variable contents
@@ -384,34 +393,38 @@ RABCDAsm users.
2. If you plan on making non-trivial changes to SWF files, you should install
the [debug Flash Player][]. This will allow you to see validation and
run-time error messages, instead of simply getting a blank rectangle.
run-time error messages, instead of simply getting an empty window.
[debug Flash Player]: http://www.adobe.com/support/flashplayer/downloads.html
3. The [Fiddler][] Web Debugging Proxy can be very useful for analysing
3. The [Fiddler][] Web Debugging Proxy can be very useful for analyzing
websites with SWF content. The following script fragment (which is to be
placed in the `OnBeforeResponse` function) will automatically save all SWF
files while preserving the directory structure.
if (oSession.oResponse.headers.ExistsAndContains("Content-Type",
"application/x-shockwave-flash")) {
// Set desired path here
var path:String = "C:\\Temp\\FiddlerCapture\\" +
oSession.host + oSession.PathAndQuery;
if (path.Contains('?'))
path = path.Substring(0, path.IndexOf('?'));
var dir:String = Path.GetDirectoryName(path);
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
oSession.utilDecodeResponse();
oSession.SaveResponseBody(path);
}
if (oSession.oResponse.headers.ExistsAndContains("Content-Type",
"application/x-shockwave-flash")) {
// Set desired path here
var path:String = "C:\\Temp\\FiddlerCapture\\" +
oSession.host + oSession.PathAndQuery;
if (path.Contains('?'))
path = path.Substring(0, path.IndexOf('?'));
var dir:String = Path.GetDirectoryName(path);
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
oSession.utilDecodeResponse();
oSession.SaveResponseBody(path);
}
A more robust version of the above snippet is available as a Fiddler plugin
[here][FiddlerAutoCapture].
Once you have edited a SWF file, you can use Fiddler's [AutoResponder][] to
replace the original file with your modified version.
[Fiddler]: http://www.fiddler2.com/fiddler2/
[AutoResponder]: http://www.fiddler2.com/fiddler2/help/AutoResponder.asp
[FiddlerAutoCapture]: https://github.com/CyberShadow/FiddlerAutoCapture
Limitations
===========
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
@@ -45,7 +45,7 @@ void main(string[] args)
while (*p++) {} // skip name
abc = tag.data[p-tag.data.ptr..$];
}
std.file.write(getName(arg) ~ to!string(count++) ~ ".abc", abc);
std.file.write(getName(arg) ~ "-" ~ to!string(count++) ~ ".abc", abc);
}
if (count == 0)
throw new Exception("No DoABC tags found");
+24 -18
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
@@ -21,8 +21,8 @@ module abcfile;
import std.string : format; // exception formatting
import std.exception;
/**
* Implements a shallow representation of an .abc file.
/**
* Implements a shallow representation of an .abc file.
* Loading and saving an .abc file using this class should produce
* output identical to the input.
*/
@@ -207,6 +207,9 @@ class ABCFile
Instruction[] instructions;
ExceptionInfo[] exceptions;
TraitsInfo[] traits;
string error;
ubyte[] rawBytes;
}
/// Destination for a jump or exception block boundary
@@ -388,7 +391,7 @@ enum MethodFlags : ubyte
NEED_REST = 0x04, // This flag creates an ActionScript 3.0 rest arguments array. Must not be used with NEED_ARGUMENTS. See Chapter 3.
HAS_OPTIONAL = 0x08, // Must be set if this method has optional parameters and the options field is present in this method_info structure.
SET_DXNS = 0x40, // Must be set if this method uses the dxns or dxnslate opcodes.
HAS_PARAM_NAMES = 0x80, // Must be set when the param_names field is present in this method_info structure.
HAS_PARAM_NAMES = 0x80, // Must be set when the param_names field is present in this method_info structure.
}
const string[8] MethodFlagNames = ["NEED_ARGUMENTS", "NEED_ACTIVATION", "NEED_REST", "HAS_OPTIONAL", "0x10", "0x20", "SET_DXNS", "HAS_PARAM_NAMES"];
@@ -1278,6 +1281,7 @@ private final class ABCReader
size_t len = readU30();
uint[] instructionAtOffset = new uint[len];
r.rawBytes = buf[pos..pos+len];
void translateLabel(ref ABCFile.Label label)
{
@@ -1307,23 +1311,25 @@ private final class ABCReader
label.offset = absoluteOffset-instructionOffset;
}
size_t start = pos;
size_t end = pos + len;
uint offset() { return pos - start; }
try
{
size_t start = pos;
size_t end = pos + len;
uint offset() { return pos - start; }
instructionAtOffset[] = uint.max;
uint[] instructionOffsets;
while (pos < end)
{
uint instructionOffset = offset;
scope(failure) pos = start + instructionOffset;
instructionAtOffset[instructionOffset] = r.instructions.length;
ABCFile.Instruction instruction;
instruction.opcode = cast(Opcode)readU8();
instruction.arguments.length = opcodeInfo[instruction.opcode].argumentTypes.length;
foreach (i, type; opcodeInfo[instruction.opcode].argumentTypes)
switch (type)
final switch (type)
{
case OpcodeArgumentType.Unknown:
throw new Exception("Don't know how to decode OP_" ~ opcodeInfo[instruction.opcode].name);
@@ -1363,9 +1369,6 @@ private final class ABCReader
foreach (ref label; instruction.arguments[i].switchTargets)
label.absoluteOffset = instructionOffset + readS24();
break;
default:
assert(0);
}
r.instructions ~= instruction;
instructionOffsets ~= instructionOffset;
@@ -1390,8 +1393,14 @@ private final class ABCReader
default:
break;
}
pos = end;
}
catch (Exception e)
{
r.instructions = null;
r.error = e.msg;
instructionAtOffset[] = 0;
}
pos = end;
r.exceptions.length = readU30();
foreach (ref value; r.exceptions)
@@ -1773,7 +1782,7 @@ private final class ABCWriter
throw new Exception("Mismatching number of arguments");
foreach (i, type; opcodeInfo[instruction.opcode].argumentTypes)
switch (type)
final switch (type)
{
case OpcodeArgumentType.Unknown:
throw new Exception("Don't know how to encode OP_" ~ opcodeInfo[instruction.opcode].name);
@@ -1819,9 +1828,6 @@ private final class ABCWriter
writeS24(0);
}
break;
default:
assert(0);
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
+36 -33
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
@@ -23,7 +23,7 @@ import core.stdc.string;
import abcfile;
import autodata;
/**
/**
* Represents a hierarchically-organized ActionScript program,
* with all constants expanded and bytecode disassembled to separate instructions.
*/
@@ -43,6 +43,7 @@ final class ASProgram
uint privateIndex; // unique index for private namespaces
mixin AutoCompare;
mixin AutoToString;
mixin ProcessAllData;
}
@@ -185,7 +186,7 @@ final class ASProgram
}
struct Value
{
{
ASType vkind;
union
{
@@ -259,6 +260,9 @@ final class ASProgram
Instruction[] instructions;
Exception[] exceptions;
Trait[] traits;
string error;
ubyte[] rawBytes;
}
struct Instruction
@@ -445,6 +449,7 @@ private final class ABCtoAS
n.vTypeName.params.length = multiname.TypeName.params.length;
foreach (j, param; multiname.TypeName.params)
n.vTypeName.params[j] = multinames[param];
break;
default:
break;
}
@@ -577,6 +582,8 @@ private final class ABCtoAS
e.varName = multinames[exc.varName];
}
n.traits = convertTraits(vbody.traits);
n.error = vbody.error;
n.rawBytes = vbody.rawBytes;
return n;
}
@@ -587,7 +594,7 @@ private final class ABCtoAS
r.arguments.length = instruction.arguments.length;
foreach (i, type; opcodeInfo[instruction.opcode].argumentTypes)
switch (type)
final switch (type)
{
case OpcodeArgumentType.Unknown:
throw new Exception("Don't know how to convert OP_" ~ opcodeInfo[instruction.opcode].name);
@@ -615,16 +622,16 @@ private final class ABCtoAS
r.arguments[i].stringv = abc.strings[instruction.arguments[i].index];
break;
case OpcodeArgumentType.Namespace:
r.arguments[i].namespacev = namespaces[instruction.arguments[i].index];
r.arguments[i].namespacev = namespaces.checkedGet(instruction.arguments[i].index);
break;
case OpcodeArgumentType.Multiname:
r.arguments[i].multinamev = multinames[instruction.arguments[i].index];
r.arguments[i].multinamev = multinames.checkedGet(instruction.arguments[i].index);
break;
case OpcodeArgumentType.Class:
r.arguments[i].classv = classes[instruction.arguments[i].index];
r.arguments[i].classv = classes.checkedGet(instruction.arguments[i].index);
break;
case OpcodeArgumentType.Method:
r.arguments[i].methodv = methods[instruction.arguments[i].index];
r.arguments[i].methodv = methods.checkedGet(instruction.arguments[i].index);
break;
case OpcodeArgumentType.JumpTarget:
@@ -635,9 +642,6 @@ private final class ABCtoAS
case OpcodeArgumentType.SwitchTargets:
r.arguments[i].switchTargets = instruction.arguments[i].switchTargets;
break;
default:
assert(0);
}
return r;
}
@@ -765,13 +769,12 @@ private final class AStoABC
bool add(T value) // return true if added
{
enum ivalue = cast(I)value;
if (haveNull && isNull(value))
return false;
auto cp = ivalue in pool;
auto cp = cast(I)value in pool;
if (cp is null)
{
pool[ivalue] = Entry(1, value);
pool[cast(I)value] = Entry(1, value);
return true;
}
else
@@ -783,8 +786,7 @@ private final class AStoABC
bool notAdded(T value)
{
enum ivalue = cast(I)value;
auto ep = ivalue in pool;
auto ep = cast(I)value in pool;
if (ep)
ep.hits++;
return !((haveNull && isNull(value)) || ep);
@@ -805,10 +807,9 @@ private final class AStoABC
uint get(T value)
{
enum ivalue = cast(I)value;
if (haveNull && isNull(value))
return 0;
return pool[ivalue].index;
return pool[cast(I)value].index;
}
}
@@ -1065,15 +1066,12 @@ private final class AStoABC
void visitClass(ASProgram.Class vclass)
{
if (classes.notAdded(vclass))
if (classes.add(vclass))
{
visitMethod(vclass.cinit);
visitTraits(vclass.traits);
visitInstance(vclass.instance);
bool r = classes.add(vclass);
assert(r, "Recursive class reference");
}
}
@@ -1088,7 +1086,7 @@ private final class AStoABC
strings.add(name);
foreach (ref value; options)
visitValue(value);
foreach (name; paramNames)
foreach (name; paramNames)
strings.add(name);
if (vbody)
@@ -1100,7 +1098,7 @@ private final class AStoABC
{
foreach (ref instruction; vbody.instructions)
foreach (i, type; opcodeInfo[instruction.opcode].argumentTypes)
switch (type)
final switch (type)
{
case OpcodeArgumentType.Unknown:
throw new Exception("Don't know how to visit OP_" ~ opcodeInfo[instruction.opcode].name);
@@ -1139,9 +1137,6 @@ private final class AStoABC
case OpcodeArgumentType.SwitchDefaultTarget:
case OpcodeArgumentType.SwitchTargets:
break;
default:
assert(0);
}
foreach (ref exception; vbody.exceptions)
@@ -1452,7 +1447,7 @@ private final class AStoABC
r.arguments.length = instruction.arguments.length;
foreach (i, type; opcodeInfo[instruction.opcode].argumentTypes)
switch (type)
final switch (type)
{
case OpcodeArgumentType.Unknown:
throw new Exception("Don't know how to convert OP_" ~ opcodeInfo[instruction.opcode].name);
@@ -1486,10 +1481,16 @@ private final class AStoABC
r.arguments[i].index = multinames.get(instruction.arguments[i].multinamev);
break;
case OpcodeArgumentType.Class:
r.arguments[i].index = classes.get(instruction.arguments[i].classv);
if (instruction.arguments[i].classv is null)
r.arguments[i].index = abc.classes.length;
else
r.arguments[i].index = classes.get(instruction.arguments[i].classv);
break;
case OpcodeArgumentType.Method:
r.arguments[i].index = methods.get(instruction.arguments[i].methodv);
if (instruction.arguments[i].methodv is null)
r.arguments[i].index = abc.methods.length;
else
r.arguments[i].index = methods.get(instruction.arguments[i].methodv);
break;
case OpcodeArgumentType.JumpTarget:
@@ -1500,9 +1501,6 @@ private final class AStoABC
case OpcodeArgumentType.SwitchTargets:
r.arguments[i].switchTargets = instruction.arguments[i].switchTargets;
break;
default:
assert(0);
}
return r;
}
@@ -1563,3 +1561,8 @@ private bool contains(T)(T[] arr, T val)
return true;
return false;
}
private T checkedGet(T)(T[] array, uint index, T def = T.init)
{
return index < array.length ? array[index] : def;
}
+31 -28
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
@@ -54,7 +54,7 @@ final class Assembler
{
return fromFile(filename, cast(string)read(filename), arguments);
}
static File fromFile(string filename, string data, string[] arguments = null)
{
return fromData(filename, data, arguments, getDirName(filename));
@@ -75,7 +75,7 @@ final class Assembler
}
string positionStr()
{
{
auto lines = splitlines(buf);
foreach (i, line; lines)
if (pos <= line.ptr + line.length)
@@ -94,7 +94,7 @@ final class Assembler
return file.basePath;
return null;
}
string convertFilename(string filename)
{
if (filename.length == 0)
@@ -127,7 +127,7 @@ final class Assembler
do {} while (*++files[0].pos != '\n');
}
else
return;
return;
}
}
@@ -250,7 +250,7 @@ final class Assembler
case 'd': case 'D': return 13;
case 'e': case 'E': return 14;
case 'f': case 'F': return 15;
default:
default:
throw new Exception("Malformed hex digit " ~ x);
}
}
@@ -540,8 +540,8 @@ final class Assembler
default: s ~= *files[0].pos;
}
break;
default:
s ~= *files[0].pos;
default:
s ~= *files[0].pos;
}
}
@@ -974,10 +974,10 @@ final class Assembler
auto lp = name in labels;
if (lp is null)
throw new Exception("Unknown label " ~ name);
return ABCFile.Label(*lp, offset);
}
ASProgram.Instruction[] readInstructions(ref uint[string] _labels)
{
ASProgram.Instruction[] instructions;
@@ -1010,7 +1010,7 @@ final class Assembler
instruction.arguments.length = argTypes.length;
foreach (i, type; argTypes)
{
switch (type)
final switch (type)
{
case OpcodeArgumentType.Unknown:
throw new Exception("Don't know how to assemble OP_" ~ opcodeInfo[instruction.opcode].name);
@@ -1061,9 +1061,6 @@ final class Assembler
foreach (li, s; switchTargetLabels)
switchFixups ~= LocalFixup(files[0].position, instructions.length, i, s, li);
break;
default:
assert(0);
}
if (i < argTypes.length-1)
expectChar(',');
@@ -1178,26 +1175,32 @@ final class Assembler
readProgram();
foreach (ref f; classFixups)
{
auto cp = f.name in classesByID;
if (cp is null)
if (f.name is null)
*f.ptr = null;
else
{
setFile(f.where.load);
throw new Exception("Unknown class refid: " ~ f.name);
auto cp = f.name in classesByID;
if (cp is null)
{
setFile(f.where.load);
throw new Exception("Unknown class refid: " ~ f.name);
}
*f.ptr = *cp;
}
*f.ptr = *cp;
}
foreach (ref f; methodFixups)
{
auto mp = f.name in methodsByID;
if (mp is null)
if (f.name is null)
*f.ptr = null;
else
{
setFile(f.where.load);
throw new Exception("Unknown method refid: " ~ f.name);
auto mp = f.name in methodsByID;
if (mp is null)
{
setFile(f.where.load);
throw new Exception("Unknown method refid: " ~ f.name);
}
*f.ptr = *mp;
}
*f.ptr = *mp;
}
}
catch (Exception e)
{
+31 -9
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
@@ -20,6 +20,7 @@ module autodata;
import murmurhash2a;
import std.traits;
public import std.conv;
string addAutoField(string name, bool reverseSort = false)
{
@@ -75,9 +76,9 @@ template AutoCompare()
template AutoToString()
{
static if (is(typeof(this)==class))
override string toString() { return _AutoDataToString(); }
override string toString() const { return _AutoDataToString(); }
else // struct
string toString() const { return _AutoDataToString(); }
string toString() { return _AutoDataToString(); }
string _AutoDataToString() const
{
@@ -108,7 +109,7 @@ template RawDataHandlerWrapper()
template getMixinRecursive(T, string name, string loopDepth)
{
static if (is(T U : U[]))
enum getMixinRecursive =
enum getMixinRecursive =
"{ bool _AutoDataNullTest = " ~ name ~ " is null; " ~ getRawMixin!("&_AutoDataNullTest", "bool.sizeof") ~ "}" ~
(!hasAliasing!(U) ?
getRawMixin!(name ~ ".ptr", name ~ ".length")
@@ -119,8 +120,11 @@ template RawDataHandlerWrapper()
static if (!hasAliasing!(T))
enum getMixinRecursive = getRawMixin!("&" ~ name, name ~ ".sizeof");
else
static if (is(typeof((new T).toHash())))
static if (is(T==struct))
enum getMixinRecursive = name ~ ".processData!(void, ``, ``)(handler);";
else
static if (is(T==class))
enum getMixinRecursive = "if ("~name~" !is null) " ~ name ~ ".processData!(void, ``, ``)(handler);";
else
static assert(0, "Don't know how to process type: " ~ T.stringof);
}
@@ -144,7 +148,7 @@ struct EqualsDataHandler(O)
template nullCheck(T, string name)
{
static if (is(T U : U[]))
static if (is(typeof(T.init is null)))
enum nullCheck = "if ((this." ~ name ~ " is null) != (_AutoDataOther." ~ name ~ " is null)) return false;";
else
enum nullCheck = "";
@@ -165,6 +169,23 @@ struct CmpDataHandler(O)
enum getMixin = getMixinComposite!(T, name, reverseSort).code;
}
template nullCheck(T, string name, string reverseStr)
{
static if (is(typeof(T.init is null)))
enum nullCheck = "
if (this."~name~" is null && _AutoDataOther."~name~" is null)
{ /* skip */ }
else
if (this."~name~" is null && _AutoDataOther."~name~" !is null)
return " ~ reverseStr ~ "(-1);
else
if (this."~name~" !is null && _AutoDataOther."~name~" is null)
return " ~ reverseStr ~ "( 1);
else";
else
enum nullCheck = "";
}
template getMixinComposite(T, string name, bool reverseSort)
{
enum reverseStr = reverseSort ? "-" : "";
@@ -180,9 +201,10 @@ struct CmpDataHandler(O)
enum dataCode = "{ int _AutoDataCmp = this." ~ name ~ " - _AutoDataOther." ~ name ~ "; if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }"; // TODO: use long?
else
static if (is(typeof(T.opCmp)))
enum dataCode = "{ int _AutoDataCmp = this." ~ name ~ ".opCmp(_AutoDataOther." ~ name ~ "); if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }";
enum dataCode = nullCheck!(T, name, reverseStr)
~ "{ int _AutoDataCmp = this." ~ name ~ ".opCmp(_AutoDataOther." ~ name ~ "); if (_AutoDataCmp != 0) return " ~ reverseStr ~ "_AutoDataCmp; }";
else
enum dataCode = "if (this." ~ name ~ " < _AutoDataOther." ~ name ~ ") return " ~ reverseStr ~ "(-1);" ~
enum dataCode = "if (this." ~ name ~ " < _AutoDataOther." ~ name ~ ") return " ~ reverseStr ~ "(-1);" ~
"if (this." ~ name ~ " > _AutoDataOther." ~ name ~ ") return " ~ reverseStr ~ "( 1);";
enum code = arrCode ~ dataCode;
}
@@ -192,6 +214,6 @@ struct ToStringDataHandler
{
template getMixin(T, string name, bool reverseSort)
{
enum getMixin = "_AutoDataResult ~= format(`%s = %s `, `" ~ name ~ "`, this." ~ name ~ ");";
enum getMixin = "_AutoDataResult ~= `" ~ name ~ " = ` ~ to!string(this." ~ name ~ ") ~ ` `;";
}
}
+71
View File
@@ -0,0 +1,71 @@
/*
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RABCDAsm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RABCDAsm. If not, see <http://www.gnu.org/licenses/>.
*/
/// A simple tool to build RABCDAsm in one command.
/// You can use the DC and DCFLAGS environment variables to override the detected compiler and compilation flags.
module build_rabcdasm;
version(D_Version2)
{ /* All OK */ }
else
static assert(false, "Unsupported D version.\nThis software requires a D2 ( http://www.digitalmars.com/d/2.0/ ) compiler to build.");
version(DigitalMars)
const DEFAULT_COMPILER = "dmd";
else
const DEFAULT_COMPILER = "gdmd";
const DEFAULT_FLAGS = "-O -inline";
import std.process;
import std.string;
string[][string] programs;
static this()
{
programs["rabcasm" ] = ["abcfile", "asprogram", "assembler", "autodata", "murmurhash2a"];
programs["rabcdasm" ] = ["abcfile", "asprogram", "disassembler", "autodata", "murmurhash2a"];
programs["abcexport" ] = ["swffile", "zlibx"];
programs["abcreplace" ] = ["swffile", "zlibx"];
programs["swfbinexport" ] = ["swffile", "zlibx"];
programs["swfbinreplace"] = ["swffile", "zlibx"];
programs["swfdecompress"] = ["swffile", "zlibx"];
programs["swf7zcompress"] = ["swffile", "zlibx"];
}
int main()
{
string compiler = getenv("DC");
if (compiler is null)
compiler = DEFAULT_COMPILER;
string flags = getenv("DCFLAGS");
if (flags is null)
flags = DEFAULT_FLAGS;
foreach (program, modules; programs)
{
int ret = system(format("%s %s %s %s", compiler, flags, program, join(modules, " ")));
if (ret)
return ret;
}
return 0;
}
+572 -199
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
@@ -32,7 +32,7 @@ void main(string[] args)
{
scope abc = ABCFile.read(cast(ubyte[])read(arg));
scope as = ASProgram.fromABC(abc);
scope disassembler = new Disassembler(as, getName(getBaseName(arg)));
scope disassembler = new Disassembler(as, getName(arg), getName(getBaseName(arg)));
disassembler.disassemble();
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
+50
View File
@@ -0,0 +1,50 @@
/*
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RABCDAsm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RABCDAsm. If not, see <http://www.gnu.org/licenses/>.
*/
module swfbinexport;
import std.file;
import std.path;
import std.string;
import std.stdio;
import std.exception;
import swffile;
void main(string[] args)
{
if (args.length == 1)
throw new Exception("No file specified");
foreach (arg; args[1..$])
try
{
scope swf = SWFFile.read(cast(ubyte[])read(arg));
bool found;
foreach (ref tag; swf.tags)
if (tag.type == TagType.DefineBinaryData)
{
found = true;
enforce(tag.data.length >= 6);
ushort id = *cast(short*)tag.data.ptr;
ubyte[] bin = tag.data[6..$];
std.file.write(format("%s-%d.bin", getName(arg), id), bin);
}
enforce(found, "No DefineBinaryData tags found");
}
catch (Exception e)
writefln("Error while processing %s: %s", arg, e);
}
+40
View File
@@ -0,0 +1,40 @@
/*
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RABCDAsm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RABCDAsm. If not, see <http://www.gnu.org/licenses/>.
*/
module swfbinreplace;
import std.file;
import std.conv;
import swffile;
void main(string[] args)
{
if (args.length != 4)
throw new Exception("Bad arguments. Usage: swfbinreplace file.swf id data.bin");
auto swf = SWFFile.read(cast(ubyte[])read(args[1]));
auto id = to!ushort(args[2]);
foreach (ref tag; swf.tags)
if (tag.type == TagType.DefineBinaryData && tag.data.length >= 6 && *cast(short*)tag.data.ptr == id)
{
auto bin = cast(ubyte[])read(args[3]);
tag.data = tag.data[0..6] ~ bin;
write(args[1], swf.write());
return;
}
throw new Exception("DefineBinaryData tag with specified ID not found in file");
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
+4 -4
View File
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2010 Vladimir Panteleev <vladimir@thecybershadow.net>
* Copyright 2010, 2011 Vladimir Panteleev <vladimir@thecybershadow.net>
* This file is part of RABCDAsm.
*
* RABCDAsm is free software: you can redistribute it and/or modify
@@ -21,8 +21,8 @@ module swffile;
import std.zlib;
import zlibx;
/**
* Implements a shallow representation of a .swf file.
/**
* Implements a shallow representation of a .swf file.
* Loading and saving a .swf file using this class should produce
* output identical to the input (aside zlib compression differences).
*/
@@ -230,7 +230,7 @@ private final class SWFWriter
buf ~= swf.frameSize.bytes;
buf ~= toArray(swf.frameRate);
buf ~= toArray(swf.frameCount);
foreach (ref tag; swf.tags)
{
ushort u = cast(ushort)(tag.type << 6);
+2 -2
View File
@@ -13,7 +13,7 @@ ubyte[] exactUncompress(ubyte[] srcbuf, size_t destlen)
auto destbuf = new ubyte[destlen];
uint err;
zs.next_in = srcbuf.ptr;
zs.avail_in = srcbuf.length;
@@ -37,7 +37,7 @@ ubyte[] exactUncompress(ubyte[] srcbuf, size_t destlen)
}
if (zs.avail_out != 0)
throw new Exception("Too little data in stream");
err = etc.c.zlib.inflateEnd(&zs);
if (err != Z_OK)
goto Lerr;