gpt4 book ai didi

c - 以编程方式更改外部 DLL 的 VersionInfo

转载 作者:行者123 更新时间:2023-11-30 14:43:27 26 4
gpt4 key购买 nike

我正在尝试以编程方式更改 DLL 文件的 VersionInfo 属性。我用过this article作为引用。

#include <iostream>
#include <stdio.h>
#include <windows.h>

int main(int argc, char** argv) {
LPCTSTR lpszFile = "E:\\_test\\rand_test\\test.dll";
DWORD dwHandle,
dwSize;

struct {
WORD wLanguage;
WORD wCodePage;
} *lpTranslate;

// determine the size of the resource information
dwSize = GetFileVersionInfoSize(lpszFile, &dwHandle);
if (0 < dwSize)
{
unsigned char* lpBuffer = (unsigned char*) malloc(dwSize);

// Get whole VersionInfo resource/structure
GetFileVersionInfo(lpszFile, 0, dwSize, lpBuffer);

char strSubBlock[37]; // fits "\\StringFileInfo\\xxxxxxxx\\CompanyName\0"
LPTSTR pValueBuffer;

HANDLE hResource = BeginUpdateResource(lpszFile, FALSE);
if (NULL != hResource)
{
UINT uTemp;

// get the language information
if (!VerQueryValue(lpBuffer, "\\VarFileInfo\\Translation", (LPVOID *) &lpTranslate, &uTemp) != FALSE)
{
printf("Error 1\n");
return 1;
}

sprintf(strSubBlock, "\\StringFileInfo\\%04x%04x\\CompanyName", lpTranslate->wLanguage, lpTranslate->wCodePage);

if (!VerQueryValue(lpBuffer, (LPTSTR) ((LPCTSTR) strSubBlock), (LPVOID *) &pValueBuffer, &uTemp)) {
printf("Error 2\n");
return 1;
}
// PROBLEM!!!
// (pValueBuffer-lpBuffer) is 0x438 (longer than the Versioninfo resource!) but should be 0xB8
// so, pValueBuffer does not point to the actual company name.

ZeroMemory(pValueBuffer, strlen(pValueBuffer) * sizeof(TCHAR));
strcpy(pValueBuffer, "My Company, Inc."); // String may only become smaller or equal, never bigger than strlen(pValueBuffer)

if (UpdateResource(hResource,
RT_VERSION,
MAKEINTRESOURCE(VS_VERSION_INFO),
lpTranslate->wLanguage, // or 0
lpBuffer,
dwSize) != FALSE)
{
EndUpdateResource(hResource, FALSE);
}
}
free(lpBuffer);
}

return 0;
}

我想我已经理解了代码所做的一切。计划是读取 Versioninfo block ,然后找到例如的位置CompanyName 使用 VerQueryValue,然后更改数据,然后使用 UpdateResource 将其写回。

但是有一个问题:VerQueryValue 应该输出 CompanyName 字符串所在的位置。但相反,它给出了一个指针位置,该位置距离几百个字节,因此它指向 VersionInfo 结构之外的某个位置。

我做错了什么以及如何让它发挥作用?

(另外,有人知道是否有一种更优雅的方法来完成这项任务,甚至可能消除字符串必须小于或等于原始字符串的限制?)

最佳答案

版本资源这是序列化树。如果你想修改它 - 你需要将其反序列化为内存中的树结构,修改节点,然后序列化到新内存。

尽管msdn中定义了几个Version Information Structures ,实际上它们都有共同的格式

struct RsrcHeader 
{
WORD wLength;
WORD wValueLength;
WORD wType;
WCHAR szKey[];
// aligned on 4*n
// BYTE Value[wValueLength]; // if (wType == 0)
// or
// WCHAR Value[wValueLength]; // if (wType == 1)
// every element aligned on 4*n
// RsrcHeader childs[];
};

因此可以编写通用的解析和序列化程序

#if DBG
#define DBG_OPT(x) _CRT_UNPARENTHESIZE(x)
#else
#define DBG_OPT(x)
#endif

