Some Malicious PE Stats – SANS Internet Storm Center


During my last FOR610 session, a student asked me if I had some statistics in mind about the compilers used to generate malicious PE files? A couple of months ago, I shared some stats about the trend in 64bits VS. 32bits malware[1]. Can we go a bit further? I (vibe-)coded a Python script based on the pefile library[2] to extract some info from the PE headers. Indeed, the PE file format contains a lot of metadata! They can be accessed using a lot of tools, like Detect It Easy:

Note: When you assess a PE file, a gold rule to follow is to never trust what you see because these metadata can be tempered!

I tried to detect the compiler using three techniques:

  • The “Rich Header” is a block of data containing useful information (but undocumented by Microsoft). It’s an XOR-obfuscated block that the Microsoft linker embeds between the DOS stub and the NT headers of PE files built with the MSVC toolchain. It records the @comp.id (product id + build number) and use-count of every object file that went into the link, which lets you fingerprint the exact compiler/linker/assembler build used, as well as, even the count of source files. pefile is able to handle these data smoothly.
  • The .NET CLR header (IMAGE_COR20_HEADER) + CLR metadata root, for managed (C#/VB.NET/F#) binaries. This gives the CLR runtime version and the embedded metadata version string (e.g. “v4.0.30319”). This is manually parsed per the public ECMA-335 spec (there’s no MSVC Rich Header in managed-only PEs).
  • A light heuristic string scan for common non-Microsoft compiler signatures (GCC/MinGW, Clang/LLVM, Delphi/Borland, Free Pascal, Go, Rust), since none of those toolchains write a Rich Header. Just because strings are always easy to process and may reveal juicy information!

As said above, there is no official Microsoft documentation for the Rich Header, and no single authoritative mapping of every product-id -> tool/version exists. But they are community references that helps! The well-known “comp_id.txt” is one of them and constantly updated[3].

Now that we have a tool, where can we find fresh meat? Malware Bazaar is a good candidate because it is pretty popular and get new samples daily. They allow (but don’t abuse) to download their data set for free! The first step was to download all the archive they offer[4]. I downloaded a total of 1.3 TB of ZIP archives, one archive per day from 2020-02-24 to 2026-07-08.

Because PE files can be embedded into other files and to avoid using to much storage, I rewrote the script:

  • To unzip files in memory and avoid touching the disk
  • To perform a recursive scan up to 3 levels

Here are the stats I gathered after “a few days” of processing!

High level stats













Total scanned files 23.501.548
Not PE 22.580.068
Valid PE 690.689
Encrypted or unreadable 227.755
Invalid PE 1.508
ZIP Bomb 951
Invalid ZIP 519
Error 36
Skipped Nested ZIP (> 3 levels) 19
File Too Large 3

About the architecture:





32 Bits (or other architecture) 565.179
64 Bits 125.510

Interesting, this confirms my previous research: 32 bits PE file remain popular.

Rich Header:





Rich Header Present 371.103
No Rich Header (Maybe stripping, a non-MSVC toolchain, tempeing,…) 319.586

Top-10 linker versions:













linker 48.0 102.307
linker 6.0 91.788
linker 9.0 62.070
linker 8.0 47.829 
linker 2.25 36.673
linker 10.0 36.549
linker 14.0 29.786
linker 11.0 25.784
linker 14.29 24.655
linker 80.0 22.691

Top MSVC Rich Header compiler builds (useful for clustering samples built in the same environment/campaign):













build 26213 19.603
build 24213 15.389
build 30034 14.325
build 26706 7.755
build 24215 5.253
build 32533 5.033
build 33030 4.442
build 31823 3.738
build 25834 3.530
build 27412 3.294

Finally, and the most interesting status, what tools are used by attackers?













Unidentified (no Rich Header, no signature match)

272.439

39.4%

Microsoft toolchain (Rich Header present, no recognized C/C++ entry) 216173 31.3%
Borland C++/Delphi 20172 2.9%
Microsoft Visual C/C++ (Rich Header, compiler build 26213) 19603 2.8%
GCC / MinGW 13804 2.0%
Go 6254 0.9%
Embarcadero/Borland Delphi 6174 0.9%
Rust 1329 0.2%
Clang/LLVM 91 0.0%
Free Pascal (FPC) 1 0.0%

Interesting to see that arising programming languages like Go or Rust remain exotic in the data set! I expected more popularity!

[1] https://isc.sans.edu/diary/2026+64Bits+Malware+Trend/32718

[2] https://github.com/erocarrera/pefile

[3] https://github.com/dishather/richprint/blob/master/comp_id.txt

[4] https://bazaar.abuse.ch/export/

Xavier Mertens (@xme)

Senior ISC Handler | SANS Principal Instructor | Freelance Consultant

Xameco | PGP Key



Source link

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *