02 Jun 2017

Enigma’s EP_CryptDecryptBuffer internals

For one of my private projects, I needed to decrypt some data. Original executable uses Enigma's EP_CryptDecryptBuffer function but I needed to implement the same thing using .NET. Much to my surprise, there was no information about what encryption algorithm is used by Enigma or how it works internally. So, I started by compiling Enigma's sample project CryptBuffer and debugging the executable.

TL;DR - IDEA cipher in CBC mode, password = MD5(user_password), IV for CBC comes from IDEA.Encrypt(8-zeroes, password).

Research

After protecting my executable with Enigma, few assembly lines

got changed into something horrible that looked like an Enigma's VM:

I didn't feel like spending my time on analyzing that. Much easier solution was to put hardware breakpoints on my data and password and wait for them to trigger. In a few seconds I landed into code that looked like MD5 (notice the constants!):

and few hits later I landed into code that I didn't recognize at first:

Delphi compiler had helpfully included RTTI information telling me that this second piece of code belongs to a class called TIdeaCipher. Now I had all the information I needed, I just had to put it all together. smile

Implementing decryption in C#

There aren't many IDEA implementations in C#. In fact, there are 2: by BouncyCastle and by LexBritvin. Since I'm not a big fan of huge and complex libraries like BouncyCastle, so I took the simplest possible code: from Github and modified it a bit.

First, we need change password generation algorithm to use MD5 to generate real password:

Second, we need to add support for CBC mode. It requires both calculating correct IV value and pre/post-processing each block we're encrypting or decrypting.

Calculating IV is quite simple:

Processing each block is slightly harder but not a rocket science either. As explained in image borrowed from Wikipedia:
.

Before decrypting the data block, we need to store the encrypted values as IV for the next block. After decrypting the block, we need to XOR each byte of data with a corresponding byte of IV. Unfortunately, during encryption the data flow is different, so the simple crypt function has to be replaced with 2 functions: encrypt and decrypt.

Few more cosmetic changes and that's it! We got clean and nice implementation of EP_CryptDecryptBuffer in pure C#. smile
Download link: https://bitbucket.org/kao/ep_cryptdecryptbuffer/

Have fun!

P.S. My implementation only supports cases where data length is divisible by 8, adding support for other lengths is left as an exercise for the reader.

12 May 2017

VMProtect and dbghelp.dll bug in export processing

If your Olly is crashing when loading executable protected by VMProtect, you most likely have outdated dbghelp.dll somewhere on your path. Grab the latest version from Microsoft and put it in the Olly folder.

Well, that might be enough to work around the issue that I had - but I still wanted to know what's causing the crash.

Cause of the problem

If you try to debug Olly with another Olly, you'll see the Access Violation happening somewhere in dbghelp.dll:

Check register values in Olly:

For some reason, value in EDX is garbage and therefore access violation happens.

Call stack doesn't tell us much:

And same piece of code in IDA doesn't help much either:

So, it's debugging time! Set breakpoint to start of LoadExportSymbols, then set hardware breakpoint on write to address [ebp+ptrAllocatedMemory].

First hit is initialization of variable with 0:

Second hit stores the address of allocated memory:

And third time is a charm:

Good folks at Microsoft have left us with a nice buffer overflow. exportFunctionName is defined as byte array of size 2048 bytes. Any exported function name longer than that will cause stack overflow and (possibly) subsequent crash.

010Editor with PETemplate confirms that the export name is indeed very long (3100 chars):

From what I can tell, it's a similar (but not the same) bug to what was described by j00ru at http://j00ru.vexillium.org/?p=405 (see "PE Image Fuzzing (environment + process)")

Stay safe!

P.S Here's an example file, if you want to test your Olly: https://forum.tuts4you.com/topic/38963-vmprotect-professional-v-309-custom-protection/
P.P.S. CFF Explorer, HIEW and IDA do not show us any exports in this example file - but that's a matter of another story..

21 Apr 2017

Updated Enigma VirtualBox unpacker again

This update has been long overdue. Finally it supports files larger than 2GB! smile

