In association with heise online

The pseudo trojan

After a surprisingly short period of familiarisation, I can read the code quite fluently and begin to annotate it. In the end, I use the comments to build a more readily understandable pseudo-code version. While no compiler in the world could transform this version into executable code, my well-trained brain can realise at a glance what is going on.

1 function Main()
2 {
3 var ii as Number;
4 var i as Number;
5 var j as Number;
6 var bytes as ByteArray;
7 var Gaa as Loader;
9 Gaa = NULL;
10 bytes = new ByteArray;
12 j = 0;
13 for (i=0; i <; i++)
14 j = j + 1;
15 bytes[[i]] = ([[i]] XOR Eys.Dae.charCodeAt(j));
16 if (j > Eys.Dae.length) {
17 j = 0; // re-initialise
18 }
19 }

21 Gaa = new Loader;
23 ii = 0;
24 while (ii < 2) {
25 ii = ii + 1; // doesn't make sense, but it is!!!
26 }
28 addChild(Gaa);
29 Gaa.loaderInfo.addEventListener(Event.COMPLETE, function(e:Event));
30 Gaa.loadBytes(bytes);

The function code highlighted in green uses the values in Eys.Dae as a mask which is placed on the large data buffer in a repetitive pattern to combine the values via XOR. i and j are the offsets into the respective buffers. While i runs from the first to the last byte of the data buffer in a linear way, the j counter is reset to 0 whenever it reaches the end of the mask.

Now things get exciting: After the function has decoded the buffer, it loads it via loader.loadBytes() and executes it as a Flash file. Therefore, the decoded buffer has to be a Flash file too. I want to see it!

However, to get to it I need Eys.Dae and Some further nosing around in the P-code produces the structure of the Eys class with its two properties Dae and data. And there it is, our "open sesame"

7     findproperty      Dae
9 pushstring "fx46RIu1kelToyIVefnbEF"
11 setproperty Dae

in form of the Dae string with the XOR code word. data turns out to be a field which is 10,343 bytes long and is filled one by one via pushbyte:

   20    pushbyte          37
22 pushbyte 47
25909 pushbyte 21
25911 newarray [10343]

// fill data array with 10,343 values popped from stack
25914 setproperty data

All I need to do now is find the "pushed" values and decode them myself. I briefly toy with the idea of obtaining them from the formatted abcdump file, but then opt for the more elegant solution and extract them directly from the SWF file. After all, the opcodes of the P-code instructions have been neatly described by Adobe in the VM documentation.

So I look for the start of the loading routine and find it in line 20 of the P-code listing. However, I need the corresponding location in the SWF file. The debug command directly in front of it contains the opcode 0xEF followed by four parameters; the subsequent findproperty turns into 0x5E and, like pushbyte with 0x24, it expects only one argument:

13    debug          1 19 1 4    //  ef ?? ?? ?? ??
18 findproperty data // 5e ??
20 pushbyte 37 // 24 ??
22 pushbyte 47 // 24 ??

That's enough to locate the code in a hex editor. I use the hex editor to copy the entire routine into a file called "push_stub.bin". Next, I quickly throw together a simple decoding program in C++. The task becomes slightly more involved because of the also present pushshort instructions (opcode 0x25) which write an 'unsigned integer' of 30 bits. I'm glad my programming skills are still reasonably up to scratch.

With all this going on, I nearly missed the occasionally inserted dup instructions which repeat the last value written to the stack. However, this ultimately only means adding another IF query and three extra lines of code to my little C++ program which also does the XOR for me and writes the decoded Flash file to "decoded.bin".

Next: The dirty dozen

Print Version | Permalink:
  • Twitter
  • Facebook
  • submit to slashdot
  • StumbleUpon
  • submit to reddit

  • July's Community Calendar

The H Open

The H Security

The H Developer

The H Internet Toolkit