Under the hood: Yoda’s Crypter 1.3
Yoda’s Crypter (yC) was released 2004, but never seemed to gain popularity amongst malware writers. But still, it isn’t uncommon to run into a sample protected by it. yC utilizes a polymorphic stub to hide better, but the packer can be easily fingerprinted.
I switched on every possible option in the packer, and packed a testfile with it. I’ll try to go through all the options and display them in the code. At the same time, we’ll walk through the unpacking process.
Here’s a screenshot of the options available when packing a file with yC:
When we take look at the entrypoint, there’s a small stub that looks like this:
At location 0040B092 starts the polymorphic part of the code:
The stub always starts with the command lods, and ends with stosb. Once the loop is done, rest of the loader part is visible. When you use breakpoints remember to use hardware breakpoints to make bypassing CRC checks easier.
Next, a check is made whether the binary is running under Windows NT:
Next, we come to a CRC checking:
The checksum function itself is trivial and looks like this:
The value of the CRC will be saved in the eax register, and stored into memory for later use. Next, the loader will install a SEH-frame, and does a check to see whether SoftIce is present:
If you want to avoid unnecessary hassle and the whole SoftIce check, make sure that the je command is taken from offset 0040B115 to 0040B15F. Since the memory address used in the test dword ptr ds:[edx], 1 is a DWORD used for ProtectionFlags, you can bypass a lot of hassle by zeroing out the DWORD from memory. This will effectively bypass all the protection checks in the loader code :)
Next, the loader will load and resolve the necessary imports, and after that it’ll perform a jump to the next stage using a push/ret trick:
The next stage starts with checking whether to use anti-dumping or not:
To bypass this, make sure that the jump from offset 0040B2C0 to 0040B2FD is taken. After this, the loader will mark the PE header as writable.
After fixing the PE Header access the loader will check whether to perform a CRC check. To around that nuisance, make sure that the jump from offset 0040B33F to 0040B42E is taken.
What follows next is the final decryption:
Set a breakpoint at the retn command, and press F9 to run the target. What follows now is the final stage. First, the jump to OEP is prepared:
A check is made to see whether there is a TLS table present:
Depending on the malware you’re unpacking there might or might not be a TLS table present. In both cases, just trace through the code until you hit the mov edx, ebp at offset 0040B59B.
Then the loader checks whether the CRCs were calculated. If they were, and they don’t match, it’ll exit quietly. If you bypassed the CRC as was instructed above, the loader will process forward. A check is made to see whether API redirection was toggled on the options when the binary was packed:
Make sure the jump at offset 0040B5D3 is taken. The loader will start resolving the imports.
I hope you zeroed out the ProtectionFlags up in the beginning, cause we’ll skip some hassle :)
When the import loading starts at offset 0040B62F, trace into the function a few times:
The CALL seen in the above is a small decryption loop to get the cleartext import name. Afterwards, the loader will do an obfuscated jump using the push/ret trick. Trace into the ret, and you’ll see this:
To fasten things up, we’ll set a breakpoint at the memory address used in the jump command. So, in the above sample, set a breakpoint at address 0040B7C8. Then press F9 to run to target:
The loader will check the ProtectionFlags whether to wipe the header to make dumping harder. If you zeroed the ProtectionFlags, you’ll run past this cleanly. Next, loader will check it’s own CRC. The ProtectionFlags don’t affect this, so I hope you used hardware breakpoints.
The CALL in the above is the GetChecksum method that was seen in the above. Whatever you decide to do, make sure you get to the command at offset 0040B82F. Next part will decrypt the jump code to the OEP:
Set a breakpoint at 0040B855, and run to it. Once more, an obfuscated jump is made using the push/ret trick. Singlestep into the ret and you’ll land on a IsDebuggerPresent test:
So, one way or the other, make your way to the mov edx, ebp at offset 0040B890. What follows next is a check on the ProtectionFlags to see whether to do an check for SoftIce.
If you cleared the flags in the beginning you’ll skip right pass this nicely, otherwise navigate through the check manually. After the jump there’s yet another obfuscated jump. This phase will zero out the loader code and data:
While the cleaning is done, the loader gets ready to cause an exception:
As you can see, the code installs an exception handler, and jumps to the zeroed out code which will cause an access violation. This will transfer the execution to the SEH structure that was just installed:
The SEH will make EIP point to the OEP. Trace through the SEH, and trace over the ntdll.dll code until you go into ZwContinue. You’ll land right on the OEP, and can dump the malware. Have fun and enjoy :)