Full changelog:

  • Supports files larger than 2GB. Yeah!
  • Correctly recognizes EnigmaVB 7.50-7.70;
  • You can use command-line EnigmaVBUnpacker.exe /nogui [pathToFile] to unpack file, save results to !unpacker.log and close automatically.
  • NEW: fixed "Error creating temporary file"

Hopefully I didn't break anything during the rewrite. But if I did, send me an email and I'll fix it! smile

EDIT 2x: Very stupid error fixed. /me embarrassed. Sorry.

09 Mar 2017

Recovering data from faulty HDD

I'm extremely lucky. In my 15+ years of messing with computers, I've never lost data due to HDD developing bad blocks and dying. Never! smile

Other people are not that fortunate. So, last weekend I was asked to look at an Acer laptop that just won't start. Windows startup screen shows up, stays for 5-10 minutes and computer reboots. Safe mode doesn't start, Alt-F10 Acer Recovery Console won't show up, nothing. At least I got Windows Memory Diagnostics to show up - and it didn't find anything wrong with RAM.

After I disabled Automatic Restart on System Failure (and waited 10+ minutes for Windows to crash), I got this nice error UNMOUNTABLE_BOOT_VOLUME (STOP: 0x000000ED):

Considering how much time it takes to get to the error, it's probably a bad hard disk.

Disclaimer: data recovery is a very delicate science. If you value your data, I suggest that you use a specialized data-recovery service. But if you are short on cash or just want to have some fun with dying HDD, please read on! Just remember that each HDD issue is different and what worked for me might not work for you.

Disassembly time!

I removed 2 screws to get access to HDD. First thing I saw was this huge scratch all over HDD bracket and cover plastic.

Apparently Mr.Awesome Neighborhood PC Repair Dude has tried to remove HDD with a screwdriver and failed. He had also broken few plastic clips on HDD cover - but who cares about those, right? At least, he did no visible damage to the electronic parts of HDD. smile

Let's try to attach disk to another PC and see if it's really bad.

Windows hates bad disks

Let me tell you, attaching it to my Windows computer was a bad idea. When disk was plugged in, Windows took 5 minutes to start. Any program took 1-2 minutes to start. To be honest, I have no idea why Windows were acting so weirdly, but hey, kids, don't try this at home! smile

At least I got an output from Crystal Disk Info which confirmed my suspicions - bad HDD:

On the side note, Internet is full of really stupid advices. If you suspect that your disk might be physically damaged and dying, never ever use "chkdsk" or similar tools on it! They will likely fail and/or corrupt your data even more. Make a full disk copy and try to fix data there.

Lesson learned - don't use Windows if your HDD is dying. Linux is much safer and data-recovery friendly!

Clonezilla

After some Googling, I found Clonezilla. It's a free Linux-based software that helps with disk imaging/cloning. Reviews were nice, so I made a bootable USB with Clonezilla and tried it out.

It failed.

After enabling "Expert options" and enabling ––rescue flag, it started to do something. However, estimated completion time of 40+ hours wasn't exactly exciting. Apparently, Clonezilla/partclone is slow! I'd love to have a solution that actually works, preferrably today.

Ddrescue and open-source stupidities

Few more Google searches later I learned about ddrescue. It's yet-another-Linux-software that can do almost anything - iff you can master its arcane command-line arguments. As their "manual" tells it succinctly:

This tutorial is for those already able to use the dd command. If you don't know what dd is, better search the net for some introductory material about dd and GNU ddrescue first.

Dude, I AM reading the ddrescue manual. What other introductory material about ddrescue should I search for? sad

Since ddrescue is included in clonezilla USB image, I launched bash and tried the simplest possible version:

It failed with error "Can't open input file: Permission denied". Apparently, you need to use sudo. My next attempt was actually successful!

So, here we are, after 5 hours of running.. Estimated remaining run time is 25 minutes and it has recovered everything but 100MB of data from the HDD... Fingers crossed!

18 hours later my fingers were still crossed.. WTF?

Well... Hidden in the ddrescue manual is this great note:

The 'remaining time' is calculated using the average rate of the last 30 seconds and does not take into account ... Therefore it may be very imprecise, may vary widely during the rescue, and may show a non-zero value at the end of the rescue. In particular it may go down to a few seconds at the end of the first pass, just to grow to hours or days in the following passes.

