驱动开发:内核RIP劫持实现DLL注入

打印 上一主题 下一主题

主题 523|帖子 523|积分 1569

本章将探索内核级DLL模块注入实现原理,DLL模块注入在应用层中通常会使用CreateRemoteThread直接开启远程线程执行即可,驱动级别的注入有多种实现原理,而其中最简单的一种实现方式则是通过劫持EIP的方式实现,其实现原理可总结为,挂起目标进程,停止目标进程EIP的变换,在目标进程开启空间,并把相关的指令机器码和数据拷贝到里面去,然后直接修改目标进程EIP使其强行跳转到我们拷贝进去的相关机器码位置,执行相关代码后,然后再次跳转回来执行原始指令集。
在内核模式中实现这一过程大体可分为如下步骤;

  • 1.通过PsLookupProcessByProcessId将进程PID转为EProcess结构
  • 2.通过KeStackAttachProcess附加到目标进程
  • 3.通过GetUserModule得到当前进程中Ntdll.dll模块的基址
  • 4.通过GetModuleExport得到Ntdll.dll模块内LdrLoadDll函数基址
  • 5.通过ZwGetNextThread得到当前线程句柄
  • 6.通过PsSuspendThread暂停当前线程运行
  • 7.此时通过GetWow64Code生成特定的加载代码,并放入ZwAllocateVirtualMemory生成的内存中
  • 8.修改当前EIP的值指向newAddress内存地址
  • 7.通过PsResumeThread恢复线程执行,让其执行我们的ShellCode代码
  • 8.最后调用KeUnstackDetachProcess脱离目标进程,并释放句柄
首先需要定义一个标准头文件,并将其命名为lyshark.h其定义部分如下所示,此部分内容摘录于微软官方文档,如果需要了解结构体内的含义,请去自行查阅微软官方文档;
  1. // 署名权
  2. // right to sign one's name on a piece of work
  3. // PowerBy: LyShark
  4. // Email: me@lyshark.com
  5. #include <ntifs.h>
  6. #include <windef.h>
  7. #include <intrin.h>
  8. #include <ntimage.h>
  9. #include <ntstrsafe.h>
  10. // 线程结构体偏移值
  11. #define MAXCOUNTS 0x200
  12. #define INITIALSTACKOFFSET 0x28
  13. #define WOW64CONTEXTOFFSET 0x1488
  14. #define WOW64_SIZE_OF_80387_REGISTERS 80
  15. #define WOW64_MAXIMUM_SUPPORTED_EXTENSION 512
  16. // 导出函数
  17. NTKERNELAPI PPEB NTAPI PsGetProcessPeb(IN PEPROCESS Process);
  18. // 定义自定义函数指针
  19. typedef PVOID(NTAPI* PPsGetThreadTeb)(IN PETHREAD Thread);
  20. typedef PVOID(NTAPI* PPsGetProcessWow64Process)(_In_ PEPROCESS Process);
  21. typedef NTSTATUS(NTAPI* PPsResumeThread)(PETHREAD Thread, OUT PULONG PreviousCount);
  22. typedef NTSTATUS(NTAPI* PPsSuspendThread)(IN PETHREAD Thread, OUT PULONG PreviousSuspendCount OPTIONAL);
  23. typedef NTSTATUS(NTAPI* PZwGetNextThread)(_In_ HANDLE ProcessHandle, _In_ HANDLE ThreadHandle, _In_ ACCESS_MASK DesiredAccess, _In_ ULONG HandleAttributes, _In_ ULONG Flags, _Out_ PHANDLE NewThreadHandle);
  24. // 存放全局函数指针的变量
  25. PPsGetThreadTeb g_PsGetThreadTeb = NULL;
  26. PPsResumeThread g_PsResumeThread = NULL;
  27. PPsSuspendThread g_PsSuspendThread = NULL;
  28. PZwGetNextThread g_ZwGetNextThread = NULL;
  29. PPsGetProcessWow64Process g_PsGetProcessWow64Process = NULL;
  30. // 定义微软结构体
  31. typedef struct _PEB_LDR_DATA32
  32. {
  33.         ULONG Length;
  34.         UCHAR Initialized;
  35.         ULONG SsHandle;
  36.         LIST_ENTRY32 InLoadOrderModuleList;
  37.         LIST_ENTRY32 InMemoryOrderModuleList;
  38.         LIST_ENTRY32 InInitializationOrderModuleList;
  39. } PEB_LDR_DATA32, *PPEB_LDR_DATA32;
  40. typedef struct _PEB_LDR_DATA
  41. {
  42.         ULONG Length;
  43.         UCHAR Initialized;
  44.         PVOID SsHandle;
  45.         LIST_ENTRY InLoadOrderModuleList;
  46.         LIST_ENTRY InMemoryOrderModuleList;
  47.         LIST_ENTRY InInitializationOrderModuleList;
  48. } PEB_LDR_DATA, *PPEB_LDR_DATA;
  49. typedef struct _LDR_DATA_TABLE_ENTRY32
  50. {
  51.         LIST_ENTRY32 InLoadOrderLinks;
  52.         LIST_ENTRY32 InMemoryOrderLinks;
  53.         LIST_ENTRY32 InInitializationOrderLinks;
  54.         ULONG DllBase;
  55.         ULONG EntryPoint;
  56.         ULONG SizeOfImage;
  57.         UNICODE_STRING32 FullDllName;
  58.         UNICODE_STRING32 BaseDllName;
  59.         ULONG Flags;
  60.         USHORT LoadCount;
  61.         USHORT TlsIndex;
  62.         LIST_ENTRY32 HashLinks;
  63.         ULONG TimeDateStamp;
  64. } LDR_DATA_TABLE_ENTRY32, *PLDR_DATA_TABLE_ENTRY32;
  65. typedef struct _LDR_DATA_TABLE_ENTRY
  66. {
  67.         LIST_ENTRY InLoadOrderLinks;
  68.         LIST_ENTRY InMemoryOrderLinks;
  69.         LIST_ENTRY InInitializationOrderLinks;
  70.         PVOID DllBase;
  71.         PVOID EntryPoint;
  72.         ULONG SizeOfImage;
  73.         UNICODE_STRING FullDllName;
  74.         UNICODE_STRING BaseDllName;
  75.         ULONG Flags;
  76.         USHORT LoadCount;
  77.         USHORT TlsIndex;
  78.         LIST_ENTRY HashLinks;
  79.         ULONG TimeDateStamp;
  80. } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
  81. typedef struct _PEB32
  82. {
  83.         UCHAR InheritedAddressSpace;
  84.         UCHAR ReadImageFileExecOptions;
  85.         UCHAR BeingDebugged;
  86.         UCHAR BitField;
  87.         ULONG Mutant;
  88.         ULONG ImageBaseAddress;
  89.         ULONG Ldr;
  90.         ULONG ProcessParameters;
  91.         ULONG SubSystemData;
  92.         ULONG ProcessHeap;
  93.         ULONG FastPebLock;
  94.         ULONG AtlThunkSListPtr;
  95.         ULONG IFEOKey;
  96.         ULONG CrossProcessFlags;
  97.         ULONG UserSharedInfoPtr;
  98.         ULONG SystemReserved;
  99.         ULONG AtlThunkSListPtr32;
  100.         ULONG ApiSetMap;
  101. } PEB32, *PPEB32;
  102. typedef struct _PEB
  103. {
  104.         UCHAR InheritedAddressSpace;
  105.         UCHAR ReadImageFileExecOptions;
  106.         UCHAR BeingDebugged;
  107.         UCHAR BitField;
  108.         PVOID Mutant;
  109.         PVOID ImageBaseAddress;
  110.         PPEB_LDR_DATA Ldr;
  111.         PVOID ProcessParameters;
  112.         PVOID SubSystemData;
  113.         PVOID ProcessHeap;
  114.         PVOID FastPebLock;
  115.         PVOID AtlThunkSListPtr;
  116.         PVOID IFEOKey;
  117.         PVOID CrossProcessFlags;
  118.         PVOID KernelCallbackTable;
  119.         ULONG SystemReserved;
  120.         ULONG AtlThunkSListPtr32;
  121.         PVOID ApiSetMap;
  122. } PEB, *PPEB;
  123. typedef struct _KLDR_DATA_TABLE_ENTRY
  124. {
  125.         LIST_ENTRY InLoadOrderLinks;
  126.         PVOID ExceptionTable;
  127.         ULONG ExceptionTableSize;
  128.         PVOID GpValue;
  129.         ULONG UnKnow;
  130.         PVOID DllBase;
  131.         PVOID EntryPoint;
  132.         ULONG SizeOfImage;
  133.         UNICODE_STRING FullDllName;
  134.         UNICODE_STRING BaseDllName;
  135.         ULONG Flags;
  136.         USHORT LoadCount;
  137.         USHORT __Unused5;
  138.         PVOID SectionPointer;
  139.         ULONG CheckSum;
  140.         PVOID LoadedImports;
  141.         PVOID PatchInformation;
  142. } KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;
  143. typedef struct _WOW64_FLOATING_SAVE_AREA
  144. {
  145.         DWORD ControlWord;
  146.         DWORD StatusWord;
  147.         DWORD TagWord;
  148.         DWORD ErrorOffset;
  149.         DWORD ErrorSelector;
  150.         DWORD DataOffset;
  151.         DWORD DataSelector;
  152.         BYTE RegisterArea[WOW64_SIZE_OF_80387_REGISTERS];
  153.         DWORD Cr0NpxState;
  154. } WOW64_FLOATING_SAVE_AREA;
  155. typedef struct _WOW64_CONTEXT
  156. {
  157.         DWORD padding;
  158.         DWORD ContextFlags;
  159.         DWORD Dr0;
  160.         DWORD Dr1;
  161.         DWORD Dr2;
  162.         DWORD Dr3;
  163.         DWORD Dr6;
  164.         DWORD Dr7;
  165.         WOW64_FLOATING_SAVE_AREA FloatSave;
  166.         DWORD SegGs;
  167.         DWORD SegFs;
  168.         DWORD SegEs;
  169.         DWORD SegDs;
  170.         DWORD Edi;
  171.         DWORD Esi;
  172.         DWORD Ebx;
  173.         DWORD Edx;
  174.         DWORD Ecx;
  175.         DWORD Eax;
  176.         DWORD Ebp;
  177.         DWORD Eip;
  178.         DWORD SegCs;
  179.         DWORD EFlags;
  180.         DWORD Esp;
  181.         DWORD SegSs;
  182.         BYTE ExtendedRegisters[WOW64_MAXIMUM_SUPPORTED_EXTENSION];
  183. } WOW64_CONTEXT, *PWOW64_CONTEXT;
  184. // 自定义注入结构体
  185. typedef struct _INJECT_BUFFER
  186. {
  187.         UCHAR Code[0x200];
  188.         UNICODE_STRING Path;
  189.         UNICODE_STRING32 Path32;
  190.         wchar_t Buffer[488];
  191.         PVOID ModuleHandle;
  192.         ULONG Complete;
  193.         NTSTATUS Status;
  194.         ULONG64 orgRipAddress;
  195.         ULONG64 orgRip;
  196. } INJECT_BUFFER, *PINJECT_BUFFER;
