Windows API 编程-----DLL编程之禁止加载自己
和可执行文件一样,动态链接库也有自己的入口地址,如果系统或者当前进程的某个线程调用LoadLibrary函数加载或者使用FreeLibrary卸载该动态链接库的时候,会自动使用3个特定的堆栈参数跳转到该地址来运行。入口函数是为了完成动态链接库代码的初始化和善后工作,比如卸载后的资源释放。
这三个参数具有特殊的含义。
BOOL APIENTRY DllMain(
HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
第一个参数是实例句柄,这个所谓的句柄实际上就是该加载进程在内存中的景象地址,注意进程句柄和动态链接库的模块句柄是不一样的。比如,如果用户想使用hModule去加载该动态链接库中的一个位图资源,那将永远得不到结果。动态链接库的模块句柄依附于加载进程,脱离进程独立于系统空间中的动态链接库是不存在的,也没有意义。动态链接库总是要加载到进程中的某个地址,该地址就是动态链接库的模块句柄,这个句柄不同于进程实例句柄,它是相对于进程入口地址的一个偏移量,只有通过模块句柄才能寻址到该动态链接库中嵌套的各种窗口或者其他资源。
ul_reason_for_call 参数表示该动态链接库是在什么条件下被加载的,即加载的原因。当用户显式采用LoadLibrary(Ex)函数加载一个动态链接库或者由进程本身隐式加载该库时,该入口函数就会被调用,入口参数 ul_reason_for_call 这时就等于DLL_PROCESS_ATTACH,入口函数的返回值就是LoadLibrary函数的返回值,它们都是通过EAX寄存器来传递的。根据LoadLibrary(Ex)函数的说明,这个函数如果返回一个NULL值,表示加载失败。实际上在DllMain 函数中,只要返回FALSE,LoadLibrary(Ex)函数就会返回一个NULL值。如果动态链接库需要排他调用,可以在入口点函数中判断加载进程的文件名,或者履行其他合法性检查;如果不希望被某个进程调用,可以直接在DllMain函数中返回FALSE。DLL_PROCESS_ATTACH分支往往用于实现系统初始化,比如建立数据库链接,创建钩子函数,分配系统资源,保存入口进程实例句柄等。
同样,当进程不再使用该动态链接库,比如调用ExitProcess函数或者显式调用FreeLibrary函数时,系统又会使用DLL_PROCESS_DETACH参数执行相关分支。用于释放系统资源、断开数据库链接、卸载钩子函数、关闭文件、释放内存等。
注意:DLL_PROCESS_DETACH分支的执行是有条件的,进程的意外终止,并不会执行DLL_PROCESS_DETACH分支语句,这样分支中的关闭资源、断开链接、关闭文件等善后语句就无法执行,这将会造成一些数据的潜在丢失。因此除非万不得已,不要轻易使用TerminateProcess函数终止进程执行。
如果线程创建时DLL完成到进程空间的映射,这样系统会使用DLL_THREAD_ATTACH进入入口点。而系统执行ExitThread函数时会执行DLL_THREAD_DETACH分支。同样的规则适用于线程,用户不要轻易使用TerminateThread函数,这也会导致一些不可预知的内存泄漏或者资源没有释放和数据丢失。
如果用户不在乎DLL_THREAD_DETACH和DLL_THREAD_ATTACH通知,又希望提高创建和撤销线程的性能,可以在收到DLL_THREAD_ATTACH通知时,调用DisableThreadLibraryCalls函数。
注意:关于lpReserved参数----在静态(隐式)加载和调用LoadLibray函数实现动态(显式)加载动态库时,这两种情况是不一样的,动态加载时这个值为0。如果用户希望自己编写的的动态链接库只能被动态加载或者只能被静态加载,可以通过判断这个参数来实现。
代码示例:
dllmain.cpp(生成mydll.dll):
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"
#include<stdio.h>
#include<Psapi.h>
#include<Windows.h>
typedef void(*pFnPtr)(char*); BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{ char szName[MAX_PATH];
if (lpReserved != )
{
//只允许动态加载,静态加载将提示错误并退出
MessageBox(NULL, "只允许动态加载", "Sorry", MB_OK);
return FALSE;
}
GetModuleBaseName(GetCurrentProcess(),NULL ,szName,MAX_PATH);//获取当前主进程的base name
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
//故意将调用进程的名字改为test.exe,该动态链接库将无法加载。
if (strcmp(szName, "test.exe") == )
return FALSE;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
} extern "C"
{
//主调进程将调用该函数,该函数再调用主调进程的ExeFn函数
_declspec(dllexport) int fnImportingDLL()
{
MessageBox(NULL, "Dll Function called!", "mydll", MB_OK);
pFnPtr fn = (pFnPtr)::GetProcAddress(GetModuleHandle(NULL), "ExeFn");
if (fn)
fn("梦回吹角连营");
else
{
MessageBox(NULL, "It Did not work:", "From DLL", MB_OK);
return -;
}
}
}
main.cpp(生成console.exe):
#include<iostream>
#include<Windows.h>
#define _DYNAMIC_
#ifndef _DYNAMIC_
#pragma comment(lib,"mydll.lib") //静态加载
extern "C" _declspec(dllexport) int fnImportingDLL();
#endif
typedef int(*pfnImportingDLL)(); using namespace std;
int main(int argc, char* argv[])
{
#ifdef _DYNAMIC_ //动态加载
pfnImportingDLL fnImportingDLL = NULL;
HMODULE hModule=::LoadLibrary("mydll.dll");
if (hModule == NULL)
{
cout << "无法加载mydll.dll" << endl;
return -;
}
fnImportingDLL =(pfnImportingDLL) GetProcAddress(hModule, "fnImportingDLL");
if (fnImportingDLL == NULL)
{
cout << "找不到fnImportingDLL函数" << endl;
return -;
}
#endif
cout << "I'm going...\n";
fnImportingDLL();
cout << "Game Over\n";
#ifdef _DYNAMIC_
::FreeLibrary(hModule);
#endif
return ;
} extern "C"
{
//该函数将有动态链接库中的函数来调用
_declspec(dllexport) void ExeFn(char* lpszMessage)
{
MessageBox(NULL, lpszMessage, "From Exe", MB_OK);
}
}
将生成的 console.exe文件和mydll.dll文件放在同一个文件夹下
注释掉 _DYNAMIC_ 宏将静态加载mydll.dll,这样会弹出对话框提示只能动态加载,因为在DllMain中检查了lpReserved的值并做了判断。


将console.exe的名字改为test.exe,然后在cmd中运行test.exe,将显示无法加载mydll.dll。

Windows API 编程-----DLL编程之禁止加载自己的更多相关文章
- 使用Windows API进行串口编程
使用Windows API进行串口编程 串口通信一般分为四大步:打开串口->配置串口->读写串口->关闭串口,还可以在串口上监听读写等事件.1.打开和关闭串口Windows中串口 ...
- dll的两种加载方式(pend)+ delayload
看过关于动态库的调用例子,于是决定动手做一做:dll的对外接口声明头文件,Mydll.h: //Mydll.h #include <stdio.h> #include <stdlib ...
- ArcGIS API for Silverlight 调用GP服务加载等值线图层
原文:ArcGIS API for Silverlight 调用GP服务加载等值线图层 第二篇.Silverlight客户端调用GP服务 利用ArcGIS API for Silverlight实现G ...
- [转] 从 dll 程序集中动态加载窗体
无涯 原文 从 dll 程序集中动态加载窗体 [原创] 昨天晚上花了一晚上时间写了一个从程序集中动态加载窗体的程序.将任何包含窗体的代码编译成 dll 文件,再把 dll 文件拷贝到本程序的目录下,本 ...
- Windows -- 从注册表删除IE浏览器加载项
Windows -- 从注册表删除IE浏览器加载项 1. 一部分加载项从注册表以下位置直接删除 2. 一部分扩展项从注册表以下位置直接删除
- selenium chrome.options禁止加载图片和js
#新建一个选项卡 from selenium import webdriver options = webdriver.ChromeOptions() #禁止加载图片 prefs = { 'profi ...
- 基于C++简单Windows API的socket编程(阻塞模式)
1. 概述:简单的基于Windows API的socket点对点聊天程序,为了方便初学者,本文代码均采用阻塞原理编写. 2. 代码样例 Server.cpp(服务端) #include <cst ...
- Scala函数式编程(六) 懒加载与Stream
前情提要 Scala函数式编程指南(一) 函数式思想介绍 scala函数式编程(二) scala基础语法介绍 Scala函数式编程(三) scala集合和函数 Scala函数式编程(四)函数式的数据结 ...
- 学习:Windows API核心DLL文件
在 Windows 的系统目录中,存在着很多的动态链接库文件(DLL 文件).这些 DLL 文件中包括了 Windows API 函数可执行程序. DLL 将各函数"导出",这样应 ...
随机推荐
- Kettle 解决数据锁的问题(事务(进程 ID 51)与另一个进程被死锁在 锁 资源上)
1.Kettle做了一个作业, 执行的时候问题发生在步骤2和步骤3之间,也就是步骤2还未完全执行完的时候,步骤3就要更新步骤2插入的数据,造成死锁.(我的理解是既然都分开作业了,那么每个作业都是一个单 ...
- 高阶篇:4.2.3)DFMEA现有设计:预防控制与探测控制
本章目的:在现有设计中,明确预防控制与探测控制的定义和手段. 1.现有控制的填写部位: 2.现行设计控制(h)定义: 作为设计过程的一部分,现行设计控制是已经实施或承诺的活动,它将确保设计充分考虑设计 ...
- autokeras 在windows10下的安装与使用
注意:autokeras只适用于python3.6 先打开命令行(cmd), 输入 python --version 查看python版本,是否需要降级和升级. 降级的命令如下: conda inst ...
- 对java的理解
一门编程语言,分三部分. 核心语法,库,数据结构.
- python四则运算2.0
github项目地址: https://github.com/kongkalong/python PSP 预估耗时(分钟) Planning .Estimate 48*60 Development . ...
- vue-quill-editor html编辑器
在Vue项目使用quill-editor带样式编辑器(更改插入图片和视频) https://www.cnblogs.com/zhengweijie/p/7305903.html vue-quil ...
- Robot Framework(Collections 库)
Collections 库 Collections 库同样为Robot Framework 标准类库,它所提供的关键字主要用于列表.索引.字典的处理. 在使用之前需要在测试套件(项目)中添加:
- [目录]ASP.NET web api开发实战
第一章:Restful web service v.s. RPC style web service 第二章:ASP.NET web api v.s. WCF v.s. ASP.NET web ser ...
- Spark中自定义累加器Accumulator
1. 自定义累加器 自定义累加器需要继承AccumulatorParam,实现addInPlace和zero方法. 例1:实现Long类型的累加器 object LongAccumulatorPara ...
- React.js 小书 Lesson21 - ref 和 React.js 中的 DOM 操作
作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson21 转载请注明出处,保留原文链接和作者信息. 在 React.js 当中你基本不需要和 DO ...