DLL延时加载技术与资源释放

0x00 前言

诸如调用非Windows的第三方库,我们或许会使用到dll文件,而这个时候原本程序运行需要相应的dll文件才能加载启动。通过DLL延时加载技术,使用延时加载的方式编译链接可执行的文件,可以先运行程序,再在依赖的DLL正式被调用时加载DLL。通常可通过资源文件写入dll,在释放完资源后,正式调用DLL时加载执行,避免丢失缺少DLL文件,从而单exe落地文件,避免麻烦。

0x01 介绍

在使用Visual Studio的场景下,如果使用DLL延时加载,只需要对项目的链接选项进行手动设置即可。

具体步骤如下:

属性—>链接器—>输入—>延迟加载的DLL—>输入:dll名称

DLL延迟加载技术的原理,其实就是在导入表中去掉xxx.dll这一项,等到DLL被正式调用的时候,才会加载DLL文件。这样,程序在正式调用DLL之前,都是可以正常执行的。

具体利用场景可以结合资源释放,在需要单exe的条件下,通过释放DLL资源,再延迟加载DLL,从而达到更方便的使用效果。

而资源释放,其实就是把一些需要额外加载的图片、文本、DLL作为资源的形式插入到主程序内,在必要的时候进行释放,使我们的主程序只有一个exe文件,降低落地计算机磁盘前期直接被发现的风险。

简单点来理解资源释放的原理,其实就是从资源中获取文件,写入到指定文件位置。

我们可以通过右键项目增加资源文件,如果文件类型不确定,可以增加自定义类型的资源文件。

0x02 编码实现

首先类似自定义的DLL,这里就写了一个小demo,起名为hello_world.dll:

Dolman.cpp

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
#include <iostream>
#include <cstring>
using namespace std; BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
} extern "C" __declspec(dllexport) int hello()
{
int a = 666;
return a;
}

生成即自定义DLL。

再者,主程序,设置资源放入自定义dll,并设置延时加载hello_world.dll。

say_hello.cpp

// say_hello.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
// #include <iostream>
#include<windows.h>
#include "resource.h" BOOL FreeMyResource(UINT uiResouceName, char* lpszResourceType, char* lpszSaveFileName); void GetCurrentPath(char* lpszCurrentPath, DWORD dwSize); void FreeRes_ShowError(char* pszText); // CDelayLoadDll_TestDlg 消息处理程序 void FreeRes_ShowError(char* pszText)
{
char szErr[MAX_PATH] = { 0 };
::wsprintf(szErr, "%s Error[%d]\n", pszText, ::GetLastError());
::MessageBox(NULL, szErr, "ERROR", MB_OK);
} // 释放资源
BOOL FreeMyResource(UINT uiResouceName, char* lpszResourceType, char* lpszSaveFileName)
{
HRSRC hRsrc = ::FindResource(NULL, MAKEINTRESOURCE(uiResouceName), lpszResourceType);
if (NULL == hRsrc)
{
FreeRes_ShowError("FindResource");
return FALSE;
}
DWORD dwSize = ::SizeofResource(NULL, hRsrc);
if (0 >= dwSize)
{
FreeRes_ShowError("SizeofResource");
return FALSE;
}
HGLOBAL hGlobal = ::LoadResource(NULL, hRsrc);
if (NULL == hGlobal)
{
FreeRes_ShowError("LoadResource");
return FALSE;
}
LPVOID lpVoid = ::LockResource(hGlobal);
if (NULL == lpVoid)
{
FreeRes_ShowError("LockResource");
return FALSE;
} FILE* fp = NULL;
fopen_s(&fp, lpszSaveFileName, "wb+");
if (NULL == fp)
{
FreeRes_ShowError("LockResource");
return FALSE;
}
fwrite(lpVoid, sizeof(char), dwSize, fp);
fclose(fp); return TRUE;
} // 获取当前目录
void GetCurrentPath(char* lpszCurrentPath, DWORD dwSize)
{
::GetModuleFileName(NULL, lpszCurrentPath, dwSize);
char* p = ::strrchr(lpszCurrentPath, '\\');
p[0] = '\0';
} int main()
{
typedef int (*_pHello)();
//std::cout << "Hello World!\n";
// 释放DLL
// 获取当前目录
char szCurrentPath[MAX_PATH] = { 0 };
GetCurrentPath(szCurrentPath, MAX_PATH);
// 构造路径
::lstrcat(szCurrentPath, "\\hello_world.dll");
FreeMyResource(IDR_TEST1, "test", szCurrentPath);
HINSTANCE hDll = LoadLibrary("hello_world.dll");
_pHello hello = (_pHello)GetProcAddress(hDll, "hello");
int nHello = hello();
std::cout << nHello << std::endl;
}

