Overriding private methods in ActionScript, the hard way

July 10, 2009 at 10:49 AM | ActionScript | View Comments

Are you working with a proprietary .swc? Does it have lots of bugs? Did the authors, in all their infinite wisdom, decide to hide those bugs in private methods, so you stand no chance of being able to fix them? Well, friend, let me show you how to fix that.

Step 0: Uncompressing the swc/swf

First make a backup copy of the library (just incase you botch something):

 $ cp binary_library.swc binary_library_backup.swc

Then unzip the swc file like you would any other zip file:

 $ unzip binary_library.swc

This will extract, among other things, a library.swf file.

This library.swf will probably be compressed, so you've also got to uncompress it. To do that, I like to use SWFTOOLS:

 $ swfcombine -d library.swf -o uncompressed_library.swf

Step 1: Dumping the ABC

Now that you've got a nice uncompressed swf, it's time to decompile it. To do this, you can use or my patched version of swfdump.

 $ java -jar swfdump.jar -abc library.swf > library.abc

Step 2: Finding the multiname pool entry

Now pull up library.abc in your favorite text editor and search for the method's name under the "MultiName Constant Pool Entries" heading. For example, if the method's name is "priv", you'll be looking for something like this:

6 MultiName Constant Pool Entries
07 01 04 private:priv <-- here
07 02 06 :void
07 02 09 :pub
07 02 01 :A
07 02 10 :Object

Note that the method may be prefixed with a namespace:

6 MultiName Constant Pool Entries
...
07 01 04 com.foo.ClassName:methodName

Technical details: The first of those three bytes refers to the entry kind. The second is a one-based index into the list of namespaces (which are listed under "Namespace Constant Pool Entries") and the third is a one-based index into the list of string constants ("String Constant Pool Entries"). For all the details, see section "4.3 Constant Pool", "4.4.3 Multiname" and "4.1 Primitive data types" (for the definition of u30 – making sure to read the paragraph witch mentions that it uses little-endian byte order) in AVM 2 Machine Overview.

Note: If you're dealing with a large .swf, there may be four or even five bytes:

07 01 B9 03 :methodName

Don't worry – that's ok!

Make note of the bytes (in this case, 07 01 04) which prefix the method, then move on to step 3.

Step 3: Find a similar method

Next thing you've got to do is find a method of the same class which has a pubic (or protected) scope. In this case, we have a method called 'pub':

6 MultiName Constant Pool Entries
07 01 04 private:priv
07 02 06 :void
07 02 09 :pub <-- here

Make note here of the byte (02): that tells the AVM which namespace the method belongs to.

Step 4: Hex edit the uncompressed library

Now, pull up your favorite hex editor and open up the uncompressed_library.swf, which you created in step 0. Now, remember those bytes which prefix the method name? Search for them (and make sure you only find one instance of them – if there are multiple instances of them, expand the search to take into account the next few bytes (so, in this case, 07 01 04 07 02 06). Now, once you've found them, simply replace the second byte (in this case 01) with the second byte of the similar method:

07 01 04

is replaced with:

07 02 04

Step 5: Checking that you got it right

To check and make sure that you got it right, run the swfutil again, then check the output:

$ java -jar swfdump.jar -abc uncompressed_library.swc

You should see your change reflected in the MultiName constant pool entries:

6 MultiName Constant Pool Entries
07 02 04 :priv
07 02 06 :void

Note that the method is no longer prefixed with 'private' (or whatever the original namespace was).

Now, if the utility crashes, or something else doesn't work, go back and try again – you'll get it eventually.

Step 6: Putting it all back together

You're almost done! All that's left to do is put everything back into the .swc.

First, copy uncompressed_library.swf over top of library.swf:

$ cp library_uncompressed.swf library.swf

Or, optionally, you can re-compress it:

$ swfcombine -z -d library_uncompressed.swf -o library.swf

Then put library.swf back into the swc:

$ zip binary_library.swc library.swf

Finally try linking against it to see if everything worked!

See also:

Permalink + Comments

Evil private access modifier.

July 10, 2009 at 10:48 AM | Uncategorized | View Comments

If you're following me on Twitter, you'll know by now how I feel about the private access modifier.

My rage culminated this morning when, after spending the last three days working around bugs in a binary library, I came across a particularly nasty one. In a private method. That I couldn't work around.

Stupid private methods.

Anyway, I finally broke down and learned ABC, the Actionscript Byte Code format, and "fixed" the stupid method. If you're interested, you can read my post detailing how I did it.

Permalink + Comments

One Advantage of Using UUIDs as Primary Keys

July 07, 2009 at 02:33 PM | Uncategorized | View Comments

A quick note for those unfamiliar with UUIDs or using UUIDs as the primary key of a table in a database:

  • UUID stands for "Universally Unique IDentifier" (they are exactly the same as "GUIDs" (Globally Unique IDentifier), but "universal" sounds cooler than "global"), and are basically† 128 random bits, conveniently grouped into four fields. They look something like this: f81d4fae-7dec-11d0-a765-00a0c91e6bf6. If you're that kind of person, you can read RFC4122 for more information.
  • Because these identifiers are universally unique, they make great primary keys for databases: instead of using a bland auto-increment integer, generate a UUID for each row and use that instead. See linked discussions for more information.

It seems that the question of using UUIDs as PKs has been discussed at length, and I won't try to add to that. I just want to share one useful thing I've been doing with them: giving test data useful names.

Since data are almost always referenced by their primary key, I've found it useful to give my test data "helpful" PKs. For example:

[ { id: "with_children", children: [ ... ] },
  { id: "without_children", children: [ ] } ]

This way it can be easily referenced (for example, http://..../model/with_children) and it's easy to debug (I never need to remember "what was row 13 again?").

It also means I can write test fixtures by hand, without magic numbers everywhere:

- model: models.foo
  id: parent_pk
  fields:
      name: The Parent
      parent: null

- model: models.foo
  id: child_pk
  fields:
      name: The Child
      parent: parent_pk

Nitpickers: yes, this does imply that your UUID implementation can somehow turn ASCII strings into UUIDs.

†: although not entirely – see, for example, the different versions.

Permalink + Comments