Files
hfiref0x f9a3362f0e Add test utility
Test code for pattern lookups
2022-05-27 11:46:22 +07:00

419 lines
9.5 KiB
C++

#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
//
// Search callback, return TRUE to stop search.
//
typedef BOOL(CALLBACK* pfnSearchCallback)(
_In_ PBYTE Buffer,
_In_ ULONG PatternSize,
_In_opt_ PVOID CallbackContext
);
typedef struct _SEARCH_PARAMS {
PBYTE Buffer;
DWORD BufferSize;
PBYTE Pattern;
DWORD PatternSize;
PBYTE Mask;
pfnSearchCallback Callback;
PVOID CallbackContext;
} SEARCH_PARAMS, * PSEARCH_PARAMS;
DWORD SearchPattern(
_In_ PSEARCH_PARAMS SearchParams
)
{
PBYTE p;
DWORD c, i, n;
BOOLEAN found;
BYTE low, high;
DWORD bufferSize;
if (SearchParams == NULL)
return 0;
if ((SearchParams->PatternSize == 0) || (SearchParams->PatternSize > SearchParams->BufferSize))
return 0;
bufferSize = SearchParams->BufferSize - SearchParams->PatternSize;
for (n = 0, p = SearchParams->Buffer, c = 0; c <= bufferSize; ++p, ++c)
{
found = 1;
for (i = 0; i < SearchParams->PatternSize; ++i)
{
low = p[i] & 0x0f;
high = p[i] & 0xf0;
if (SearchParams->Mask[i] & 0xf0)
{
if (high != (SearchParams->Pattern[i] & 0xf0))
{
found = 0;
break;
}
}
if (SearchParams->Mask[i] & 0x0f)
{
if (low != (SearchParams->Pattern[i] & 0x0f))
{
found = 0;
break;
}
}
}
if (found) {
if (SearchParams->Callback(p,
SearchParams->PatternSize,
SearchParams->CallbackContext))
{
return n + 1;
}
n++;
}
}
return n;
}
#define MAX_DOS_HEADER (256 * (1024 * 1024))
PIMAGE_NT_HEADERS GetImageNtHeader(
_In_ PVOID Base)
{
PIMAGE_NT_HEADERS NtHeaders = NULL;
if (Base != NULL && Base != (PVOID)-1) {
__try {
if ((((PIMAGE_DOS_HEADER)Base)->e_magic == IMAGE_DOS_SIGNATURE) &&
(((ULONG)((PIMAGE_DOS_HEADER)Base)->e_lfanew) < MAX_DOS_HEADER)) {
NtHeaders = (PIMAGE_NT_HEADERS)((PCHAR)Base + ((PIMAGE_DOS_HEADER)Base)->e_lfanew);
if (NtHeaders->Signature != IMAGE_NT_SIGNATURE) {
NtHeaders = NULL;
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
NtHeaders = NULL;
}
}
return NtHeaders;
}
PVOID LookupImageSectionByName(
_In_ CHAR* SectionName,
_In_ ULONG SectionNameLength,
_In_ PVOID DllBase,
_Out_ PULONG SectionSize
)
{
BOOLEAN bFound = FALSE;
ULONG i;
PVOID Section;
IMAGE_NT_HEADERS* NtHeaders = GetImageNtHeader(DllBase);
IMAGE_SECTION_HEADER* SectionTableEntry;
if (SectionSize)
*SectionSize = 0;
if (NtHeaders == NULL)
return NULL;
SectionTableEntry = (PIMAGE_SECTION_HEADER)((PCHAR)NtHeaders +
sizeof(ULONG) +
sizeof(IMAGE_FILE_HEADER) +
NtHeaders->FileHeader.SizeOfOptionalHeader);
i = NtHeaders->FileHeader.NumberOfSections;
while (i > 0) {
if (memcmp(
(CHAR*)SectionTableEntry->Name,
SectionName,
SectionNameLength) == 0)
{
bFound = TRUE;
break;
}
i -= 1;
SectionTableEntry += 1;
}
if (!bFound)
return NULL;
Section = (PVOID)((ULONG_PTR)DllBase + SectionTableEntry->VirtualAddress);
if (SectionSize)
*SectionSize = SectionTableEntry->Misc.VirtualSize;
return Section;
}
VOID UnmapInputFile(
_In_ PVOID FileMapping
)
{
if (FileMapping) UnmapViewOfFile(FileMapping);
}
PVOID MapInputFile(
_In_ LPCTSTR lpFileName,
_Out_ LARGE_INTEGER* liFileSize
)
{
DWORD lastError = 0;
HANDLE fileHandle, sectionHandle = NULL;
PVOID pvImageBase = NULL;
do {
liFileSize->QuadPart = 0;
fileHandle = CreateFile(lpFileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_SUPPORTS_BLOCK_REFCOUNTING | FILE_ATTRIBUTE_NORMAL,
NULL);
if (fileHandle == INVALID_HANDLE_VALUE)
break;
if (!GetFileSizeEx(fileHandle, liFileSize))
break;
sectionHandle = CreateFileMapping(fileHandle, NULL,
PAGE_READONLY | SEC_IMAGE,
0,
0,
NULL);
if (sectionHandle == NULL)
break;
pvImageBase = MapViewOfFile(
sectionHandle,
FILE_MAP_READ,
0, 0, 0);
if (pvImageBase == NULL)
break;
} while (FALSE);
lastError = GetLastError();
if (fileHandle != INVALID_HANDLE_VALUE) CloseHandle(fileHandle);
if (sectionHandle) CloseHandle(sectionHandle);
SetLastError(lastError);
return pvImageBase;
}
int _isspace(int c)
{
return (c == '\t' || c == '\n' ||
c == '\v' || c == '\f' || c == '\r' || c == ' ' ? 1 : 0);
}
char* trimstring(
_In_ const char* src,
_In_ char* dst
)
{
while (*src) {
if (!_isspace(*src)) {
*dst++ = *src;
}
src++;
}
*dst = 0;
return dst;
}
size_t hex2bin(
_In_ const char* src,
_In_ unsigned char* dst)
{
unsigned char value = 0;
unsigned char c;
size_t i = 0;
while (*src) {
c = *src;
if (c >= '0' && c <= '9')
value = (c - '0');
else if (c >= 'A' && c <= 'F')
value = (10 + (c - 'A'));
else if (c >= 'a' && c <= 'f')
value = (10 + (c - 'a'));
else {
if (_isspace(c)) {
src++;
continue;
}
}
dst[i / 2] += value << (((i + 1) % 2) * 4);
i++;
src++;
}
return i / 2;
}
__inline TCHAR nibbletoh(BYTE c, BOOLEAN upcase)
{
if (c < 10)
return TEXT('0') + c;
c -= 10;
if (upcase)
return TEXT('A') + c;
return TEXT('a') + c;
}
LPTSTR PrintHex(
_In_reads_bytes_(Length) LPBYTE Buffer,
_In_ ULONG Length,
_In_ BOOLEAN UpcaseHex
)
{
ULONG c;
PTCHAR lpText;
BYTE x;
lpText = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR) + ((SIZE_T)Length * 2 * sizeof(TCHAR)));
if (lpText) {
for (c = 0; c < Length; ++c) {
x = Buffer[c];
lpText[c * 2] = nibbletoh(x >> 4, UpcaseHex);
lpText[c * 2 + 1] = nibbletoh(x & 15, UpcaseHex);
}
lpText[Length * 2] = 0;
}
return lpText;
}
BOOL CALLBACK SearchPatternCallback(
_In_ PBYTE Buffer,
_In_ ULONG PatternSize,
_In_opt_ PVOID CallbackContext
)
{
LPCSTR pszSection = (LPCSTR)CallbackContext;
LPCSTR pszFound;
pszFound = PrintHex(Buffer, PatternSize, TRUE);
if (pszFound) {
printf_s("%s: %p\t%s\r\n", pszSection, Buffer, pszFound);
LocalFree((HLOCAL)pszFound);
}
return FALSE;
}
void ProcessFile(
_In_ LPCSTR pszFileName,
_In_ LPCSTR pszSection,
_In_ LPCSTR pszPattern,
_In_ LPCSTR pszMask)
{
PVOID pvImageBase = NULL, pvSection;
LARGE_INTEGER fileSize;
SIZE_T nLen, patternLen, maskLen;
ULONG sectionSize = 0;
BYTE* pbPattern = NULL;
BYTE* pbMask = NULL;
DWORD patternSize, maskSize;
SEARCH_PARAMS sparams;
do {
nLen = strlen(pszSection);
if (nLen < 2) {
printf_s("Section name %s is too short\r\n", pszSection);
return;
}
patternLen = strlen(pszPattern);
maskLen = strlen(pszMask);
pbPattern = (BYTE*)LocalAlloc(LPTR, patternLen);
pbMask = (BYTE*)LocalAlloc(LPTR, maskLen);
if (pbPattern == NULL || pbMask == NULL) {
printf_s("Could not allocate temporary buffer\r\n");
break;
}
patternSize = (ULONG)hex2bin(pszPattern, pbPattern);
maskSize = (ULONG)hex2bin(pszMask, pbMask);
if (patternSize != maskSize) {
printf_s("Pattern and mask must be the same size\r\n");
break;
}
pvImageBase = MapInputFile(pszFileName, &fileSize);
if (pvImageBase == NULL) {
printf_s("Cannot map input file %s, GetLastError(%lx)", pszFileName, GetLastError());
break;
}
pvSection = LookupImageSectionByName((CHAR*)pszSection, (ULONG)nLen, pvImageBase, &sectionSize);
if (pvSection == NULL || sectionSize == 0) {
printf_s("Section %s not found or has invalid size %lx", pszSection, sectionSize);
break;
}
sparams.Buffer = (PBYTE)pvSection;
sparams.BufferSize = sectionSize;
sparams.Callback = SearchPatternCallback;
sparams.CallbackContext = (PVOID)pszSection;
sparams.Pattern = pbPattern;
sparams.PatternSize = patternSize;
sparams.Mask = pbMask;
if (0 == SearchPattern(&sparams))
printf_s("Nothing found, check input parameters!\r\n");
} while (FALSE);
if (pvImageBase) UnmapInputFile(pvImageBase);
if (pbPattern) LocalFree(pbPattern);
if (pbMask) LocalFree(pbMask);
}
int main(int argc, char* argv[])
{
if (argc > 4) {
printf_s("File %s, looking for:\r\n\tPattern:\t%s\r\n\tMask:\t\t%s\r\n\tSection:\t%s\r\n",
argv[1],
argv[3],
argv[4],
argv[2]);
ProcessFile(argv[1], argv[2], argv[3], argv[4]);
}
else {
printf_s("sp [File] [Section] [Pattern] [Mask]\r\n");
}
ExitProcess(0);
}