From b4b709769e849e559aed00c9f1e66f6c7c0b5229 Mon Sep 17 00:00:00 2001 From: anders_k Date: Thu, 19 Oct 2017 14:16:09 +0000 Subject: [PATCH] Support named version resource in VxD files so we can handle MSGame.VxD git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6934 212acab6-be3b-0410-9dea-997c60f758d6 --- Source/BinInterop.cpp | 161 ++++++++++++------------------------------ Source/util.cpp | 51 ++++++++++++- Source/util.h | 6 +- 3 files changed, 100 insertions(+), 118 deletions(-) diff --git a/Source/BinInterop.cpp b/Source/BinInterop.cpp index f5afbe86..b2001d41 100644 --- a/Source/BinInterop.cpp +++ b/Source/BinInterop.cpp @@ -18,10 +18,14 @@ #include "BinInterop.h" #include "ResourceEditor.h" #include "util.h" +#include // strlen #include // _tcstoul #include #define MKPTR(cast, base, offset) ( (cast) ( ((char*)(base)) + (offset) ) ) +#define LE2HE16 FIX_ENDIAN_INT16 // Little-endian 2 Host-endian +#define LE2HE32 FIX_ENDIAN_INT32 +#define HE2LE16 LE2HE16 const size_t invalid_res_id = ~(size_t)0; FILE* MSTLB_fopen(const TCHAR*filepath, size_t*pResId) @@ -379,132 +383,57 @@ static bool GetDLLVersionUsingAPI(const TCHAR *filepath, DWORD &high, DWORD &low return found; } -#pragma pack(push, pre_vxd_ver, 1) -typedef struct _VXD_VERSION_RESOURCE { - char cType; - WORD wID; - char cName; - WORD wOrdinal; - WORD wFlags; - DWORD dwResSize; - BYTE bVerData; -} VXD_VERSION_RESOURCE, *PVXD_VERSION_RESOURCE; -#pragma pack(pop, pre_vxd_ver) - -#ifdef _WIN32 -static void* CreateReadOnlyFullMappedView(LPCTSTR szFile, DWORD Access, DWORD Share, DWORD Mode) -{ - void *pView = NULL; - HANDLE hFile = CreateFile(szFile, Access, Share, NULL, Mode, 0, NULL); - if (hFile == INVALID_HANDLE_VALUE) return pView; - HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); - if (hMap != INVALID_HANDLE_VALUE) - { - CloseHandle(hFile); - if ((pView = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0))) - { - CloseHandle(hMap); - } - else - { - DWORD error = GetLastError(); - CloseHandle(hMap); - SetLastError(error); - } - } - else - { - DWORD error = GetLastError(); - CloseHandle(hFile); - SetLastError(error); - } - return pView; -} - -static BOOL GetVxdVersion(LPCTSTR szFile, LPDWORD lpdwLen, LPVOID lpData) -{ - BOOL result = FALSE; - DWORD resSize = 0, outSize = *lpdwLen; - void *pView = CreateReadOnlyFullMappedView(szFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING); - if (!pView) return FALSE; - - PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER) pView; - if (pDosHdr->e_magic == IMAGE_DOS_SIGNATURE) - { - PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS) ((ULONG_PTR) pView + pDosHdr->e_lfanew); - if ((DWORD) pNtHdr->Signature == IMAGE_VXD_SIGNATURE) // Is it a little-endian VXD? - { - PIMAGE_VXD_HEADER pLEHdr = (PIMAGE_VXD_HEADER) pNtHdr; - if (pLEHdr->e32_winreslen != 0) - { - PVXD_VERSION_RESOURCE pVerRes; - pVerRes = (VXD_VERSION_RESOURCE*) ((ULONG_PTR) pView + pLEHdr->e32_winresoff); - resSize = pVerRes->dwResSize; - if (lpData && outSize >= resSize) - { - void *pResData = &(pVerRes->bVerData); - ZeroMemory(lpData, outSize); - CopyMemory(lpData, pResData, resSize); - result = TRUE; - } - else - SetLastError(ERROR_INSUFFICIENT_BUFFER); - } - else - SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND); - } - else - SetLastError(ERROR_BAD_FORMAT); - } - else - SetLastError(ERROR_BAD_FORMAT); - - UnmapViewOfFile(pView); - *lpdwLen = resSize; - return result; -} - -static DWORD GetVxdVersionInfoSize(LPCTSTR szFile) -{ - DWORD result = 0; - if (!GetVxdVersion(szFile, &result, NULL)) - { - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) // Successfully queried the required size? - { - SetLastError(0); - return result; - } - } - return result; -} - -static BOOL GetVxdVersionInfo(LPCTSTR szFile, DWORD dwLen, LPVOID lpData) -{ - return GetVxdVersion(szFile, &dwLen, lpData); -} -#endif //_WIN32 +#pragma pack(push, 1) +typedef struct tagMINI_IMAGE_VXD_HEADER { + WORD e32_magic, endian; + BYTE data[180]; + DWORD e32_winresoff, e32_winreslen; + WORD e32_devid, e32_ddkver; +} MINI_IMAGE_VXD_HEADER, *PMINI_IMAGE_VXD_HEADER; +#pragma pack(pop) static bool GetDLLVersionFromVXD(const TCHAR *filepath, DWORD &high, DWORD &low) { bool found = false; -#ifdef _WIN32 - DWORD verSize = GetVxdVersionInfoSize(filepath); - if (verSize) + FILEVIEW map; + char *filedata = create_file_view_readonly(filepath, map); + if (filedata) { - void *buf = malloc(verSize); - if (buf) + PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER) filedata; + if ((pDosHdr->e_magic == 0x5A4D) | (pDosHdr->e_magic == 0x4D5A)) { - UINT valSize; - VS_FIXEDFILEINFO *pvsf; - if (GetVxdVersionInfo(filepath, verSize, buf) && VerQueryValue(buf, _T("\\"), (void**) &pvsf, &valSize)) + PMINI_IMAGE_VXD_HEADER pVxdHdr = MKPTR(PMINI_IMAGE_VXD_HEADER, pDosHdr, LE2HE32(pDosHdr->e_lfanew)); + if (pVxdHdr->e32_magic == HE2LE16(0x454C) && pVxdHdr->endian == 0) // Is it a little-endian VXD? { - high = pvsf->dwFileVersionMS, low = pvsf->dwFileVersionLS; - found = true; + UINT minvsvi16 = 2 + 2 + 16, minvsffi = 52, minressecsize = ((1 + 2) + (1 + 2) + 2 + 4) + minvsvi16 + minvsffi; + PMINI_IMAGE_VXD_HEADER pLEHdr = pVxdHdr; + UINT ressecsize = LE2HE32(pLEHdr->e32_winreslen); + if (ressecsize >= minressecsize && pLEHdr->e32_winresoff != 0) + { + // MSKB201685 just assumes that the first item is the version and we do the same. + char *pRes = MKPTR(char*, pDosHdr, LE2HE32(pLEHdr->e32_winresoff)); + UINT ressize, ofs = 3, succ = *MKPTR(BYTE*, pRes, 0) == 0xff && *MKPTR(WORD*, pRes, 1) == HE2LE16(16); // RT_VERSION + if (succ) succ = *MKPTR(BYTE*, pRes, ofs) == 0xff ? (ofs += (1 + 2) + 2) : (ofs += (strlen(MKPTR(char*, pRes, ofs)) + !0) + 2); // Ordinal or string name + if (succ) succ = ofs + 4 < ressecsize; + if (succ) ressize = LE2HE32(*MKPTR(DWORD*, pRes, ofs)), ofs += 4; + if (succ && ressize >= minvsvi16 + minvsffi && ressize < ressecsize) + { + WORD *pVSVI = MKPTR(WORD*, pRes, ofs); // VS_VERSIONINFO (16-bit/ASCII version) + if (LE2HE16(pVSVI[0]) >= minvsvi16 + minvsffi && LE2HE16(pVSVI[1]) >= minvsffi && !memcmp(&pVSVI[2], "VS_VERSION_INFO", 16)) + { + VS_FIXEDFILEINFO *pFFI = MKPTR(VS_FIXEDFILEINFO*, pVSVI, 2 + 2 + 16); + if (LE2HE32(pFFI->dwSignature) == 0xFEEF04BD) + { + high = LE2HE32(pFFI->dwFileVersionMS), low = LE2HE32(pFFI->dwFileVersionLS); + found = true; + } + } + } + } } - free(buf); } + close_file_view(map); } -#endif return found; } diff --git a/Source/util.cpp b/Source/util.cpp index bfeeef63..133042ce 100644 --- a/Source/util.cpp +++ b/Source/util.cpp @@ -58,6 +58,38 @@ using namespace std; extern int g_display_errors; extern FILE *g_output, *g_errout; +#ifdef _WIN32 +static char* CreateMappedFileView(LPCTSTR szFile, DWORD FAccess, DWORD FShare, DWORD FMode, DWORD PProtect, DWORD MAccess) +{ + char *pView = NULL, restoreGLE = false; + HANDLE hFile = CreateFile(szFile, FAccess, FShare, NULL, FMode, 0, NULL); + if (hFile == INVALID_HANDLE_VALUE) return pView; + HANDLE hMap = CreateFileMapping(hFile, NULL, PProtect, 0, 0, NULL); + if (hMap != INVALID_HANDLE_VALUE) + { + CloseHandle(hFile); + if ((pView = (char*) MapViewOfFile(hMap, MAccess, 0, 0, 0))) + { + CloseHandle(hMap); + } + else + { + DWORD error = restoreGLE ? GetLastError() : 0; + CloseHandle(hMap); + if (restoreGLE) SetLastError(error); + } + } + else + { + DWORD error = restoreGLE ? GetLastError() : 0; + CloseHandle(hFile); + if (restoreGLE) SetLastError(error); + } + return pView; +} +#endif //~ _WIN32 + + double my_wtof(const wchar_t *str) { char buf[100]; @@ -585,7 +617,7 @@ int my_open(const TCHAR *pathname, int flags) #endif return result; } -#endif//!_WIN32 +#endif //! _WIN32 FILE* my_fopen(const TCHAR *path, const char *mode) { @@ -669,6 +701,23 @@ BYTE* alloc_and_read_file(const TCHAR *filepath, unsigned long &size) return result; } +void close_file_view(FILEVIEW&mmfv) +{ +#ifdef _WIN32 + if (mmfv.base) UnmapViewOfFile(mmfv.base); +#else + // TODO +#endif +} +char* create_file_view_readonly(const TCHAR *filepath, FILEVIEW&mmfv) +{ +#ifdef _WIN32 + return mmfv.base = CreateMappedFileView(filepath, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, PAGE_READONLY, FILE_MAP_READ); +#else + return 0; // TODO +#endif +} + tstring get_full_path(const tstring &path) { #ifdef _WIN32 TCHAR real_path[1024], *fnpart; diff --git a/Source/util.h b/Source/util.h index 97f03df4..a1ee00d8 100644 --- a/Source/util.h +++ b/Source/util.h @@ -268,7 +268,7 @@ int my_open(const TCHAR *pathname, int flags); #define OPEN(a, b) _topen(a, b) -#endif // ~_WIN32 +#endif //~ _WIN32 FILE* my_fopen(const TCHAR *path, const char *mode); #define FOPEN(a, b) my_fopen((a), (b)) @@ -279,6 +279,10 @@ const UINT64 invalid_file_size64 = ~ (UINT64) 0; BYTE* alloc_and_read_file(FILE *f, unsigned long &size); BYTE* alloc_and_read_file(const TCHAR *filepath, unsigned long &size); +typedef struct { char*base; size_t internal; } FILEVIEW; +void close_file_view(FILEVIEW&mmfv); +char* create_file_view_readonly(const TCHAR *filepath, FILEVIEW&mmfv); + // round a value up to be a multiple of 512 // assumption: T is an int type template inline T align_to_512(const T x) { return (x+511) & ~511; }