Loadlibrary
Loadlibrary
的底层是LoadLibraryEx
第三个参数:
-
DONT_RESOLVE_DLL_REFERENCES
: 这个标志用于告诉系统将DLL映射到调用进程的地址空间中,但是不调用DllMain并且不加载依赖Dll(只映射自己本身)。 -
LOAD_LIBRARY_AS_DATAFILE
: 这个标志与DONT_RESOLVE_DLL_REFERENCES
标志相类似,因为系统只是将DLL映射到进程的地址空间中,就像它是数据文件一样。系统并不花费额外的时间来准备执行文件中的任何代码。 -
LOAD_LIBRARY_SEARCH_USER_DIRS
: 搜索路径的使用使用AddDllDirectory
和SetDllDirectory
设置的路径(保护Dll自己和依赖Dll)。 -
LOAD_LIBRARY_SEARCH_SYSTEM32
: 从%windows%\system32加载Dll和其依赖项。 -
LOAD_LIBRARY_SEARCH_APPLICATION_DIR
: 应用程序安装路径搜索Dll和其依赖项。 -
LOAD_WITH_ALTERED_SEARCH_PATH
: 按照如下目录搜索:
默认环境下LoadLibrary
按照以下目录搜索
SetDllDirectory
函数如下
跟到KernelBaseGetGlobalData
跟到0环可以发现,在转换之后可以得到路径
LoadLibraryExW
函数原型
首先通过BaseGetProcessDllPath
获取路径,然后调用LdrLoadDll
加载dll
NTSTATUS __stdcall LdrLoadDll(PWSTR SearchPath, PULONG LoadFlags, PUNICODE_STRING DllName, PVOID *BaseAddress)
{
//...
if ( SearchPath )
{
result = RtlInitUnicodeStringEx(&DestinationString, SearchPath);
if ( result < 0 )
return result;
NewSearchPath = &DestinationString;
}
else
{
NewSearchPath = &LdrpDefaultPath;
}
//...
v7 = LdrpLoadDll(DllName, (int)NewSearchPath, v6, 1, 0, (int)&DllName);
//...
return v7;
}
再调用LdrpLoadDll
int __stdcall LdrpLoadDll(PCUNICODE_STRING Source, int a2, int a3, char a4, int a5, int a6)
{
//...
if ( !LdrpInLdrInit )
RtlEnterCriticalSection(&LdrpLoaderLock);
//...
LdrpFindOrMapDll(*(PCUNICODE_STRING *)((char *)&v31 + 1), v29, a3, v27[0], (int)&v33, (int)&v31);
//...
if ( v21 & 0x1000000 )
v22 = LdrpCorProcessImports((void *)v21, v33);
else
v22 = LdrpProcessStaticImports(v33, v29);
//...
LdrpRunInitializeRoutines(0);
//...
if ( !LdrpInLdrInit )
RtlLeaveCriticalSection(&LdrpLoaderLock);
}
通过分析函数,其流程如下
-
加载锁
RtlEnterCriticalSection(&LdrpLoaderLock)
-
通过
LdrpFindOrMapDll
加载dll -
处理导入表信息
-
运行回调函数
LdrpRunInitializeRoutines
-
释放锁
RtlLeaveCriticalSection(&LdrpLoaderLock)
在第4步运行LdrpRunInitializeRoutines
其实就是调用DllMain
,也就是说加载dll首先会加载锁,再调用DllMain