Holy fuck, why on earth would you show "remaining time" if you very well know that it's "very imprecise"? Does it make your program go any faster? No. Does it help your user in any way? No. It just pisses everyone off.

All in all, ddrescue ran for around 48 hours - recovering 99.98% of data. There were still 45MB of non-scraped data left but I decided that it's not worth to wait 40-50 more hours to rescue mere 20-30 megabytes.

Lesson learned - reading data from unreadable sectors is really slow. Prepare to wait for days!

Analyze the rescued image

Recovering data is great. But what to do with the 0.02% of data that were unreadable? ddrescue log can tell you that sector 0x12345000 was unreadable - but you will have no idea which file occupied that sector. Since I'm a Windows guy, I decided to modify ddrescue's suggested approach a bit and used Windows tools when possible.

First, run ddrescue with ––fill-mode argument:

It will take the image file and mark all unreadable sectors with "BABEC0DE" and relevant sector/position information based on the log file. The affected part of file will look like this:

You can pick whatever text you want - I didn't want to use suggested "DEADBEEF" constant, as it is much more commonly used and might actually appear in some valid files.

Second, reboot into Windows and use OSFMount to mount the created hdimage.img:

Finally you can see files and folders from the damaged disk. Now use whichever Windows tool you like to search for "BABEC0DE". In my case, there were 16 files affected - 12 videos and 4 log files. So, nothing of value was lost! smile

Write the rescued image to the new hard drive

If you have Acronis or other Windows cloning software, you could use that to write HDD image to new disk. Since I didn't have any, I use Clonezilla's bootable USB and Linux standard dd command:

After an hour and a half all the data were transferred to the new disk. Now I just needed to put HDD back into the laptop, boot up the system and run chkdsk to make sure that everything is fixed.

After 3 evenings and plenty of swear words, it's a great success! smile

Final words

There are two kinds of people, those who back up their stuff and those who have never lost all their data. Be smart and make sure you have proper backups! Otherwise, be prepared to spend few evenings learning Linux disk management tools and cursing their command-lines.

Till next time!

06 Feb 2017

Updated Molebox unpacker

During last year, the most common complaint on this blog was "your Molebox unpacker cannot unpack this crazy big EXE of MMORPG game X, Y or Z."

Sounds like an easy problem to fix, right? Well, that's not true - but I finally did it!

TL;DR:

In the rest of the post I'll describe the obstacles I had to overcome while solving this seemingly simple problem.

Delphi TMemoryStream limitation

First, unpacker is written using classic (non-.NET) Delphi and compiled as x86 executable. And standard Delphi streams are retarded. TMemoryStream uses GetMem - which ends up somewhere in Delphi memory manager and VirtualAlloc. That doesn't work well with 800+MB files.

I ended up with implementing custom stream backed by temporary file (CreateFile with FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE).

Pointer magic

Since the original unpacker was using TMemoryStream, the whole file was loaded in memory as a continuous memory block and I could easily read/write each byte of file using pointers. Something like this:

Guess what? Files don't work that way.. sad I had to do a full and complete rewrite of all those methods.

Zlib conflicts

Original unpacker was compiled with Delphi 3. Delphi 3 didn't have Zlib library, so you had to supply your own Zlib implementation. But it won't compile with new versions of Delphi, giving error message

Unit Graphutil was compiled with a different version of zlib.TZDecompressionStream.

The solution was to get rid of my Zlib implementation and rewrite all methods that deal with decompression.

ANSI strings

In Delphi 3 all strings were ANSI. Starting from Delphi 20072009, strings are Unicode. Since Molebox internally uses ANSI, it required changing quite a few structure definitions and rewriting several string manipulation routines. It's a lot of fun (and source of the most obscure bugs), trust me!

Conclusion

I hope you find this unpacker useful. But if it doesn't work for you, please send me an error report with all the details you can and I'll try to fix it. Have fun!

02 Dec 2016

Deobfuscating AutoIt scripts

