驱动开发:内核特征码扫描PE代码段

打印 上一主题 下一主题

主题 857|帖子 857|积分 2573

在笔者上一篇文章《驱动开发:内核特征码搜索函数封装》中为了定位特征的方便我们封装实现了一个可以传入数组实现的SearchSpecialCode定位函数,该定位函数其实还不能算的上简单,本章LyShark将对特征码定位进行简化,让定位变得更简单,并运用定位代码实现扫描内核PE的.text代码段,并从代码段中得到某个特征所在内存位置。
老样子为了后续教程能够继续,先来定义一个lyshark.h头文件,该头文件中包含了我们本篇文章所必须要使用到的结构体定义,这些定义的函数如果不懂请去看LyShark以前的文章,这里就不罗嗦了。
  1. #include <ntifs.h>
  2. #include <ntimage.h>
  3. typedef struct _KLDR_DATA_TABLE_ENTRY
  4. {
  5.         LIST_ENTRY64 InLoadOrderLinks;
  6.         ULONG64 __Undefined1;
  7.         ULONG64 __Undefined2;
  8.         ULONG64 __Undefined3;
  9.         ULONG64 NonPagedDebugInfo;
  10.         ULONG64 DllBase;
  11.         ULONG64 EntryPoint;
  12.         ULONG SizeOfImage;
  13.         UNICODE_STRING FullDllName;
  14.         UNICODE_STRING BaseDllName;
  15.         ULONG   Flags;
  16.         USHORT  LoadCount;
  17.         USHORT  __Undefined5;
  18.         ULONG64 __Undefined6;
  19.         ULONG   CheckSum;
  20.         ULONG   __padding1;
  21.         ULONG   TimeDateStamp;
  22.         ULONG   __padding2;
  23. }KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;
  24. typedef struct _RTL_PROCESS_MODULE_INFORMATION
  25. {
  26.         HANDLE Section;
  27.         PVOID MappedBase;
  28.         PVOID ImageBase;
  29.         ULONG ImageSize;
  30.         ULONG Flags;
  31.         USHORT LoadOrderIndex;
  32.         USHORT InitOrderIndex;
  33.         USHORT LoadCount;
  34.         USHORT OffsetToFileName;
  35.         UCHAR  FullPathName[256];
  36. } RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;
  37. typedef struct _RTL_PROCESS_MODULES
  38. {
  39.         ULONG NumberOfModules;
  40.         RTL_PROCESS_MODULE_INFORMATION Modules[1];
  41. } RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;
  42. typedef enum _SYSTEM_INFORMATION_CLASS
  43. {
  44.         SystemBasicInformation = 0x0,
  45.         SystemProcessorInformation = 0x1,
  46.         SystemPerformanceInformation = 0x2,
  47.         SystemTimeOfDayInformation = 0x3,
  48.         SystemPathInformation = 0x4,
  49.         SystemProcessInformation = 0x5,
  50.         SystemCallCountInformation = 0x6,
  51.         SystemDeviceInformation = 0x7,
  52.         SystemProcessorPerformanceInformation = 0x8,
  53.         SystemFlagsInformation = 0x9,
  54.         SystemCallTimeInformation = 0xa,
  55.         SystemModuleInformation = 0xb,
  56.         SystemLocksInformation = 0xc,
  57.         SystemStackTraceInformation = 0xd,
  58.         SystemPagedPoolInformation = 0xe,
  59.         SystemNonPagedPoolInformation = 0xf,
  60.         SystemHandleInformation = 0x10,
  61.         SystemObjectInformation = 0x11,
  62.         SystemPageFileInformation = 0x12,
  63.         SystemVdmInstemulInformation = 0x13,
  64.         SystemVdmBopInformation = 0x14,
  65.         SystemFileCacheInformation = 0x15,
  66.         SystemPoolTagInformation = 0x16,
  67.         SystemInterruptInformation = 0x17,
  68.         SystemDpcBehaviorInformation = 0x18,
  69.         SystemFullMemoryInformation = 0x19,
  70.         SystemLoadGdiDriverInformation = 0x1a,
  71.         SystemUnloadGdiDriverInformation = 0x1b,
  72.         SystemTimeAdjustmentInformation = 0x1c,
  73.         SystemSummaryMemoryInformation = 0x1d,
  74.         SystemMirrorMemoryInformation = 0x1e,
  75.         SystemPerformanceTraceInformation = 0x1f,
  76.         SystemObsolete0 = 0x20,
  77.         SystemExceptionInformation = 0x21,
  78.         SystemCrashDumpStateInformation = 0x22,
  79.         SystemKernelDebuggerInformation = 0x23,
  80.         SystemContextSwitchInformation = 0x24,
  81.         SystemRegistryQuotaInformation = 0x25,
  82.         SystemExtendServiceTableInformation = 0x26,
  83.         SystemPrioritySeperation = 0x27,
  84.         SystemVerifierAddDriverInformation = 0x28,
  85.         SystemVerifierRemoveDriverInformation = 0x29,
  86.         SystemProcessorIdleInformation = 0x2a,
  87.         SystemLegacyDriverInformation = 0x2b,
  88.         SystemCurrentTimeZoneInformation = 0x2c,
  89.         SystemLookasideInformation = 0x2d,
  90.         SystemTimeSlipNotification = 0x2e,
  91.         SystemSessionCreate = 0x2f,
  92.         SystemSessionDetach = 0x30,
  93.         SystemSessionInformation = 0x31,
  94.         SystemRangeStartInformation = 0x32,
  95.         SystemVerifierInformation = 0x33,
  96.         SystemVerifierThunkExtend = 0x34,
  97.         SystemSessionProcessInformation = 0x35,
  98.         SystemLoadGdiDriverInSystemSpace = 0x36,
  99.         SystemNumaProcessorMap = 0x37,
  100.         SystemPrefetcherInformation = 0x38,
  101.         SystemExtendedProcessInformation = 0x39,
  102.         SystemRecommendedSharedDataAlignment = 0x3a,
  103.         SystemComPlusPackage = 0x3b,
  104.         SystemNumaAvailableMemory = 0x3c,
  105.         SystemProcessorPowerInformation = 0x3d,
  106.         SystemEmulationBasicInformation = 0x3e,
  107.         SystemEmulationProcessorInformation = 0x3f,
  108.         SystemExtendedHandleInformation = 0x40,
  109.         SystemLostDelayedWriteInformation = 0x41,
  110.         SystemBigPoolInformation = 0x42,
  111.         SystemSessionPoolTagInformation = 0x43,
  112.         SystemSessionMappedViewInformation = 0x44,
  113.         SystemHotpatchInformation = 0x45,
  114.         SystemObjectSecurityMode = 0x46,
  115.         SystemWatchdogTimerHandler = 0x47,
  116.         SystemWatchdogTimerInformation = 0x48,
  117.         SystemLogicalProcessorInformation = 0x49,
  118.         SystemWow64SharedInformationObsolete = 0x4a,
  119.         SystemRegisterFirmwareTableInformationHandler = 0x4b,
  120.         SystemFirmwareTableInformation = 0x4c,
  121.         SystemModuleInformationEx = 0x4d,
  122.         SystemVerifierTriageInformation = 0x4e,
  123.         SystemSuperfetchInformation = 0x4f,
  124.         SystemMemoryListInformation = 0x50,
  125.         SystemFileCacheInformationEx = 0x51,
  126.         SystemThreadPriorityClientIdInformation = 0x52,
  127.         SystemProcessorIdleCycleTimeInformation = 0x53,
  128.         SystemVerifierCancellationInformation = 0x54,
  129.         SystemProcessorPowerInformationEx = 0x55,
  130.         SystemRefTraceInformation = 0x56,
  131.         SystemSpecialPoolInformation = 0x57,
  132.         SystemProcessIdInformation = 0x58,
  133.         SystemErrorPortInformation = 0x59,
  134.         SystemBootEnvironmentInformation = 0x5a,
  135.         SystemHypervisorInformation = 0x5b,
  136.         SystemVerifierInformationEx = 0x5c,
  137.         SystemTimeZoneInformation = 0x5d,
  138.         SystemImageFileExecutionOptionsInformation = 0x5e,
  139.         SystemCoverageInformation = 0x5f,
  140.         SystemPrefetchPatchInformation = 0x60,
  141.         SystemVerifierFaultsInformation = 0x61,
  142.         SystemSystemPartitionInformation = 0x62,
  143.         SystemSystemDiskInformation = 0x63,
  144.         SystemProcessorPerformanceDistribution = 0x64,
  145.         SystemNumaProximityNodeInformation = 0x65,
  146.         SystemDynamicTimeZoneInformation = 0x66,
  147.         SystemCodeIntegrityInformation = 0x67,
  148.         SystemProcessorMicrocodeUpdateInformation = 0x68,
  149.         SystemProcessorBrandString = 0x69,
  150.         SystemVirtualAddressInformation = 0x6a,
  151.         SystemLogicalProcessorAndGroupInformation = 0x6b,
  152.         SystemProcessorCycleTimeInformation = 0x6c,
  153.         SystemStoreInformation = 0x6d,
  154.         SystemRegistryAppendString = 0x6e,
  155.         SystemAitSamplingValue = 0x6f,
  156.         SystemVhdBootInformation = 0x70,
  157.         SystemCpuQuotaInformation = 0x71,
  158.         SystemNativeBasicInformation = 0x72,
  159.         SystemErrorPortTimeouts = 0x73,
  160.         SystemLowPriorityIoInformation = 0x74,
  161.         SystemBootEntropyInformation = 0x75,
  162.         SystemVerifierCountersInformation = 0x76,
  163.         SystemPagedPoolInformationEx = 0x77,
  164.         SystemSystemPtesInformationEx = 0x78,
  165.         SystemNodeDistanceInformation = 0x79,
  166.         SystemAcpiAuditInformation = 0x7a,
  167.         SystemBasicPerformanceInformation = 0x7b,
  168.         SystemQueryPerformanceCounterInformation = 0x7c,
  169.         SystemSessionBigPoolInformation = 0x7d,
  170.         SystemBootGraphicsInformation = 0x7e,
  171.         SystemScrubPhysicalMemoryInformation = 0x7f,
  172.         SystemBadPageInformation = 0x80,
  173.         SystemProcessorProfileControlArea = 0x81,
  174.         SystemCombinePhysicalMemoryInformation = 0x82,
  175.         SystemEntropyInterruptTimingInformation = 0x83,
  176.         SystemConsoleInformation = 0x84,
  177.         SystemPlatformBinaryInformation = 0x85,
  178.         SystemThrottleNotificationInformation = 0x86,
  179.         SystemHypervisorProcessorCountInformation = 0x87,
  180.         SystemDeviceDataInformation = 0x88,
  181.         SystemDeviceDataEnumerationInformation = 0x89,
  182.         SystemMemoryTopologyInformation = 0x8a,
  183.         SystemMemoryChannelInformation = 0x8b,
  184.         SystemBootLogoInformation = 0x8c,
  185.         SystemProcessorPerformanceInformationEx = 0x8d,
  186.         SystemSpare0 = 0x8e,
  187.         SystemSecureBootPolicyInformation = 0x8f,
  188.         SystemPageFileInformationEx = 0x90,
  189.         SystemSecureBootInformation = 0x91,
  190.         SystemEntropyInterruptTimingRawInformation = 0x92,
  191.         SystemPortableWorkspaceEfiLauncherInformation = 0x93,
  192.         SystemFullProcessInformation = 0x94,
  193.         SystemKernelDebuggerInformationEx = 0x95,
  194.         SystemBootMetadataInformation = 0x96,
  195.         SystemSoftRebootInformation = 0x97,
  196.         SystemElamCertificateInformation = 0x98,
  197.         SystemOfflineDumpConfigInformation = 0x99,
  198.         SystemProcessorFeaturesInformation = 0x9a,
  199.         SystemRegistryReconciliationInformation = 0x9b,
  200.         MaxSystemInfoClass = 0x9c,
  201. } SYSTEM_INFORMATION_CLASS;
  202. // 声明函数
  203. // By: Lyshark.com
  204. NTSYSAPI PIMAGE_NT_HEADERS NTAPI RtlImageNtHeader(_In_ PVOID Base);
  205. NTSTATUS NTAPI ZwQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, ULONG SystemInformationLength, PULONG ReturnLength);
  206. typedef VOID(__cdecl *PMiProcessLoaderEntry)(PKLDR_DATA_TABLE_ENTRY section, IN LOGICAL Insert);
  207. typedef NTSTATUS(*NTQUERYSYSTEMINFORMATION)(IN ULONG SystemInformationClass, OUT PVOID SystemInformation, IN ULONG_PTR SystemInformationLength, OUT PULONG_PTR ReturnLength OPTIONAL);
