F00F bug or why morons shouldn’t be writing about security (again)


Every once in a while, I read an article about security which is so incredibly bad that I just have to comment on it.

This time, it's an article from iTWire called "When F00F bug hit 20 years ago, Intel reacted the same way". It's written by Sam Varghese who claims to have decades of experience in the field. Let's see..

Make Intel CPU to hang remotely and anonymously?

Let me write that down!

Any Intel Pentium/Pentium MMX could be remotely and anonymously caused to hang, merely by sending it the byte sequence "F0 0F C7 C8".

This statement is incorrect in so many ways!

Yes, there was a bug in Pentium CPUs. CPU would freeze when executing instruction lock cmpxchg8b eax which has the opcode "F0 0F C7 C8". Can you see the difference?

  1. CPU doesn't hang on merely seeing the data sequence "F0 0F C7 C8". It hangs when trying to execute these bytes. Big difference! And if someone is able to run arbitrary instructions on your CPU, you have much bigger problems than just a simple hang.
  2. There is no f*ing way to run any code on any CPU remotely and anonymously. You can remotely exploit a bug in firmware/OS/software to execute some code - that's called remote code execution. But that is not specific to Intel CPUs and have nothing to do with the F00F bug in particular.

Dear Sam Varghese, please stop writing about security. Open a hotdog stand or do anything else that doesn't involve computers. You just don't get them.

MSDN is sometimes wrong


While reversing a certain executable, I needed to figure out what data it sends over SSL/TLS. It's not using standard WinHttp functions but custom Schannel/SSPI implementation that's similar to CURL.

One of the steps in the process is to obtain SecurityFunctionTable using code like this:

