How Windows PE Files Use Custom Resources to Embed Anything

Author

Pavel Yosifovich has 25+ years as Software developer, trainer, consultant, author, and speaker. Co-author of “Windows Internals”. Author of “Windows Kernel Programming”, “Windows 10 System Programming, as well as System and kernel programming courses and “Windows Internals” series.

Pavel Yosifovich, Windows internals expert and author of the TrainSec Windows Internals course series, walks through one of the PE format’s most overlooked features: custom resources. Everyone knows PE files contain code. Most people know they contain data. Fewer people think carefully about the resource section — and even fewer realize it can hold absolutely anything. In this post we’ll look at what PE resources actually are, how Windows handles the standard ones, and what you can do with custom resource types that Windows knows nothing about. Along the way, we’ll crack open Process Explorer and find something interesting hiding inside.

What Exactly Lives Inside a Windows PE File?

A Windows PE file — whether it’s an executable or a DLL — can contain three distinct kinds of things.

First, there’s code. This is what the processor executes. Most executables have it; DLLs typically do too, though technically neither is required to.

Second, there’s global data. Global variables end up here. Some of it is read-only — mapped into a protected memory region, so writing to it gives you an access violation. Some is read-write, meaning it can change at runtime. Either way, it’s typed, named, and accessed directly through normal programming constructs.

Third — and this is what we’re interested in — there are resources. Resources are read-only data, but they’re a different kind of read-only than global variables. They don’t have names in the programming sense. They’re more free-form. And technically, they can be anything.

The distinction matters: global data has direct, typed access through the linker. Resources have indirect access through a set of APIs that retrieve raw bytes by type name and ID. That indirection is what makes them flexible.

What Are the Standard Resource Types and How Do You Access Them?

Windows recognizes a set of well-known resource types that are documented and have corresponding APIs. Icons, cursors, bitmaps, menus, dialogs, string tables, manifests — these are all resources. The format of each is documented by Microsoft, and APIs like LoadMenu, LoadIcon, LoadBitmap, and LoadString know how to take a resource and convert it into its runtime representation.

So if you call LoadMenu, Windows reads the menu resource from the PE, interprets the binary format, and hands you back a menu handle you can attach to a window. Simple enough. The application doesn’t need to ship a separate file containing its menu definitions — they’re baked into the binary.

Open any executable in a PE viewer and you’ll see exactly this. Process Explorer has icons, cursors, manifests, menus, string tables, bitmaps — all standard, all interpreted by Windows through documented APIs. Nothing surprising there. But keep scrolling through the resource section and you’ll find things that are decidedly not standard.

What Can a Custom Resource Actually Be?

Here’s where it gets interesting.

A resource doesn’t have to be one of the documented types. It can have any type name or numeric ID you like. Windows has no idea what it is, and it doesn’t need to. The only thing Windows provides is a way to locate and retrieve the raw bytes at runtime. We’ll look at that in a separate video.

In practice, this means you can embed literally any binary data inside a PE file. Configuration files, other executables, drivers, encrypted payloads, lookup tables — it doesn’t matter. As long as your code knows how to interpret the data, those files don’t need to exist as separate files on disk. The PE is self-contained.

I actually did this myself at one point. Process Explorer has a custom resource type called INI — it’s a dark theme resource, and I’m the one who created it. Back when Process Explorer was using my dark mode implementation (before Windows 10/11 had their own), those color values needed to come from somewhere. Embedding them as a custom resource meant the binary didn’t depend on an external config file that could get lost, moved, or placed in the wrong directory.

How Does Process Explorer Hide a Driver and a 64-bit Binary Inside Itself?

This is the interesting question. If you run Process Explorer without admin rights, it works — but with limitations. No driver means you can’t peer inside protected processes like CSRSS (which runs as Protected Process Light, or PPL). With admin rights and a loaded driver, things are different. But look in the Sysinternals folder: where is that driver file?

It’s not there. At least, not as a standalone file.

Open the 32-bit Process Explorer executable in Total PE or Resource Hacker. Look through the resource section. Beyond the expected icons and menus, there’s a custom resource type called BINRES. Two entries. The viewer doesn’t know what they are — there’s no registered handler for BINRES — but we can take a look: both start with MZ, the classic PE magic header, followed by “This program cannot be run in DOS mode.”

(If you’re not already familiar with why inspecting PPL processes requires a driver in the first place, the Protected Processes & PPL post covers the protection level hierarchy and why SYSTEM-level access alone isn’t enough.)

Both entries are embedded PE files.

Export them. Run the larger one — about 2 MB — through your PE viewer. It has its own resources, it’s marked as a 64-bit image, and it’s not a DLL. Extract it and run it directly: you get a fully functional 64-bit Process Explorer. The smaller one — around 32 KB — has a native subsystem, is a DLL, and its imports list only the kernel. In other words, it’s a driver.

So Process Explorer doesn’t need any of those files on disk, because they live inside the binary. At runtime, the 32-bit variant extracts them to a temp directory (or a location it has write access to), loads the driver, and launches the 64-bit version. If the files already exist in the expected location, it reuses them; if not, it re-extracts. Neat, and completely self-contained.

The 64-bit variant, by the way, also has its own BINRES resource — the 64-bit driver, embedded there for when the 64-bit process explorer needs to load it.

What Does the Custom Resource Technique Mean for Security Research?

This pattern should be on your radar — both for what legitimate software does with it and for what malware does.

Embedding payloads inside PE resources is a technique that real tools like Process Explorer use for perfectly reasonable reasons: self-containment, simplified deployment, no dependency on external files. But the same mechanism is a staple of malware. A second-stage payload, shellcode, an encrypted DLL, or a configuration blob can sit quietly in the resource section of a benign-looking binary and be extracted at runtime — without ever touching disk as a standalone file in a way that a naive file-scanner would catch.

Some analysis approaches focus primarily on imported functions, section name heuristics, or overall file entropy. A resource section with an embedded PE inside a named custom type can slip through those if the outer binary otherwise looks clean. And if the embedded content is additionally encrypted or compressed, the resource-section bytes won’t show obvious PE signatures until they’re extracted and decrypted at runtime. For a related technique that also manipulates PE loading to evade detection, the When Process Hollowing Isn’t Process Hollowing post covers how leaving the original image mapped in memory defeats naive hollowing detection — useful context if you’re building detection logic.

$1,938

$1,356 or $140 X 10 payments

Windows Internals Master

Broadens and deepens your understanding of the inner workings of Windows.

Keep Learning

If you want to go deeper on the PE format and how Windows actually loads and maps executables — including section layout, the loader internals, and how resources are accessed at runtime — the Windows Internals course series covers all of this at the level a security researcher actually needs.

For a thorough understanding of the Sysinternals tools — including Process Explorer, how it uses its driver, how it handles protected processes, and what it can and can’t see without one — the Sysinternals Tools Deep Dive 1 course goes well beyond what the documentation tells you.

And if you want to actually write code that embeds and retrieves custom resources — including how to do this in a Visual Studio project, which is what the next video covers — Windows System Programming 1 covers the Win32 resource APIs and the broader programming model you’ll need.


blue depth

About the author

Pavel Yosifovich has 25+ years as Software developer, trainer, consultant, author, and speaker. Co-author of “Windows Internals”. Author of “Windows Kernel Programming”, “Windows 10 System Programming, as well as System and kernel programming courses and “Windows Internals” series.