Skip to content

Commit

Permalink
Drop alignment requirement and switch to big-endian values
Browse files Browse the repository at this point in the history
* Also add a more user friendly error message if the target does not exist
  and fix a couple minor issues.
  • Loading branch information
pbatard committed Jul 13, 2020
1 parent 10386a8 commit d5c1a1a
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 19 deletions.
8 changes: 4 additions & 4 deletions .vs/winpatch.vcxproj.user
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerCommandArguments>F:\Windows\System32\drivers\USBXHCI.SYS 910063E8370000EA 910063E8360000EA 3700010AD5033F9F 3600010AD5033F9F</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>F:\Windows\System32\drivers\USBXHCI.SYS EA000037E8630091 EA000036E8630091 0A010037E8430091 0A010036E8430091</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LocalDebuggerCommandArguments>F:\Windows\System32\drivers\USBXHCI.SYS 910063E8370000EA 910063E8360000EA 3700010AD5033F9F 3600010AD5033F9F</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>F:\Windows\System32\drivers\USBXHCI.SYS EA000037E8630091 EA000036E8630091 0A010037E8430091 0A010036E8430091</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerCommandArguments>C:\tmp\USBXHCI.SYS 910063E8370000EA 910063E8360000EA 3700010AD5033F9F 3600010AD5033F9F</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>C:\tmp\USBXHCI.SYS EA000037E8630091 EA000036E8630091 0A010037E8430091 0A010036E8430091</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerCommandArguments>C:\tmp\USBXHCI.SYS 910063E8370000EA 910063E8360000EA 3700010AD5033F9F 3600010AD5033F9F</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>C:\tmp\USBXHCI.SYS EA000037E8630091 EA000036E8630091 0A010037E8430091 0A010036E8430091</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>
26 changes: 23 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,27 @@ Compilation

Use Visual Studio 2019 and invoke the `.sln` to compile.

Usage
-----

```
winpatch target original_qword patched_qword [original_qword patched_qword [...]]
```

Where:
* `target` is the path of the system file you want to patch
* `original_qword` is a **64-bit hex value** that matches the original data you want to patch
* `patched_qword` is a **64-bit hex value** with the data you want to replace the orignal with.

Note that the qwords are big-endian, which means the hex values should appear in the same byte
order as the one you see from a hex-dump of the file.

No specific alignment is required on the qwords (meaning that `winpatch` will match and patch
qwords that start on a odd byte address for instance).

The exit code of winpatch is the number of qwords that were successfully patched (`0` if none
were) or a negative value on error.

Example
-------

