Advanced DoSWF encryption? Challenge accepted!

Greetings!
As I previously wrote about flash files unpacking, you can achieve that using static unpacking or dumping swf file from memory usually. There are some exceptions however, and I’ll tell you about one such exception in this article.

Developer of the DoSWF protector (made in China) used few simple yet interesting tricks to prevent revealing of the original SWF, I like something harder than clicking one button)
I guess many poor “hackers” (as they like to name themselves) have no idea why dumped files are not working, and can’t do anything about it.

Let me show you an example how to unpack SWF encrypted with DoSWF (many pictures ahead!)…
Let’s start from picking some nice SWF, like this demo of the Stardust particles engine for example:
Stardust

It can be decompiled easily:
Clean SWF

Now about DoSWF itself a bit. I used latest available ATM trial version (5.2.9) usually available online here: http://www.doswf.cn/swfencrypt/
Since we wish to know how to unpack (decrypt) protected SWF, we should use options from the Encrypt tab:
DoSWF Encrypt
I disabled all other options to keep this example clearer and let us focus on the unpacking.

We should have something similar to this after protected SWF decompilation:
DoSWF Loader

It looks standard for any kind of packed SWF file – we can see few classes for encrypted SWF decryption and loading. We can see embedded ByteArray or BitmapData nearby – that’s where encrypted SWF (or its parts ;)) is stored usually.
I should mention not any decompiler capable of dealing with DoSWF obfuscation – some hang forever, some just crash while trying to read and decompile such messy bytecode. I strongly recommend to use Action Script Viewer (ASV) or AS3 Sorcerer for decompilation. These tools can save you a lot of time and usually capable to munch any kind of obfuscated bytecode – tools developer makes his work very well! Hey, Burak! xD

Protected SWF runs fine but we can see DoSWF logo watermark since we used trial version of the protector:
DoSWF Watermark
SWF opens DoSWF main site sometimes as well.

New we are about to try unpack this SWF and since we can play it we should be able to dump it.
You could use whatever tool you want for this or even make dumps by hands, but I’d suggest to use SWF Revealer Ultimate – advanced dumper / unpacker from the ASV author. Docs quote: “if you can view the SWF in the standalone player, you will be able to see it and reveal any and all of the data”.
BTW: SWFRUL makes his job different way comparing to usual SWF Revealer (tool for ASV). This tool is sold as limited edition – there are about 15 licenses worldwide available now in total so hurry if you’re interested in this tool!

SWFRUL reveals two SWF files in our target:
SWFRUL

Let’s get them out and look into them a bit.

We’ll not see working original SWF while trying to run these reveals SWFs. One will show us nothing, second one – buggy GUI of our original SWF. Okay, let’s dive a bit deeper and look what exactly happened to our original SWF.

After opening first SWF in the decompiler, we can see something similar to what we saw in original SWF:
Dumped SWF with code
First thing we could notice – absence of the document class. Something is really wrong here. Moreover, if we’ll try to look for any library items in this SWF we will fail! There is no any library at all!
Looks like in this SWF we have abc bytecode only… And we’ll confirm this after looking into the SWF with any inspector, like Adobe SWF Investigator for example – there is no any tags except the FileAttibutes, DoSWF and ShowFrame. That’s why we didn’t saw a document class – SWF should contain SymbolClass tag for that.
SWF with code tags

Now we can guess all other content of the original SWF is stored in the second revealed SWF especially counting we saw a buggy GUI of our original file there.
And this can be easily approved after looking into this SWF in the inspector:
Investigating second SWF
We can see here our original SymbolClass tag with document class specified (Symbol with zero refid) as well.

Looks like we should try to merge both revealed SWF files to restore the original one. And I’d like to suggest to move DoABC tag from first file to the second one. This can be achieves using different tools. I use old and good SWiX for tasks like this – it’s a useful XML-based SWF editor. You can open both files there and copy-past what you want from one file to another, that’s it. Okay, copy-pasting DoABC tag and saving result:
Editing SWF in SWiX

We’ll see something like this after running output file:
Corrupted SWF

Pretty scary show =) We can see numerous bugs in GUI, not working particles or any other functionality malfunction, a lot errors thrown by Debug Flash Player. From the other hand, we can see the DoSWF logo watermark and Stats working there! This is a good sign – DoABC tag is working as expected!

Now we should investigate why all this working so bad. Let’s decompile main class and look into its constructor code.
Decompiled corrupted SWF

Clever ASV replaced ugly obfuscated names with _SafeStr*. Since I didn’t use original SWF obfuscation we can easily distinguish original code from DoSWF added one – usually it’s somewhat harder to do this, but extra clarity is not an issue for this typical example.

