new byte pattern search alg
Ported to C from @x64dbg's patternfind.cpp. https://github.com/x64dbg/x64dbg/blob/development/src/dbg/patternfind.cpp This one is much better than my previous implementation because now I can use wildcards on single nibbles!
This commit is contained in:
45
wufuc/core.c
45
wufuc/core.c
@@ -5,6 +5,7 @@
|
||||
#include <sddl.h>
|
||||
#include "service.h"
|
||||
#include "util.h"
|
||||
#include "patternfind.h"
|
||||
#include "core.h"
|
||||
|
||||
DWORD WINAPI NewThreadProc(LPVOID lpParam) {
|
||||
@@ -46,7 +47,7 @@ DWORD WINAPI NewThreadProc(LPVOID lpParam) {
|
||||
get_svcdll(_T("wuauserv"), lpServiceDll, _countof(lpServiceDll));
|
||||
|
||||
HMODULE hwu = GetModuleHandle(lpServiceDll);
|
||||
if (hwu && PatchWUModule(hwu)) {
|
||||
if (hwu && PatchWUAgentHMODULE(hwu)) {
|
||||
_tdbgprintf(_T("Patched previously loaded Windows Update module!"));
|
||||
}
|
||||
ResumeAndCloseThreads(lphThreads, cb);
|
||||
@@ -66,35 +67,20 @@ DWORD WINAPI NewThreadProc(LPVOID lpParam) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL PatchWUModule(HMODULE hModule) {
|
||||
BOOL PatchWUAgentHMODULE(HMODULE hModule) {
|
||||
LPSTR lpszPattern;
|
||||
SIZE_T n1, n2;
|
||||
#ifdef _WIN64
|
||||
lpszPattern =
|
||||
"FFF3" // push rbx
|
||||
"4883EC??" // sub rsp,??
|
||||
"33DB" // xor ebx,ebx
|
||||
"391D????????" // cmp dword ptr ds:[???????????],ebx
|
||||
"7508" // jnz $+8
|
||||
"8B05????????"; // mov eax,dword ptr ds:[???????????]
|
||||
lpszPattern = "FFF3 4883EC?? 33DB 391D???????? 7508 8B05????????";
|
||||
n1 = 10;
|
||||
n2 = 18;
|
||||
#elif defined(_WIN32)
|
||||
if (WindowsVersionCompare(VER_EQUAL, 6, 1, 0, 0, VER_MAJORVERSION | VER_MINORVERSION)) {
|
||||
lpszPattern =
|
||||
"833D????????00" // cmp dword ptr ds:[????????],0
|
||||
"743E" // je $+3E
|
||||
"E8????????" // call <wuaueng.IsCPUSupported>
|
||||
"A3????????"; // mov dword ptr ds:[????????],eax
|
||||
lpszPattern = "833D????????00 743E E8???????? A3????????";
|
||||
n1 = 2;
|
||||
n2 = 15;
|
||||
} else if (WindowsVersionCompare(VER_EQUAL, 6, 3, 0, 0, VER_MAJORVERSION | VER_MINORVERSION)) {
|
||||
lpszPattern =
|
||||
"8BFF" // mov edi,edi
|
||||
"51" // push ecx
|
||||
"833D????????00" // cmp dword ptr ds:[????????],0
|
||||
"7507" // jnz $+7
|
||||
"A1????????"; // mov eax,dword ptr ds:[????????]
|
||||
lpszPattern = "8BFF 51 833D????????00 7507 A1????????";
|
||||
n1 = 5;
|
||||
n2 = 13;
|
||||
}
|
||||
@@ -105,20 +91,21 @@ BOOL PatchWUModule(HMODULE hModule) {
|
||||
MODULEINFO modinfo;
|
||||
GetModuleInformation(GetCurrentProcess(), hModule, &modinfo, sizeof(MODULEINFO));
|
||||
|
||||
SIZE_T rva;
|
||||
if (!FindPattern(modinfo.lpBaseOfDll, modinfo.SizeOfImage, lpszPattern, 0, &rva)) {
|
||||
SIZE_T rva = patternfind(modinfo.lpBaseOfDll, modinfo.SizeOfImage, 0, lpszPattern);
|
||||
if (rva == -1) {
|
||||
_tdbgprintf(_T("No pattern match!"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
SIZE_T fpIsDeviceServiceable = (SIZE_T)modinfo.lpBaseOfDll + rva;
|
||||
_tdbgprintf(_T("Pattern match at offset %p."), fpIsDeviceServiceable);
|
||||
|
||||
BOOL result = FALSE;
|
||||
|
||||
DWORD flOldProtect;
|
||||
DWORD flNewProtect = PAGE_READWRITE;
|
||||
BOOL *lpbNotRunOnce = (BOOL *)(fpIsDeviceServiceable + n1 + sizeof(DWORD) + *(DWORD *)(fpIsDeviceServiceable + n1));
|
||||
if (*lpbNotRunOnce) {
|
||||
DWORD flOldProtect;
|
||||
DWORD flNewProtect = PAGE_READWRITE;
|
||||
VirtualProtect(lpbNotRunOnce, sizeof(BOOL), flNewProtect, &flOldProtect);
|
||||
*lpbNotRunOnce = FALSE;
|
||||
VirtualProtect(lpbNotRunOnce, sizeof(BOOL), flOldProtect, &flNewProtect);
|
||||
@@ -128,8 +115,6 @@ BOOL PatchWUModule(HMODULE hModule) {
|
||||
|
||||
BOOL *lpbCachedResult = (BOOL *)(fpIsDeviceServiceable + n2 + sizeof(DWORD) + *(DWORD *)(fpIsDeviceServiceable + n2));
|
||||
if (!*lpbCachedResult) {
|
||||
DWORD flOldProtect;
|
||||
DWORD flNewProtect = PAGE_READWRITE;
|
||||
VirtualProtect(lpbCachedResult, sizeof(BOOL), flNewProtect, &flOldProtect);
|
||||
*lpbCachedResult = TRUE;
|
||||
VirtualProtect(lpbCachedResult, sizeof(BOOL), flOldProtect, &flNewProtect);
|
||||
@@ -145,14 +130,14 @@ HMODULE WINAPI _LoadLibraryExA(
|
||||
_In_ DWORD dwFlags
|
||||
) {
|
||||
HMODULE result = LoadLibraryExA(lpFileName, hFile, dwFlags);
|
||||
_dbgprintf("Loaded %s.", lpFileName);
|
||||
if (result) {
|
||||
_dbgprintf("Loaded %s.", lpFileName);
|
||||
CHAR path[MAX_PATH + 1];
|
||||
if (!get_svcdllA("wuauserv", path, _countof(path))) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!_stricmp(lpFileName, path) && PatchWUModule(result)) {
|
||||
if (!_stricmp(lpFileName, path) && PatchWUAgentHMODULE(result)) {
|
||||
_dbgprintf("Patched Windows Update module!");
|
||||
}
|
||||
}
|
||||
@@ -165,14 +150,14 @@ HMODULE WINAPI _LoadLibraryExW(
|
||||
_In_ DWORD dwFlags
|
||||
) {
|
||||
HMODULE result = LoadLibraryExW(lpFileName, hFile, dwFlags);
|
||||
_wdbgprintf(L"Loaded library: %s.", lpFileName);
|
||||
if (result) {
|
||||
_wdbgprintf(L"Loaded library: %s.", lpFileName);
|
||||
WCHAR path[MAX_PATH + 1];
|
||||
if (!get_svcdllW(L"wuauserv", path, _countof(path))) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!_wcsicmp(lpFileName, path) && PatchWUModule(result)) {
|
||||
if (!_wcsicmp(lpFileName, path) && PatchWUAgentHMODULE(result)) {
|
||||
_wdbgprintf(L"Patched Windows Update module!");
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
DWORD WINAPI NewThreadProc(LPVOID lpParam);
|
||||
|
||||
BOOL PatchWUModule(HMODULE hModule);
|
||||
BOOL PatchWUAgentHMODULE(HMODULE hModule);
|
||||
|
||||
HMODULE WINAPI _LoadLibraryExA(
|
||||
_In_ LPCSTR lpFileName,
|
||||
|
118
wufuc/patternfind.c
Normal file
118
wufuc/patternfind.c
Normal file
@@ -0,0 +1,118 @@
|
||||
#include <Windows.h>
|
||||
#include "patternfind.h"
|
||||
|
||||
/*
|
||||
Work in progress. Ported to C from x64dbg's patternfind.cpp:
|
||||
https://github.com/x64dbg/x64dbg/blob/development/src/dbg/patternfind.cpp
|
||||
x64dbg license (GPL-3.0):
|
||||
https://github.com/x64dbg/x64dbg/blob/development/LICENSE
|
||||
*/
|
||||
|
||||
int hexchtoint(CHAR ch) {
|
||||
int result = -1;
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
result = ch - '0';
|
||||
} else if (ch >= 'A' && ch <= 'F') {
|
||||
result = ch - 'A' + 10;
|
||||
} else if (ch >= 'a' && ch <= 'f') {
|
||||
result = ch - 'a' + 10;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
SIZE_T formathexpattern(LPCSTR patterntext, LPSTR formattext, SIZE_T formattextsize) {
|
||||
SIZE_T len = strlen(patterntext);
|
||||
SIZE_T result = 0;
|
||||
for (SIZE_T i = 0; i < len && (!formattext || result < formattextsize); i++) {
|
||||
if (patterntext[i] == '?' || hexchtoint(patterntext[i]) != -1) {
|
||||
if (formattext) {
|
||||
formattext[result] = patterntext[i];
|
||||
}
|
||||
result++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL patterntransform(LPCSTR patterntext, LPPATTERNBYTE pattern, SIZE_T *patternsize) {
|
||||
SIZE_T cb = formathexpattern(patterntext, NULL, 0);
|
||||
if (!cb || cb > *patternsize) {
|
||||
return FALSE;
|
||||
}
|
||||
LPSTR formattext = calloc(cb, sizeof(CHAR));
|
||||
cb = formathexpattern(patterntext, formattext, cb);
|
||||
|
||||
if (cb % 2) {
|
||||
formattext[++cb] = '?';
|
||||
}
|
||||
formattext[cb] = '\0';
|
||||
|
||||
for (SIZE_T i = 0, j = 0, k = 0; i < cb; i++, j ^= 1, k = (i - j) / 2) {
|
||||
if (formattext[i] == '?') {
|
||||
pattern[k].nibble[j].wildcard = TRUE;
|
||||
} else {
|
||||
pattern[k].nibble[j].wildcard = FALSE;
|
||||
pattern[k].nibble[j].data = hexchtoint(formattext[i]) & 0xf;
|
||||
}
|
||||
}
|
||||
free(formattext);
|
||||
*patternsize = cb / 2;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
SIZE_T patternfind(LPCBYTE data, SIZE_T datasize, SIZE_T startindex, LPCSTR pattern) {
|
||||
SIZE_T result = -1;
|
||||
SIZE_T searchpatternsize = strlen(pattern);
|
||||
LPPATTERNBYTE searchpattern = calloc(searchpatternsize, sizeof(PATTERNBYTE));
|
||||
if (patterntransform(pattern, searchpattern, &searchpatternsize)) {
|
||||
for (SIZE_T i = startindex, j = 0; i < datasize; i++) //search for the pattern
|
||||
{
|
||||
if ((searchpattern[j].nibble[0].wildcard || searchpattern[j].nibble[0].data == ((data[i] >> 4) & 0xf))
|
||||
&& (searchpattern[j].nibble[1].wildcard || searchpattern[j].nibble[1].data == (data[i] & 0xf))) { //check if our pattern matches the current byte
|
||||
|
||||
if (++j == searchpatternsize) { //everything matched
|
||||
result = i - searchpatternsize + 1;
|
||||
break;
|
||||
}
|
||||
} else if (j > 0) { //fix by Computer_Angel
|
||||
i -= j;
|
||||
j = 0; //reset current pattern position
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//VOID patternwritebyte(LPBYTE byte, LPPATTERNBYTE pbyte) {
|
||||
// BYTE n1 = (*byte >> 4) & 0xf;
|
||||
// BYTE n2 = *byte & 0xf;
|
||||
// if (!pbyte->nibble[0].wildcard) {
|
||||
// n1 = pbyte->nibble[0].data;
|
||||
// }
|
||||
// if (!pbyte->nibble[1].wildcard) {
|
||||
// n2 = pbyte->nibble[1].data;
|
||||
// }
|
||||
// *byte = ((n1 << 4) & 0xf0) | (n2 & 0xf);
|
||||
//}
|
||||
//
|
||||
//VOID patternwrite(LPBYTE data, SIZE_T datasize, LPCSTR pattern) {
|
||||
// SIZE_T writepatternsize = strlen(pattern);
|
||||
// if (writepatternsize > datasize) {
|
||||
// writepatternsize = datasize;
|
||||
// }
|
||||
// LPPATTERNBYTE writepattern = calloc(writepatternsize, sizeof(PATTERNBYTE));
|
||||
// if (!patterntransform(pattern, writepattern, &writepatternsize)) {
|
||||
// return;
|
||||
// }
|
||||
// for (size_t i = 0; i < writepatternsize; i++) {
|
||||
// patternwritebyte(&data[i], &writepattern[i]);
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//SIZE_T patternsnr(LPBYTE data, SIZE_T datasize, SIZE_T startindex, LPCSTR searchpattern, LPCSTR replacepattern) {
|
||||
// SIZE_T result = patternfind(data, datasize, startindex, searchpattern, NULL, 0);
|
||||
// if (result == -1)
|
||||
// return result;
|
||||
// patternwrite(data + result, datasize - result, replacepattern);
|
||||
// return result;
|
||||
//}
|
16
wufuc/patternfind.h
Normal file
16
wufuc/patternfind.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
typedef struct _PATTERNBYTE {
|
||||
struct _PATTERNNIBBLE {
|
||||
BYTE data;
|
||||
BOOL wildcard;
|
||||
} nibble[2];
|
||||
} PATTERNBYTE, *PPATTERNBYTE, *LPPATTERNBYTE;
|
||||
|
||||
int hexchtoint(CHAR ch);
|
||||
SIZE_T formathexpattern(LPCSTR patterntext, LPSTR formattext, SIZE_T formattextsize);
|
||||
BOOL patterntransform(LPCSTR patterntext, LPPATTERNBYTE pattern, SIZE_T *patternsize);
|
||||
SIZE_T patternfind(LPCBYTE data, SIZE_T datasize, SIZE_T startindex, LPCSTR pattern);
|
||||
//VOID patternwritebyte(LPBYTE byte, LPPATTERNBYTE pbyte);
|
||||
//VOID patternwrite(LPBYTE data, SIZE_T datasize, LPCSTR pattern)
|
||||
//SIZE_T patternsnr(LPBYTE data, SIZE_T datasize, SIZE_T startindex, LPCSTR searchpattern, LPCSTR replacepattern);
|
41
wufuc/util.c
41
wufuc/util.c
@@ -38,47 +38,6 @@ LPVOID *FindIAT(HMODULE hModule, LPSTR lpFunctionName) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BOOL FindPattern(LPCBYTE pvData, SIZE_T nNumberOfBytes, LPSTR lpszPattern, SIZE_T nStart, SIZE_T *lpOffset) {
|
||||
SIZE_T length = strlen(lpszPattern);
|
||||
SIZE_T nBytes;
|
||||
if (length % 2 || (nBytes = length / 2) > nNumberOfBytes) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
LPBYTE lpBytes = malloc(nBytes * sizeof(BYTE));
|
||||
BOOL *lpbwc = malloc(nBytes * sizeof(BOOL));
|
||||
|
||||
LPSTR p = lpszPattern;
|
||||
BOOL valid = TRUE;
|
||||
for (SIZE_T i = 0; i < nBytes; i++) {
|
||||
if ((lpbwc[i] = strncmp(p, "??", 2)) && sscanf_s(p, "%2hhx", &lpBytes[i]) != 1) {
|
||||
valid = FALSE;
|
||||
break;
|
||||
}
|
||||
p += 2;
|
||||
}
|
||||
BOOL result = FALSE;
|
||||
if (valid) {
|
||||
for (SIZE_T i = nStart; i < nNumberOfBytes - nStart - (nBytes - 1); i++) {
|
||||
BOOL found = TRUE;
|
||||
for (SIZE_T j = 0; j < nBytes; j++) {
|
||||
if (lpbwc[j] && pvData[i + j] != lpBytes[j]) {
|
||||
found = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
*lpOffset = i;
|
||||
result = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(lpBytes);
|
||||
free(lpbwc);
|
||||
return result;
|
||||
}
|
||||
|
||||
VOID SuspendProcessThreads(DWORD dwProcessId, DWORD dwThreadId, HANDLE *lphThreads, SIZE_T dwSize, SIZE_T *lpcb) {
|
||||
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
|
||||
THREADENTRY32 te;
|
||||
|
@@ -14,8 +14,6 @@ VOID DetourIAT(HMODULE hModule, LPSTR lpFuncName, LPVOID *lpOldAddress, LPVOID l
|
||||
|
||||
LPVOID *FindIAT(HMODULE hModule, LPSTR lpFuncName);
|
||||
|
||||
BOOL FindPattern(LPCBYTE lpBytes, SIZE_T nNumberOfBytes, LPSTR lpszPattern, SIZE_T nStart, SIZE_T *lpOffset);
|
||||
|
||||
VOID SuspendProcessThreads(DWORD dwProcessId, DWORD dwThreadId, HANDLE *lphThreads, SIZE_T dwSize, SIZE_T *lpcb);
|
||||
|
||||
VOID ResumeAndCloseThreads(HANDLE *lphThreads, SIZE_T dwSize);
|
||||
|
@@ -177,6 +177,7 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="core.c" />
|
||||
<ClCompile Include="dllmain.c" />
|
||||
<ClCompile Include="patternfind.c" />
|
||||
<ClCompile Include="rundll32.c" />
|
||||
<ClCompile Include="service.c" />
|
||||
<ClCompile Include="util.c" />
|
||||
@@ -186,6 +187,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="core.h" />
|
||||
<ClInclude Include="patternfind.h" />
|
||||
<ClInclude Include="service.h" />
|
||||
<ClInclude Include="shellapihelper.h" />
|
||||
<ClInclude Include="util.h" />
|
||||
|
Reference in New Issue
Block a user