CFF bug in RVA2Offset

kao

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. 😉

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:

foreach (SectionHeader sec in SectionHeaders)
{
   // try to calculate how much data this section actually contains. This goes wrong, if physical size > virtual size.
   dataSize = sec.sizeOfRawData ? align_up(sec.sizeOfRawData, pe.fileAlignment) : sec.virtualSize;

   // check if our RVA falls into this range
   if ( RVA >= sec.virtualAddress && RVA < dataSize + sec.virtualAddress )
   {
      // if so, convert RVA to offset
      return (RVA - sec.virtualAddress + sec.ptrRawData);
   }
}

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:

   // calculate how much data this section actually contains. 
   dataSize = align_up(sec.sizeOfRawData, pe.fileAlignment);
   if (dataSize > align_up(sec.virtualSize, pe.sectionAlignment))
   {
      dataSize = align_up(sec.virtualSize, pe.sectionAlignment);
   }

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. 😀

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

CFF bugs in processing managed resources

kao

Users on tuts4you quite often ask questions like "Can you identify which obfuscator was used". When I was analyzing one such assembly, my CFF Explorer started to act erratically. New tabs would not open and on exit CFF Explorer crashed with access violation.
CFF acting up
That's weird, I said to myself and decided to figure out what's causing it.

Uninitialized buffers and unchecked return values

First bug is a classic. In pseudo-code it looks like this:

bool ReadResourceHeader(ManagedResource resource, ResourcesInfo *info)
{
   DWORD MagicNumber = ReadDword();
   if (MagicNumber != RESOURCES_MAGIC_NUMBER)
      return FALSE;

   if (FAILED(ReadSomething(&xyz)))
      return FALSE;
   info.FieldX = xyz;
   ...
   return TRUE;
}

void BuggyFunction()
{
   ResourcesInfo info;
   foreach (ManagedResource resource in exefile)
   {
      ReadResourceHeader(resource, &info);
      for (int i = 0; i < info.EntryCount; i++)
      {
          ...
      }
   }
}

First issue is that nobody initialized ResourcesInfo structure, so all fields will initially contain random garbage. As soon as ReadResourceHeader fails to read or validate something, it returns, and lots of fields will still contain random garbage.

It wouldn't be a big problem, if Daniel checked the return value of the function. But his code just continues processing even if the data initialization failed. And, to make matters worse, it just hides all exceptions by putting try-except handlers around most of the code. No wonder CFF is occasionally acting weird! 🙂

This bug is quite hard to demonstrate, as it needs to have few lucky coincidences in the uninitialized data. But I'm sure that a skilled person would convert it into arbitrary code execution in no time. Not me, though... 🙂

Buffer overflow

Second bug is also a classic. In pseudo-code it looks like this:

WCHAR Str[MAX_PATH];
ZeroMemory(Str, MAX_PATH * sizeof (WCHAR));
if (!DecodeInt(ptr, &NameSize, &ValueSize))
   return FALSE;
memcpy(Str, ptr, NameSize);

So, what's wrong here? Daniel takes a fixed-size buffer and initializes it with all zeros (unlike previous case). Then he reads size of data (NameSize). And then he copies NameSize bytes into a fixed-size buffer - without checking if that's gonna overflow or not.. Yikes!

Example file demonstrating this bug: https://www.mediafire.com/?x4idsa21toh0t36 (you need to click on Resource Editor -> .NET Resources to trigger the buggy code. Afterwards, CFF Explorer will start acting weird).

Solution

Just like in a previous case where I added support for ConfuserEx and undocumented fields, I had to make few binary patches to CFF Explorer.

Fixed exe file is here: Please get latest version from this post

Have fun and stay safe!

Improved CFF Explorer

kao

CFF Explorer is another invaluable tool for .NET reversers. Unfortunately it is closed-source and is not actively maintained anymore.

One of the most annoying problems is that it cannot correctly process .NET metadata in some assemblies protected by ConfuserEx (and few other protectors).
CFF shows garbage
As you can see, Module data make no sense and Methods also look weird.

Cause of the problem

The problem is caused by obscure and undocumented field in Metadata Table Stream. DNLib is one of the very few tools/libraries that properly supports it:

/// 
/// MDStream flags
/// 
[Flags]
public enum MDStreamFlags : byte {
	/// #Strings stream is big and requires 4 byte offsets
	BigStrings = 1,
	/// #GUID stream is big and requires 4 byte offsets
	BigGUID = 2,
	/// #Blob stream is big and requires 4 byte offsets
	BigBlob = 4,
	/// 
	Padding = 8,
	/// 
	DeltaOnly = 0x20,
	/// Extra data follows the row counts
	ExtraData = 0x40,
	/// Set if certain tables can contain deleted rows. The name column (if present) is set to "_Deleted"
	HasDelete = 0x80,
}

...

/// 
/// Gets the  bit
/// 
public bool HasExtraData {
	get { return (flags & MDStreamFlags.ExtraData) != 0; }
}

...

ulong valid = validMask;
var sizes = new uint[64];
for (int i = 0; i < 64; valid >>= 1, i++) {
	uint rows = (valid & 1) == 0 ? 0 : imageStream.ReadUInt32();
	if (i >= maxPresentTables)
		rows = 0;
	sizes = rows;
	if (i < mdTables.Length)
		mdTables[i] = new MDTable((Table)i, rows, tableInfos[i]);
}

if (HasExtraData)
	extraData = imageStream.ReadUInt32();

This extraData field is causing us troubles.. Oh, well, it's time to fix it! 🙂

Solution

Since CFF Explorer is closed-source, I had to reverse-engineer parts of it. Then I created a small code cave and added extra code that checks flag value and skips over extraData field, if necessary. If you're interested how exactly it was done, check address 004689CC and added code at 00589800.

CFF works fine
Much better, isn't it?

Download link for patched EXE: Please get latest version from this post