So, we see suspicious method _SafeStr4() right in the beginning of the constructor code. And we can see strange empty _SafeStr3() as well (I guess it’s just a garbage).
If we’ll study the main class further we’ll see a lot of the extra code added by DoSWF, and looks like all it can be disabled just with removing _SafeStr4() call.
So let’s clean constructor’s code a bit. You can use any tools you prefer for this, I prefer RABCDAsm and any kind of GUI for it, like WinRABCDAsm.

Well, after disassembling the SWF we should find the main class constructor bytecode (Waypoints.class.asasm). Here it is:

     getlocal0
     pushscope

     getlocal0
     callpropvoid        QName(PackageNamespace(""), "@doswf__mnΙΏ"), 0

     findproperty        QName(PrivateNamespace(null, "Waypoints#0"), "matrix")
     findpropstrict      QName(PackageNamespace("flash.geom"), "Matrix")
     pushdouble          0.5
     pushbyte            0
     dup
     pushdouble          0.5
     constructprop       QName(PackageNamespace("flash.geom"), "Matrix"), 4
     initproperty        QName(PrivateNamespace(null, "Waypoints#0"), "matrix")

     getlocal0
     constructsuper      0

     findpropstrict      QName(PackageInternalNs(""), "__setProp_xml_btn_Scene1_XMLbtn_1")
     callpropvoid        QName(PackageInternalNs(""), "__setProp_xml_btn_Scene1_XMLbtn_1"), 0

     returnvoid

We can see the call of the @doswf__mnΙΏ (ASV renamed it to the _SafeStr4) method right at the beginning of the bytecode list.
Okay, let’s remove this call (I’ll not cover how to edit bytecode right way in this article, it’s simple enough – just read the specs – that’s all you need for this) and re-assemble the SWF file.
Run it and see almost nothing have changed except the DoSWF logo watermark is absent now πŸ˜‰

So we still have buggy SWF and it still opens DoSWF site sometimes.
Let’s remove this noisy site opening code. The easiest way to find a place where it happens is to look for any navigateToURL () calls through the whole sources. And we can easily find it after such lookup – in my case there were not so many matches for this search and target code was found in the idv.cjcat.stardust.common.particles.Particle class. Please note it can be any other class in your case since placement of this code is selected randomly when DoSWF encrypts SWF file.
I noticed such ugly yet effective method for doswf.com link hiding there:

var _local2 = "ht" + "tp:/" + "/ww" + "w.d" + "osw" + "f.c" + "om";

Low compiler effectiveness makes this possible.

Okay, let’s look at the disasm listing of the “infected” class) We should search for any anomalies at the class static constructor since protector inlines his method there.

    getlocal0
    pushscope

    findpropstrict      Multiname("Particle", [PackageNamespace("idv.cjcat.stardust.common.particles")])
    getlex              QName(PackageNamespace(""), "Object")
    pushscope

    getlex              QName(PackageNamespace(""), "Object")
    newclass            "idv.cjcat.stardust.common.particles:Particle"
    popscope
    initproperty        QName(PackageNamespace("idv.cjcat.stardust.common.particles"), "Particle")

    newfunction         "idv.cjcat.stardust.common.particles:Particle.sinit/inline_method#0"
    pushnull
    call                0
    pop
    returnvoid

Gotcha! We can see the suspicious inline method call right at the end of the constructor. We can ensure this is a protector’s code just looking into inline_method#0 bytecode.
Removing this method call from static constructor, reassembling SWF file and voilΓ ! Our restored SWF doesn’t open protector’s main site anymore.
As you could notice, we just removed all visible watermarks of the protector’s trial version πŸ˜‰ There are a lot of unused junk bytecode now in the SWF though so it’s easy to reveal we used trial protector’s version – we need to clean SWF further to remove any trial version signs, but this article is not about that.

Okay, we still have buggy SWF and looks like it’s time to look into errors Debugger Flash PLayer throws to us.
In my case first error stack trace ended with this:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at fl.core::UIComponent/setSize()
at …

Let’s inspect the fl.core::UIComponent/setSize() method to find what’s wrong there.
Here is a source code of this function

_width = _arg1;
_height = _arg2;
invalidate(InvalidationType.SIZE);
dispatchEvent(new ComponentEvent(ComponentEvent.RESIZE, false));

We have null object reference error so we should look for any possible null references there. Two first lines can’t harm us, but third have InvalidationType.SIZE constant usage. It could be null.
So let’s view the InvalidationType class source code:

    public class InvalidationType 
    {

        public static const ALL:String = "all";
        public static const SIZE:String = "size";
        public static const STYLES:String = "styles";
        public static const RENDERER_STYLES:String = "rendererStyles";
        public static const STATE:String = "state";
        public static const DATA:String = "data";
        public static const SCROLL:String = "scroll";
        public static const SELECTED:String = "selected";

        public function InvalidationType()
        {
            if (!ApplicationDomain.currentDomain.hasDefinition("Ȋ"))
            {
                return;
            };
            super();
        }

    }

    import flash.system.ApplicationDomain;

    if (!ApplicationDomain.currentDomain.hasDefinition("Ȋ"))
    {
        return;
    };

