- 公开视频 -> 链接点击跳转公开课程
- 博客首页 -> 链接点击跳转博客主页
目录
动态链接库
创建动态链接库
相关函数
遍历模块
导出未文档化
动态链接库
-
动态链接库(DLL)
- 动态链接库(Dynamic-Link Library,简称DLL)是一种包含可由多个程序同时使用的代码和数据的文件。DLL允许程序共享代码,从而减少内存使用和磁盘空间占用,同时使得程序的更新和维护更加方便。
-
导出函数
- 在DLL中,导出函数是可以被其他程序或DLL调用的函数。为了使函数能够被导出,需要在函数定义前加上特定的关键字,如
__declspec(dllexport)
。
- 在DLL中,导出函数是可以被其他程序或DLL调用的函数。为了使函数能够被导出,需要在函数定义前加上特定的关键字,如
-
导入库
- 导入库(Import Library)是一个特殊的库文件,它包含了指向DLL中导出函数的符号信息。当编译器链接一个程序时,它会使用导入库来解析对DLL中函数的引用。导入库通常与DLL文件一起提供,以便程序能够正确地加载和调用DLL中的函数。
-
代码重用
- 动态链接库(DLL)允许不同的程序共享同一代码库。这意味着,如果多个程序需要执行相同的任务,它们可以调用同一个DLL中的函数,而不是每个程序都包含该函数的副本。这样可以减少磁盘空间的使用,并且在内存中只需要一个代码副本,从而提高了内存的使用效率。
-
模块化
- DLL提供了一种模块化的编程方式,使得程序的结构更加清晰。每个DLL可以看作是一个独立的模块,负责特定的功能。这种模块化的设计使得程序的开发、测试和维护更加容易,因为可以单独更新或修复某个DLL,而不需要重新编译整个程序。
-
内存效率
- 当多个程序使用同一个DLL时,Windows操作系统通常会在内存中只加载该DLL的一个副本。这意味着,即使多个程序都在运行,它们也共享同一个DLL的物理内存副本。这种共享机制减少了内存的消耗,提高了系统的整体性能。
创建动态链接库
- 工程项目
- 创建动态链接库项目
- 空项目 - 配置类型 - DLL(动态库)
- 入口函数
-
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; }
-
- 导出函数
- __declspec(dllexport) 声明函数为导出函数。
extern "C"
避免CPP中函数重载导致导出函数名不同。- 模块定义文件(*.def)
-
.cpp #include <Windows.h> INT Add(INT A, INT B) { return A + B; } INT Sub(INT A, INT B) { return A - B; } EXTERN_C __declspec(dllexport) INT Div(INT A, INT B) { return A / B; } .def LIBRARY EXPORTS Add Sub
- 导入函数
- LoadLibrary
- GetProcAddres
- PFNCALLBACK
- FreeLibrary
-
#include <iostream> #include <Windows.h> typedef int(__cdecl* PFNAdd)(INT, INT); int main() { HMODULE hModule = LoadLibraryA("D:\\0xCC\\Project\\Win32\\Debug\\TESTDLL.dll"); if (hModule) { PFNAdd pFun = (PFNAdd)GetProcAddress(hModule, "Add"); if (pFun) { std::cout << pFun(1, 2) << std::endl; } FreeLibrary(hModule); } return 0; }
- 创建动态链接库项目
相关函数
GetModuleFileName
函数用于获取指定模块的完整路径,该模块必须已经被映射到调用进程的地址空间中。GetModuleHandle
函数用于获取一个模块的句柄,该模块必须已经被映射到调用进程的地址空间中。GetModuleFileNameEx
函数与GetModuleFileName
类似,但它可以在指定的进程中获取模块的完整路径。GetModuleBaseName
函数用于获取指定模块的基本名称(不包括路径),该模块必须已经被映射到调用进程的地址空间中。GetProcessImageFileName
函数用于获取指定进程的映像文件名(即进程的可执行文件名)。-
#include <iostream> #include <Windows.h> #include <Psapi.h> int main() { // 获取模块基址 HMODULE hMain = GetModuleHandleA(NULL); HMODULE hKe32 = GetModuleHandleA("Kernel32.dll"); HMODULE hTest = GetModuleHandleA("TEST.dll"); // 获取模块路径(本进程) CHAR szBuffer[MAX_PATH] = { 0 }; GetModuleFileNameA(hMain, szBuffer, MAX_PATH); std::cout << szBuffer << std::endl; GetModuleFileNameA(hKe32, szBuffer, MAX_PATH); std::cout << szBuffer << std::endl; // 获取模块路径(跨进程) // GetModuleFileNameEx // 获取模块名称 GetModuleBaseNameA(GetCurrentProcess(), hMain, szBuffer, MAX_PATH); std::cout << szBuffer << std::endl; GetModuleBaseNameA(GetCurrentProcess(), hKe32, szBuffer, MAX_PATH); std::cout << szBuffer << std::endl; // 获取进程主模块 GetProcessImageFileNameA(GetCurrentProcess(), szBuffer, MAX_PATH); std::cout << szBuffer << std::endl; return 0; }
遍历模块
-
CreateToolhelp32Snapshot
-
MODULEENTRY32
-
Module32First
-
Module32Next
导出未文档化
#include <iostream>
#include <Windows.h>
#include <winternl.h>
// Kernel32.dll - OpenProcess
// ntdll.dll - NtOpenProcess
typedef NTSTATUS(NTAPI* PFNNTOPENPROCESS)
(
PHANDLE ProcessHandle,
ACCESS_MASK AccessMask,
POBJECT_ATTRIBUTES ObjectAttributes,
CLIENT_ID* ClientId
);
int main()
{
HMODULE hNtdll = LoadLibrary(TEXT("ntdll.dll"));
if (hNtdll)
{
PFNNTOPENPROCESS lpNtOpenProcess = (PFNNTOPENPROCESS)GetProcAddress(hNtdll, "NtOpenProcess");
if (lpNtOpenProcess)
{
HANDLE hProcess = NULL;
OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
CLIENT_ID clientId = { 0 };
clientId.UniqueProcess = (HANDLE)25500;
InitializeObjectAttributes(&ObjectAttributes, NULL, NULL, NULL, NULL);
NTSTATUS status = lpNtOpenProcess(&hProcess, PROCESS_ALL_ACCESS, &ObjectAttributes, &clientId);
if (status == 0)
{
std::cout << "ProcessHandle -> " << hProcess << std::endl;
CloseHandle(hProcess);
}
}
FreeLibrary(hNtdll);
}
return 0;
}