Every once in a while, someone posts an interesting challenge concerning protected or obfuscated AutoIt scripts. Today I'd like to show some basic approaches to AutoIt deobfuscation. As a target I'll use a very simple protection called AutoGuardIt and the crackme from Tuts4You thread. If you don't have access to Tuts4You, here is the alternative download link: https://www.mediafire.com/?qs52emp7tkk472g

In general, there is nothing hard in decompiling AutoIt scripts. The Autoit script interpreter is designed in such a way that it's really easy to convert P-Code back to the script form. There's also a tidy.exe utility which takes ugly hand-written script and reformats it to make it really pretty. All of this makes writing deobfuscators much easier because you can start with well-formatted AutoIt script and your deobfuscator can consist of simple regexps and string replaces. It will not be very pretty code but it will work.

While I was preparing this blog post, SmilingWolf came up with a full-featured solution written in Python. It's a nice solution but it doesn't explain how or why it works. So, in this article I will explain how the protection works, show the basic techniques and sample source code to defeat each of the protection steps. Making a full-featured deobfuscator is left as an exercise for the reader.

Required tools

  • C# compiler. All my examples were tested under Visual Studio 2010 but any recent version should do
  • MyAutToExe. I'm using my personal modification of myAutToExe. You can download it from Bitbucket: https://bitbucket.org/kao/myauttoexe
  • Tool for testing regexps. I'm using http://regexr.com/
  • Some brains. You can't become a reverser if you can't think for yourself.

Decompiling the script

There are 2 public tools for extracting compiled AutoIt script: MyAutToExe and Exe2Aut.

Exe2Aut uses dynamic approach for obtaining script - it runs the file and gets decrypted and decompressed script from process memory. That's usually the easiest way but you really don't want to run the malware on your computer.

MyAutToExe uses static approach - it analyzes file and tries to locate, decrypt and decompress the script on its own. That's more safe approach but it's easier to defeat using different packers, modified script markers and so on. To extract script from this crackme, I used my own MyAutToExe (see "Required tools" section above).

Analyzing the obfuscation

Once the script is extracted and decompiled, it looks quite strange and unreadable:

Let's look at each of the obfuscation techniques and see how it works and how it can be defeated.

Integer decomposition

AutoGuardIt takes constants and converts them to series of math operations. Example:

Deobfuscator should be able to take the expression, evaluate it and replace the expression with the correct value.

The biggest problem here is the precedence of operations (multiply and divide should be processed before addition and subtraction), so you can't start from the beginning of line and do it one step at a time. This would be wrong:

After some thinking and few Google searches, I found a LoreSoft.MathExpressions library that does all the heavy lifting for me. smile

The following C# code snippet will find all math expressions, extract them, evaluate them and replace expression with the actual value:

Pseudo-random integers

This is quite strange protection that relies on a fact that AutoIt's Random function is actually pseudo-random number generator. If you seed it with the same seed, you get the same results. Example:

In general, it's a very bad idea because there's no guarantee that random number generator will not change in the next version of AutoIt. But for now it works..

Since I was already using myAutToExe, I decided to use RanRot_MT.dll from the package.

a = StringLen("xyz")

Small integers can be obfuscated by using function StringLen:

To clean them up, a simple regex can be used:

End result:

Chr(x)

Some strings in the executable are split into bytes, and each byte is then encoded as call to Chr function:

Another simple regex will kill all of those:

The result will be valid but still hardly readable string:

And one more simple search-replace will fix that:

End result:

If 1 Then

Once you remove the integer obfuscations, you'll see a lot of useless statements like this:

This condition is always true, so we can remove both If and EndIf lines and improve readability.

The problem here is that If's can be nested and you can't just remove first EndIf that you encounter. Consider this example:

Taking all that into account, I came up with this ugly but working* code:

* - see below for some scenarios where this code might fail.

If a = a Then

Variation of previous protection. In such cases, using regexp is much more efficient than simple string comparison

Do Until 1

It's pretty much the same protection as If 1 Then and it can be defeated the exact same way.

While 1 / ExitLoop / WEnd

Another protection of the same kind, just uses 3 lines of code instead of 2. Same approach, just make sure you match the correct lines and remove all 3 of them.