编译即可。

0x03 实测

打包生成主程序后,拿到另一台机器运行测试。单exe运行后,释放dll资源到当前目录(可指定别的目录,如temp临时目录下),调用导出函数成功,输出666.

0x04 关于报错

Tips:

关于如果Visual Studio 2019 出现const char *“ 类型的实参与 “LPCWSTR“ 类型的形参不兼容这类错误。

解决方法:

右击项目文件 — 单击属性 — 配置属性 — 高级 — 高级属性 — 字符集

使用 Unicode 字符集”改为“使用多字节字符集

关于如果Visual Studio 2019 出现4996类错误。

解决方法:

右击项目文件 — 单击属性 — 配置属性 — c/c++ — 语言 — 符合模式

修改符合模式为否。

0x05 参考

https://www.cnblogs.com/predator-wang/p/4956615.html

https://www.write-bug.com/article/1601.html

DLL延时加载技术与资源释放的更多相关文章

  1. [整理]DLL延时加载 && 设置进程私有环境变量

    DLL延时加载鉴于静态和动态加载之间,即无需在代码中显示加载但它内队依然是动态加载的方式只是系统帮处理了.这样做好处是: 1. 可以加快启动时间(因为它是动态加载在需要的时间加载), 2. 减小编写L ...

  2. JAVA的单例模式与延时加载

    延迟加载(lazy load)是(也称为懒加载),也叫延迟实例化,延迟初始化等,主要表达的思想就是:把对象的创建延迟到使用的时候创建,而不是对象实例化的时候创建.延迟加载机制是为了避免一些无谓的性能开 ...

  3. Image Lazy Load:那些延时加载图片的开源插件(jQuery)

    图片延时加载技术对大流量的网站来说是十分实用的.目前图片在网站中大量使用,如果不加处理的话会对服务器和带宽造成级大压力,通过只渲染当前用户可见区域的图片,可以极大地减少网站的请求数,降低网络带宽资源. ...

  4. 服务器文档下载zip格式 SQL Server SQL分页查询 C#过滤html标签 EF 延时加载与死锁 在JS方法中返回多个值的三种方法(转载) IEnumerable,ICollection,IList接口问题 不吹不擂,你想要的Python面试都在这里了【315+道题】 基于mvc三层架构和ajax技术实现最简单的文件上传 事件管理

    服务器文档下载zip格式   刚好这次项目中遇到了这个东西,就来弄一下,挺简单的,但是前台调用的时候弄错了,浪费了大半天的时间,本人也是菜鸟一枚.开始吧.(MVC的) @using Rattan.Co ...

  5. 011.Delphi插件之QPlugins,延时加载服务

    这个DEMO是是把DLL插件的相关信息做成了一个配置文件,主程序加载这个配置文件,从而起到延时加载的作用 主程序代码如下 unit Frm_Main; interface uses Winapi.Wi ...

  6. MyBatis入门(五)---延时加载、缓存

    一.创建数据库 1.1.建立数据库 /* SQLyog Enterprise v12.09 (64 bit) MySQL - 5.7.9-log : Database - mybatis ****** ...

  7. Android 高仿腾讯旗下app的 皮肤加载技术

    http://www.cnblogs.com/punkisnotdead/p/4968851.html 以前写的这篇文章 可以高仿出 知乎 新浪微博等 绝大多数app的换肤技术,但是遗漏了腾讯的效果, ...

  8. 图片延时加载jquery.inview.js用法详解

    我们在网站上总能见到这样的效果,若是有图片,图片都是先用loading加载一小段时间,然后紧接着出来要显示的图片,即效果如下: v2_loading.gif,几秒钟时间过渡到v2_pic_01_s.j ...

  9. FaceBook页面加载技术

    1. 技术背景 FaceBook页面加载技术 试想这样一个场景,一个经常访问的网站,每次打开它的页面都要要花费6 秒:同时另外一个网站提供了相似的服务,但响应时间只需3 秒,那么你会如何选择呢?数据表 ...

随机推荐

  1. RHCE_DAY01

    shell概述 shell是一个程序,它连接了用户和Linux内核,它可以解释用户输入的命令传递给内核,让用户可以更加方便的使用Linux系统 shell 本身并不是内核的一部分,它只是站在内核的基础 ...

  2. C++ //纯虚函数和抽象类 // 语法 virtual 返回值类型 函数名 (参数列表)=0 //当类中有了纯虚函数 这个类也称为抽象类

    1 //纯虚函数和抽象类 2 // 语法 virtual 返回值类型 函数名 (参数列表)=0 3 //当类中有了纯虚函数 这个类也称为抽象类 4 5 6 #include <iostream& ...

  3. OpenStack中VNC协议实现多屏共享(多屏不踢访问)

    OpenStack中VNC协议实现多屏共享 by 无若   libvirt设置基本说明:   <devices> <graphics type='sdl' display=':0.0 ...

  4. js引用类型深拷贝、浅拷贝方法封装

    引用类型的深拷贝.浅拷贝在前端领域一直是个很重要的知识点,不仅在业务中频繁使用,也是面试官们喜欢考的的知识点之一.本篇将封装引用类型的深拷贝.浅拷贝方法,并解决在封装过程中出现的问题. 一.浅拷贝 浅 ...

  5. Python函数调用中的值传递和引用传递问题

    这一问题O' Reilly出版的"Learning Python" 2nd Edition的 13.4 节有专门论述,对于不可变(immutabe)对象,函数参数(这里是x和y)只 ...

  6. shell免交互

    目录 一.Here Document免交互 1.1.Here Document概述 1.2.注意事项 1.3.免交互示例 wc -l实现对行数的统计 read命令接收输入并打印 passwd给用户设置 ...

  7. Woc,考场(面试)忘记打平衡树怎么办,Trie救你命

    Woc,考场(面试)忘记打平衡树怎么办,Trie救你命 文本只发布于博客园,其他地方出现本文均是未经许可的盗版. 算法导入 众所周知平衡树很难打(大佬除外),还老是调错.万一这种事情发生在关键时刻你就 ...

  8. 微信小程序开发——后端Java(一)

    一.前言 最近接触了小程序的开发,后端选择Java,因为小程序的代码运行在腾讯的服务器上,而我们自己编写的Java代码运行在我们自己部署的服务器上,所以一开始不是很明白小程序如何与后台进行通信的,然后 ...

  9. SpringMVC/boot-CSRF安全方案

    1. CSRF原理与防御方案概述 一. 原理 增删改的接口参数值都有规律可循,可以被人恶意构造增删改接口 将恶意构造的增删改接口发给对应特定用户,让特定用户点击 特定用户使用自己的认证信息对该接口发起 ...

  10. Mysql的分区表

    概论: 分区表一般用作Mysql库表的水平切割(也就是常说的mysql性能优化的几种通用手法"读写分离.分库分表"中的一种),适用于单表的数据量可能很大的场景.因为分区表可以将一个 ...