特征码匹配搜索

搜索特征码

ida生成特征码插件

GitHub - Chordp/PatternGen

GitHub - kweatherman/sigmakerex: Enhanced IDA Pro signature generator plugin.

search.h

#pragma once
#include <ntifs.h>
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemBasicInformation,
SystemProcessorInformation, // obsolete...delete
SystemPerformanceInformation,
SystemTimeOfDayInformation,
SystemPathInformation,
SystemProcessInformation,
SystemCallCountInformation,
SystemDeviceInformation,
SystemProcessorPerformanceInformation,
SystemFlagsInformation,
SystemCallTimeInformation,
SystemModuleInformation,
SystemLocksInformation,
SystemStackTraceInformation,
SystemPagedPoolInformation,
SystemNonPagedPoolInformation,
SystemHandleInformation,
SystemObjectInformation,
SystemPageFileInformation,
SystemVdmInstemulInformation,
SystemVdmBopInformation,
SystemFileCacheInformation,
SystemPoolTagInformation,
SystemInterruptInformation,
SystemDpcBehaviorInformation,
SystemFullMemoryInformation,
SystemLoadGdiDriverInformation,
SystemUnloadGdiDriverInformation,
SystemTimeAdjustmentInformation,
SystemSummaryMemoryInformation,
SystemMirrorMemoryInformation,
SystemPerformanceTraceInformation,
SystemObsolete0,
SystemExceptionInformation,
SystemCrashDumpStateInformation,
SystemKernelDebuggerInformation,
SystemContextSwitchInformation,
SystemRegistryQuotaInformation,
SystemExtendServiceTableInformation,
SystemPrioritySeperation,
SystemVerifierAddDriverInformation,
SystemVerifierRemoveDriverInformation,
SystemProcessorIdleInformation,
SystemLegacyDriverInformation,
SystemCurrentTimeZoneInformation,
SystemLookasideInformation,
SystemTimeSlipNotification,
SystemSessionCreate,
SystemSessionDetach,
SystemSessionInformation,
SystemRangeStartInformation,
SystemVerifierInformation,
SystemVerifierThunkExtend,
SystemSessionProcessInformation,
SystemLoadGdiDriverInSystemSpace,
SystemNumaProcessorMap,
SystemPrefetcherInformation,
SystemExtendedProcessInformation,
SystemRecommendedSharedDataAlignment,
SystemComPlusPackage,
SystemNumaAvailableMemory,
SystemProcessorPowerInformation,
SystemEmulationBasicInformation,
SystemEmulationProcessorInformation,
SystemExtendedHandleInformation,
SystemLostDelayedWriteInformation,
SystemBigPoolInformation,
SystemSessionPoolTagInformation,
SystemSessionMappedViewInformation,
SystemHotpatchInformation,
SystemObjectSecurityMode,
SystemWatchdogTimerHandler,
SystemWatchdogTimerInformation,
SystemLogicalProcessorInformation,
SystemWow64SharedInformation,
SystemRegisterFirmwareTableInformationHandler,
SystemFirmwareTableInformation,
SystemModuleInformationEx,
SystemVerifierTriageInformation,
SystemSuperfetchInformation,
SystemMemoryListInformation,
SystemFileCacheInformationEx,
MaxSystemInfoClass // MaxSystemInfoClass should always be the last enum
} SYSTEM_INFORMATION_CLASS;

typedef struct _RTL_PROCESS_MODULE_INFORMATION {
HANDLE Section; // Not filled in
PVOID MappedBase;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT OffsetToFileName;
UCHAR FullPathName[256];
} RTL_PROCESS_MODULE_INFORMATION, * PRTL_PROCESS_MODULE_INFORMATION;

typedef struct _RTL_PROCESS_MODULES {
ULONG NumberOfModules;
RTL_PROCESS_MODULE_INFORMATION Modules[1];
} RTL_PROCESS_MODULES, * PRTL_PROCESS_MODULES;


NTSTATUS NTAPI ZwQuerySystemInformation(
__in SYSTEM_INFORMATION_CLASS SystemInformationClass,
__out_bcount_opt(SystemInformationLength) PVOID SystemInformation,
__in ULONG SystemInformationLength,
__out_opt PULONG ReturnLength
);


typedef struct _FindCode {
UCHAR code[0x200];//特征码最长长度
ULONG len;//特征码实际长度
int offset;//特征匹配搜索位置距离findAddressByCode参数beginAddr的偏移
ULONG lastAddressOffset;//需要返回的位置距离findAddressByCode参数beginAddr的偏移
}FindCode, * PFindCode;

ULONG_PTR QuerySysModule(char* MoudleName, _Out_opt_ ULONG_PTR* module);