class RsrcNode
{
struct RsrcHeader
{
WORD wLength;
WORD wValueLength;
WORD wType;
WCHAR szKey[];
};

C_ASSERT(sizeof(RsrcHeader) == 6);

RsrcNode* _first, *_next;
PCWSTR _name;
const void* _pvValue;
ULONG _cbValue;
WORD _wValueLength;
WORD _wType;

DBG_OPT((PCSTR _prefix)); // only for debug output

public:

bool ParseResourse(PVOID buf, ULONG size, ULONG* pLength, PCSTR prefix);

RsrcNode(DBG_OPT((PCSTR prefix = "")))
: _next(0), _first(0) DBG_OPT((, _prefix(prefix)))
{
}

~RsrcNode();

bool IsStringValue() const
{
return _wType;
}

const void* getValue(ULONG& cb)
{
cb = _cbValue;
return _pvValue;
}

void setValue(const void* pv, ULONG cb)
{
_pvValue = pv, _cbValue = cb;
_wValueLength = (WORD)(_wType ? cb / sizeof(WCHAR) : cb);
}

RsrcNode* find(const PCWSTR strings[], ULONG n);

ULONG GetSize() const;

PVOID Store(PVOID buf, ULONG* pcb) const;
};

bool RsrcNode::ParseResourse(PVOID buf, ULONG size, ULONG* pLength, PCSTR prefix)
{
union {
PVOID pv;
RsrcHeader* ph;
ULONG_PTR up;
PCWSTR sz;
};

pv = buf;

if (size < sizeof(RsrcHeader) || (up & 3))
{
return false;
}

WORD wType = ph->wType;
ULONG wValueLength = ph->wValueLength, wLength = ph->wLength;
ULONG cbValue = 0;

switch (wType)
{
case 1:
cbValue = wValueLength * sizeof(WCHAR);
break;
case 0:
cbValue = wValueLength;
break;
default:
return false;
}

*pLength = wLength;

if (wLength > size || wLength < sizeof(RsrcHeader) || cbValue >= (wLength -= sizeof(RsrcHeader)))
{
return false;
}

wLength -= cbValue;

sz = ph->szKey, _name = sz;

do
{
if (wLength < sizeof(WCHAR))
{
return false;
}

wLength -= sizeof(WCHAR);

} while (*sz++);

DbgPrint("%s%S {\n", prefix, _name);

if (up & 3)
{
if (wLength < 2)
{
return false;
}
up += 2, wLength -= 2;
}

_wType = wType, _wValueLength = (WORD)wValueLength, _cbValue = cbValue, _pvValue = pv;

if (wValueLength && wType)
{
if (sz[wValueLength - 1])
{
return false;
}
DbgPrint("%s\t%S\n", prefix, sz);
}

if (wLength)
{
if (!*--prefix) return false;

up += wValueLength;

do
{
if (up & 3)
{
if (wLength < 2)
{
return false;
}

up += 2;

if (!(wLength -= 2))
{
break;
}
}

if (RsrcNode* node = new RsrcNode(DBG_OPT((prefix))))
{
node->_next = _first, _first = node;

if (node->ParseResourse(ph, wLength, &size, prefix))
{
continue;
}
}

return false;

} while (up += size, wLength -= size);

prefix++;
}

DbgPrint("%s}\n", prefix);

return true;
}

RsrcNode::~RsrcNode()
{
if (RsrcNode* next = _first)
{
do
{
RsrcNode* cur = next;
next = next->_next;
delete cur;
} while (next);
}

DBG_OPT((DbgPrint("%s%S\n", _prefix, _name)));
}

RsrcNode* RsrcNode::find(const PCWSTR strings[], ULONG n)
{
PCWSTR str = *strings++;

if (!str || !wcscmp(str, _name))
{
if (!--n)
{
return this;
}

if (RsrcNode* next = _first)
{
do
{
if (RsrcNode* p = next->find(strings, n))
{
return p;
}
} while (next = next->_next);
}
}

return 0;
}

ULONG RsrcNode::GetSize() const
{
ULONG size = sizeof(RsrcHeader) + (1 + (ULONG)wcslen(_name)) * sizeof(WCHAR);

if (_cbValue)
{
size = ((size + 3) & ~3) + _cbValue;
}

if (RsrcNode* next = _first)
{
do
{
size = ((size + 3) & ~3) + next->GetSize();
} while (next = next->_next);
}

return size;
}

