[PATCH 2/3] mspatcha: Implement GetFilePatchSignature functions.

Jeff Smith whydoubt at gmail.com
Fri May 22 11:21:35 CDT 2020


Signed-off-by: Jeff Smith <whydoubt at gmail.com>
---
 dlls/mspatcha/mspatcha_main.c   |  46 +++++++++----
 dlls/mspatcha/signature.c       | 117 ++++++++++++++++++++++++++++++++
 dlls/mspatcha/signature.h       |  15 ++++
 dlls/mspatcha/tests/signature.c |  68 +++++++++++++++++++
 include/patchapi.h              |   1 +
 5 files changed, 235 insertions(+), 12 deletions(-)

diff --git a/dlls/mspatcha/mspatcha_main.c b/dlls/mspatcha/mspatcha_main.c
index 34dc46b216..bda761adfe 100644
--- a/dlls/mspatcha/mspatcha_main.c
+++ b/dlls/mspatcha/mspatcha_main.c
@@ -231,10 +231,19 @@ BOOL WINAPI GetFilePatchSignatureA(LPCSTR filename, ULONG flags, PVOID data, ULO
     PPATCH_IGNORE_RANGE ignore_range, ULONG retain_range_count,
     PPATCH_RETAIN_RANGE retain_range, ULONG bufsize, LPSTR buffer)
 {
-    FIXME("stub - %s, %x, %p, %u, %p, %u, %p, %u, %p\n", debugstr_a(filename), flags, data,
+    BOOL ret;
+    WCHAR *filenameW;
+
+    TRACE("%s, %x, %p, %u, %p, %u, %p, %u, %p\n", debugstr_a(filename), flags, data,
         ignore_range_count, ignore_range, retain_range_count, retain_range, bufsize, buffer);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+
+    if (!(filenameW = strdupAW(filename)))
+        return FALSE;
+    ret = get_patch_signature(filenameW, flags, ignore_range_count, ignore_range,
+        retain_range_count, retain_range, bufsize, buffer);
+
+    HeapFree(GetProcessHeap(), 0, filenameW);
+    return ret;
 }
 
 /*****************************************************
@@ -244,10 +253,21 @@ BOOL WINAPI GetFilePatchSignatureW(LPCWSTR filename, ULONG flags, PVOID data, UL
     PPATCH_IGNORE_RANGE ignore_range, ULONG retain_range_count,
     PPATCH_RETAIN_RANGE retain_range, ULONG bufsize, LPWSTR buffer)
 {
-    FIXME("stub - %s, %x, %p, %u, %p, %u, %p, %u, %p\n", debugstr_w(filename), flags, data,
+    BOOL ret;
+    LPSTR abuffer;
+
+    TRACE("%s, %x, %p, %u, %p, %u, %p, %u, %p\n", debugstr_w(filename), flags, data,
         ignore_range_count, ignore_range, retain_range_count, retain_range, bufsize, buffer);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+
+    if (!(abuffer = HeapAlloc(GetProcessHeap(), 0, bufsize / 2)))
+        return FALSE;
+    ret = get_patch_signature(filename, flags, ignore_range_count, ignore_range,
+        retain_range_count, retain_range, bufsize / 2, abuffer);
+    if (ret)
+        MultiByteToWideChar(CP_ACP, 0, abuffer, -1, buffer, bufsize);
+
+    HeapFree(GetProcessHeap(), 0, abuffer);
+    return ret;
 }
 
 /*****************************************************
@@ -257,10 +277,11 @@ BOOL WINAPI GetFilePatchSignatureByHandle(HANDLE handle, ULONG flags, PVOID opti
     PPATCH_IGNORE_RANGE ignore_range, ULONG retain_range_count,
     PPATCH_RETAIN_RANGE retain_range, ULONG bufsize, LPSTR buffer)
 {
-    FIXME("stub - %p, %x, %p, %u, %p, %u, %p, %u, %p\n", handle, flags, options,
+    TRACE("%p, %x, %p, %u, %p, %u, %p, %u, %p\n", handle, flags, options,
         ignore_range_count, ignore_range, retain_range_count, retain_range, bufsize, buffer);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+
+    return get_patch_signature_by_handle(handle, flags, ignore_range_count, ignore_range,
+        retain_range_count, retain_range, bufsize, buffer);
 }
 
 /*****************************************************
@@ -271,10 +292,11 @@ BOOL WINAPI GetFilePatchSignatureByBuffer(PBYTE file_buf, ULONG file_size, ULONG
     ULONG retain_range_count, PPATCH_RETAIN_RANGE retain_range,
     ULONG bufsize, LPSTR buffer)
 {
-    FIXME("stub - %p, %u, %x, %p, %u, %p, %u, %p, %u, %p\n", file_buf, file_size, flags, options,
+    TRACE("%p, %u, %x, %p, %u, %p, %u, %p, %u, %p\n", file_buf, file_size, flags, options,
         ignore_range_count, ignore_range, retain_range_count, retain_range, bufsize, buffer);
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+
+    return get_patch_signature_by_buffer(file_buf, file_size, flags, ignore_range_count, ignore_range,
+        retain_range_count, retain_range, bufsize, buffer);
 }
 
 /*****************************************************
diff --git a/dlls/mspatcha/signature.c b/dlls/mspatcha/signature.c
index 6f6c085de7..434615b8c4 100644
--- a/dlls/mspatcha/signature.c
+++ b/dlls/mspatcha/signature.c
@@ -19,14 +19,131 @@
  */
 
 #include <stdarg.h>
+#include <stdlib.h>
 
 #include "windef.h"
+#include "winternl.h"
 #include "wine/heap.h"
 
 #include "patchapi.h"
 
 #include "signature.h"
 
+typedef struct
+{
+    unsigned int i[2];
+    unsigned int buf[4];
+    unsigned char in[64];
+    unsigned char digest[16];
+} MD5_CTX;
+
+extern VOID WINAPI MD5Init( MD5_CTX *);
+extern VOID WINAPI MD5Update( MD5_CTX *, const unsigned char *, unsigned int );
+extern VOID WINAPI MD5Final( MD5_CTX *);
+
+BOOL get_patch_signature(LPCWSTR filename, ULONG flags,
+    ULONG ignore_range_count, PPATCH_IGNORE_RANGE ignore_range,
+    ULONG retain_range_count, PPATCH_RETAIN_RANGE retain_range,
+    ULONG bufsize, LPSTR buffer)
+{
+    HANDLE file_handle;
+    BOOL res;
+    DWORD err = ERROR_SUCCESS;
+
+    file_handle = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+    if (file_handle == INVALID_HANDLE_VALUE)
+        return FALSE;
+
+    res = get_patch_signature_by_handle(file_handle, flags, ignore_range_count, ignore_range,
+            retain_range_count, retain_range, bufsize, buffer);
+
+    err = GetLastError();
+    CloseHandle(file_handle);
+    SetLastError(err);
+
+    return res;
+}
+
+BOOL get_patch_signature_by_handle(HANDLE file_handle, ULONG flags,
+    ULONG ignore_range_count, PPATCH_IGNORE_RANGE ignore_range,
+    ULONG retain_range_count, PPATCH_RETAIN_RANGE retain_range,
+    ULONG bufsize, LPSTR buffer)
+{
+    LPVOID file_buf;
+    LARGE_INTEGER file_size;
+    DWORD err;
+    BOOL res;
+
+    if (file_handle == INVALID_HANDLE_VALUE)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
+
+    file_size.QuadPart = 0;
+    if (!GetFileSizeEx(file_handle, &file_size))
+        return FALSE;
+
+    file_buf = heap_alloc(file_size.QuadPart);
+    if (!file_buf)
+        return FALSE;
+
+    res = ReadFile(file_handle, file_buf, file_size.QuadPart, NULL, NULL);
+    if (res)
+        res = get_patch_signature_by_buffer(file_buf, file_size.QuadPart, flags,
+            ignore_range_count, ignore_range, retain_range_count, retain_range, bufsize, buffer);
+
+    err = GetLastError();
+    heap_free(file_buf);
+    SetLastError(err);
+
+    return res;
+}
+
+BOOL get_patch_signature_by_buffer(PVOID file_buffer, ULONG file_size, ULONG flags,
+    ULONG ignore_range_count, PPATCH_IGNORE_RANGE ignore_range,
+    ULONG retain_range_count, PPATCH_RETAIN_RANGE retain_range,
+    ULONG bufsize, LPSTR buffer)
+{
+    if (!normalize_for_patch_signature(file_buffer, file_size, flags, 0x10000000, 0x10000000,
+            ignore_range_count, ignore_range, retain_range_count, retain_range))
+        return FALSE;
+
+    if (flags & PATCH_OPTION_SIGNATURE_MD5)
+    {
+        static const char hex[16] = "0123456789abcdef";
+        MD5_CTX ctx;
+        UINT i;
+
+        MD5Init(&ctx);
+        MD5Update(&ctx, file_buffer, file_size);
+        MD5Final(&ctx);
+
+        if (bufsize < 33)
+            goto insufficient_buffer;
+        for (i = 0; i < 16; i++)
+        {
+            buffer[i*2] = hex[ctx.digest[i] >> 4];
+            buffer[i*2+1] = hex[ctx.digest[i] & 0xf];
+        }
+        buffer[32] = 0;
+    }
+    else
+    {
+        DWORD crc = RtlComputeCrc32(0, file_buffer, file_size);
+
+        if (bufsize < 9)
+            goto insufficient_buffer;
+        _ltoa(crc, buffer, 16);
+    }
+
+    return TRUE;
+
+insufficient_buffer:
+    SetLastError(ERROR_INSUFFICIENT_BUFFER);
+    return FALSE;
+}
+
 /*
  * Check for PE32 signatures and return file offset if found.
  */
diff --git a/dlls/mspatcha/signature.h b/dlls/mspatcha/signature.h
index b55ab84b7c..fb18f7e288 100644
--- a/dlls/mspatcha/signature.h
+++ b/dlls/mspatcha/signature.h
@@ -18,6 +18,21 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+BOOL get_patch_signature(LPCWSTR filename, ULONG flags,
+    ULONG ignore_range_count, PPATCH_IGNORE_RANGE ignore_range,
+    ULONG retain_range_count, PPATCH_RETAIN_RANGE retain_range,
+    ULONG bufsize, LPSTR buffer);
+
+BOOL get_patch_signature_by_handle(HANDLE file_handle, ULONG flags,
+    ULONG ignore_range_count, PPATCH_IGNORE_RANGE ignore_range,
+    ULONG retain_range_count, PPATCH_RETAIN_RANGE retain_range,
+    ULONG bufsize, LPSTR buffer);
+
+BOOL get_patch_signature_by_buffer(PVOID file_buffer, ULONG file_size, ULONG flags,
+    ULONG ignore_range_count, PPATCH_IGNORE_RANGE ignore_range,
+    ULONG retain_range_count, PPATCH_RETAIN_RANGE retain_range,
+    ULONG bufsize, LPSTR buffer);
+
 DWORD get_pe_offset(LPCVOID file_buffer, ULONG file_size);
 
 BOOL normalize_pe(PVOID file_buffer, ULONG file_size, DWORD pe_offset,
diff --git a/dlls/mspatcha/tests/signature.c b/dlls/mspatcha/tests/signature.c
index bd2f9dc8be..ad570ef735 100644
--- a/dlls/mspatcha/tests/signature.c
+++ b/dlls/mspatcha/tests/signature.c
@@ -24,6 +24,8 @@
 
 static BOOL (WINAPI *pNormalizeFileForPatchSignature)(PVOID, ULONG, ULONG, PATCH_OPTION_DATA*, ULONG,
         ULONG, ULONG, PPATCH_IGNORE_RANGE, ULONG, PPATCH_RETAIN_RANGE);
+static BOOL (WINAPI *pGetFilePatchSignatureByBuffer)(PBYTE, ULONG, ULONG, PVOID, ULONG,
+        PPATCH_IGNORE_RANGE, ULONG, PPATCH_RETAIN_RANGE, ULONG, LPSTR);
 
 static BYTE array[1024];
 
@@ -36,6 +38,7 @@ static BOOL init_function_pointers(void)
         return FALSE;
     }
     pNormalizeFileForPatchSignature = (void *)GetProcAddress(mspatcha, "NormalizeFileForPatchSignature");
+    pGetFilePatchSignatureByBuffer = (void *)GetProcAddress(mspatcha, "GetFilePatchSignatureByBuffer");
 
     return TRUE;
 }