void initFindCodeStruct(PFindCode findCode, PCHAR code, ULONG_PTR offset, ULONG_PTR lastAddrOffset);

ULONG_PTR findAddressByCode(ULONG_PTR beginAddr, ULONG_PTR endAddr, PFindCode findCode, ULONG numbers);

ULONG_PTR searchNtCode(char* code, int offset);

ULONG_PTR searchCode(char* moduleName, char* segmentName, char* code, int offset);

serch.c

#include "SearchCode.h"
#include <ntimage.h>

UCHAR charToHex(UCHAR* ch) {
unsigned char temps[2] = { 0 };
for (int i = 0; i < 2; i++) {
if (ch[i] >= '0' && ch[i] <= '9') {
temps[i] = (ch[i] - '0');
}
else if (ch[i] >= 'A' && ch[i] <= 'F') {
temps[i] = (ch[i] - 'A') + 0xA;
}
else if (ch[i] >= 'a' && ch[i] <= 'f') {
temps[i] = (ch[i] - 'a') + 0xA;
}
}
return ((temps[0] << 4) & 0xf0) | (temps[1] & 0xf);
}

char* CharToUper(char* wstr, BOOLEAN isAllocateMemory) {
char* ret = NULL;

if (isAllocateMemory) {
int len = strlen(wstr) + 2;
ret = ExAllocatePool(PagedPool, len);
memset(ret, 0, len);
memcpy(ret, wstr, len - 2);
}
else {
ret = wstr;
}

_strupr(ret);

return ret;
}

void initFindCodeStruct(PFindCode findCode, PCHAR code, ULONG_PTR offset, ULONG_PTR lastAddrOffset) {

memset(findCode, 0, sizeof(FindCode));
findCode->lastAddressOffset = lastAddrOffset;
findCode->offset = offset;

PCHAR pTemp = code;
ULONG_PTR i = 0;
for (i = 0; *pTemp != '\0'; i++) {
/*
* https://github.com/Chordp/PatternGen插件生成特征码有空格而且是两个??代表一个字节
*/
if (
(*pTemp == '*' && *(pTemp + 1) == '*') ||
(*pTemp == '?' && *(pTemp + 1) == '?')
) {
findCode->code[i] = *pTemp;
pTemp += 2;
continue;
}

if (*pTemp == ' ') {
pTemp++;
i--;
continue;
}
findCode->code[i] = charToHex(pTemp);
pTemp += 2;
}

findCode->len = i;
}

/*
* 采用多段式匹配
*/
ULONG_PTR findAddressByCode(ULONG_PTR beginAddr, ULONG_PTR endAddr, PFindCode findCode, ULONG numbersOfFc) {
ULONG64 j = 0;
LARGE_INTEGER rtna = { 0 };
for (ULONG_PTR ad = beginAddr; ad <= endAddr; ad++) {
if (!MmIsAddressValid((PVOID)ad)) {
ad = ad & (~0xfff) + PAGE_SIZE - 1;//跳过一个4k页
continue;
}
for (j = 0; j < numbersOfFc; j++) {
FindCode fc = findCode[j];
ULONG_PTR tempAddress = ad;

UCHAR* code = (UCHAR*)(tempAddress + fc.offset);
BOOLEAN isFlags = FALSE;//TRUE表示i地址不匹配

for (ULONG_PTR k = 0; k < fc.len; k++) {
if (!MmIsAddressValid((PVOID)(code + k))) {
isFlags = TRUE;
break;
}

if (fc.code[k] == '*' || fc.code[k] == '?') continue;

if (code[k] != fc.code[k]) {
isFlags = TRUE;
break;
}
}

if (isFlags) break;

}

//等于说明地址i可以匹配所有FindCode特征,说明找到了
if (j == numbersOfFc) {//
rtna.QuadPart = ad;
rtna.LowPart += findCode[0].lastAddressOffset;
break;
}

}

return rtna.QuadPart;
}


