惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

SecWiki News
SecWiki News
N
Netflix TechBlog - Medium
D
Docker
Stack Overflow Blog
Stack Overflow Blog
云风的 BLOG
云风的 BLOG
U
Unit 42
Recorded Future
Recorded Future
G
Google Developers Blog
T
Threatpost
Google DeepMind News
Google DeepMind News
D
DataBreaches.Net
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
The Blog of Author Tim Ferriss
C
Cyber Attacks, Cyber Crime and Cyber Security
A
Arctic Wolf
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
GbyAI
GbyAI
V
Vulnerabilities – Threatpost
Project Zero
Project Zero
WordPress大学
WordPress大学
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
M
MIT News - Artificial intelligence
月光博客
月光博客
Spread Privacy
Spread Privacy
Know Your Adversary
Know Your Adversary
人人都是产品经理
人人都是产品经理
D
Darknet – Hacking Tools, Hacker News & Cyber Security
The Hacker News
The Hacker News
K
Kaspersky official blog
Simon Willison's Weblog
Simon Willison's Weblog
MongoDB | Blog
MongoDB | Blog
J
Java Code Geeks
I
Intezer
Y
Y Combinator Blog
P
Proofpoint News Feed
G
GRAHAM CLULEY
L
LINUX DO - 热门话题
Schneier on Security
Schneier on Security
B
Blog
Jina AI
Jina AI
V2EX - 技术
V2EX - 技术
雷峰网
雷峰网
Last Week in AI
Last Week in AI
V
V2EX
Martin Fowler
Martin Fowler
P
Palo Alto Networks Blog
Latest news
Latest news
Google DeepMind News
Google DeepMind News
L
Lohrmann on Cybersecurity
The Last Watchdog
The Last Watchdog

The Old New Thing

Making an agile version of a Windows Runtime delegate in C++/WinRT, part 1 - The Old New Thing Why has the display control panel pointer truncation bug gone unfixed for so long? - The Old New Thing Speculating on how the buggy control panel extension truncated a value that it had right in front of it - The Old New Thing The case of the invalid function pointer when shutting down the display control panel - The Old New Thing Microspeak: Double-click and drill down - The Old New Thing Why don't we just make the entire stack out of guard pages? - The Old New Thing The case of the mysterious changes to integers when there shouldn't have been any code generation effect - The Old New Thing I've decoded a #pragma detect_mismatch error and fixed the mismatch, but I still get the error - The Old New Thing The other kind of control flow guard check: The combined validate and call - The Old New Thing How did Windows 95 decide that a setup program ran? - The Old New Thing I opened a file with FILE_FLAG_DELETE_ON_CLOSE, but now I changed my mind - The Old New Thing How did we conclude that CcNamespace.dll was the ringleader of a group of DLLs that unloaded prematurely? - The Old New Thing The case of the thread executing from an unloaded third-party DLL - The Old New Thing It rather involved being on the other side of this airtight hatchway: Changing administrative settings - The Old New Thing 2026 mid-year link clearance - The Old New Thing A compatibility note on the abuse of Windows window class extra bytes - The Old New Thing The evolution of window and class extra bytes in Windows - The Old New Thing The case of the DLL that was not present in memory despite not being formally unloaded, part 2 - The Old New Thing Raymond's hot take on Hainanese chicken - The Old New Thing The case of the DLL that was not present in memory despite not being formally unloaded, part 1 - The Old New Thing Cancellation of Windows Runtime activities is asynchronous - The Old New Thing Microspeak elaborated: Isn't escrow just a release candidate by another name? - The Old New Thing In memory of the man who put red and green squiggles under words - The Old New Thing Why doesn't Get­Last­Input­Info() return info for the user I'm impersonating? - The Old New Thing Windows stack limit checking retrospective, follow-up - The Old New Thing Retrofitting the WM_COPY­DATA message onto Windows 3.1 - The Old New Thing The time the x86 emulator team found code so bad that they fixed it during emulation - The Old New Thing How can I schedule work on a thread pool with low latency? Understanding the rationale behind a rule when trying to circumvent it What’s the opposite of Clip­Cursor that lets me exclude the cursor from a region? The Microsoft Company Party where everybody played name tag swap Rotation revisited: Shuffling more than three blocks, and other small notes The back cover of C++: The Programming Language also raises questions not answered by the front cover Rotation revisited: Avoiding having to calculate the gcd when doing cycle decomposition Rotation revisited: Cycle decomposition in clang’s libcxx Rotation revisited: A shocking discovery about gcc’s unidirectional rotation algorithm Rotation revisited: Another unidirectional algorithm The placeholder name for the Windows 8 experience was “modern” Sharing the result of a single Windows Runtime IAsyncOperation among multiple coroutines, part 3 Sharing the result of a single Windows Runtime IAsyncOperation among multiple coroutines, part 2 Sharing the result of a single Windows Runtime IAsyncOperation among multiple coroutines, part 1 If C# and JavaScript lets me await a Windows Runtime asynchronous operation more than once, why not C++/WinRT? A hypothetical redesign of System.Diagnostics.Process to avoid confusion over properties that are valid only when you are the one who called Start Why do you say that a COM STA thread must pump messages if I see sample code creating STA threads and not pumping messages? How do I use Win32 structures from the Windows Runtime? What is the history of the ERROR_ARENA_TRASHED error code? The classic TreeView control lets me sort by name or by lParam, but why not both? Just shows that nobody cares about debugging the parity flag any more The case of the Create­File­Mapping that always reported ERROR_ALREADY_EXISTS
What does it mean when the bottom bit of my HMODULE is set? - The Old New Thing
Raymond Chen · 2026-06-19 · via The Old New Thing