Expand All @@ -38,7 +59,7 @@ Provided that the driver for the system you want to patch resides in `F:\Windows
from an elevated command prompt, you can use `winpatch` as follows:

```
winpatch F:\Windows\System32\drivers\USBXHCI.SYS 910063E8370000EA 910063E8360000EA 3700010AD5033F9F 3600010AD5033F9F
winpatch F:\Windows\System32\drivers\USBXHCI.SYS EA000037E8630091 EA000036E8630091 0A010037E8430091 0A010036E8430091
```

Obviously, since you have patched a system file, you also have to disable signature enforcement with
Expand All @@ -52,8 +73,7 @@ bcdedit /store S:\EFI\Microsoft\Boot\BCD /set {default} nointegritychecks on
How it works
------------

Besides the patching (which currently __must__ be aligned to 64-bit, i.e. winpatch does match
with QWORDs that start at a 32-bit offset in the file), winpatch performs the following:
Besides the patching, winpatch performs the following:

1. Take ownership of the system file if needed.
2. Delete the existing digital signature, if any.
Expand Down
33 changes: 27 additions & 6 deletions src/winpatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
#include "msapi_utf8.h"

#pragma comment(lib, "imagehlp.lib")
#pragma comment(lib, "shlwapi.lib")
#pragma intrinsic(_byteswap_uint64)

#define _STRINGIFY(x) #x
#define STRINGIFY(x) _STRINGIFY(x)
Expand Down Expand Up @@ -479,12 +481,14 @@ static int main_utf8(int argc, char** argv)

if (argc < 2) {
fprintf(stderr, "Usage: %s filename [QWORD QWORD [QWORD QWORD]...].\n", appname(argv[0]));
fprintf(stderr, "The QWORDs *must* be aligned to 64-bit.\n");
return -2;
}

fprintf(stderr, "%s %s © 2020 Pete Batard <pete@akeo.ie>\n\n",
appname(argv[0]), APP_VERSION_STR);
fprintf(stderr, "%s %s © 2020 Pete Batard <pete@akeo.ie>\n\n", appname(argv[0]), APP_VERSION_STR);
fprintf(stderr, "This program is free software; you can redistribute it and/or modify it under \n");
fprintf(stderr, "the terms of the GNU General Public License as published by the Free Software \n");
fprintf(stderr, "Foundation; either version 3 of the License or any later version.\n\n");
fprintf(stderr, "Official project and latest downloads at: https://github.com/pbatard/winpatch\n\n");

if (GetSystemDirectoryU(system_dir, sizeof(system_dir)) == 0)
static_strcpy(system_dir, "C:\\Windows\\System32");
Expand All @@ -493,6 +497,11 @@ static int main_utf8(int argc, char** argv)
return -1;
}

if (!PathFileExistsU(argv[1])) {
fprintf(stderr, "File '%s' doesn't exist\n", argv[1]);
return -1;
}

if (!TakeOwnership(argv[1])) {
fprintf(stderr, "Could not take ownership of %s\n", argv[1]);
return -1;
Expand Down Expand Up @@ -529,20 +538,32 @@ static int main_utf8(int argc, char** argv)
for (i = 0; i < argc - 2; i++)
patch[i] = strtoull(argv[i + 2], NULL, 16);

for (pos = 0; fread(&val, sizeof(uint64_t), 1, file) == 1; pos += sizeof(uint64_t)) {
if (fread(&val, 1, 7, file) != 7) {
fprintf(stderr, "Could not read file\n");
return -1;
}
val = _byteswap_uint64(val);
for (pos = 0; fread(&val, 1, 1, file) == 1; pos++) {
for (i = 0; i < argc - 2; i += 2) {
if (val == patch[i]) {
fprintf(stdout, "%08llX: %016llX -> %016llX... ", pos, val, patch[i + 1]);
fprintf(stdout, "%08llX: %016llX -> %016llX... ", pos, patch[i], patch[i + 1]);
fseek(file, -1 * (long)sizeof(uint64_t), SEEK_CUR);
if (fwrite(&patch[i + 1], sizeof(uint64_t), 1, file) != 1) {
val = _byteswap_uint64(patch[i + 1]);
if (fwrite(&val, sizeof(uint64_t), 1, file) != 1) {
fprintf(stdout, "ERROR!\n");
} else {
fprintf(stdout, "SUCCESS\n");
patched++;
fflush(file);
// We don't allow patch overlap so move 7 bytes ahead
pos += fread(&val, 1, 7, file);
val = _byteswap_uint64(val) >> 8;
}
fflush(file);
break;
}
}
val <<= 8;
}
free(patch);
fclose(file);
Expand Down
12 changes: 6 additions & 6 deletions src/winpki.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
*/

/* Memory leaks detection - define _CRTDBG_MAP_ALLOC as preprocessor macro */
#ifdef _CRTDBG_MAP_ALLOC
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#endif
Expand Down Expand Up @@ -69,7 +70,7 @@ static char* winpki_error_str(void)
if (error_code == 0x800706D9)
return "This system is missing required cryptographic services";
if (error_code == 0x80070020)
return "Cannot sign file residing in a system directory";
return "Some data handles to this file have not been properly closed";

if ((error_code >> 16) != 0x8009) {
static_sprintf(error_string, "Windows error 0x%08X", error_code);
Expand Down Expand Up @@ -208,7 +209,7 @@ PCCERT_CONTEXT CreateSelfSignedCert(LPCSTR szCertSubject)
certExtension[0].Value.cbData = dwSize;
certExtension[0].Value.pbData = pbEnhKeyUsage;

// Set URL as Alt Name parameter
// Set Alt Name parameter
if ( (!CryptEncodeObject(X509_ASN_ENCODING, X509_ALTERNATE_NAME, (LPVOID)&certAltNameInfo, NULL, &dwSize))
|| ((pbAltNameInfo = (BYTE*)malloc(dwSize)) == NULL)
|| (!CryptEncodeObject(X509_ASN_ENCODING, X509_ALTERNATE_NAME, (LPVOID)&certAltNameInfo, pbAltNameInfo, &dwSize)) ) {
Expand Down Expand Up @@ -372,11 +373,10 @@ BOOL SelfSignFile(LPCSTR szFileName, LPCSTR szCertSubject)
PF_DECL(SignerFreeSignerContext);

BOOL r = FALSE;
LPWSTR wszFileName = NULL;
HRESULT hResult = S_OK;
PCCERT_CONTEXT pCertContext = NULL;
DWORD dwIndex;
SIGNER_FILE_INFO signerFileInfo;
SIGNER_FILE_INFO signerFileInfo = { 0 };
SIGNER_SUBJECT_INFO signerSubjectInfo;
SIGNER_CERT_STORE_INFO signerCertStoreInfo;
SIGNER_CERT signerCert;
Expand Down Expand Up @@ -458,7 +458,7 @@ BOOL SelfSignFile(LPCSTR szFileName, LPCSTR szCertSubject)
out:
if (pCertContext != NULL)
DeletePrivateKey(pCertContext);
free((void*)wszFileName);
free((void*)signerFileInfo.pwszFileName);
if (pSignerContext != NULL)
pfSignerFreeSignerContext(pSignerContext);
if (pCertContext != NULL)
Expand Down

0 comments on commit d5c1a1a

Please sign in to comment.