复制代码
SearchOPcode 特征码定位基址: 在注入之前我们需要通过SearchOPcode()函数动态的寻找几个关键函数的基址,以PsSuspendThread函数的寻找为例,通过WinDBG我们可以定位到该函数,该函数模块在ntoskrnl.exe中,且无法直接通过MmGetSystemRoutineAddress拿到,为了能通过代码拿到该函数的入口地址,我提取fffff804204de668到fffff804204de670位置处的特征码,由于fffff804204de668距离PsSuspendThread函数开头只有24字节,所以直接通过-24即可得到。

通过调用SearchOPcode()并传入机器码即可直接拿到PsSuspendThread的入口地址,根据上述方式我们需要分别得到PsSuspendThread,PsResumeThread这几个函数的内存基址,这些函数的具体作用如下所示;

  • PsSuspendThread() 用于暂停或者挂起线程
  • PsResumeThread() 用于恢复线程
其次还需要通过MmGetSystemRoutineAddress函数动态的得到ZwGetNextThread,PsGetThreadTeb,PsGetProcessWow64Process这几个函数的基址,这些函数的具体作用如下所示;

  • ZwGetNextThread() 用于获取下一个活动线程
  • PsGetThreadTeb() 用于获取线程TEB结构
  • PsGetProcessWow64Process() 判断当前进程是否为32位