pInitSecurityInterface = (INIT_SECURITY_INTERFACE)GetProcAddress( g_hSecurity, "InitSecurityInterfaceA" );
if(pInitSecurityInterface == NULL) { 
   printf( "Error 0x%x reading InitSecurityInterface entry point.\n", GetLastError() ); 
   return FALSE; 
g_pSSPI = pInitSecurityInterface(); // call InitSecurityInterfaceA(void);
if(g_pSSPI == NULL) { 
   printf("Error 0x%x reading security interface.\n", GetLastError()); 
   return FALSE; 

And then you can use the obtained SECURITY_FUNCTION_TABLE to call different SSPI functions.

Sure, InitSecurityInterface and the SECURITY_FUNCTION_TABLE structure are described on MSDN (just the start of structure is shown for brevity):

So, I added the corresponding structure definition to IDA and tried to analyze the calls. It made no sense whatsoever.

What's happening here?

After some head scratching, I searched WDK for SECURITY_FUNCTION_TABLE definition. And here it is:

I wonder where the Reserved1 field has gone... 😉

Fix the structure definition in IDA and magically all the calls make perfect sense:

Morale of the story - MSDN is great for quick reference but having a full Windows SDK/WDK installed is priceless.

Morale #2 - always carefully check IDA standard structures. Apparently, IDA doesn't have SECURITY_FUNCTION_TABLE defined - but it does have proper definition for SecurityFunctionTable.

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:

Log data, item 0
 Message=Access violation when reading [C4983C3E]
6D529B8E   8B55 F4          MOV EDX,DWORD PTR SS:[EBP-C]
6D529B91   66:833C42 00     CMP WORD PTR DS:[EDX+EAX*2],0
6D529B96   75 07            JNZ SHORT DBGHELP.6D529B9F

Check register values in Olly:

EAX 00000000   <----------------
ECX 00000001
EDX C4983C3E   <----------------
EBX 0458A390
ESP 0018A450
EBP 0018AC94
ESI 045EE7E8
EDI 045EF738
EIP 6D529B91 DBGHELP.6D529B91

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

Call stack doesn't tell us much:

Call stack of main thread
Procedure / arguments                 Called from              Name from PDB
DBGHELP.6D52997D                      DBGHELP.6D52ACFD         LoadExportSymbols(struct _MODULE_ENTRY *, struct _IMGHLP_DEBUG_DATA *)
DBGHELP.6D52A755                      DBGHELP.6D52B035         load(char *, DWORD)
DBGHELP.6D52ADB8                      DBGHELP.6D5264B2         InternalLoadModule(char *, char *FullPath, char *Str1, unsigned __int64, unsigned __int32, void *, struct _DBGHELP_MODLOAD_DATA *, unsigned __int32)
DBGHELP.SymLoadModuleEx               DBGHELP.6D526502              
DBGHELP.SymLoadModule64               DBGHELP.6D526522            
DBGHELP.SymLoadModule                 OLLYDBG.00491502

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

.text:6D529B8E loop_check_something:                   ; CODE XREF: LoadExportSymbols(_MODULE_ENTRY *,_IMGHLP_DEBUG_DATA *)+225j
.text:6D529B8E                 mov     edx, [ebp+ptrAllocatedMemory]
.text:6D529B91                 cmp     word ptr [edx+eax*2], 0 ; <----------------
.text:6D529B96                 jnz     short loc_6D529B9F
.text:6D529B98                 add     [ebp+var_10], 10h
.text:6D529B9C                 inc     [ebp+arg_4]
.text:6D529B9F loc_6D529B9F:                           ; CODE XREF: LoadExportSymbols(_MODULE_ENTRY *,_IMGHLP_DEBUG_DATA *)+219j
.text:6D529B9F                 inc     eax
.text:6D529BA0                 cmp     eax, ecx
.text:6D529BA2                 jb      short loop_check_something

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:

.text:6D529986                 xor     ecx, ecx
.text:6D529988                 test    byte ptr dword_6D57F438+1, 4
.text:6D52998F                 mov     [ebp+ptrAllocatedMemory], ecx

Second hit stores the address of allocated memory:

.text:6D529AA7                 call    _pMemAlloc@4    ; pMemAlloc(x)
.text:6D529AAC                 xor     ecx, ecx
.text:6D529AAE                 cmp     eax, ecx
.text:6D529AB0                 mov     [ebp+ptrAllocatedMemory], eax
.text:6D529AB3                 jz      loc_6D529D56

And third time is a charm:

.text:6D529AF5                 lea     edx, [ebp+exportFunctionName] ; 0018A45C
.text:6D529AFB                 sub     edx, eax        ; EDX = FBAD009A
.text:6D529AFD loop_strcpy_overflows:                  ; CODE XREF: LoadExportSymbols(_MODULE_ENTRY *,_IMGHLP_DEBUG_DATA *)+188j
.text:6D529AFD                 mov     cl, [eax]
.text:6D529AFF                 mov     [edx+eax], cl   ; <----------------
.text:6D529B02                 inc     eax
.text:6D529B03                 test    cl, cl
.text:6D529B05                 jnz     short loop_strcpy_overflows

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

NetBalancer: should you trust it?


Last few months people kept bashing antivirus and security software in general. Like on Twitter or their personal pages. Sure, Twitter is full of opinionated idiots who just love to complain about everything that doesn't match their point of view. On a few occasions they are right and even I have written about some of the issues with antiviruses before.


But you'd be f*king stupid to delete your antivirus just because it has some bugs. Doorlocks get picked by criminals every day and people still use them. Professional lockpickers do exist - it's their job to break lock's security mechanism and get you back in the house when you lose your keys. Tavis Ormandy is a professional lockpicker - only he works in the digital world. It's his job to break digital security mechanisms and help vendors to fix the issues.

Having said that, not all software is created equal. Sometimes new and dangerous features get added to an otherwise great software. These features look good on paper but they can really ruin someone's day. Today, I'll demonstrate one such feature.

Introducing SeriousBit NetBalancer

NetBalancer is a Windows application for local network traffic control and monitoring. It shows you the network traffic on your computer and helps you to set limits, priorities and rules for that traffic. Some sort of a firewall - but better. It can prioritize your traffic, schedule it for specific times, do statistics, make graphs and charts and what not. And it looks really good!

Predefined Priorities

NetBalancer's Predefined Priorities is a feature that looks great on paper.

For those of you who are not sure what priorities are best for your PC we decided in NetBalancer 8.5 to add some predefined priorities.
These priorities include the most used programs and processes, currently about 1700 total (and counting), and are set to match the needs of most users

It could be used for virtually everything:

  • giving high priority to VoIP applications and games
  • making sure background processes (eg. software updaters) don't interrupt your Youtube experience
  • and even blocking malware

The possibilities are endless. In fact, virtually all of the antivirus products use similar databases to preconfigure their firewalls. It makes total sense after all!

However, the devil is in the details. All such databases must be maintained. New version of Skype comes out, you need to update database. League of Legends releases new update, you must update the database. And you must do it very fast, so that your users don't suffer from misbehaved firewall. It's a lot of work.

Since NetBalancer is made by a small company called SeriousBit SRL, I was naturally curious how they manage to do that. 🙂

Inside Predefined Priorities

First, I needed to obtain the complete database of the priorities. You could try to find something in C:\ProgramData\SeriousBit\NetBalancer\ but it would be more interesting to find and download correct files for the official servers, right? 🙂 After a quick string search, I learned that priorities can be downloaded from https://netbalancer.com/api/internal/predefinedpriorities. It's a huge JSON file but isn't encrypted or signed in any way.

That's a serious red flag right there. Security companies vigorously protect their databases - it's their know-how, their crown jewels. And they use digital signatures to make sure that the databases aren't tampered with. After all, which developer wants to see his product in news like "MalwareBytes: multiple security issues"? 🙂

OK, in this case JSON file is downloaded over HTTPS, therefore it's slightly harder to intercept traffic and modify it. So, let's ignore this issue for a moment and look at the JSON data instead.

In a minute or two, I was in the full "WTF?" mode.

Here's an excerpt from the JSON, prettified for easier viewing:

    "$type": "Events.PredefinedPriority, Events",
    "ExeNameCrc": 1772190657,
    "Priority": {
      "$type": "Events.AppPriorityInfo, Events",
      "AdapterId": -1521929413,
      "ExecutablePath": "driver.okaya.g200l.rar",
      "DownloadPriority": "High",
      "UploadPriority": "Normal",
      "DownloadLimit": 30000,
      "UploadLimit": 30000,
      "DownloadDelay": 0,
      "UploadDelay": 0,
      "DownloadDelayJitter": 0,
      "UploadDelayJitter": 0,
      "DownloadDropRate": 0.0,
      "UploadDropRate": 0.0,
      "PerConnectionLimits": false
    "$type": "Events.PredefinedPriority, Events",
    "ExeNameCrc": 3944917558,
    "Priority": {
      "$type": "Events.AppPriorityInfo, Events",
      "AdapterId": 2089926557,
      "ExecutablePath": "msi1f5.tmp",
      "DownloadPriority": "High",
      "UploadPriority": "Normal",
      "DownloadLimit": 30000,
      "UploadLimit": 30000,
      "DownloadDelay": 0,
      "UploadDelay": 0,
      "DownloadDelayJitter": 0,
      "UploadDelayJitter": 0,
      "DownloadDropRate": 0.0,
      "UploadDropRate": 0.0,
      "PerConnectionLimits": false

Setting high priority for RAR and TMP files.. More than 2000 entries like that? WTF?

How about this?

    "$type": "Events.PredefinedPriority, Events",
    "ExeNameCrc": 4213633860,
    "Priority": {
      "$type": "Events.AppPriorityInfo, Events",
      "AdapterId": -118159810,
      "ExecutablePath": "sexual babe receives screwed - xnxx.com.flv",
      "DownloadPriority": "High",
      "UploadPriority": "Normal",
      "DownloadLimit": 30000,
      "UploadLimit": 30000,
      "DownloadDelay": 0,
      "UploadDelay": 0,
      "DownloadDelayJitter": 0,
      "UploadDelayJitter": 0,
      "DownloadDropRate": 0.0,
      "UploadDropRate": 0.0,
      "PerConnectionLimits": false

Yes, I want to download my porn with a high priority, thank you very much!

But how on earth that got through the QA process? Is there any QA process in SeriousBit SRL? I highly doubt that..

Unsolicited user data gathering

All those entries made me think - how is it possible that NetBalancer's database contains such crap information? Most obvious answer was - it's submitted by users. To verify the guess, I took a sneak peek inside SeriousBit.NetBalancer.Core.dll. And there it was:

  public static void smethod_1(bool bool_0)
      using (WebClient webClient = new WebClient())
        NameValueCollection expr_77 = new NameValueCollection();
        expr_77["priorities"] = gparam_.smethod_0(true);
        NameValueCollection data = expr_77;
        bytes = webClient.UploadValues("https://netbalancer.com/api/internal/predefinedpriorities", "POST", data);
    catch (Exception arg_126_0)
      GClass48.smethod_11(arg_126_0, "LoadFromWww", "C:\\wrk\\seriousbit\\netb\\deskapp\\src\\SeriousBit.NetBalancer.Core\\Priorities\\PredefinedPrioritiesTable.cs", 91);
      if (bool_0)
      GClass51.smethod_1("LastPredefinedPrioritiesLoaded", DateTime.Now);

The call is coming from here:

        if (GClass51.smethod_0("PredefinedPrioritiesEnabled", false, true) && GClass51.smethod_0("LoadPredefinedPrioritiesAutomatically", true, true) && GClass51.smethod_0("LastPredefinedPrioritiesLoaded", DateTime.MinValue, true) < DateTime.Now.AddDays(-7.0))

There you have it - if you have enabled "Predefined Priorities", NetBalancer will also silently upload all your priorities to their servers.

Want to wreak some havoc with unsuspecting users of NetBalancer? Post your own JSON file that blocks all traffic for all the browsers - apparently NetBalancer doesn't validate user submissions and will happily distribute them to other users. 😀

Abusing existing database

I was also wondering what is the meaning of ExeNameCrc field. 🙂 Turns out that NetBalancer uses CRC32 of filename as a key in the dictionary that manages process priorities To make matters easier, they also supply you with a proper filename in ExecutablePath field. So, if you want to make sure your malware has unlimited traffic and high download priority, just name it swarm.exe:

    "$type": "Events.PredefinedPriority, Events",
    "ExeNameCrc": 1475648703,
    "Priority": {
      "$type": "Events.AppPriorityInfo, Events",
      "AdapterId": 1630508967,
      "ExecutablePath": "swarm.exe",
      "DownloadPriority": "High",
      "UploadPriority": "High",
      "DownloadLimit": 0,
      "UploadLimit": 0,
      "DownloadDelay": 0,
      "UploadDelay": 0,
      "DownloadDelayJitter": 0,
      "UploadDelayJitter": 0,
      "DownloadDropRate": 0.0,
      "UploadDropRate": 0.0,
      "PerConnectionLimits": false

Indeed, CRC32("swarm.exe") = 1475648703, as you can verify in some online CRC32 calculator..

A quick test confirms that too:


Trust is a delicate subject. On the one hand, all the Cloud and Connected things make your life much easier. On the other hand, you must choose wisely who you trust and what data he/she can access. I doubt that SeriousBit intentionally created such buggy and dangerous feature in NetBalancer. But that doesn't mean I would ever want it to be running on my machine!

Have fun and stay safe!

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

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! 🙂

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:

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

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:

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?


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?

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

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

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!
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.
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. 🙂

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

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

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

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

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


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.


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


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:


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:


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.


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