//返回值为模块的大小
ULONG_PTR QuerySysModule(char* MoudleName, _Out_opt_ ULONG_PTR* module) {
RTL_PROCESS_MODULES info;
ULONG retPro = NULL;
ULONG_PTR moduleSize = 0;



NTSTATUS ststas = ZwQuerySystemInformation(SystemModuleInformation, &info, sizeof(info), &retPro);
char* moduleUper = CharToUper(MoudleName, TRUE);

if (ststas == STATUS_INFO_LENGTH_MISMATCH) {
//申请长度
ULONG len = retPro + sizeof(RTL_PROCESS_MODULES);
PRTL_PROCESS_MODULES mem = (PRTL_PROCESS_MODULES)ExAllocatePool(PagedPool, len);
ASSERT(mem != 0);
memset(mem, 0, len);
ststas = ZwQuerySystemInformation(SystemModuleInformation, mem, len, &retPro);

if (!NT_SUCCESS(ststas)) {
ExFreePool(moduleUper);
ExFreePool(mem);
return 0;
}

//开始查询

if (strstr(MoudleName, "ntkrnlpa.exe") || strstr(MoudleName, "ntoskrnl.exe")) {
PRTL_PROCESS_MODULE_INFORMATION ModuleInfo = &(mem->Modules[0]);
if (module) {
*module = ModuleInfo->ImageBase;
}
moduleSize = ModuleInfo->ImageSize;
}
else {
for (int i = 0; i < mem->NumberOfModules; i++) {
PRTL_PROCESS_MODULE_INFORMATION processModule = &mem->Modules[i];
CharToUper(processModule->FullPathName, FALSE);
if (strstr(processModule->FullPathName, moduleUper)) {
if (module) {
*module = processModule->ImageBase;
}

moduleSize = processModule->ImageSize;

break;
}

}
}
ExFreePool(mem);
}

ExFreePool(moduleUper);
return moduleSize;
}


ULONG_PTR searchNtCode(char* code, int offset) {
FindCode fs[1] = { 0 };
initFindCodeStruct(&fs[0], code, 0, offset);


SIZE_T moduleBase = 0;
ULONG_PTR size = QuerySysModule("ntoskrnl.exe", &moduleBase);

ULONG_PTR func = findAddressByCode(moduleBase, size + moduleBase, fs, 1);

return func;
}

ULONG_PTR searchCode(char* moduleName, char* segmentName, char* code, int offset) {
FindCode fs[1] = { 0 };
initFindCodeStruct(&fs[0], code, 0, offset);
SIZE_T moduleBase = 0;
ULONG size = QuerySysModule(moduleName, &moduleBase);

if (!moduleBase) {
return 0;
}


PIMAGE_DOS_HEADER pDos = (PIMAGE_DOS_HEADER)moduleBase;

PIMAGE_NT_HEADERS pNts = (PIMAGE_NT_HEADERS)((PUCHAR)moduleBase + pDos->e_lfanew);

PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNts);

PIMAGE_SECTION_HEADER pTemp = NULL;

for (int i = 0; i < pNts->FileHeader.NumberOfSections; i++) {
char bufName[9] = { 0 };//pSection->Name最长8字节可能可能没有/0结尾导致比较函数误判,所以拷贝
memcpy(bufName, pSection->Name, 8);
if (_stricmp(bufName, segmentName) == 0) {
pTemp = pSection;
break;
}
pSection++;
}

if (pTemp) {
moduleBase = pSection->VirtualAddress + moduleBase;
size = pSection->SizeOfRawData;
}

//防止缺页导致蓝屏 其他函数没有改,太懒了,用的时候记得加上
PVOID mem = ExAllocatePool(NonPagedPool, size);
if (!mem) {
return 0;
}
SIZE_T retSize = 0;
MmCopyVirtualMemory(IoGetCurrentProcess(),moduleBase,IoGetCurrentProcess(),mem,size,KernelMode,&retSize);

ULONG_PTR func = findAddressByCode(moduleBase, size + moduleBase, fs, 1);

ExFreePool(mem);
return func;
}

findAddressByCode可采用多点匹配来确定是否匹配正确

比如搜索PsLookupProcessByProcessId函数提取_PspCidTable所在偏移

image-20240514192213374

image-20240514192450155

选取上面两段特征码后开始匹配

FindCode fc[2] = { 0 };
UNICODE_STRING name = { 0 };

initFindCodeStruct(&fc[0],"FF ?? ?? 8B ?? ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B F8 85 FF",0,+5);
//8407963f-84079623=1c,第二段特征码从第一段特征码搜索到的位置+1c处开始
initFindCodeStruct(&fc[1], "75 ?? 8B D3 E8 ?? ?? ?? ?? 84 C0 75 ??",0x1C,0);

RtlInitUnicodeString(&name,L"PsLookupProcessByProcessId");
PUCHAR funcAd=(PUCHAR)MmGetSystemRoutineAddress(&name);

ULONG_PTR PspCidTableOffset=findAddressByCode(funcAd,funcAd+0x200,fc,2);

image-20240514191848694

ULONG func = searchCode("ntoskrnl.exe", "PAGE", "66 ?? ?? ?? ?? ?? ?? 57 FF ?? ?? 8B ?? ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B F8", -0x13);//用来找到PsLookupProcessByProcessId函数开始,-13是因为要从特征码开始减去13才会到函数头