一、显式加载DLL模块使用函数 LoadLibrary/LoadLibraryEx

HINSTANCE LoadLibrary(PCTSTR pSzDLLPathName);

HINSTANCE LoadLibraryEx(
PCTSTR pSzDLLPathName,
HANDLE hF1le,
DWORD dwF1ags
);

pSzDLLPathName:加载的dll文件的路径。
hFile:保留供将来使用,现在是 NULL。
dwFlags:必须将它设置为 0 。或者设置 DONT_RESOLVE_DLL_REFERENCES、 LOAD_LIBRARY_AS_DATAFILE 和 LOAD_WITH_ALTERED_SEARCH_PATH 等标志的一个组合。

(1)DONT_RESOLVE_DLL_REFERENCES:标志使系统只需将 DLL 映射到调用进程的地址空间,而不用调用 DllMain(通常会调用)。

(2)LOAD_LIBRARY_AS_DATAFILE:系统只是将 DLL 映射到进程的地址空间中,就像它是数据文件一样。系统并不花费额外的时间来准备执行文件中的任何代码。如果不指定 LOAD_LIBRARY_AS_DATAFILE 标志,系统会认为需要执行文件中的代码,并用相应的方式来设置页面保护属性。例如使用此标志载入DLL,当对这个 DLL 调用 GetProcAddress 的时候,返回值会是 NULL,而 GetLastError 将会返回 ERROR_MOD_NOT_FOUND。

由于下面几个原因,该标志是非常有用的:

  • 加载只有资源没有函数的DLL时: 首先,如果有一个DLL(它只包含资源,但不包含函数),那么可以设定这个标志,使 DLL的文件映像能够映射到进程的地址空间中。
  • 调用加载资源的函数: 然后可以在调用加载资源的函数时,使用LoadLibraryEx函数返回的HINSTANCE值。
  • 加载EXE访问其中资源: 通常情况下,加载一个.exe文件,就能够启动一个新进程,但是也可以使用 LoadLibraryEx函数将.exe文件的映像映射到进程的地址空间中。借助映射的 .exe文件的HINSTANCE值,就能够访问文件中的资源。由于.exe文件没有DllMain函数,因此,当调用LoadLibraryEx来加载一个.exe文件时,必须设定 LOAD_LIBRARY_AS_DATAFILE 标志。

(3)LOAD_WITH_ALTERED_SEARCH_PATH:用于改变 LoadLibraryEx用来查找特定的DLL文件时使用的搜索算法。如果设定了该标志,那么LoadLibraryEx 函数就按照下面的顺序来搜索文件:

  • pszDLLPathName参数中设定的目录。
  • 进程的当前目录。
  • Windows的系统目录。
  • Windows目录。
  • PATH环境变量中列出的目录。

(4)LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE:与 LOAD_LIBRARY_AS_DATAFILE 相似,但是是以独占方式打开 DLL 文件,禁止任何其他程序在当前程序使用该 DLL 文件的时候对其修改。

(5)LOAD_LIBRARY_AS_IMAGE_RESOURCE:与 LOAD_LIBRARY_AS_DATAFILE 相似,但是载入 DLL 的时候,会对 RVA 进行修复(变成 RAW)。这样 RVA 可以直接使用,不必再根据 DLL 载入到的内存地址来对它们进行转换了。当需要对 DLL 进行解析来遍历 PE 段时,这个标志特别有用。


二、显式卸载DLL模块 FreeLibrary

BOOL FreeLibrary(HINSTANCE hinstD11);

也可以通过调用下面的函数从进程的地址空间中卸载 DLL,该函数是在Kernel32.dll中实现的:

VOID FreeLibraryAndExitThread(HINSTANCE hinstDll, DWORD dwExitCode);

微软创建 FreeLibraryAndExitThread 原因:

假定你要编写一个 DLL,当它被初次映射到进程的地址空间中时,该 D L L就创建一个线程。当该线程完成它的操作时,它通过调用FreeLibrary函数,从进程的地址空间中卸载该 DLL,并且终止运行,然后立即调用ExitThread。但是,如果线程分开调用 FreeLibrary和ExitThread,就会出现一个严重的问题。这个问题是调用FreeLibrary会立即从进程的地址空间中卸载 DLL。当调用的FreeLibrary返回时,包含对ExitThread调用的代码就不再可以使用(指DLL中函数的代码),因此线程将无法执行任何代码。这将导致访问违规,同时整个进程终止运行。

而使用此函数,FreeLibrary 返回时,下一条要执行的指令在 Kernel32.dll 中,可以继续调用 ExitThread。


关于 DLL 使用计数:只有使用计数递减至0,DLL才会从进程空间中撤销映像。

LoadLibrary和LoadLibraryEx 这两个函数用于对与特定的库相关的进程使用计数进行递增;
FreeLibrary和FreeLibraryAndExitThread这两个函数则用于对库的每个进程的使用计数进行递减。


其他函数

GetModuleHandle 函数可以根据名称返回加载的DLL的句柄(地址),当然也可以检查一个DLL是否被映射到进程的地址空间中。

GetModuleFileName 函数可以根据DLL句柄返回DLL完整路径。