For $random=0 to 123.456 / ExitLoop / Next

Another protection, very similar to previous ones.

Here one must be very careful not to remove the real for cycles from program, so it's better to use regexps. Apart from that, it's pretty much the same code again.

Assign/Execute

This type of protection relies on AutoIt's Assign function. First, an alias to a function is defined:

Later, alias is used to call the function:

Deobfuscation is a simple operation: find all calls to Assign, extract the variable name and the function name, then replace all references to the variable with the function name:

BinaryToString

As you can see in the example above, some strings in the script are replaced with calls to BinaryToString. Here's a another example of the same protection where part of code is replaced with BinaryToString + call to Execute.

Merging all 3 lines into one and converting hex strings to bytes gives us the following code:

which using the methods described earlier can be deobfuscated as:

Functions returning constants

Some strings are not only encoded using BinaryToString but also moved to a separate function.

Deobfuscated code will look like this:

It's quite tricky to find the correct return value for each function and replace function calls with correct values. In addition to that, regexes aren't really suitable for such tasks. smile The code I wrote is really ugly, so I'm not going to show it. Go, figure it out yourself! smile

Switch control-flow obfuscation

This is actually the hardest one of them all. The example code looks like this:

You must find the initial value of the variable. Then you must find the correct start/end of the Switch, all the switch cases and all other assignments to the control variable. Then you'll be able to reorder all the code. It's a moderately hard problem for which I don't have a pretty solution. smile

Here's my code which seems to work:

After cleanup, the deobfuscated code looks like this:

Unused variable assignments

There are random variable assignments sprinkled all over the code.

They are only assigned once and never used. To clean them up, one can locate the assignments using regex, count how many times this variable appears in the code and remove it, if it's only assigned once. Something like this:

You can remove string and integer assignments using very similar regex.

Lather, rinse, repeat

If you run each of the mentioned deobfuscations only once, you'll end up with half-deobfuscated code. Also, there isn't one specific order in which the deobfuscations should be applied. Of course, you could just run the entire loop 100 times, but it's just ugly.

Therefore, I prefer to run the code in the loop like this:

It will run all the deobfuscations until there's nothing left to clean up. Then run tidy.exe on the output and you'll get a nicely readable script.. smile

Possible problems and gotchas

Deobfuscators based on string matching are very easy to implement. However, one must be very careful to write correct regular expressions and string comparisons. My example code works very well on this specific crackme. However, it will mess up with code like this:

You can work around such issues by using more specific regexes with anchors. During my research, I used http://regexr.com/ a lot, and I find it really helpful. Give it a try!

Conclusion

In this article I showed basic approaches that can be used to deobfuscate (not only) AutoIt scripts. They are extremely simple and work well for one-time tasks. For more complex tasks, deobfuscators based on abstract syntax trees or disassembled P-Code are much more efficient but more time-consuming to create.

Have fun!

27 Sep 2016

Why I’m not using x64dbg

x64dbg is (probably) the most user-friendly x64 debugger right now. It's pretty, it's open-source and it usually works. But I find it very hard to switch from WinDbg to x64dbg for several reasons. Some of them are purely emotional (don't worry, I'm not going to bore you to death explaining those) but most of them are technical and related to the way x64dbg is being developed.

So, here goes slightly exaggerated but still serious list of my grievances. smile

Insane system requirements

Both DNSpy and x64dbg suffer from this disease. They love to use the "latest and greatest" of technologies, meaning Visual Studio 2017, .NET 4.6 and what not. That's perfectly fine when you're writing normal software. But debugger is not a normal software.

If I have a customer with a software crashing on his production servers, I can't tell him "You need to install Windows 7 SP2 and 3 different VS redistributables and reboot your machine twice just for me to run my debugger". No, I really can't.

Debugger must run on any and all systems out-of-the box. Olly does that. WinDbg does that. And it wouldn't be hard to link x64bdg with static VS runtime libs and target WinXP while using all the modern goodies. But for some reason it's not done that way.

Updated 30-Sep-2016: Mr. eXoDia let me know that now x64dbg is distributed together with the necessary runtime DLLs. We can remove this grievance off of my list. Hooray! smile

