Signed-off-by: Jeff Smith whydoubt@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