20.1 DLL模块的显式加载和符号链接--《Windows核心编程》的更多相关文章

  1. dll显式加载与隐式加载

    使用动态DLL有两种方法,一种是隐式链接,一种是显式链接,如果用loadlibrary就是显示链接,用lib就属于隐式链接. 两种方法对于你的程序调用动态库时没有任何区别,只是你在编程时,步骤是不一样 ...

  2. DLL动态库的创建,隐式加载和显式加载

    动态库的创建 打开VS,创建如下控制台工程,工程命名为DllTest: 在弹出的对话框中选择"DLL"后单击"完成"按钮: 在工程中新建DllTest.h和Dl ...

  3. 《Entity Framework 6 Recipes》中文翻译系列 (28) ------ 第五章 加载实体和导航属性之测试实体是否加载与显式加载关联实体

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-11  测试实体引用或实体集合是否加载 问题 你想测试关联实体或实体集合是否已经 ...

  4. 【EF学习笔记08】----------加载关联表的数据 显式加载

    显式加载 讲解之前,先来看一下我们的数据库结构:班级表 学生表 加载从表集合类型 //显示加载 Console.WriteLine("=========查询集合===========&quo ...

  5. 【DLL】动态库的创建,隐式加载和显式加载(转)

    原文转自:https://blog.csdn.net/dcrmg/article/details/53437913

  6. Windows核心编程 第二十章 DLL的高级操作技术

    第2 0章 D L L的高级操作技术 看了下这章的内容,谈不上高级,都是些常用相关,但是还是有一些细节需要注意. 20.1 DLL模块的显式加载和符号链接 如果线程需要调用D L L模块中的函数,那么 ...

  7. 【windows核心编程】DLL相关(1)

    DLL相关的东西 1.DLL的加载方式 隐式: #pragma comment(lib, "XX.lib"); 编译器去查找名为XX.dll的DLL,除了名字相同,该DLL和该LI ...

  8. 《windows核心编程系列》十九谈谈使用远程线程来注入DLL。

    windows内的各个进程有各自的地址空间.它们相互独立互不干扰保证了系统的安全性.但是windows也为调试器或是其他工具设计了一些函数,这些函数可以让一个进程对另一个进程进行操作.虽然他们是为调试 ...

  9. RequireJS 模块的定义与加载

    模块不同于传统的脚本文件,它良好地定义了一个作用域来避免全局名称空间污染.它可以显式地列出其依赖关系,并以函数(定义此模块的那个函数)参数的形式将这些依赖进行注入,而无需引用全局变量.RequireJ ...

  10. laravel 嵌套的渴求式加载

    今天在通过需求表A查询场地类型表B,然后通过表B的场地类型id去查询表C场地类型名的时候遇到了一个小的问题. 需求表A的字段:id.user_id .name等等: 中间表B的字段:id.appeal ...

随机推荐

  1. 高级数据结构---B树和B+树及mysql索引分析

    mysql索引数据结构:https://www.cnblogs.com/nijunyang/p/11406688.html 几种树结构的对比: 二叉查找树:二叉搜索树,二叉排序树,优点查找快,但是在某 ...

  2. 【驱动】以太网扫盲(二)phy寄存器简介

    PHY 寄存器的地址空间为 5 位,从 0 到 31 最多可以定义 32 个寄存器(随着芯片功能不断增加,很多 PHY 芯片采用分页技术来扩展地址空间以定义更多的寄存器),IEEE802.3 定义了地 ...

  3. C#查找算法2:插值查找

    插值查找,有序表的一种查找方式.插值查找是根据查找关键字与查找表中最大最小记录关键字比较后的查找方法.插值查找基于二分查找,将查找点的选择改进为自适应选择,提高查找效率. 原理:    (midInd ...

  4. Redis 缓存与数据库数据不一致问题

    Redis缓存与数据库数据不一致问题是指在使用Redis作为缓存系统时,由于缓存和数据库之间的操作没有同步或处理不当,导致缓存中的数据与数据库中的数据不同步,产生数据不一致的情况. 现象: 数据库更新 ...

  5. 解决python报错:ModuleNotFoundError: No module named '_sysconfigdata_x86_64_conda_linux_gnu'

    技术背景 在上一篇博客中执行过conda的更新以及用conda安装了gxx_linux-64之后,再执行pip的一些指令时,就会给出如下所示的报错: $ python3 -m pip list Tra ...

  6. 2023第十四届极客大挑战 — PWN WP

    WP可能有点简陋,因为是直接从docx导入到博客的,实在不想再重新写了!大家凑合着看吧!哈哈哈,问题不大! pwn方向出自:队友 nc_pwntools 只要过了chal1和chal2即可执行任意命令 ...

  7. 如何部署两个JMS网关,形成双机热备

    大家使用JMS的过程中,可能会留意到,不管是微服务在注册时,还是RemoteClient构造时,所指向的网关都是一个NetAddress数组,之所以网关地址是多个,而不是一个,那是因为网关是一个双击热 ...

  8. Shell-循环-for-while

  9. [转帖]两种Nginx日志切分方案,狼厂主要在用第1种

    两种Nginx日志切分方案,狼厂主要在用第1种 nginx的日志切分问题一直是运维nginx时需要重点关注的.本文将简单说明下nginx支持的两种日志切分方式. 一.定时任务切分 所谓的定时任务切分, ...

  10. [转帖]clickhouse 超底层原理& 高可用集群 实操(史上最全)

    https://www.cnblogs.com/crazymakercircle/p/16718469.html 文章很长,而且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录 博客园版 为您奉上珍贵 ...