前言:
如果你自己写了一个C++动态库,不希望别人的程序能调用,那么本篇文章能为你提供一个思路,通过获取调用了动态库的进程的信息进行判断。
核心代码:
#include <Windows.h>
#include <TlHelp32.h>
#include <Psapi.h>
#include <tchar.h>
#pragma comment(lib, "psapi.lib")
#pragma comment(lib, "version.lib")
// 获取文件的详细信息
int get_file_detail_info(LPCWSTR procPath, LPCTSTR pName, LPTSTR ptBuf, UINT lenBuf) {
try
{
DWORD dwDummyHandle = 0;
DWORD dwLen = 0;
LPBYTE pVersionInfo = NULL;
BOOL bRetVal;
VS_FIXEDFILEINFO FileVersion;
struct TRANSLATION
{
WORD langID;
WORD charset;
} Translation;
Translation.langID = 0x0409;
Translation.charset = 1252;
dwLen = GetFileVersionInfoSize(procPath, &dwDummyHandle);
if (dwLen == 0) {
//write_log("test", "GetFileVersionInfoSize Error!!");
return -1;
}
pVersionInfo = new BYTE[dwLen];
bRetVal = GetFileVersionInfo(procPath, NULL, dwLen, pVersionInfo);
if (bRetVal == FALSE) {
//write_log("test", "GetFileVersionInfo Error!!");
return -1;
}
LPVOID pVI;
UINT uLen;
bRetVal = VerQueryValue(pVersionInfo, L"\\", &pVI, &uLen);
if (bRetVal == FALSE) {
//write_log("test", "VerQueryValue Error!!");
return -1;
}
memcpy(&FileVersion, pVI, sizeof(VS_FIXEDFILEINFO));
bRetVal = VerQueryValue(pVersionInfo, L"\\VarFileInfo\\Translation", &pVI, &uLen);
if (bRetVal && uLen >= 4) {
memcpy(&Translation, pVI, sizeof(TRANSLATION));
}
else {
//write_log("test", "Translation Error[1]!!");
return -1;
}
if (FileVersion.dwSignature != VS_FFI_SIGNATURE) {
//write_log("test", "Translation Error[2]!!");
return -1;
}
LPVOID pVal;
UINT iLenVal;
if (pName != NULL) {
TCHAR szQuery[1024];
_stprintf_s(szQuery, 1024, L"\\StringFileInfo\\%04X%04X\\%s", Translation.langID, Translation.charset, pName);
bRetVal = VerQueryValue(pVersionInfo, szQuery, &pVal, &iLenVal);
if (bRetVal) {
_stprintf_s(ptBuf, lenBuf, L"%s", (TCHAR*)pVal);
}
else {
_stprintf_s(ptBuf, lenBuf, L"%s", L"");
}
}
delete[] pVersionInfo;
return 0;
}
catch (const std::exception&)
{
return -99;
}
}
// 鉴权
int auth_func(wstring dll_company_name) {
try
{
int res = 0;
PROCESSENTRY32 pe32; //进程结构
pe32.dwSize = sizeof(PROCESSENTRY32);
// 给系统内所有的进程拍个快照
HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
// 某个进程所有的DLL快照句柄
HANDLE hModuleSnap = NULL;
if (hProcessSnap == INVALID_HANDLE_VALUE) {
return -1;
}
BOOL bMore = ::Process32First(hProcessSnap, &pe32);
HANDLE hProcess = NULL;
WCHAR procPath[_MAX_PATH] = { 0 };
MODULEENTRY32 lpme;
lpme.dwSize = sizeof(MODULEENTRY32);
BOOL bRet = FALSE;
// 遍历进程快照,显示每个进程的信息
while (bMore) {
// 打开一个已存在的进程对象,并返回进程句柄
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID);
// 得到该进程的全路径
GetModuleFileNameEx(hProcess, NULL, procPath, _MAX_PATH);
wstring exeName(pe32.szExeFile);
// write_log("debug", L"PorcessName: " + exeName); // 进程名称 xx.exe
// write_log("debug", "PID: " + to_string(pe32.th32ProcessID)); // 进程PID
// 给一个已存在的进程内所有的DLL拍个快照
hModuleSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pe32.th32ProcessID);
bRet = ::Module32First(hModuleSnap, &lpme);
// 遍历DLL快照,显示该进程所加载的DLL信息
while (bRet) {
wstring dllPath(lpme.szExePath);
// write_log("debug", L"--- " + dllPath); // 进程完整路径 及 引用DLL文件完整路径
if (dllPath.find(string2wstring(currentName)) != string::npos && exeName != L"[System Process]") {
// 找到本程序集的调用者【父进程】
// write_log("test", L"Parent Process: " + wstring(procPath));
// 获取父进程信息
TCHAR* companyNameStr = new TCHAR[1024];
get_file_detail_info(procPath, L"CompanyName", companyNameStr, 1024); // 公司
TCHAR* copyrightStr = new TCHAR[1024];
get_file_detail_info(procPath, L"LegalCopyright", copyrightStr, 1024); // 版权
// 判断父进程是否获得授权
if (wstring(companyNameStr).find(dll_company_name) != string::npos && wstring(copyrightStr).find(dll_company_name) != string::npos) {
res = 1;
}
}
bRet = ::Module32Next(hModuleSnap, &lpme);
}
// 关闭快照对象
::CloseHandle(hModuleSnap);
bMore = ::Process32Next(hProcessSnap, &pe32);
// write_log("debug", "---------");
}
// 关闭快照对象
::CloseHandle(hProcessSnap);
return res;
}
catch (const std::exception&)
{
return -99;
}
}
调用方式:
// 动态库入口函数
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH: {
// 鉴权,为全局变量赋值
isAuth = auth_func(L"xxxx有限公司") == 1;
break;
}
case DLL_THREAD_ATTACH: {
break;
}
case DLL_THREAD_DETACH: {
break;
}
case DLL_PROCESS_DETACH: {
}
}
return TRUE;
}
调用者(*.exe)需要做的对应更改:
以.NET为例,项目属性中的Copyright标签与Company标签都需要打上版权标识
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
<PlatformTarget>x86</PlatformTarget>
<Copyright>xxxx有限公司© 2025</Copyright>
<Company>xxxx有限公司</Company>
</PropertyGroup>
</Project>

1万+

被折叠的 条评论
为什么被折叠?