完整代码如下所示,运行这段代码将定位到我们所需的所有内核函数的基址信息;
  1. // 署名权
  2. // right to sign one's name on a piece of work
  3. // PowerBy: LyShark
  4. // Email: me@lyshark.com
  5. #include "lyshark.h"
  6. // 内核特征码定位函数封装
  7. // 参数1:传入驱动句柄
  8. // 参数2:传入驱动模块名
  9. // 参数3:传入节表名称
  10. // 参数4:传入待搜索机器码字节数组
  11. // 参数5:传入机器码长度
  12. // 参数6:基址修正字节数
  13. PVOID SearchOPcode(PDRIVER_OBJECT pObj, PWCHAR DriverName, PCHAR sectionName, PUCHAR opCode, DWORD len, DWORD offset)
  14. {
  15.         PVOID dllBase = NULL;
  16.         UNICODE_STRING uniDriverName;
  17.         PKLDR_DATA_TABLE_ENTRY firstentry;
  18.         // 获取驱动入口
  19.         PKLDR_DATA_TABLE_ENTRY entry = (PKLDR_DATA_TABLE_ENTRY)pObj->DriverSection;
  20.         firstentry = entry;
  21.         RtlInitUnicodeString(&uniDriverName, DriverName);
  22.         // 开始遍历
  23.         while ((PKLDR_DATA_TABLE_ENTRY)entry->InLoadOrderLinks.Flink != firstentry)
  24.         {
  25.                 if (entry->FullDllName.Buffer != 0 && entry->BaseDllName.Buffer != 0)
  26.                 {
  27.                         // 如果找到了所需模块则将其基地址返回
  28.                         if (RtlCompareUnicodeString(&uniDriverName, &(entry->BaseDllName), FALSE) == 0)
  29.                         {
  30.                                 dllBase = entry->DllBase;
  31.                                 break;
  32.                         }
  33.                 }
  34.                 entry = (PKLDR_DATA_TABLE_ENTRY)entry->InLoadOrderLinks.Flink;
  35.         }
  36.         if (dllBase)
  37.         {
  38.                 __try
  39.                 {
  40.                         // 载入模块基地址
  41.                         PIMAGE_DOS_HEADER ImageDosHeader = (PIMAGE_DOS_HEADER)dllBase;
  42.                         if (ImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
  43.                         {
  44.                                 return NULL;
  45.                         }
  46.                         // 得到模块NT头以及Section节头
  47.                         PIMAGE_NT_HEADERS64 pImageNtHeaders64 = (PIMAGE_NT_HEADERS64)((PUCHAR)dllBase + ImageDosHeader->e_lfanew);
  48.                         PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((PUCHAR)pImageNtHeaders64 + sizeof(pImageNtHeaders64->Signature) + sizeof(pImageNtHeaders64->FileHeader) + pImageNtHeaders64->FileHeader.SizeOfOptionalHeader);
  49.                         PUCHAR endAddress = 0;
  50.                         PUCHAR starAddress = 0;
  51.                         // 寻找符合条件的节
  52.                         for (int i = 0; i < pImageNtHeaders64->FileHeader.NumberOfSections; i++)
  53.                         {
  54.                                 if (memcmp(sectionName, pSectionHeader->Name, strlen(sectionName) + 1) == 0)
  55.                                 {
  56.                                         starAddress = pSectionHeader->VirtualAddress + (PUCHAR)dllBase;
  57.                                         endAddress = pSectionHeader->VirtualAddress + (PUCHAR)dllBase + pSectionHeader->SizeOfRawData;
  58.                                         break;
  59.                                 }
  60.                                 pSectionHeader++;
  61.                         }
  62.                         if (endAddress && starAddress)
  63.                         {
  64.                                 // 找到会开始寻找特征
  65.                                 for (; starAddress < endAddress - len - 1; starAddress++)
  66.                                 {
  67.                                         // 验证访问权限
  68.                                         if (MmIsAddressValid(starAddress))
  69.                                         {
  70.                                                 DWORD i = 0;
  71.                                                 for (; i < len; i++)
  72.                                                 {
  73.                                                         // 判断是否为通配符'*'
  74.                                                         if (opCode[i] == 0x2a)
  75.                                                         {
  76.                                                                 continue;
  77.                                                         }
  78.                                                         // 找到了一个字节则跳出
  79.                                                         if (opCode[i] != starAddress[i])
  80.                                                         {
  81.                                                                 break;
  82.                                                         }
  83.                                                 }
  84.                                                 // 找到次数完全匹配则返回地址
  85.                                                 if (i == len)
  86.                                                 {
  87.                                                         return starAddress + offset;
  88.                                                 }
  89.                                         }
  90.                                 }
  91.                         }
  92.                 }
  93.                 __except (EXCEPTION_EXECUTE_HANDLER) {}
  94.         }
  95.         return NULL;
  96. }
  97. NTSTATUS UnDriver(PDRIVER_OBJECT driver)
  98. {
  99.         return STATUS_SUCCESS;
  100. }
  101. NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
  102. {
  103.         DbgPrint("Hello LyShark.com \n");
  104.         /*
  105.         0: kd> uf PsSuspendThread
  106.         nt!PsSuspendThread:
  107.         fffff804`204de650 4889542410      mov     qword ptr [rsp+10h],rdx
  108.         fffff804`204de655 48894c2408      mov     qword ptr [rsp+8],rcx
  109.         fffff804`204de65a 53              push    rbx
  110.         fffff804`204de65b 56              push    rsi
  111.         fffff804`204de65c 57              push    rdi
  112.         fffff804`204de65d 4156            push    r14
  113.         fffff804`204de65f 4157            push    r15
  114.         fffff804`204de661 4883ec30        sub     rsp,30h
  115.         fffff804`204de665 4c8bf2          mov     r14,rdx
  116.         fffff804`204de668 488bf9          mov     rdi,rcx
  117.         fffff804`204de66b 8364242000      and     dword ptr [rsp+20h],0
  118.         fffff804`204de670 65488b342588010000 mov   rsi,qword ptr gs:[188h]
  119.         fffff804`204de679 4889742470      mov     qword ptr [rsp+70h],rsi
  120.         fffff804`204de67e 66ff8ee4010000  dec     word ptr [rsi+1E4h]
  121.         fffff804`204de685 4c8db9c8060000  lea     r15,[rcx+6C8h]
  122.         fffff804`204de68c 4c897c2478      mov     qword ptr [rsp+78h],r15
  123.         fffff804`204de691 498bcf          mov     rcx,r15
  124.         fffff804`204de694 e8c7ff95ff      call    nt!ExAcquireRundownProtection (fffff804`1fe3e660)
  125.         fffff804`204de699 84c0            test    al,al
  126.         fffff804`204de69b 0f84495a1100    je      nt!PsSuspendThread+0x115a9a (fffff804`205f40ea)  Branch
  127.         */
  128.         UCHAR SuspendOpCode[] = { 0x48, 0x8b, 0xf9, 0x83, 0x64, 0x24, 0x20, 0x00, 0x65, 0x48, 0x8b, 0x34, 0x25, 0x88, 0x01 };
  129.         /*
  130.         0: kd> uf PsResumeThread
  131.         nt!PsResumeThread:
  132.         fffff804`204c7ab0 48895c2408      mov     qword ptr [rsp+8],rbx
  133.         fffff804`204c7ab5 4889742410      mov     qword ptr [rsp+10h],rsi
  134.         fffff804`204c7aba 57              push    rdi
  135.         fffff804`204c7abb 4883ec20        sub     rsp,20h
  136.         fffff804`204c7abf 488bda          mov     rbx,rdx
  137.         fffff804`204c7ac2 488bf9          mov     rdi,rcx
  138.         fffff804`204c7ac5 e8ee4fa5ff      call    nt!KeResumeThread (fffff804`1ff1cab8)
  139.         fffff804`204c7aca 65488b142588010000 mov   rdx,qword ptr gs:[188h]
  140.         fffff804`204c7ad3 8bf0            mov     esi,eax
  141.         fffff804`204c7ad5 83f801          cmp     eax,1
  142.         fffff804`204c7ad8 7521            jne     nt!PsResumeThread+0x4b (fffff804`204c7afb)  Branch
  143.         */
  144.         UCHAR ResumeOpCode[] = { 0x48, 0x8b, 0xf9, 0xe8, 0xee, 0x4f, 0xa5, 0xff, 0x65, 0x48, 0x8b, 0x14, 0x25, 0x88 };
  145.         // 特征码检索PsSuspendThread函数基址
  146.         g_PsSuspendThread = (PPsSuspendThread)SearchOPcode(Driver, L"ntoskrnl.exe", "PAGE", SuspendOpCode, sizeof(SuspendOpCode), -24);
  147.         DbgPrint("PsSuspendThread = %p \n", g_PsSuspendThread);
  148.         // 特征码检索PsResumeThread基址
  149.         g_PsResumeThread = (PPsResumeThread)SearchOPcode(Driver, L"ntoskrnl.exe", "PAGE", ResumeOpCode, sizeof(ResumeOpCode), -18);
  150.         DbgPrint("PsResumeThread = %p \n", g_PsResumeThread);
  151.         // 动态获取内存中的ZwGetNextThread基址
  152.         UNICODE_STRING ZwGetNextThreadString = RTL_CONSTANT_STRING(L"ZwGetNextThread");
  153.         g_ZwGetNextThread = (PZwGetNextThread)MmGetSystemRoutineAddress(&ZwGetNextThreadString);
  154.         DbgPrint("ZwGetNextThread = %p \n", g_ZwGetNextThread);
  155.         // 动态获取内存中的PsGetThreadTeb基址
  156.         UNICODE_STRING PsGetThreadTebString = RTL_CONSTANT_STRING(L"PsGetThreadTeb");
  157.         g_PsGetThreadTeb = (PPsGetThreadTeb)MmGetSystemRoutineAddress(&PsGetThreadTebString);
  158.         DbgPrint("PsGetThreadTeb = %p \n", g_PsGetThreadTeb);
  159.         // 动态获取内存中的PsGetProcessWow64Process基址
  160.         UNICODE_STRING PsGetProcessWow64ProcessString = RTL_CONSTANT_STRING(L"PsGetProcessWow64Process");
  161.         g_PsGetProcessWow64Process = (PPsGetProcessWow64Process)MmGetSystemRoutineAddress(&PsGetProcessWow64ProcessString);
  162.         DbgPrint("PsGetProcessWow64Process = %p \n", g_PsGetProcessWow64Process);
  163.         Driver->DriverUnload = UnDriver;
  164.         return STATUS_SUCCESS;
  165. }
复制代码
编译并运行如上代码片段,则会输出我们所需函数的入口地址,输出效果图如下所示;

GetUserModule 获取模块基址: 此函数的功能是获取到当前内核下特定模块的基址,函数接收三个参数,在入口DriverEntry位置通过KeStackAttachProcess附加到进程空间内,如果是32位进程则通过PsGetProcessWow64Process得到进程的PEB结构,如果是64位则通过PsGetProcessPeb得到PEB进程环境块的目的是为了解析PLIST_ENTRY32链表,通过RtlCompareUnicodeString对比模块是否符合要求,如果符合则在此链表中取出LdrDataTableEntry32->DllBase模块基址并返回给调用者,其完整代码片段如下所示;

  • 1.通过KeStackAttachProcess附加到用户层进程空间内
  • 2.通过各种函数获取到进程PEB进程环境块
  • 3.遍历PLIST_ENTRY32链表,判断ModuleName是否所需
  • 4.获取LdrDataTableEntry32->DllBase中的模块基址
  1. // 署名权
  2. // right to sign one's name on a piece of work
  3. // PowerBy: LyShark
  4. // Email: me@lyshark.com
  5. #include "lyshark.h"
  6. // 得到当前用户进程下的模块基址
  7. // 参数1:传入用户EProcess结构
  8. // 参数2:传入模块名
  9. // 参数3:是否32位
  10. PVOID GetUserModule(IN PEPROCESS EProcess, IN PUNICODE_STRING ModuleName, IN BOOLEAN IsWow64)
  11. {
  12.         if (EProcess == NULL)
  13.                 return NULL;
  14.         __try
  15.         {
  16.                 // 执行32位
  17.                 if (IsWow64)
  18.                 {
  19.                         // 获取32位下的PEB进程环境块
  20.                         PPEB32 Peb32 = (PPEB32)g_PsGetProcessWow64Process(EProcess);
  21.                         if (Peb32 == NULL)
  22.                                 return NULL;
  23.                         if (!Peb32->Ldr)
  24.                                 return NULL;
  25.                         // 循环遍历链表 寻找模块
  26.                         for (PLIST_ENTRY32 ListEntry = (PLIST_ENTRY32)((PPEB_LDR_DATA32)Peb32->Ldr)->InLoadOrderModuleList.Flink;
  27.                                 ListEntry != &((PPEB_LDR_DATA32)Peb32->Ldr)->InLoadOrderModuleList;
  28.                                 ListEntry = (PLIST_ENTRY32)ListEntry->Flink)
  29.                         {
  30.                                 UNICODE_STRING UnicodeString;
  31.                                 PLDR_DATA_TABLE_ENTRY32 LdrDataTableEntry32 = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY32, InLoadOrderLinks);
  32.                                 // 初始化模块名
  33.                                 RtlUnicodeStringInit(&UnicodeString, (PWCH)LdrDataTableEntry32->BaseDllName.Buffer);
  34.                                 // 对比模块名是否符合
  35.                                 if (RtlCompareUnicodeString(&UnicodeString, ModuleName, TRUE) == 0)
  36.                                         return (PVOID)LdrDataTableEntry32->DllBase;
  37.                         }
  38.                 }
  39.                 // 执行64位
  40.                 else
  41.                 {
  42.                         // 得到64位PEB进程环境块
  43.                         PPEB Peb = PsGetProcessPeb(EProcess);
  44.                         if (!Peb)
  45.                                 return NULL;
  46.                         if (!Peb->Ldr)
  47.                                 return NULL;
  48.                         // 开始遍历模块
  49.                         for (PLIST_ENTRY ListEntry = Peb->Ldr->InLoadOrderModuleList.Flink;
  50.                                 ListEntry != &Peb->Ldr->InLoadOrderModuleList;
  51.                                 ListEntry = ListEntry->Flink)
  52.                         {
  53.                                 // 得到表头
  54.                                 PLDR_DATA_TABLE_ENTRY LdrDataTableEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
  55.                                 // 判断是否是所需要的模块
  56.                                 if (RtlCompareUnicodeString(&LdrDataTableEntry->BaseDllName, ModuleName, TRUE) == 0)
  57.                                         return LdrDataTableEntry->DllBase;
  58.                         }
  59.                 }
  60.         }
  61.         __except (EXCEPTION_EXECUTE_HANDLER){}
  62.         return NULL;
  63. }
  64. NTSTATUS UnDriver(PDRIVER_OBJECT driver)
  65. {
  66.         return STATUS_SUCCESS;
  67. }
  68. NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
  69. {
  70.         DbgPrint("Hello LyShark.com \n");
  71.         // 动态获取内存中的PsGetProcessWow64Process基址
  72.         UNICODE_STRING PsGetProcessWow64ProcessString = RTL_CONSTANT_STRING(L"PsGetProcessWow64Process");
  73.         g_PsGetProcessWow64Process = (PPsGetProcessWow64Process)MmGetSystemRoutineAddress(&PsGetProcessWow64ProcessString);
  74.         DbgPrint("PsGetProcessWow64Process = %p \n", g_PsGetProcessWow64Process);
  75.         PEPROCESS pEprocess = NULL;
  76.         DWORD pid = 6084;
  77.         // 根据PID得到进程Eprocess结构
  78.         if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)pid, &pEprocess)))
  79.         {
  80.                 // 初始化结构
  81.                 UNICODE_STRING ntdllString = RTL_CONSTANT_STRING(L"Ntdll.dll");
  82.                 KAPC_STATE kApc = { 0 };
  83.                 // 附加到进程内
  84.                 KeStackAttachProcess(pEprocess, &kApc);
  85.                 // 获取NTDLL的模块基地址
  86.                 PVOID ntdll_address = GetUserModule(pEprocess, &ntdllString, TRUE);
  87.                 if (ntdll_address != NULL)
  88.                 {
  89.                         DbgPrint("[*] Ntdll Addr = %p \n", ntdll_address);
  90.                 }
  91.                 // 取消附加
  92.                 KeUnstackDetachProcess(&kApc);
  93.                 // 递减计数
  94.                 ObDereferenceObject(pEprocess);
  95.         }
  96.         Driver->DriverUnload = UnDriver;
  97.         return STATUS_SUCCESS;
  98. }