PVOID RsrcNode::Store(PVOID buf, ULONG* pcb) const
{
union {
RsrcHeader* ph;
ULONG_PTR up;
PVOID pv;
};

pv = buf;

ph->wType = _wType;
ph->wValueLength = _wValueLength;

ULONG size = (1 + (ULONG)wcslen(_name)) * sizeof(WCHAR), cb;

memcpy(ph->szKey, _name, size);

up += (size += sizeof(RsrcHeader));

if (_cbValue)
{
up = (up + 3) & ~3;
memcpy(pv, _pvValue, _cbValue);
up += _cbValue;
size = ((size + 3) & ~3) + _cbValue;
}

if (RsrcNode* next = _first)
{
do
{
up = (up + 3) & ~3;
pv = next->Store(pv, &cb);
size = ((size + 3) & ~3) + cb;
} while (next = next->_next);
}

reinterpret_cast<RsrcHeader*>(buf)->wLength = (WORD)size;

*pcb = size;

return pv;
}

通过这个辅助结构,我们可以通过以下方式更新版本:

#include "VerHlp.h"

BOOL UpdateVersion(PVOID pvVersion, ULONG cbVersion, PVOID& pvNewVersion, ULONG& cbNewVersion)
{
BOOL fOk = FALSE;

char prefix[16];
memset(prefix, '\t', sizeof(prefix));
prefix[RTL_NUMBER_OF(prefix) - 1] = 0;
*prefix = 0;

if (RsrcNode* node = new RsrcNode)
{
if (node->ParseResourse(pvVersion, cbVersion, &cbVersion, prefix + RTL_NUMBER_OF(prefix) - 1))
{
static const PCWSTR str[] = {
L"VS_VERSION_INFO", L"StringFileInfo", 0, L"CompanyName"
};

if (RsrcNode *p = node->find(str, RTL_NUMBER_OF(str)))
{
if (p->IsStringValue())
{
ULONG cb;
const void* pvCompanyName = p->getValue(cb);
DbgPrint("CompanyName: %S\n", pvCompanyName);

static WCHAR CompanyName[] = L"[ New Company Name ]";

if (cb != sizeof(CompanyName) ||
memcmp(pvCompanyName, CompanyName, sizeof(CompanyName)))
{
p->setValue(CompanyName, sizeof(CompanyName));

cbVersion = node->GetSize();

if (pvVersion = LocalAlloc(0, cbVersion))
{
node->Store(pvVersion, &cbNewVersion);
pvNewVersion = pvVersion;
fOk = TRUE;
}
}
}
}
}
delete node;
}

return fOk;
}

struct EnumVerData
{
HANDLE hUpdate;
BOOL fDiscard;
};

BOOL CALLBACK EnumResLangProc(HMODULE hModule,
PCWSTR lpszType,
PCWSTR lpszName,
WORD wIDLanguage,
EnumVerData* Ctx
)
{
if (HRSRC hResInfo = FindResourceExW(hModule, lpszType, lpszName, wIDLanguage))
{
if (HGLOBAL hg = LoadResource(hModule, hResInfo))
{
if (ULONG size = SizeofResource(hModule, hResInfo))
{
if (PVOID pv = LockResource(hg))
{
if (UpdateVersion(pv, size, pv, size))
{
if (UpdateResource(Ctx->hUpdate, lpszType, lpszName, wIDLanguage, pv, size))
{
Ctx->fDiscard = FALSE;
}

LocalFree(pv);
}
}
}
}
}

return TRUE;
}

ULONG UpdateVersion(PCWSTR FileName)
{
ULONG dwError = NOERROR;

EnumVerData ctx;

if (ctx.hUpdate = BeginUpdateResource(FileName, FALSE))
{
ctx.fDiscard = TRUE;

if (HMODULE hmod = LoadLibraryExW(FileName, 0, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE))
{
if (!EnumResourceLanguages(hmod, RT_VERSION,
MAKEINTRESOURCE(VS_VERSION_INFO),
(ENUMRESLANGPROCW)EnumResLangProc, (LONG_PTR)&ctx))
{
dwError = GetLastError();
}

FreeLibrary(hmod);
}
else
{
dwError = GetLastError();
}

if (!dwError && !EndUpdateResourceW(ctx.hUpdate, ctx.fDiscard))
{
dwError = GetLastError();
}
}
else
{
dwError = GetLastError();
}

return dwError;
}

关于c - 以编程方式更改外部 DLL 的 VersionInfo,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53916682/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com