LoadLibraryEx(DONT_RESOLVE_DLL_REFERENCES) is fundamentally flawed

原文地址:http://blogs.msdn.com/b/oldnewthing/archive/2005/02/14/372266.aspx

-----------------------------------分割线-------------------------------------------------------------------------------

There is a flag to the LoadLibraryEx function called DONT_RESOLVE_DLL_REFERENCES. The documentation says,

If this value is used, and the executable module is a DLL, the system does not call DllMain for process and thread initialization and termination. Also, the system does not load additional executable modules that are referenced by the specified module.

If you are planning only to access data or resources in the DLL, it is better to use LOAD_LIBRARY_AS_DATAFILE.

In my opinion, the above text that "suggests" the LOAD_LIBRARY_AS_DATAFILE flag is not strong enough.

DONT_RESOLVE_DLL_REFERENCES is a time bomb.

Look carefully at what the flag does and doesn't do. The module is loaded into memory, but its initialization function is not called and no dependent DLLs are loaded. [Typo fixed, 10am.] As a result, you cannot run code from this DLL. (More accurately, if you try, it will crash because the DLL hasn't initialized itself and none of its imports to DLLs have been resolved.) However, unlike the LOAD_LIBRARY_AS_DATAFILE flag, the loaded DLLcan be found by GetModuleHandle and can be used by GetProcAddress.

Clearly, GetProcAddress is a bad idea for something loaded by DONT_RESOLVE_DLL_REFERENCES, because as we already noted, you can't run any code from the DLL. What's the point of getting a procedure address from a DLL if you can't call it, after all?

The GetModuleHandle part triggers the time bomb.

It is common for somebody to call GetModuleHandle to see if a DLL is loaded, and if so, use GetProcAddressto get a procedure address and call it. If the DLL had been loaded with DONT_RESOLVE_DLL_REFERENCES, both the GetModuleHandle will succeed, but the resulting function will crash when called. The code doing this has no idea that the DLL was loaded with DONT_RESOLVE_DLL_REFERENCES; it has no way of protecting itself.

(Note that code that does this is unsafe anyway, because the code that originally loaded the DLL might decide to do a FreeLibrary on another thread, causing the code to be ripped out from underneath the first thread. This second problem can be "fixed" by using GetModuleHandleEx, which can be instructed to increment the DLL reference count, but that doesn't fix the first problem.)

Even if you used LoadLibrary to load the DLL and passed that handle to GetProcAddress, you still crash, because the LoadLibrary notices that the DLL is already loaded and merely increments the reference count.

#include <windows.h>

typedef HINSTANCE (WINAPI *SXA)(HWND, LPCSTR, LPCSTR,
                                LPCSTR, LPCSTR, int);

int __cdecl main(int argc, char* argv[])
{
 if (argc > 1) // set the time bomb
  LoadLibraryEx("shell32.dll", NULL, DONT_RESOLVE_DLL_REFERENCES);

 // victim code runs here
 HINSTANCE h = LoadLibrary("shell32.dll");
 if (h) {
  SXA f = (SXA)GetProcAddress(h, "ShellExecuteA");
  if (f) {
   f(NULL, NULL, "notepad.exe", NULL, NULL, SW_SHOWNORMAL);
  }
  FreeLibrary(h);
 }
}

If you run this program with no command line arguments, then everything works just fine: Notepad is launched without incident. However, if you pass a command line argument, this sets the time bomb, and the call to ShellExecuteA crashes in flames because shell32.dll was loaded without having its DLL references resolved.

In other words, DONT_RESOLVE_DLL_REFERENCES is fundamentally flawed and should be avoided. It continues to exist solely for backwards compatibility.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值