复制代码
运行如上这段程序,则会取出进程ID为6084中Ntdll.dll的模块基址,输出效果图如下所示;

GetModuleExport 取导出表函数基址: 此函数的功能是获取到当前内核下特定模块中的特定函数(内存中)基址,函数接收两个参数,在入口DriverEntry位置通过KeStackAttachProcess附加到进程空间内,通过解析IMAGE_DIRECTORY_ENTRY_EXPORT导出表取出导出函数名,此处需要注意如果函数名指针小于等于0xFFFF则说明是序号导出,如果大于0xFFFF则说明是名字导出,判断名字是否一致,如果一致则返回当前内存的ModuleBase模块基址加上pAddressOfFuncs[OrdIndex]相对偏移,从而获取到内存中的绝对地址,完整代码片段如下所示;
  1. // 署名权
  2. // right to sign one's name on a piece of work
  3. // PowerBy: LyShark
  4. // Email: me@lyshark.com
  5. #include "lyshark.h"
  6. // 根据函数名得到导出表地址
  7. // 参数1:传入模块入口地址
  8. // 参数2:传入导出函数名
  9. PVOID GetModuleExport(IN PVOID ModuleBase, IN PCCHAR FunctionName)
  10. {
  11.         PIMAGE_DOS_HEADER ImageDosHeader = (PIMAGE_DOS_HEADER)ModuleBase;
  12.         PIMAGE_NT_HEADERS32 ImageNtHeaders32 = NULL;
  13.         PIMAGE_NT_HEADERS64 ImageNtHeaders64 = NULL;
  14.         PIMAGE_EXPORT_DIRECTORY ImageExportDirectory = NULL;
  15.         ULONG ExportDirectorySize = 0;
  16.         ULONG_PTR FunctionAddress = 0;
  17.         if (ModuleBase == NULL)
  18.                 return NULL;
  19.         __try
  20.         {
  21.                 // 判断是否是DOS头
  22.                 if (ImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
  23.                 {
  24.                         return NULL;
  25.                 }
  26.                 // 获取PE结构节NT头
  27.                 ImageNtHeaders32 = (PIMAGE_NT_HEADERS32)((PUCHAR)ModuleBase + ImageDosHeader->e_lfanew);
  28.                 ImageNtHeaders64 = (PIMAGE_NT_HEADERS64)((PUCHAR)ModuleBase + ImageDosHeader->e_lfanew);
  29.                 // 判断是否是64位
  30.                 if (ImageNtHeaders64->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
  31.                 {
  32.                         // 如果是64位则执行如下
  33.                         ImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(ImageNtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + (ULONG_PTR)ModuleBase);
  34.                         ExportDirectorySize = ImageNtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
  35.                 }
  36.                 else
  37.                 {
  38.                         // 如果32位则执行如下
  39.                         ImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(ImageNtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + (ULONG_PTR)ModuleBase);
  40.                         ExportDirectorySize = ImageNtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
  41.                 }
  42.                 // 取出导出表Index,名字,函地址等
  43.                 PUSHORT pAddressOfOrds = (PUSHORT)(ImageExportDirectory->AddressOfNameOrdinals + (ULONG_PTR)ModuleBase);
  44.                 PULONG  pAddressOfNames = (PULONG)(ImageExportDirectory->AddressOfNames + (ULONG_PTR)ModuleBase);
  45.                 PULONG  pAddressOfFuncs = (PULONG)(ImageExportDirectory->AddressOfFunctions + (ULONG_PTR)ModuleBase);
  46.                 // 循环导出表
  47.                 for (ULONG i = 0; i < ImageExportDirectory->NumberOfFunctions; ++i)
  48.                 {
  49.                         USHORT OrdIndex = 0xFFFF;
  50.                         PCHAR  pName = NULL;
  51.                         // 说明是序号导出
  52.                         if ((ULONG_PTR)FunctionName <= 0xFFFF)
  53.                         {
  54.                                 // 得到函数序号
  55.                                 OrdIndex = (USHORT)i;
  56.                         }
  57.                         // 说明是名字导出
  58.                         else if ((ULONG_PTR)FunctionName > 0xFFFF && i < ImageExportDirectory->NumberOfNames)
  59.                         {
  60.                                 // 得到函数名
  61.                                 pName = (PCHAR)(pAddressOfNames[i] + (ULONG_PTR)ModuleBase);
  62.                                 OrdIndex = pAddressOfOrds[i];
  63.                         }
  64.                         else
  65.                                 return NULL;
  66.                         // 判断函数名是否符合
  67.                         if (((ULONG_PTR)FunctionName <= 0xFFFF && (USHORT)((ULONG_PTR)FunctionName) == OrdIndex + ImageExportDirectory->Base) ||
  68.                                 ((ULONG_PTR)FunctionName > 0xFFFF && strcmp(pName, FunctionName) == 0))
  69.                         {
  70.                                 // 得到完整地址
  71.                                 FunctionAddress = pAddressOfFuncs[OrdIndex] + (ULONG_PTR)ModuleBase;
  72.                                 break;
  73.                         }
  74.                 }
  75.         }
  76.         __except (EXCEPTION_EXECUTE_HANDLER){}
  77.         return (PVOID)FunctionAddress;
  78. }
  79. NTSTATUS UnDriver(PDRIVER_OBJECT driver)
  80. {
  81.         return STATUS_SUCCESS;
  82. }
  83. NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
  84. {
  85.         DbgPrint("Hello LyShark.com \n");
  86.         PEPROCESS pEprocess = NULL;
  87.         DWORD pid = 6084;
  88.         // 根据PID得到进程Eprocess结构
  89.         if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)pid, &pEprocess)))
  90.         {
  91.                 KAPC_STATE kApc = { 0 };
  92.                 // ntdll.dll模块基址
  93.                 PVOID ntdll_address = (PVOID)0x0000000077540000;
  94.                 // 附加到进程内
  95.                 KeStackAttachProcess(pEprocess, &kApc);
  96.                 // 取模块中LdrLoadDll函数基址
  97.                 PVOID LdrLoadDllAddress = GetModuleExport(ntdll_address, "LdrLoadDll");
  98.                 DbgPrint("[*] LdrLoadDllAddress = %p \n", LdrLoadDllAddress);
  99.                 // 取消附加
  100.                 KeUnstackDetachProcess(&kApc);
  101.                 // 递减计数
  102.                 ObDereferenceObject(pEprocess);
  103.         }
  104.         Driver->DriverUnload = UnDriver;
  105.         return STATUS_SUCCESS;
  106. }
复制代码
编译并运行如上代码片段,即可获取到进程6084号,ntdll.dll模块中LdrLoadDll的内存地址,其输出效果图如下所示;