复制代码
我们继续,首先实现特征码字符串的解析与扫描实现此处UtilLySharkSearchPattern函数就是LyShark封装过的,这里依次介绍一下参数传递的含义。

  • pattern 用于传入一段字符串特征值(以\x开头)
  • len 代表输入特征码长度(除去\x后的长度)
  • base 代表扫描内存的基地址
  • size 代表需要向下扫描的长度
  • ppFound 代表扫描到首地址以后返回的内存地址
这段代码该如何使用,如下我们以定位IoInitializeTimer为例,演示UtilLySharkSearchPattern如何定位特征的,如下代码pattern变量中就是我们需要定位的特征值,pattern_size则是需要定位的特征码长度,在address地址位置向下扫描128字节,找到则返回到find_address变量内。
  1. // 署名
  2. // PowerBy: LyShark
  3. // Email: me@lyshark.com
  4. #include "lyshark.h"
  5. PVOID GetIoInitializeTimerAddress()
  6. {
  7.         PVOID VariableAddress = 0;
  8.         UNICODE_STRING uioiTime = { 0 };
  9.         RtlInitUnicodeString(&uioiTime, L"IoInitializeTimer");
  10.         VariableAddress = (PVOID)MmGetSystemRoutineAddress(&uioiTime);
  11.         if (VariableAddress != 0)
  12.         {
  13.                 return VariableAddress;
  14.         }
  15.         return 0;
  16. }
  17. // 对指定内存执行特征码扫描
  18. NTSTATUS UtilLySharkSearchPattern(IN PUCHAR pattern, IN ULONG_PTR len, IN const VOID* base, IN ULONG_PTR size, OUT PVOID* ppFound)
  19. {
  20.         // 计算匹配长度
  21.         // LyShark.com 特征码扫描
  22.         NT_ASSERT(ppFound != 0 && pattern != 0 && base != 0);
  23.         if (ppFound == 0 || pattern == 0 || base == 0)
  24.         {
  25.                 return STATUS_INVALID_PARAMETER;
  26.         }
  27.         __try
  28.         {
  29.                 for (ULONG_PTR i = 0; i < size - len; i++)
  30.                 {
  31.                         BOOLEAN found = TRUE;
  32.                         for (ULONG_PTR j = 0; j < len; j++)
  33.                         {
  34.                                 if (pattern[j] != ((PUCHAR)base)[i + j])
  35.                                 {
  36.                                         found = FALSE;
  37.                                         break;
  38.                                 }
  39.                         }
  40.                         if (found != FALSE)
  41.                         {
  42.                                 *ppFound = (PUCHAR)base + i;
  43.                                 DbgPrint("[LyShark.com] 特征码匹配地址: %p \n", (PUCHAR)base + i);
  44.                                 return STATUS_SUCCESS;
  45.                         }
  46.                 }
  47.         }
  48.         __except (EXCEPTION_EXECUTE_HANDLER)
  49.         {
  50.                 return STATUS_UNHANDLED_EXCEPTION;
  51.         }
  52.         return STATUS_NOT_FOUND;
  53. }
  54. VOID UnDriver(PDRIVER_OBJECT driver)
  55. {
  56.         DbgPrint(("Uninstall Driver Is OK \n"));
  57. }
  58. NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
  59. {
  60.         DbgPrint(("hello lyshark.com \n"));
  61.         // 返回匹配长度5
  62.         CHAR pattern[] = "\x48\x89\x6c\x24\x10";
  63.         PVOID *find_address = NULL;
  64.         int pattern_size = sizeof(pattern) - 1;
  65.         DbgPrint("匹配长度: %d \n", pattern_size);
  66.         // 得到基地址
  67.         PVOID address = GetIoInitializeTimerAddress();
  68.         // 扫描特征
  69.         NTSTATUS nt = UtilLySharkSearchPattern((PUCHAR)pattern, pattern_size, address, 128, &find_address);
  70.         DbgPrint("[LyShark 返回地址 => ] 0x%p \n", (ULONG64)find_address);
  71.         Driver->DriverUnload = UnDriver;
  72.         return STATUS_SUCCESS;
  73. }