Uncertain direction and feature bloat

Antoine de Saint Exupery said:

Perfection is finally attained not when there is no longer anything to add, but when there is no longer anything to take away

These are really wise words and Olly is designed that way. It does all the basic stuff and has stable SDK that enables plugin authors to implement all the extras.

On the contrary, Mr. eXoDia is adding features left and right and the direction of x64dbg development looks more like this:
BrownianMovement

For example, why does a debugger need 3 (yes, three!) different assembler engines?
assemble

Want another example? Let's just look at the latest weekly digest.. How about this:

... change to the info box. Basically the pointer values in the instruction were not resolved (so if the instruction contained qword ptr ds:[rsp+30] it would not show the value of rsp+30). Personally this is quite useless

Yes, Mr. eXoDia, you're right. It is useless for everyone but few people.

And how about:

The commands plugload and plugunload have been added. This is useful for plugin developers who want to test plugins without having to restart x64dbg all the time.

How many people in the entire world will actually benefit from that? 5? 10?

So, why add such bloat? Once you add something, that something must be maintained. And it's very hard to remove stuff later, as it might break something else. So, please don't..

Broken features

When I am on a job and need to debug something, last thing I want to spend my time on, is fighting with debugger bugs. And my customers certainly don't want to pay me for doing that.

Oleh Yuschuk got it exactly right with the OllyDbg. There were few releases - but they were properly tested and rock solid. From what I can see, x64dbg is going the other way:
compiles_ship_it

Frequent commits like "Fixed search for constant references", "Fixed intermodular calls in module", "Fixed FS/GS memory branch destinations" is not something you want to see in any software, let alone a debugger.

Well, it wouldn't matter much, if there was some known-stable version I could put in my tool collection and use it anytime anywhere. But no, Mr. eXoDia thinks that "No more excuses to not update every day!" is a way to go. Instead of using tried-and-tested version, I should use a probably buggy and unstable one? Dafuq?

Conclusion

So, those are my 3 biggest complaints about x64dbg. I'd love to love x64dbg. I'd love to use x64dbg for everything. But right now I just can't.

How about you?

21 Sep 2016

IDA bug in PE export processing

Hi, I'm back from vacation. And now I'm catching up on all the things that have happened during that time. So, here's a short writeup regarding publicly-known IDA bug and how it will (not) affect reversers.

It was supposed to be a long post showing how to use PatchDiff to locate patched code and then backport it. But, as you'll see later, that's not necessary at all. Maybe another time..

Initial research by Palo Alto

When checking my RSS feed, I stumbled upon the article by Palo Alto researchers called "The Dukes R&D Finds a New Anti-Analysis Technique". It stated:

Using the exported functions by ordinal meant the exported function name was unnecessary, which allowed the developer of this DLL to leave the names for the exported functions blank ... The less obvious reason is that it takes advantage of a bug in the popular IDA disassembler that was recently fixed in the latest version of IDA.

Bug in IDA?! How nice, I want to test this!

Testing the bug

Palo Alto report contained most of the information to reproduce the issue. But IDA 6.95 changelog was even more detailed about what was fixed:

BUGFIX: PE: IDA would not detect DLL exports with empty names
BUGFIX: PE: IDA would show no exports if the export directory's DLL name was an empty string

Armed with the detailed description, I used MASM32 package and their Examples to build a DLL file.

Empty DLL name

First, I took hex editor and changed DLL name in export directory.
export_dll_name_1
export_dll_name_2
Now the exported DLL name is 0-length string. Let's see what IDA does..

I started with IDA 6.95 Demo you can download from official site. No surprises here, the bug is fixed:
export_dll_name_IDA695

Then I took legit copy of IDA 6.90. As already demonstrated by Palo Alto, it's buggy:
export_dll_name_IDA690

Naturally, I wanted to see how old this bug is. So, I took a copy of IDA 6.80. Surprise, surprise, it's not buggy!
export_dll_name_IDA680
So, it looks like this bug was introduced in IDA 6.90.

Empty export name