GetCurrentContext 获取当前线程上下文: 此函数的功能是获取附加进程内当前线程的上下文地址,函数接收一个参数,内部通过PsLookupProcessByProcessId得到进程EProcess结构体,通过KeStackAttachProcess附加到进程内,调用g_ZwGetNextThread获取当当前线程上下文,函数ObReferenceObjectByHandle用于将Handle转换为线程对象,之后再通过g_PsSuspendThread暂停线程后,即可通过各类函数获取到该线程的绝大部分信息,最终在调用结束时记得调用g_PsResumeThread恢复线程的运行,并KeUnstackDetachProcess脱离附加,解析上下文环境完整代码如下所示;
  1. // 署名权
  2. // right to sign one's name on a piece of work
  3. // PowerBy: LyShark
  4. // Email: me@lyshark.com
  5. #include "lyshark.h"
  6. // ShellCode 注入线程函数
  7. NTSTATUS GetCurrentContext(ULONG pid, PVOID* allcateAddress)
  8. {
  9.         PEPROCESS pEprocess = NULL;
  10.         // 根据PID得到进程Eprocess结构
  11.         if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)pid, &pEprocess)))
  12.         {
  13.                 KAPC_STATE kApc = { 0 };
  14.                 // 附加到进程内
  15.                 KeStackAttachProcess(pEprocess, &kApc);
  16.                 HANDLE threadHandle = NULL;
  17.                 // 得到当前正在运行的线程上下文
  18.                 if (NT_SUCCESS(g_ZwGetNextThread((HANDLE)-1, (HANDLE)0, 0x1FFFFF, 0x240, 0, &threadHandle)))
  19.                 {
  20.                         PVOID threadObj = NULL;
  21.                         // 在对象句柄上提供访问验证,如果可以授予访问权限,则返回指向对象的正文的相应指针。
  22.                         NTSTATUS state = ObReferenceObjectByHandle(threadHandle, 0x1FFFFF, *PsThreadType, KernelMode, &threadObj, NULL);
  23.                         if (NT_SUCCESS(state))
  24.                         {
  25.                                 // 暂停线程
  26.                                 g_PsSuspendThread(threadObj, NULL);
  27.                                 __try
  28.                                 {
  29.                                         // 得到TEB
  30.                                         PVOID pTeb = g_PsGetThreadTeb(threadObj);
  31.                                         if (pTeb)
  32.                                         {
  33.                                                 DbgPrint("[+] 线程环境块TEB = %p \n", pTeb);
  34.                                                 // 得到当前线程上下文
  35.                                                 /* WOW64CONTEXTOFFSET = TlsSlots + 8
  36.                                                         0: kd> dt _TEB
  37.                                                         nt!_TEB
  38.                                                         + 0x000 NtTib            : _NT_TIB
  39.                                                         + 0x1258 StaticUnicodeString : _UNICODE_STRING
  40.                                                         + 0x1268 StaticUnicodeBuffer : [261] Wchar
  41.                                                         + 0x1472 Padding3 : [6] UChar
  42.                                                         + 0x1478 DeallocationStack : Ptr64 Void
  43.                                                         + 0x1480 TlsSlots : [64] Ptr64 Void
  44.                                                         + 0x1680 TlsLinks : _LIST_ENTRY
  45.                                                         + 0x1690 Vdm : Ptr64 Void
  46.                                                         + 0x1698 ReservedForNtRpc : Ptr64 Void
  47.                                                         + 0x16a0 DbgSsReserved : [2] Ptr64 Void
  48.                                                 */
  49.                                                 PWOW64_CONTEXT  pCurrentContext = (PWOW64_CONTEXT)(*(ULONG64*)((ULONG64)pTeb + WOW64CONTEXTOFFSET));
  50.                                                 DbgPrint("[-] 当前上下文EIP = %p \n", pCurrentContext->Eip);
  51.                                                 // 检查上下文是否可读
  52.                                                 ProbeForRead((PVOID)pCurrentContext, sizeof(pCurrentContext), sizeof(CHAR));
  53.                                                 UCHAR Code[] = {
  54.                                                         0xb8, 0x0, 0x0, 0x0, 0x0,        // mov eax, orgEip
  55.                                                         0x58,                            // pop eax
  56.                                                         0xc3                             // ret
  57.                                                 };
  58.                                                 // 将ShellCode拷贝到InjectBuffer中等待处理
  59.                                                 RtlCopyMemory(allcateAddress, Code, sizeof(Code));
  60.                                                 DbgPrint("[*] 拷贝 [%p] 内存 \n", allcateAddress);;
  61.                                                 // 修改代码模板,将指定位置替换为我们自己的代码
  62.                                                 *(ULONG*)((PUCHAR)allcateAddress + 1) = pCurrentContext->Eip;
  63.                                                 DbgPrint("[*] 替换 [ %p ] 跳转地址 \n", pCurrentContext->Eip);
  64.                                                 // 执行线程
  65.                                                 pCurrentContext->Eip = (ULONG)(ULONG64)(allcateAddress);
  66.                                                 DbgPrint("[*] 执行 [ %p ] 线程函数 \n", pCurrentContext->Eip);
  67.                                         }
  68.                                 }
  69.                                 __except (EXCEPTION_EXECUTE_HANDLER) {}
  70.                                 // 恢复线程
  71.                                 g_PsResumeThread(threadObj, NULL);
  72.                                 ObDereferenceObject(threadObj);
  73.                         }
  74.                         NtClose(threadHandle);
  75.                 }
  76.                 // 关闭线程
  77.                 KeUnstackDetachProcess(&kApc);
  78.                 ObDereferenceObject(pEprocess);
  79.         }
  80.         return STATUS_SUCCESS;
  81. }
  82. NTSTATUS UnDriver(PDRIVER_OBJECT driver)
  83. {
  84.         UNREFERENCED_PARAMETER(driver);
  85.         return STATUS_SUCCESS;
  86. }
  87. NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
  88. {
  89.         DbgPrint("Hello LyShark.com \n");
  90.         UNREFERENCED_PARAMETER(RegistryPath);
  91.         // 初始化基址
  92.         InitAddress(Driver);
  93.         ULONG ProcessID = 4904;
  94.         PVOID AllcateAddress = NULL;
  95.         DWORD create_size = 1024;
  96.         // 申请堆 《内核远程堆分配与销毁》核心代码
  97.         NTSTATUS Status = AllocMemory(ProcessID, create_size, &AllcateAddress);
  98.         // 执行ShellCode线程注入
  99.         Status = GetCurrentContext(ProcessID, &AllcateAddress);
  100.         Driver->DriverUnload = UnDriver;
  101.         return STATUS_SUCCESS;
  102. }
复制代码
运行如上代码片段,则将输出进程ID=4904的当前进程内,线程上下文RIP地址,输出效果如下图所示;