复制代码
运行驱动程序完成特征定位,并对比定位效果。

如上述所示定位函数我们已经封装好了,相信你也能感受到这种方式要比使用数组更方便,为了能定位到内核PE结构我们需要使用RtlImageNtHeader来解析,这个内核函数专门用来得到内核程序的PE头部结构的,在下方案例中首先我们使用封装过的LySharkToolsUtilKernelBase函数拿到内核基址,如果你不懂函数实现细节请阅读《驱动开发:内核取ntoskrnl模块基地址》这篇文章,拿到基址以后可以直接使用RtlImageNtHeader对其PE头部进行解析,如下所示。
  1. // 署名
  2. // PowerBy: LyShark
  3. // Email: me@lyshark.com
  4. #include "lyshark.h"
  5. // 定义全局变量
  6. static PVOID g_KernelBase = 0;
  7. static ULONG g_KernelSize = 0;
  8. // 得到KernelBase基地址
  9. // lyshark.com
  10. PVOID LySharkToolsUtilKernelBase(OUT PULONG pSize)
  11. {
  12.         NTSTATUS status = STATUS_SUCCESS;
  13.         ULONG bytes = 0;
  14.         PRTL_PROCESS_MODULES pMods = 0;
  15.         PVOID checkPtr = 0;
  16.         UNICODE_STRING routineName;
  17.         if (g_KernelBase != 0)
  18.         {
  19.                 if (pSize)
  20.                 {
  21.                         *pSize = g_KernelSize;
  22.                 }
  23.                 return g_KernelBase;
  24.         }
  25.         RtlInitUnicodeString(&routineName, L"NtOpenFile");
  26.         checkPtr = MmGetSystemRoutineAddress(&routineName);
  27.         if (checkPtr == 0)
  28.                 return 0;
  29.         __try
  30.         {
  31.                 status = ZwQuerySystemInformation(SystemModuleInformation, 0, bytes, &bytes);
  32.                 if (bytes == 0)
  33.                 {
  34.                         return 0;
  35.                 }
  36.                 pMods = (PRTL_PROCESS_MODULES)ExAllocatePoolWithTag(NonPagedPoolNx, bytes, L"LyShark");
  37.                 RtlZeroMemory(pMods, bytes);
  38.                 status = ZwQuerySystemInformation(SystemModuleInformation, pMods, bytes, &bytes);
  39.                 if (NT_SUCCESS(status))
  40.                 {
  41.                         PRTL_PROCESS_MODULE_INFORMATION pMod = pMods->Modules;
  42.                         for (ULONG i = 0; i < pMods->NumberOfModules; i++)
  43.                         {
  44.                                 if (checkPtr >= pMod[i].ImageBase && checkPtr < (PVOID)((PUCHAR)pMod[i].ImageBase + pMod[i].ImageSize))
  45.                                 {
  46.                                         g_KernelBase = pMod[i].ImageBase;
  47.                                         g_KernelSize = pMod[i].ImageSize;
  48.                                         if (pSize)
  49.                                         {
  50.                                                 *pSize = g_KernelSize;
  51.                                         }
  52.                                         break;
  53.                                 }
  54.                         }
  55.                 }
  56.         }
  57.         __except (EXCEPTION_EXECUTE_HANDLER)
  58.         {
  59.                 return 0;
  60.         }
  61.         if (pMods)
  62.         {
  63.                 ExFreePoolWithTag(pMods, L"LyShark");
  64.         }
  65.         DbgPrint("KernelBase = > %p \n", g_KernelBase);
  66.         return g_KernelBase;
  67. }
  68. VOID UnDriver(PDRIVER_OBJECT driver)
  69. {
  70.         DbgPrint(("Uninstall Driver Is OK \n"));
  71. }
  72. NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
  73. {
  74.         DbgPrint(("hello lyshark.com \n"));
  75.         // 获取内核第一个模块的基地址
  76.         PVOID base = LySharkToolsUtilKernelBase(0);
  77.         if (!base)
  78.                 return STATUS_NOT_FOUND;
  79.         // 得到NT头部PE32+结构
  80.         // lyshark.com
  81.         PIMAGE_NT_HEADERS64 pHdr = RtlImageNtHeader(base);
  82.         if (!pHdr)
  83.                 return STATUS_INVALID_IMAGE_FORMAT;
  84.         // 首先寻找代码段
  85.         PIMAGE_SECTION_HEADER pFirstSection = (PIMAGE_SECTION_HEADER)(pHdr + 1);
  86.         for (PIMAGE_SECTION_HEADER pSection = pFirstSection; pSection < pFirstSection + pHdr->FileHeader.NumberOfSections; pSection++)
  87.         {
  88.                 ANSI_STRING LySharkSection, LySharkName;
  89.                 RtlInitAnsiString(&LySharkSection, ".text");
  90.                 RtlInitAnsiString(&LySharkName, (PCCHAR)pSection->Name);
  91.                 DbgPrint("[LyShark.PE] 名字: %Z | 地址: %p | 长度: %d \n", LySharkName, (PUCHAR)base + pSection->VirtualAddress, pSection->Misc.VirtualSize);
  92.         }
  93.         Driver->DriverUnload = UnDriver;
  94.         return STATUS_SUCCESS;
  95. }