Aha! Looks like we just found the source of the null reference error! Protector added the simple definition (it can be any public class, function or namespace with specified name) existence check in both regular and static constructor. I guess this definition exists in the DoSWF loader, so checks works fine if this code is running in the loader’s domain. But we have no loader with such definition, so checks will not pass and all static variables will not be initialized! That’s why InvalidationType.SIZE is null.

Let’s inspect this checks in the disassembler. We’ll look into the static constructor bytecode since regular constructor is empty (excluding that check):

    getlocal0
    pushscope

    findpropstrict      Multiname("InvalidationType", [PackageNamespace("fl.core")])
    getlex              QName(PackageNamespace("flash.system"), "ApplicationDomain")
    getproperty         QName(PackageNamespace(""), "currentDomain")
    pushstring          "Ȋ"
    callproplex         QName(PackageNamespace(""), "hasDefinition"), 1
    iftrue              L9

    returnvoid

L9:
    getlex              QName(PackageNamespace(""), "Object")
    pushscope

    getlex              QName(PackageNamespace(""), "Object")
    newclass            "fl.core:InvalidationType"
    popscope
    initproperty        QName(PackageNamespace("fl.core"), "InvalidationType")

    returnvoid

We can clearly see the definition check right at the constructor’s bytecode start. Se as I said before – we will have static constants not initialized in case check will not pass.
Let’s remove this check, reassemble and run our SWF file. Well, debug Flash Player is not throwing this error anymore and we can see some visual changes in the SWF as well (at least semi-transparent panel is absent now):
Fixed error

We can guess there are lot of such checks in the SWF – that’s why we see all this errors and broken SWF. So we could search for the ApplicationDomain.currentDomain usage through all sources or just create needed fake definition to let that checks pass normally πŸ˜‰
But I like a clean code so my choice is a first approach which one can be easily automated BTW.
After processing SWF and removing all such checks we get the normally working SWF finally! Looks like there is no any other additional checks there.

Let me warn you protector adds this checks to the randomly selected classes, so every single protected file is unique but common check removing tactics is still the same.

As you can see yourself even such tricky hacks as separating SWF and loading them into the same domain, inlining different checks and watermarks can’t guarantee SWF will not be revealed and restored. The only one real thing is the names obfuscation – I think it’s pretty enough in most cases since original names can’t be restored anymore automatically, only manually by reverse-engineer guessing what names were before obfuscation.
If you have anything to add here or you have any questions – you’re welcome, just leave your comment here! Any comments are welcome at all actually)

And yeah, almost forgot – with the last Easter! πŸ˜‰

Found a typo? Please, highlight it and press Shift + Enter or click here to inform me!

Share Button

Comments

Advanced DoSWF encryption? Challenge accepted! — 18 Comments

  1. Great read! I too have the “Invalid SWF file. Wrong Signature” problem, but I guess it’s the same as others, just some binary information only it’s loader can use.

    Anyway thanks for the article.

  2. Pingback: Free SWF Decompilers | 8tut.com

  3. I too had a problem with a SWF file. I used the same method used by “Medic”. I was able to save a few SWF files from the same page and all of them could be opened through SoThink Decompiler except for one. When I try to decompile it, a message appears that this file has been corrupted. I tried “viewing” it through AS3 Sorcerer and it says Invalid SWF Signature.
    Any help is greatly appreciated. Thank you very much! πŸ™‚

    • Hey there! Can’t say anything about it without inspecting that file. Feel free to write me some more details via contact form.

  4. I’m interested in how to Decompile a “Corrupted .SWF File”. I am usning SoThink Decompiler 7 and the method I am using is:

    I am running Firefox – – I load the Flash Game, I then open a new tab and enter “about:Cache” and choose “Disk Cache”

    CNTRL+F to bring up my search bar… I then search “.swf” and scroll through… locate my game.

    I click the game one time and it takes me to the CACHE ENTRY INFORMATION… I locate File On Disk and HIGHLIGHT all info up to CACHE/ thus leaving out the numbers afterwards.

    I pull my address onto my desktop and rename it only adding .swf to the name. Then I click and drag the file to SoThink Decompiler, now a folder opens and I search the numbers that i left out after cache and find my code. ONLY PROBLEM is that when I try to open this code I get the “CORRUPTED .SWF FILE”

    I know this is just a security feature they have implemented, possibly skipping lines, renaming codes, etc…

    What I would LIKE to do is view this Corrupted File and FIX it so I can continue with my mission!! πŸ˜‰

    Any thoughts would be GREATLY appreciated!!! πŸ˜‰

    • Ah, already answered you in email (to others – AS3 Sorcerer decompiles that swf just fine).

    • Lol, man. This is not SWF. It’s just binary trash (array of bytes actually) without loader which decrypts it.