@@ -307,6 +310,70 @@ static void test_normalize_rebase(void)
         image_base_initial, header->OptionalHeader.ImageBase);
 }
 
+static void test_signature_by_buffer(void)
+{
+    PIMAGE_NT_HEADERS32 header;
+    BOOL result;
+    DWORD err;
+    char buf[33];
+
+    if (!pGetFilePatchSignatureByBuffer)
+        return;
+
+    /* Test CRC32 signature */
+    memset(array, 0xcc, 8);
+    buf[0] = '\0';
+    result = pGetFilePatchSignatureByBuffer(array, 8, 0, NULL, 0, NULL, 0, NULL, 9, buf);
+    ok(result == TRUE, "Expected %d, got %d\n", TRUE, result);
+    ok(!strcmp(buf, "58ea8bb8"), "Expected %s, got %s\n", "58ea8bb8", buf);
+
+    /* Test MD5 signature w/ insufficient buffer */
+    memset(array, 0xcc, 8);
+    buf[0] = '\0';
+    SetLastError(0xdeadbeef);
+    result = pGetFilePatchSignatureByBuffer(array, 8, 0, NULL, 0, NULL, 0, NULL, 8, buf);
+    err = GetLastError();
+    ok(result == FALSE, "Expected %d, got %d\n", FALSE, result);
+    ok(err == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got %#x\n", err);
+    ok(!buf[0], "Got unexpected %s\n", buf);
+
+    /* Test MD5 signature */
+    memset(array, 0xcc, 8);
+    buf[0] = '\0';
+    result = pGetFilePatchSignatureByBuffer(array, 8, PATCH_OPTION_SIGNATURE_MD5, NULL,
+        0, NULL, 0, NULL, 33, buf);
+    ok(result == TRUE, "Expected %d, got %d\n", TRUE, result);
+    ok(!strcmp(buf, "7bffa66e1c861fcbf38426d134508908"), "Expected %s, got %s\n",
+        "7bffa66e1c861fcbf38426d134508908", buf);
+
+    /* Test MD5 signature w/ insufficient buffer */
+    memset(array, 0xcc, 8);
+    buf[0] = '\0';
+    SetLastError(0xdeadbeef);
+    result = pGetFilePatchSignatureByBuffer(array, 8, PATCH_OPTION_SIGNATURE_MD5, NULL,
+        0, NULL, 0, NULL, 32, buf);
+    err = GetLastError();
+    ok(result == FALSE, "Expected %d, got %d\n", FALSE, result);
+    ok(err == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got %#x\n", err);
+    ok(!buf[0], "Got unexpected %s\n", buf);
+
+    /* Test signature of PE32 executable image */
+    memset(array, 0, 1024);
+    setup_pe_with_sections(array, &header, NULL);
+    header->FileHeader.TimeDateStamp = 0xdeadbeef;
+    header->OptionalHeader.CheckSum = 0xdeadbeef;
+    header->OptionalHeader.ImageBase = 0x400000;
+    result = pGetFilePatchSignatureByBuffer(array, 1024, 0, NULL, 0, NULL, 0, NULL, 9, buf);
+    ok(result == TRUE, "Expected %d, got %d\n", TRUE, result);
+    ok(!strcmp(buf, "f953f764"), "Expected %s, got %s\n", "f953f764", buf);
+    ok(header->FileHeader.TimeDateStamp == 0x10000000, "Expected %#x, got %#x\n",
+        0x10000000, header->FileHeader.TimeDateStamp);
+    ok(header->OptionalHeader.CheckSum == 0x9dd2, "Expected %#x, got %#x\n",
+        0x9dd2, header->OptionalHeader.CheckSum);
+    ok(header->OptionalHeader.ImageBase == 0x10000000, "Expected %#x, got %#x\n",
+        0x10000000, header->OptionalHeader.ImageBase);
+}
+
 START_TEST(signature)
 {
     if (!init_function_pointers())
@@ -316,4 +383,5 @@ START_TEST(signature)
     test_normalize_retain_range();
     test_normalize_flags();
     test_normalize_rebase();
+    test_signature_by_buffer();
 }
diff --git a/include/patchapi.h b/include/patchapi.h
index 1ccdf9dec7..9540154568 100644
--- a/include/patchapi.h
+++ b/include/patchapi.h
@@ -36,6 +36,7 @@ extern "C" {
 #define PATCH_OPTION_NO_CHECKSUM       0x00200000
 #define PATCH_OPTION_NO_RESTIMEFIX     0x00400000
 #define PATCH_OPTION_NO_TIMESTAMP      0x00800000
+#define PATCH_OPTION_SIGNATURE_MD5     0x01000000
 #define PATCH_OPTION_INTERLEAVE_FILES  0x40000000
 #define PATCH_OPTION_RESERVED1         0x80000000
 
-- 
2.23.0




More information about the wine-devel mailing list