For completeness sake, I repeated the experiment with empty exported API name.
export_api_name_1
export_api_name_2
The results were identical, the bug is only present in IDA 6.90.

How it affects you?

If you're using IDA Free, latest version is 6.95. You're good.
If you're using legit IDA, you have received the updated version 6.95. You're good.
If you're using the latest publicly leaked version of IDA (6.80), it didn't have the bug. So, you're good, too.

To sum it up - it's a fun bit of information but no one is really affected. Good news, I guess. smile

Example DLL files if you want to verify your tools: https://www.mediafire.com/?c9t6hm4icd3kk46

28 Jun 2016

Bugs in Enigma Virtual Box

While working on a new version of my static EnigmaVB unpacker, I tried to generate test files to cover most of the Enigma Virtual Box features. In the process, I ran into quite a few bugs in Enigma Virtual Box v7.40.

So, here's a short list:

Registry virtualization

1. Importing REG file with wrapped lines:

Data get truncated at the end of first line.

2. Importing REG file with entry type REG_NONE:

It gets virtualized as a string value "hex(0):"

File virtualization

1. If size of any embedded file > 4GB: creates invalid x86 executable;
2. If total size of all embedded files > 4GB: creates invalid x86 executable;
3. If size of main EXE > 2 GB: creates executable that seems to be valid but won't run;
..and that's only for x86 executables. I wonder how many more issue will surface when I start testing x64 executables. wink

TLS callbacks

Since Enigma Virtual Box uses TLS callbacks to initialize its hooks and handlers, it will (accidentally?) break any executable that also uses TLS callbacks. However, it preserves TLS StartAddressOfRawData, EndAddressOfRawData and AddressofIndex fields. Very weird.. smile

Have fun (and remember to test your software properly)!

06 Jun 2016

CFF bug in RVA2Offset

Yes, this is yet another post about bugs in CFF Explorer. So far I've described:

Today, I'll describe an issue with CFF Explorer's RVA2Offset function and provide a solution to the problem (patched executable).

And no, I really don't hate CFF Explorer. In fact, it's one of my favorite tools and I use it every day - that's why I keep noticing more and more issues with it. wink

Introduction

Here is an executable that demonstrates the bug: https://www.mediafire.com/?9ju0cfm36b32ys9

If you open it in CFF Explorer and try to check Import Directory. In this case, CFF will show that it's empty.

cff_bug_empty_imports

That's incorrect, import directory of this executable is present and valid. It contains 2 DLLs and 3 APIs:

actual_imports

In other executables, it can get stuck into eternal loop or - even worse - show incorrect data.

Also, CFF's Address Converter feature is affected. In my demo executable, try convert RVA 0x2000 to file offset. It will return 0:

CFF_address_converter_bug

So, what's happening here?

Background of the bug

To put it simply, bug is triggered when one section in executable has SizeOfRawData much larger than VirtualSize. In my crafted executable it looks like this:

CFF_cause_of_bug

Nitpickers corner: it's actually more complicated. The exact condition is ALIGN_UP(sec.SizeOfRawData, pe.FileAlignment) > ALIGN_UP(sec.VirtualSize, pe.SectionAlignment). But who cares about those small details, anyway?

And the offending pseudo-code in CFF Explorer looks something like this:

Fixing the bug

Since I'm doing binary patches to CFF Explorer, I'm quite limited to what I can do and how. In the end, I chose the following pseudocode:

While it doesn't look like much (and it doesn't cover edge cases, for example, when PE file is truncated), in general it should work just fine.

Download link for fixed CFF Explorer: https://www.mediafire.com/?5eg1bs9a9bv39ge
It also includes all my previous fixes.

Conclusion

While writing this post, I noticed that PE viewer in ExeinfoPE v0.0.4.1 has very similar bug. And ProtectionID v6.6.6. And PETools 1.5 Xmas edition. And Stud_PE 2.1. And LordPE. And then I ran out of tools to test. bigsmile

Obviously, I can't fix them all. All I can say - use PE editing/viewing tools that actually work, for example, HIEW or IDA. And when you're writing your own PE parser library, make sure you test it on weird executables.

Have fun and stay safe!

Further reading