The numeric value of an HMODULE is normally the base address of the DLL or EXE it represents. These base addresses are always multiples of 64KB, so the bottom 16 bits are all zero. Yet you may run across one with the bottom bit set. What does that mean?

Normally, when you load a DLL, it gets an entry in the table of loaded modules. This table is consulted by functions like GetModuleHandle and EnumProcessModules to identify all the DLLs that have been loaded. It also is used to keep track of how many times each DLL has been loaded, so that the DLL is removed from memory when the correct number of FreeLibrary calls has been made.

Many of the flags to the LoadLibraryEx function alter how the system locates the DLL to load, but some of them alter how the DLL is itself loaded into memory. The interesting one here is the LOAD_LIBRARY_AS_DATAFILE flag.

If you ask that a DLL be loaded as a data file, and there isn’t already a copy of the DLL loaded normally, then the loader will search the file system for the DLL in the manner described by the other flags, and then it will just map the DLL into memory without doing any of the usual stuff like applying fixups, and then returns you an HMODULE that represents the location where the DLL was mapped into memory, but it also sets the bottom bit as a note to itself to say “This wasn’t loaded the normal way.”

If the loader decides to map the DLL into memory directly, then the DLL does not get an entry in the list of loaded modules. While the module was loaded in a strict sense of the term, it was not loaded as a functional module. The code is not ready to execute: Its dependencies were not resolved. Its initialization was not run. It’s just a bunch of bytes mapped into memory. If you call GetModuleHandle or EnumProcessModules, the module won’t show up because those functions use the list of “properly” loaded modules, and your datafile DLL wasn’t put on that list.

Functions like FindResource recognize these “not really a module” modules. For example, if you ask to find a resource in a loaded-as-datafile module, the FindResource function knows that it has to convert RVAs in the PE header into physical file offsets.

And when you pass the HMODULE back to FreeLibrary, it sees that the bottom bit is set and knows, “Oh, this was never entered into the module list, so I don’t have to remove it from the module list either.”

This special behavior of the bottom bit is locked into the ABI thanks to this macros provided in the LoadLibraryEx documentation:

#define LDR_IS_DATAFILE(handle)      (((ULONG_PTR)(handle)) & (ULONG_PTR)1)

I don’t know if this use of the bottom bit was intended to be an implementation detail, or whether documenting it was an intentional decision, but what’s done is done, and it’s documented, so it’s too late to change it now.

Bonus chatter: You can see in the documentation another macro that reveals that the second-from-bottom bit is also used as a special signal:

#define LDR_IS_IMAGEMAPPING(handle)  (((ULONG_PTR)(handle)) & (ULONG_PTR)2)

Category

Topics

Author

Raymond Chen

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.