KernelInjectDLL 驱动注入: 如上代码中我们已经找到了驱动注入时所需用到的关键函数,那么实现代码就变得很容易了,驱动注入的实现方式有很多种,不论哪一种其实现的难度并不在于代码本身,而在于某些结构如何正确的被找到,一旦结构被找到原理方面的代码可以说非常容易获取到,如下这段完整代码则是驱动注入的一个简化版,如果你觉得不方便完全可以自行添加IOCTL控制器让其更易于使用,此处为了节约篇幅不在增加冗余代码,代码已做具体分析和备注。
此注入驱动核心实现代码如下所示,其中SearchOPcode用于在内核模块中寻找符合条件的内存地址,GetNativeCode则用于生成一段可被调用的ShellCode代码,此代码执行的目的就是将DLL动态装载到对端内存中,SetThreadStartAddress则用于填充执行线程结构信息,GetUserModule用户获取进程内特定模块的基址,GetModuleExport用于在模块内寻找特定函数的基址,KernelInjectDLL则是最终注入函数,其首先将线程暂停,并注入生成的ShellCode,然后恢复线程让ShellCode跑起来,当ShellCode跑起来后将会自动的将特定目录下的DLL拉起来,以此来实现动态加载的目的。
  1. // 署名权
  2. // right to sign one's name on a piece of work
  3. // PowerBy: LyShark
  4. // Email: me@lyshark.com
  5. #include "lyshark.h"
  6. // 内核特征码定位函数封装
  7. PVOID SearchOPcode(PDRIVER_OBJECT pObj, PWCHAR DriverName, PCHAR sectionName, PUCHAR opCode, int len, int offset)
  8. {
  9.         PVOID dllBase = NULL;
  10.         UNICODE_STRING uniDriverName;
  11.         PKLDR_DATA_TABLE_ENTRY firstentry;
  12.         // 获取驱动入口
  13.         PKLDR_DATA_TABLE_ENTRY entry = (PKLDR_DATA_TABLE_ENTRY)pObj->DriverSection;
  14.         firstentry = entry;
  15.         RtlInitUnicodeString(&uniDriverName, DriverName);
  16.         // 开始遍历
  17.         while ((PKLDR_DATA_TABLE_ENTRY)entry->InLoadOrderLinks.Flink != firstentry)
  18.         {
  19.                 // 如果找到了所需模块则将其基地址返回
  20.                 if (entry->FullDllName.Buffer != 0 && entry->BaseDllName.Buffer != 0)
  21.                 {
  22.                         if (RtlCompareUnicodeString(&uniDriverName, &(entry->BaseDllName), FALSE) == 0)
  23.                         {
  24.                                 dllBase = entry->DllBase;
  25.                                 break;
  26.                         }
  27.                 }
  28.                 entry = (PKLDR_DATA_TABLE_ENTRY)entry->InLoadOrderLinks.Flink;
  29.         }
  30.         if (dllBase)
  31.         {
  32.                 __try
  33.                 {
  34.                         // 载入模块基地址
  35.                         PIMAGE_DOS_HEADER ImageDosHeader = (PIMAGE_DOS_HEADER)dllBase;
  36.                         if (ImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
  37.                         {
  38.                                 return NULL;
  39.                         }
  40.                         // 得到模块NT头
  41.                         PIMAGE_NT_HEADERS64 pImageNtHeaders64 = (PIMAGE_NT_HEADERS64)((PUCHAR)dllBase + ImageDosHeader->e_lfanew);
  42.                         // 获取节表头
  43.                         PIMAGE_SECTION_HEADER pSectionHeader = (PIMAGE_SECTION_HEADER)((PUCHAR)pImageNtHeaders64 + sizeof(pImageNtHeaders64->Signature) + sizeof(pImageNtHeaders64->FileHeader) + pImageNtHeaders64->FileHeader.SizeOfOptionalHeader);
  44.                         PUCHAR endAddress = 0;
  45.                         PUCHAR starAddress = 0;
  46.                         // 寻找符合条件的节
  47.                         for (int i = 0; i < pImageNtHeaders64->FileHeader.NumberOfSections; i++)
  48.                         {
  49.                                 // 寻找符合条件的表名
  50.                                 if (memcmp(sectionName, pSectionHeader->Name, strlen(sectionName) + 1) == 0)
  51.                                 {
  52.                                         // 取出开始和结束地址
  53.                                         starAddress = pSectionHeader->VirtualAddress + (PUCHAR)dllBase;
  54.                                         endAddress = pSectionHeader->VirtualAddress + (PUCHAR)dllBase + pSectionHeader->SizeOfRawData;
  55.                                         break;
  56.                                 }
  57.                                 // 遍历下一个节
  58.                                 pSectionHeader++;
  59.                         }
  60.                         if (endAddress && starAddress)
  61.                         {
  62.                                 // 找到会开始寻找特征
  63.                                 for (; starAddress < endAddress - len - 1; starAddress++)
  64.                                 {
  65.                                         // 验证访问权限
  66.                                         if (MmIsAddressValid(starAddress))
  67.                                         {
  68.                                                 int i = 0;
  69.                                                 for (; i < len; i++)
  70.                                                 {
  71.                                                         // 判断是否为通配符'*'
  72.                                                         if (opCode[i] == 0x2a)
  73.                                                                 continue;
  74.                                                         // 找到了一个字节则跳出
  75.                                                         if (opCode[i] != starAddress[i])
  76.                                                                 break;
  77.                                                 }
  78.                                                 // 找到次数完全匹配则返回地址
  79.                                                 if (i == len)
  80.                                                 {
  81.                                                         return starAddress + offset;
  82.                                                 }
  83.                                         }
  84.                                 }
  85.                         }
  86.                 }
  87.                 __except (EXCEPTION_EXECUTE_HANDLER) {}
  88.         }
  89.         return NULL;
  90. }
  91. // 生成64位注入代码
  92. PINJECT_BUFFER GetNativeCode(PVOID LdrLoadDll, PUNICODE_STRING DllFullPath, ULONGLONG orgEip)
  93. {
  94.         SIZE_T Size = PAGE_SIZE;
  95.         PINJECT_BUFFER InjectBuffer = NULL;
  96.         UCHAR Code[] = {
  97.                 0x41, 0x57,                             // push r15
  98.                 0x41, 0x56,                             // push r14
  99.                 0x41, 0x55,                             // push r13
  100.                 0x41, 0x54,                             // push r12
  101.                 0x41, 0x53,                             // push r11
  102.                 0x41, 0x52,                             // push r10
  103.                 0x41, 0x51,                             // push r9
  104.                 0x41, 0x50,                             // push r8
  105.                 0x50,                                   // push rax
  106.                 0x51,                                   // push rcx
  107.                 0x53,                                   // push rbx
  108.                 0x52,                                   // push rdx
  109.                 0x55,                                   // push rbp
  110.                 0x54,                                   // push rsp
  111.                 0x56,                                   // push rsi
  112.                 0x57,                                   // push rdi
  113.                 0x66, 0x9C,                             // pushf
  114.                 0x48, 0x83, 0xEC, 0x26,                 // sub rsp, 0x28
  115.                 0x48, 0x31, 0xC9,                       // xor rcx, rcx
  116.                 0x48, 0x31, 0xD2,                       // xor rdx, rdx
  117.                 0x49, 0xB8, 0, 0, 0, 0, 0, 0, 0, 0,     // mov r8, ModuleFileName   offset +38
  118.                 0x49, 0xB9, 0, 0, 0, 0, 0, 0, 0, 0,     // mov r9, ModuleHandle     offset +48
  119.                 0x48, 0xB8, 0, 0, 0, 0, 0, 0, 0, 0,     // mov rax, LdrLoadDll      offset +58
  120.                 0xFF, 0xD0,                             // call rax
  121.                 0x48, 0xBA, 0, 0, 0, 0, 0, 0, 0, 0,     // mov rdx, COMPLETE_OFFSET offset +70
  122.                 0xC7, 0x02, 0x7E, 0x1E, 0x37, 0xC0,     // mov [rdx], CALL_COMPLETE
  123.                 0x48, 0xBA, 0, 0, 0, 0, 0, 0, 0, 0,     // mov rdx, STATUS_OFFSET   offset +86
  124.                 0x89, 0x02,                             // mov [rdx], eax
  125.                 0x48, 0x83, 0xC4, 0x26,                 // add rsp, 0x28
  126.                 0x66, 0x9D,                             // popf
  127.                 0x5F,                                   // pop rdi
  128.                 0x5E,                                   // pop rsi
  129.                 0x5C,                                   // pop rsp
  130.                 0x5D,                                   // pop rbp
  131.                 0x5A,                                   // pop rdx
  132.                 0x5B,                                   // pop rbx
  133.                 0x59,                                   // pop rcx
  134.                 0x58,                                   // pop rax
  135.                 0x41, 0x58,                             // pop r8
  136.                 0x41, 0x59,                             // pop r9
  137.                 0x41, 0x5A,                             // pop r10
  138.                 0x41, 0x5B,                             // pop r11
  139.                 0x41, 0x5C,                             // pop r12
  140.                 0x41, 0x5D,                             // pop r13
  141.                 0x41, 0x5E,                             // pop r14
  142.                 0x41, 0x5F,                             // pop r15
  143.                 0x50,                                   // push rax
  144.                 0x50,                                   // push rax
  145.                 0x48, 0xB8, 0, 0, 0, 0, 0, 0, 0, 0,     // mov rax, orgEip offset +130
  146.                 0x48, 0x89, 0x44, 0x24, 0x08,           // mov [rsp+8],rax
  147.                 0x58,                                   // pop rax
  148.                 0xC3                                    // ret
  149.         };
  150.         // 在当前进程内分配内存空间
  151.         if (NT_SUCCESS(ZwAllocateVirtualMemory(ZwCurrentProcess(), &InjectBuffer, 0, &Size, MEM_COMMIT, PAGE_EXECUTE_READWRITE)))
  152.         {
  153.                 // 初始化路径变量与长度参数
  154.                 PUNICODE_STRING UserPath = &InjectBuffer->Path;
  155.                 UserPath->Length = DllFullPath->Length;
  156.                 UserPath->MaximumLength = DllFullPath->MaximumLength;
  157.                 UserPath->Buffer = InjectBuffer->Buffer;
  158.                 RtlUnicodeStringCopy(UserPath, DllFullPath);
  159.                 // 将ShellCode拷贝到InjectBuffer中等待处理
  160.                 memcpy(InjectBuffer, Code, sizeof(Code));
  161.                 // 修改代码模板,将指定位置替换为我们自己的代码
  162.                 *(ULONGLONG*)((PUCHAR)InjectBuffer + 38) = (ULONGLONG)UserPath;
  163.                 *(ULONGLONG*)((PUCHAR)InjectBuffer + 48) = (ULONGLONG)& InjectBuffer->ModuleHandle;
  164.                 *(ULONGLONG*)((PUCHAR)InjectBuffer + 58) = (ULONGLONG)LdrLoadDll;
  165.                 *(ULONGLONG*)((PUCHAR)InjectBuffer + 70) = (ULONGLONG)& InjectBuffer->Complete;
  166.                 *(ULONGLONG*)((PUCHAR)InjectBuffer + 86) = (ULONGLONG)& InjectBuffer->Status;
  167.                 *(ULONGLONG*)((PUCHAR)InjectBuffer + 130) = orgEip;
  168.                 return InjectBuffer;
  169.         }
  170.         return NULL;
  171. }
  172. // 生成32位注入代码
  173. PINJECT_BUFFER GetWow64Code(PVOID LdrLoadDll, PUNICODE_STRING DllFullPath, ULONG orgEip)
  174. {
  175.         SIZE_T Size = PAGE_SIZE;
  176.         PINJECT_BUFFER InjectBuffer = NULL;
  177.         UCHAR Code[] = {
  178.                 0x60,                                   // pushad
  179.                 0x9c,                                   // pushfd
  180.                 0x68, 0, 0, 0, 0,                       // push ModuleHandle            offset +3
  181.                 0x68, 0, 0, 0, 0,                       // push ModuleFileName          offset +8
  182.                 0x6A, 0,                                // push Flags  
  183.                 0x6A, 0,                                // push PathToFile
  184.                 0xE8, 0, 0, 0, 0,                       // call LdrLoadDll              offset +17
  185.                 0xBA, 0, 0, 0, 0,                       // mov edx, COMPLETE_OFFSET     offset +22
  186.                 0xC7, 0x02, 0x7E, 0x1E, 0x37, 0xC0,     // mov [edx], CALL_COMPLETE     
  187.                 0xBA, 0, 0, 0, 0,                       // mov edx, STATUS_OFFSET       offset +33
  188.                 0x89, 0x02,                             // mov [edx], eax
  189.                 0x9d,                                   // popfd
  190.                 0x61,                                   // popad
  191.                 0x50,                                   // push eax
  192.                 0x50,                                   // push eax
  193.                 0xb8, 0, 0, 0, 0,                       // mov eax, orgEip
  194.                 0x89, 0x44, 0x24, 0x04,                 // mov [esp+4],eax
  195.                 0x58,                                   // pop eax
  196.                 0xc3                                    // ret
  197.         };
  198.         /*
  199.         如下代码中通过定义Code并写入调用模块加载的汇编指令集,通过运用ZwAllocateVirtualMemory在当前进程也就是附加到对端以后的进程内动态开辟了一块长度为Size的内存空间并赋予了PAGE_EXECUTE_READWRITE读写执行属性,
  200.         由于Code代码无法直接使用,则此处调用RtlCopyMemory将指令拷贝到了InjectBuffer其目的是用于后续的填充工作,最后通过*(ULONG*)((PUCHAR)InjectBuffer + 3)的方式将需要使用的函数地址,
  201.         模块信息等依次填充到汇编代码的指定位置,并返回InjectBuffer指针。
  202.         */
  203.         // 在当前进程内分配内存空间
  204.         if (NT_SUCCESS(ZwAllocateVirtualMemory(ZwCurrentProcess(), &InjectBuffer, 0, &Size, MEM_COMMIT, PAGE_EXECUTE_READWRITE)))
  205.         {
  206.                 // 初始化路径变量与长度参数
  207.                 PUNICODE_STRING32 pUserPath = &InjectBuffer->Path32;
  208.                 pUserPath->Length = DllFullPath->Length;
  209.                 pUserPath->MaximumLength = DllFullPath->MaximumLength;
  210.                 pUserPath->Buffer = (ULONG)(ULONG_PTR)InjectBuffer->Buffer;
  211.                 // 将ShellCode拷贝到InjectBuffer中等待处理
  212.                 memcpy((PVOID)pUserPath->Buffer, DllFullPath->Buffer, DllFullPath->Length);
  213.                 memcpy(InjectBuffer, Code, sizeof(Code));
  214.                 // 修改代码模板,将指定位置替换为我们自己的代码
  215.                 *(ULONG*)((PUCHAR)InjectBuffer + 3) = (ULONG)(ULONG_PTR)& InjectBuffer->ModuleHandle;
  216.                 *(ULONG*)((PUCHAR)InjectBuffer + 8) = (ULONG)(ULONG_PTR)pUserPath;
  217.                 *(ULONG*)((PUCHAR)InjectBuffer + 17) = (ULONG)((ULONG_PTR)LdrLoadDll - ((ULONG_PTR)InjectBuffer + 17) - 5 + 1);
  218.                 *(ULONG*)((PUCHAR)InjectBuffer + 22) = (ULONG)(ULONG_PTR)& InjectBuffer->Complete;
  219.                 *(ULONG*)((PUCHAR)InjectBuffer + 33) = (ULONG)(ULONG_PTR)& InjectBuffer->Status;
  220.                 *(ULONG*)((PUCHAR)InjectBuffer + 44) = orgEip;
  221.                 return InjectBuffer;
  222.         }
  223.         return NULL;
  224. }
  225. // 设置线程执行地址
  226. NTSTATUS SetThreadStartAddress(PETHREAD pEthread, BOOLEAN isWow64, PVOID LdrLoadDll, PUNICODE_STRING DllFullPath, PINJECT_BUFFER *allcateAddress)
  227. {
  228.         __try
  229.         {
  230.                 // 判断是32位则执行
  231.                 if (isWow64)
  232.                 {
  233.                         // 得到线程TEB
  234.                         PVOID pTeb = g_PsGetThreadTeb(pEthread);
  235.                         if (pTeb)
  236.                         {
  237.                                 // 得到当前线程上下文
  238.                                 PWOW64_CONTEXT  pCurrentContext = (PWOW64_CONTEXT)(*(ULONG64*)((ULONG64)pTeb + WOW64CONTEXTOFFSET));
  239.                                 // 检查上下文是否可读
  240.                                 ProbeForRead((PVOID)pCurrentContext, sizeof(pCurrentContext), sizeof(CHAR));
  241.                                 // 生成注入代码
  242.                                 PINJECT_BUFFER newAddress = GetWow64Code(LdrLoadDll, DllFullPath, pCurrentContext->Eip);
  243.                                 if (newAddress)
  244.                                 {
  245.                                         // 替换上下文地址到内存中
  246.                                         newAddress->orgRipAddress = (ULONG64)& (pCurrentContext->Eip);
  247.                                         newAddress->orgRip = pCurrentContext->Eip;
  248.                                         *allcateAddress = newAddress;
  249.                                         pCurrentContext->Eip = (ULONG)(ULONG64)(newAddress);
  250.                                 }
  251.                                 return STATUS_SUCCESS;
  252.                         }
  253.                 }
  254.                 // 执行64位代码
  255.                 else
  256.                 {
  257.                         // 验证地址是否可读取
  258.                         if (MmIsAddressValid((PVOID)* (ULONG64*)((ULONG64)pEthread + INITIALSTACKOFFSET)))
  259.                         {
  260.                                 // 当前TID
  261.                                 PKTRAP_FRAME pCurrentTrap = (PKTRAP_FRAME)(*(ULONG64*)((ULONG64)pEthread + INITIALSTACKOFFSET) - sizeof(KTRAP_FRAME));
  262.                                 // 生成注入代码
  263.                                 PINJECT_BUFFER newAddress = GetNativeCode(LdrLoadDll, DllFullPath, pCurrentTrap->Rip);
  264.                                 if (newAddress)
  265.                                 {
  266.                                         // 替换当前RIP地址
  267.                                         newAddress->orgRipAddress = (ULONG64)& (pCurrentTrap->Rip);
  268.                                         newAddress->orgRip = pCurrentTrap->Rip;
  269.                                         *allcateAddress = newAddress;
  270.                                         pCurrentTrap->Rip = (ULONG64)newAddress;
  271.                                 }
  272.                         }
  273.                         return STATUS_SUCCESS;
  274.                 }
  275.         }
  276.         __except (EXCEPTION_EXECUTE_HANDLER) {}
  277.         return STATUS_UNSUCCESSFUL;
  278. }
  279. // 得到当前用户进程下的模块基址
  280. PVOID GetUserModule(IN PEPROCESS EProcess, IN PUNICODE_STRING ModuleName, IN BOOLEAN IsWow64)
  281. {
  282.         if (EProcess == NULL)
  283.                 return NULL;
  284.         __try
  285.         {
  286.                 // 执行32位
  287.                 if (IsWow64)
  288.                 {
  289.                         // 获取32位下的PEB进程环境块
  290.                         PPEB32 Peb32 = (PPEB32)g_PsGetProcessWow64Process(EProcess);
  291.                         if (Peb32 == NULL)
  292.                                 return NULL;
  293.                         if (!Peb32->Ldr)
  294.                                 return NULL;
  295.                         // 循环遍历链表 寻找模块
  296.                         for (PLIST_ENTRY32 ListEntry = (PLIST_ENTRY32)((PPEB_LDR_DATA32)Peb32->Ldr)->InLoadOrderModuleList.Flink;
  297.                                 ListEntry != &((PPEB_LDR_DATA32)Peb32->Ldr)->InLoadOrderModuleList;
  298.                                 ListEntry = (PLIST_ENTRY32)ListEntry->Flink)
  299.                         {
  300.                                 UNICODE_STRING UnicodeString;
  301.                                 PLDR_DATA_TABLE_ENTRY32 LdrDataTableEntry32 = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY32, InLoadOrderLinks);
  302.                                 // 初始化模块名
  303.                                 RtlUnicodeStringInit(&UnicodeString, (PWCH)LdrDataTableEntry32->BaseDllName.Buffer);
  304.                                 // 对比模块名是否符合
  305.                                 if (RtlCompareUnicodeString(&UnicodeString, ModuleName, TRUE) == 0)
  306.                                         return (PVOID)LdrDataTableEntry32->DllBase;
  307.                         }
  308.                 }
  309.                 // 执行64位
  310.                 else
  311.                 {
  312.                         // 得到64位PEB进程环境块
  313.                         PPEB Peb = PsGetProcessPeb(EProcess);
  314.                         if (!Peb)
  315.                                 return NULL;
  316.                         if (!Peb->Ldr)
  317.                                 return NULL;
  318.                         // 开始遍历模块
  319.                         for (PLIST_ENTRY ListEntry = Peb->Ldr->InLoadOrderModuleList.Flink;
  320.                                 ListEntry != &Peb->Ldr->InLoadOrderModuleList;
  321.                                 ListEntry = ListEntry->Flink)
  322.                         {
  323.                                 // 得到表头
  324.                                 PLDR_DATA_TABLE_ENTRY LdrDataTableEntry = CONTAINING_RECORD(ListEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
  325.                                 // 判断是否是所需要的模块
  326.                                 if (RtlCompareUnicodeString(&LdrDataTableEntry->BaseDllName, ModuleName, TRUE) == 0)
  327.                                         return LdrDataTableEntry->DllBase;
  328.                         }
  329.                 }
  330.         }
  331.         __except (EXCEPTION_EXECUTE_HANDLER){}
  332.         return NULL;
  333. }
  334. // 根据函数名得到导出表地址
  335. PVOID GetModuleExport(IN PVOID ModuleBase, IN PCCHAR FunctionName)
  336. {
  337.         PIMAGE_DOS_HEADER ImageDosHeader = (PIMAGE_DOS_HEADER)ModuleBase;
  338.         PIMAGE_NT_HEADERS32 ImageNtHeaders32 = NULL;
  339.         PIMAGE_NT_HEADERS64 ImageNtHeaders64 = NULL;
  340.         PIMAGE_EXPORT_DIRECTORY ImageExportDirectory = NULL;
  341.         ULONG ExportDirectorySize = 0;
  342.         ULONG_PTR FunctionAddress = 0;
  343.         if (ModuleBase == NULL)
  344.                 return NULL;
  345.         __try
  346.         {
  347.                 // 判断是否是DOS头
  348.                 if (ImageDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
  349.                 {
  350.                         return NULL;
  351.                 }
  352.                 // 获取PE结构节NT头
  353.                 ImageNtHeaders32 = (PIMAGE_NT_HEADERS32)((PUCHAR)ModuleBase + ImageDosHeader->e_lfanew);
  354.                 ImageNtHeaders64 = (PIMAGE_NT_HEADERS64)((PUCHAR)ModuleBase + ImageDosHeader->e_lfanew);
  355.                 // 判断是否是64位
  356.                 if (ImageNtHeaders64->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
  357.                 {
  358.                         // 如果是64位则执行如下
  359.                         ImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(ImageNtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + (ULONG_PTR)ModuleBase);
  360.                         ExportDirectorySize = ImageNtHeaders64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
  361.                 }
  362.                 else
  363.                 {
  364.                         // 如果32位则执行如下
  365.                         ImageExportDirectory = (PIMAGE_EXPORT_DIRECTORY)(ImageNtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress + (ULONG_PTR)ModuleBase);
  366.                         ExportDirectorySize = ImageNtHeaders32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
  367.                 }
  368.                 // 取出导出表Index,名字,函地址等
  369.                 PUSHORT pAddressOfOrds = (PUSHORT)(ImageExportDirectory->AddressOfNameOrdinals + (ULONG_PTR)ModuleBase);
  370.                 PULONG  pAddressOfNames = (PULONG)(ImageExportDirectory->AddressOfNames + (ULONG_PTR)ModuleBase);
  371.                 PULONG  pAddressOfFuncs = (PULONG)(ImageExportDirectory->AddressOfFunctions + (ULONG_PTR)ModuleBase);
  372.                 // 循环导出表
  373.                 for (ULONG i = 0; i < ImageExportDirectory->NumberOfFunctions; ++i)
  374.                 {
  375.                         USHORT OrdIndex = 0xFFFF;
  376.                         PCHAR  pName = NULL;
  377.                         // 说明是序号导出
  378.                         if ((ULONG_PTR)FunctionName <= 0xFFFF)
  379.                         {
  380.                                 // 得到函数序号
  381.                                 OrdIndex = (USHORT)i;
  382.                         }
  383.                         // 说明是名字导出
  384.                         else if ((ULONG_PTR)FunctionName > 0xFFFF && i < ImageExportDirectory->NumberOfNames)
  385.                         {
  386.                                 // 得到函数名
  387.                                 pName = (PCHAR)(pAddressOfNames[i] + (ULONG_PTR)ModuleBase);
  388.                                 OrdIndex = pAddressOfOrds[i];
  389.                         }
  390.                         else
  391.                                 return NULL;
  392.                         // 判断函数名是否符合
  393.                         if (((ULONG_PTR)FunctionName <= 0xFFFF && (USHORT)((ULONG_PTR)FunctionName) == OrdIndex + ImageExportDirectory->Base) ||
  394.                                 ((ULONG_PTR)FunctionName > 0xFFFF && strcmp(pName, FunctionName) == 0))
  395.                         {
  396.                                 // 得到完整地址
  397.                                 FunctionAddress = pAddressOfFuncs[OrdIndex] + (ULONG_PTR)ModuleBase;
  398.                                 break;
  399.                         }
  400.                 }
  401.         }
  402.         __except (EXCEPTION_EXECUTE_HANDLER){}
  403.         return (PVOID)FunctionAddress;
  404. }
  405. // DLL模块注入线程函数
  406. NTSTATUS KernelInjectDLL(ULONG pid, PUNICODE_STRING DllFullPath, PINJECT_BUFFER* allcateAddress)
  407. {
  408.         PEPROCESS pEprocess = NULL;
  409.         // 根据PID得到进程Eprocess结构
  410.         if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)pid, &pEprocess)))
  411.         {
  412.                 KAPC_STATE kApc = { 0 };
  413.                 // 附加到进程内
  414.                 KeStackAttachProcess(pEprocess, &kApc);
  415.                 // 得到Ntdll.dll模块基址
  416.                 UNICODE_STRING ntdllString = RTL_CONSTANT_STRING(L"Ntdll.dll");
  417.                 PVOID NtdllAddress = GetUserModule(pEprocess, &ntdllString, g_PsGetProcessWow64Process(pEprocess) != 0);
  418.                 if (!NtdllAddress)
  419.                 {
  420.                         // 失败了则直接脱离附加
  421.                         KeUnstackDetachProcess(&kApc);
  422.                         ObDereferenceObject(pEprocess);
  423.                         return STATUS_UNSUCCESSFUL;
  424.                 }
  425.                 // 得到LdrLoadDLL模块的基址
  426.                 PVOID LdrLoadDll = GetModuleExport(NtdllAddress, "LdrLoadDll");
  427.                 if (!LdrLoadDll)
  428.                 {
  429.                         KeUnstackDetachProcess(&kApc);
  430.                         ObDereferenceObject(pEprocess);
  431.                         return STATUS_UNSUCCESSFUL;
  432.                 }
  433.                 HANDLE threadHandle = NULL;
  434.                 // 得到当前正在运行的线程上下文
  435.                 if (NT_SUCCESS(g_ZwGetNextThread((HANDLE)-1, (HANDLE)0, 0x1FFFFF, 0x240, 0, &threadHandle)))
  436.                 {
  437.                         PVOID threadObj = NULL;
  438.                         // 在对象句柄上提供访问验证,如果可以授予访问权限,则返回指向对象的正文的相应指针。
  439.                         NTSTATUS state = ObReferenceObjectByHandle(threadHandle, 0x1FFFFF, *PsThreadType, KernelMode, &threadObj, NULL);
  440.                         if (NT_SUCCESS(state))
  441.                         {
  442.                                 // 暂停线程
  443.                                 g_PsSuspendThread(threadObj, NULL);
  444.                                 // 设置线程ShellCode代码
  445.                                 SetThreadStartAddress(threadObj, g_PsGetProcessWow64Process(pEprocess) != 0, LdrLoadDll, DllFullPath, allcateAddress);
  446.                                 // 恢复线程
  447.                                 g_PsResumeThread(threadObj, NULL);
  448.                                 ObDereferenceObject(threadObj);
  449.                         }
  450.                         NtClose(threadHandle);
  451.                 }
  452.                 // 关闭线程
  453.                 KeUnstackDetachProcess(&kApc);
  454.                 ObDereferenceObject(pEprocess);
  455.         }
  456.         return STATUS_SUCCESS;
  457. }
  458. NTSTATUS UnDriver(PDRIVER_OBJECT driver)
  459. {
  460.         UNREFERENCED_PARAMETER(driver);
  461.         return STATUS_SUCCESS;
  462. }
  463. NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
  464. {
  465.         DbgPrint("Hello LyShark.com \n");
  466.         UNREFERENCED_PARAMETER(RegistryPath);
  467.         // -----------------------------------------------------------------------
  468.         // 初始化
  469.         // -----------------------------------------------------------------------
  470.         UCHAR SuspendOpCode[] = { 0x48, 0x8b, 0xf9, 0x83, 0x64, 0x24, 0x20, 0x00, 0x65, 0x48, 0x8b, 0x34, 0x25, 0x88, 0x01 };
  471.         UCHAR ResumeOpCode[] = { 0x48, 0x8b, 0xf9, 0xe8, 0xee, 0x4f, 0xa5, 0xff, 0x65, 0x48, 0x8b, 0x14, 0x25, 0x88 };
  472.         // 特征码检索PsSuspendThread函数基址
  473.         g_PsSuspendThread = (PPsSuspendThread)SearchOPcode(Driver, L"ntoskrnl.exe", "PAGE", SuspendOpCode, sizeof(SuspendOpCode), -24);
  474.         DbgPrint("PsSuspendThread = %p \n", g_PsSuspendThread);
  475.         // 特征码检索PsResumeThread基址
  476.         g_PsResumeThread = (PPsResumeThread)SearchOPcode(Driver, L"ntoskrnl.exe", "PAGE", ResumeOpCode, sizeof(ResumeOpCode), -18);
  477.         DbgPrint("PsResumeThread = %p \n", g_PsResumeThread);
  478.         // 动态获取内存中的ZwGetNextThread基址
  479.         UNICODE_STRING ZwGetNextThreadString = RTL_CONSTANT_STRING(L"ZwGetNextThread");
  480.         g_ZwGetNextThread = (PZwGetNextThread)MmGetSystemRoutineAddress(&ZwGetNextThreadString);
  481.         DbgPrint("ZwGetNextThread = %p \n", g_ZwGetNextThread);
  482.         // 动态获取内存中的PsGetThreadTeb基址
  483.         UNICODE_STRING PsGetThreadTebString = RTL_CONSTANT_STRING(L"PsGetThreadTeb");
  484.         g_PsGetThreadTeb = (PPsGetThreadTeb)MmGetSystemRoutineAddress(&PsGetThreadTebString);
  485.         DbgPrint("PsGetThreadTeb = %p \n", g_PsGetThreadTeb);
  486.         // 动态获取内存中的PsGetProcessWow64Process基址
  487.         UNICODE_STRING PsGetProcessWow64ProcessString = RTL_CONSTANT_STRING(L"PsGetProcessWow64Process");
  488.         g_PsGetProcessWow64Process = (PPsGetProcessWow64Process)MmGetSystemRoutineAddress(&PsGetProcessWow64ProcessString);
  489.         DbgPrint("PsGetProcessWow64Process = %p \n", g_PsGetProcessWow64Process);
  490.         // -----------------------------------------------------------------------
  491.         // 注入代码
  492.         // -----------------------------------------------------------------------
  493.         ULONG ProcessID = 984;
  494.         UNICODE_STRING InjectDllPath = RTL_CONSTANT_STRING(L"C:\\Users\\lyshark\\Desktop\\hook.dll");
  495.         PINJECT_BUFFER AllcateAddress = NULL;
  496.         // 执行线程注入
  497.         NTSTATUS Status = KernelInjectDLL(ProcessID, &InjectDllPath, &AllcateAddress);
  498.         if (Status == STATUS_SUCCESS)
  499.         {
  500.                 DbgPrint("[*] 线程注入PID = %d | DLL = %wZ \n", ProcessID, InjectDllPath);
  501.         }
  502.         Driver->DriverUnload = UnDriver;
  503.         return STATUS_SUCCESS;
  504. }
复制代码
首先你需要自行准备好一个DLL文件,此处我的是hook.dll将文件放入到桌面,然后设置ProcessID指定进程ID,设置InjectDllPath指定DLL路径,签名后将驱动加载起来,此时你会看到WinDBG中的输出,且应用层的进程也会弹出hello lyshark的消息,说明注入成功了,如下图所示;


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

本帖子中包含更多资源

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

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

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

本版积分规则

九天猎人

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

标签云

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