复制代码
运行这段驱动程序,你会得到当前内核的所有PE节信息,枚举效果如下所示。

既然能够得到PE头部数据了,那么我们只需要扫描这段空间并得到匹配到的数据即可,其实很容易实现,如下代码所示。
  1. // 署名
  2. // PowerBy: LyShark
  3. // Email: me@lyshark.com
  4. #include "lyshark.h"
  5. // 定义全局变量
  6. static PVOID g_KernelBase = 0;
  7. static ULONG g_KernelSize = 0;
  8. // 得到KernelBase基地址
  9. // lyshark.com
  10. PVOID LySharkToolsUtilKernelBase(OUT PULONG pSize)
  11. {
  12.         NTSTATUS status = STATUS_SUCCESS;
  13.         ULONG bytes = 0;
  14.         PRTL_PROCESS_MODULES pMods = 0;
  15.         PVOID checkPtr = 0;
  16.         UNICODE_STRING routineName;
  17.         if (g_KernelBase != 0)
  18.         {
  19.                 if (pSize)
  20.                 {
  21.                         *pSize = g_KernelSize;
  22.                 }
  23.                 return g_KernelBase;
  24.         }
  25.         RtlInitUnicodeString(&routineName, L"NtOpenFile");
  26.         checkPtr = MmGetSystemRoutineAddress(&routineName);
  27.         if (checkPtr == 0)
  28.                 return 0;
  29.         __try
  30.         {
  31.                 status = ZwQuerySystemInformation(SystemModuleInformation, 0, bytes, &bytes);
  32.                 if (bytes == 0)
  33.                 {
  34.                         return 0;
  35.                 }
  36.                 pMods = (PRTL_PROCESS_MODULES)ExAllocatePoolWithTag(NonPagedPoolNx, bytes, L"LyShark");
  37.                 RtlZeroMemory(pMods, bytes);
  38.                 status = ZwQuerySystemInformation(SystemModuleInformation, pMods, bytes, &bytes);
  39.                 if (NT_SUCCESS(status))
  40.                 {
  41.                         PRTL_PROCESS_MODULE_INFORMATION pMod = pMods->Modules;
  42.                         for (ULONG i = 0; i < pMods->NumberOfModules; i++)
  43.                         {
  44.                                 if (checkPtr >= pMod[i].ImageBase && checkPtr < (PVOID)((PUCHAR)pMod[i].ImageBase + pMod[i].ImageSize))
  45.                                 {
  46.                                         g_KernelBase = pMod[i].ImageBase;
  47.                                         g_KernelSize = pMod[i].ImageSize;
  48.                                         if (pSize)
  49.                                         {
  50.                                                 *pSize = g_KernelSize;
  51.                                         }
  52.                                         break;
  53.                                 }
  54.                         }
  55.                 }
  56.         }
  57.         __except (EXCEPTION_EXECUTE_HANDLER)
  58.         {
  59.                 return 0;
  60.         }
  61.         if (pMods)
  62.         {
  63.                 ExFreePoolWithTag(pMods, L"LyShark");
  64.         }
  65.         DbgPrint("KernelBase = > %p \n", g_KernelBase);
  66.         return g_KernelBase;
  67. }
  68. // 对指定内存执行特征码扫描
  69. NTSTATUS UtilLySharkSearchPattern(IN PUCHAR pattern, IN UCHAR wildcard, IN ULONG_PTR len, IN const VOID* base, IN ULONG_PTR size, OUT PVOID* ppFound)
  70. {
  71.         NT_ASSERT(ppFound != 0 && pattern != 0 && base != 0);
  72.         if (ppFound == 0 || pattern == 0 || base == 0)
  73.         {
  74.                 return STATUS_INVALID_PARAMETER;
  75.         }
  76.         __try
  77.         {
  78.                 for (ULONG_PTR i = 0; i < size - len; i++)
  79.                 {
  80.                         BOOLEAN found = TRUE;
  81.                         for (ULONG_PTR j = 0; j < len; j++)
  82.                         {
  83.                                 if (pattern[j] != wildcard && pattern[j] != ((PUCHAR)base)[i + j])
  84.                                 {
  85.                                         found = FALSE;
  86.                                         break;
  87.                                 }
  88.                         }
  89.                         if (found != FALSE)
  90.                         {
  91.                                 *ppFound = (PUCHAR)base + i;
  92.                                 DbgPrint("[LyShark] 特征码匹配地址: %p \n", (PUCHAR)base + i);
  93.                                 return STATUS_SUCCESS;
  94.                         }
  95.                 }
  96.         }
  97.         __except (EXCEPTION_EXECUTE_HANDLER)
  98.         {
  99.                 return STATUS_UNHANDLED_EXCEPTION;
  100.         }
  101.         return STATUS_NOT_FOUND;
  102. }
  103. // 扫描代码段中的指令片段
  104. NTSTATUS ByLySharkComUtilScanSection(IN PCCHAR section, IN PUCHAR pattern, IN UCHAR wildcard, IN ULONG_PTR len, OUT PVOID* ppFound)
  105. {
  106.         NT_ASSERT(ppFound != 0);
  107.         if (ppFound == 0)
  108.                 return STATUS_INVALID_PARAMETER;
  109.         // 获取内核第一个模块的基地址
  110.         PVOID base = LySharkToolsUtilKernelBase(0);
  111.         if (!base)
  112.                 return STATUS_NOT_FOUND;
  113.         // 得到NT头部PE32+结构
  114.         PIMAGE_NT_HEADERS64 pHdr = RtlImageNtHeader(base);
  115.         if (!pHdr)
  116.                 return STATUS_INVALID_IMAGE_FORMAT;
  117.         // 首先寻找代码段
  118.         PIMAGE_SECTION_HEADER pFirstSection = (PIMAGE_SECTION_HEADER)(pHdr + 1);
  119.         for (PIMAGE_SECTION_HEADER pSection = pFirstSection; pSection < pFirstSection + pHdr->FileHeader.NumberOfSections; pSection++)
  120.         {
  121.                 ANSI_STRING LySharkSection, LySharkText;
  122.                 RtlInitAnsiString(&LySharkSection, section);
  123.                 RtlInitAnsiString(&LySharkText, (PCCHAR)pSection->Name);
  124.                 // 判断是不是我们要找的.text节
  125.                 if (RtlCompareString(&LySharkSection, &LySharkText, TRUE) == 0)
  126.                 {
  127.                         // 如果是则开始匹配特征码
  128.                         return UtilLySharkSearchPattern(pattern, wildcard, len, (PUCHAR)base + pSection->VirtualAddress, pSection->Misc.VirtualSize, ppFound);
  129.                 }
  130.         }
  131.         return STATUS_NOT_FOUND;
  132. }
  133. VOID UnDriver(PDRIVER_OBJECT driver)
  134. {
  135.         DbgPrint(("Uninstall Driver Is OK \n"));
  136. }
  137. NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
  138. {
  139.         DbgPrint("hello lyshark.com \n");
  140.         PMiProcessLoaderEntry m_MiProcessLoaderEntry = NULL;
  141.         RTL_OSVERSIONINFOW Version = { 0 };
  142.         Version.dwOSVersionInfoSize = sizeof(Version);
  143.         RtlGetVersion(&Version);
  144.         //获取内核版本号
  145.         DbgPrint("主版本: %d -->次版本: %d --> 编译版本: %d", Version.dwMajorVersion, Version.dwMinorVersion, Version.dwBuildNumber);
  146.         if (Version.dwMajorVersion == 10)
  147.         {
  148.                 // 如果是 win10 18363 则匹配特征
  149.                 if (Version.dwBuildNumber == 18363)
  150.                 {
  151.                         CHAR pattern[] = "\x48\x89\x5c\x24\x08";
  152.                         int pattern_size = sizeof(pattern) - 1;
  153.                         ByLySharkComUtilScanSection(".text", (PUCHAR)pattern, 0xCC, pattern_size, (PVOID *)&m_MiProcessLoaderEntry);
  154.                         DbgPrint("[LyShark] 输出首地址: %p", m_MiProcessLoaderEntry);
  155.                 }
  156.         }
  157.         Driver->DriverUnload = UnDriver;
  158.         return STATUS_SUCCESS;
  159. }
复制代码
代码中首先判断系统主版本windows 10 18363如果是则执行匹配,只匹配.text也就是代码段中的数据,当遇到0xcc时则取消继续,否则继续执行枚举,程序输出效果如下所示。

在WinDBG中输入命令!dh 0xfffff8007f600000解析出内核PE头数据,可以看到如下所示,对比无误。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

拉不拉稀肚拉稀

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表