OpenProcess获取目标进程句柄;VirtualAllocEx在目标进程内申请一块可读可写内存;WriteProcessMemory将loadlibraryA的参数,也就是待注入DLL的路径,写入刚申请的内存;CreateRemoteThread对目标进程创建远程线程,线程指向LoadLibraryA函数,参数便是刚写入申请内存的DLL路径;#include <iostream>
#include<Windows.h>
using namespace std;
//目标进程ID,动态链接库的路径
BOOL inject(DWORD dwProcessId, const WCHAR \* szFilePath) {
//进程全部的权限,句柄继承(通常为FALSE),目标进程ID
HANDLE hProcess = OpenProcess(PROCESS\_ALL\_ACCESS, FALSE, dwProcessId);//返回的是进程句柄
//目标进程句柄,需要开辟的地址(NULL为操作系统分配),需要分配地址的大小,现在操作的类型,提供可读可写的属性
LPVOID lpAddress = VirtualAllocEx(hProcess, NULL, 0x100, MEM\_COMMIT | MEM\_RESERVE, PAGE\_READWRITE);
//目标进程句柄,写到什么位置的地址,需要写的内容,需要写的长度,写入的宽度(用地址的形式传值)
SIZE\_T dwRet = 0;
BOOL bRet = WriteProcessMemory(hProcess, lpAddress, szFilePath, ((wcslen(szFilePath) + 1) \* 2), &dwRet);
//判断是否写入失败
if (!bRet) {
return FALSE;
}
//目标进程句柄,安全特性(通常为NULL),栈的尺寸(可以为NULL),该线程函数启动地址(强制转换类型为LPTHREAD\_START\_ROUTINE,可用LoadLibraryW加载),需要提供的参数(此处为需要写入的地址),标志(可以为NULL),线程ID(可以为NULL)
HANDLE hThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD\_START\_ROUTINE)LoadLibraryW, lpAddress, NULL, NULL);
//-1代表一直等
WaitForSingleObject(hThread, -1);
VirtualFreeEx(hProcess, lpAddress, ((wcslen(szFilePath) + 1) \* 2), MEM\_RELEASE);
CloseHandle(hThread);
CloseHandle(hProcess);
}
int main()
{
getchar();
inject(16444, L"C:\\Users\\demo\\Desktop\\Dll1.dll");
system("pause");
return 0;
}LoadLibraryA函数,但是这个函数又是在KERNEL32.DLL模块中的,所以第一步我们需要获取模块的函数地址,在内核中我们通过遍历EPROCESS--->Peb--->Ldr-->InLoadOrderModuleList--->BaseDllName DllBase,如果BaseDllName等于KERNEL32.DLL的话就返回对应的DllBase,也就是KERNEL32.DLL模块在内存中的地址,实现代码如下://hPid传入一个64位进程,且进程中加载了KERNEL32.DLL
//unModule传入模块名,这里我们传KERNEL32.DLL
//pSize传入一个记录模块大小变量的指针
ULONG64 GetProcessModule(HANDLE hPid, UNICODE\_STRING unModule,PULONG pSize)
{
PEPROCESS pEprocess = NULL;
NTSTATUS st = STATUS\_SUCCESS;
PPEB pPeb = ExAllocatePool(NonPagedPool,sizeof(pEprocess));
PPEB\_LDR\_DATA pPebLdr = NULL;
PLDR\_DATA\_TABLE\_ENTRY pFirLdrForPebLdr = NULL;
PLDR\_DATA\_TABLE\_ENTRY pDataLdr = NULL;
PLDR\_DATA\_TABLE\_ENTRY pDataLdrTmp = NULL;
KAPC\_STATE kApc;
ULONG64 uRetAddr = 0;
st = PsLookupProcessByProcessId(hPid, &pEprocess);
if (!NT\_SUCCESS(st))
{
ObDereferenceObject(pEprocess);
return;
}
pPeb = PsGetProcessPeb(pEprocess);
KeStackAttachProcess(pEprocess, &kApc);
if (pPeb)
{
if (MmIsAddressValid(&(pPeb->Ldr)))
{
pPebLdr = pPeb->Ldr;
pFirLdrForPebLdr = pPebLdr->InLoadOrderModuleList.Blink;
pDataLdr = pFirLdrForPebLdr->InLoadOrderLinks.Flink;
pDataLdrTmp = pDataLdr;
do
{
DbgPrintEx(77, 0, "[db]%wZ,地址:%llx\n", pDataLdrTmp->BaseDllName, pDataLdrTmp->DllBase);
if (RtlEqualUnicodeString(&(pDataLdrTmp->BaseDllName), &unModule,FALSE))
{
\*pSize = pDataLdrTmp->SizeOfImage;
uRetAddr = (ULONG64)pDataLdrTmp->DllBase;
break;
}
pDataLdrTmp = pDataLdrTmp->InLoadOrderLinks.Flink;
} while (pDataLdrTmp!= pDataLdr);
}
}
KeUnstackDetachProcess(&kApc);
return uRetAddr;
}KERNEL32.DLL的模块地址,那么我们接下来就是需要再去拿一下LoadLibraryA的函数地址,这里我们采用特征码搜索,我们把KERNEL32.DLL拖入IDA Pro解析完符号后定位到LoadLibraryA函数或者附近看看有没有特征性比较强的字节段,有点话就可以直接使用特征码搜索便可以找到LoadLibraryA的函数地址了,以下是IDA Pro解析LoadLibraryA函数字节段的内容:.text:0000000180020C32 loc\_180020C32:
.text:0000000180020C32 85 C0 test eax, eax
.text:0000000180020C34 0F 95 C1 setnz cl
.text:0000000180020C37 33 C0 xor eax, eax
.text:0000000180020C39 41 89 09 mov [r9], ecx
.text:0000000180020C3C C3 retn
.text:0000000180020C3C
.text:0000000180020C3C sub\_180020C20 endp
.text:0000000180020C3C
.text:0000000180020C3C ;
.text:0000000180020C3D CC CC CC CC CC CC CC CC CC CC+db 13h dup(0CCh)
.text:0000000180020C50 ; Exported entry 969. LoadLibraryA
.text:0000000180020C50
.text:0000000180020C50 ; =============== S U B R O U T I N E ===================
.text:0000000180020C50
.text:0000000180020C50 ; Attributes: thunk
.text:0000000180020C50
.text:0000000180020C50 ; HMODULE \_\_stdcall LoadLibraryA(LPCSTR lpLibFileName)
.text:0000000180020C50 public LoadLibraryA
.text:0000000180020C50 LoadLibraryA proc near
.text:0000000180020C50
.text:0000000180020C50
.text:0000000180020C50 48 FF 25 19 19 06 00 jmp cs:LoadLibraryA\_0 0000000180020C32处有一段固定的字节码,而0000000180020C50便是我们LoadLibraryA函数的地址,所以我们只要找到0000000180020C32处的字节码位置便可轻易地通过偏移+0x1e得到LoadLibraryA函数的地址,此处用到了特征码搜索,使用方法我以前的帖子说过,这里就不再赘述,代码如下:PVOID SearchSpecialCode(PVOID pSearchBeginAddr, ULONG ulSearchLength, PUCHAR pSpecialCode, ULONG ulSpecialCodeLength)
{
PVOID pDestAddr = NULL;
PUCHAR pBeginAddr = (PUCHAR)pSearchBeginAddr;
PUCHAR pEndAddr = pBeginAddr + ulSearchLength;
PUCHAR i = NULL;
ULONG j = 0;
for (i = pBeginAddr; i <= pEndAddr; i++)
{
// 遍历特征码
for (j = 0; j < ulSpecialCodeLength; j++)
{
// 判断地址是否有效
if (FALSE == MmIsAddressValid((PVOID)(i + j)))
{
break;
}
// 匹配特征码
if (\*(PUCHAR)(i + j) != pSpecialCode[j])
{
break;
}
}
// 匹配成功
if (j >= ulSpecialCodeLength)
{
pDestAddr = (PVOID)i;
break;
}
}
return pDestAddr;
}LoadLibraryA函数地址查找代码如下:unsigned char loadliboffsetcode[] =
{
0x85, 0xC0, 0x0F, 0x95, 0xC1, 0x33, 0xC0, 0x41, 0x89, 0x09,
0xC3
};
pLoadLibAddr = SearchSpecialCode(pKernel32ModulAddr, uKernel32ModulSize, loadliboffsetcode, 11);
pLoadLibAddr = (PUCHAR)pLoadLibAddr + 0x1e;LoadLibraryA函数地址了,接下来就是在目标进程内申请一段可读可写的虚拟内存了,内核中是由对应函数可以实现申请虚拟内存的NTSYSAPI
NTSTATUS
NTAPI
ZwAllocateVirtualMemory (
\_\_in HANDLE ProcessHandle,
\_\_inout PVOID \*BaseAddress,
\_\_in ULONG\_PTR ZeroBits,
\_\_inout PSIZE\_T RegionSize,
\_\_in ULONG AllocationType,
\_\_in ULONG Protect
);NTSYSAPI
NTSTATUS
NTAPI
ZwFreeVirtualMemory (
\_\_in HANDLE ProcessHandle,
\_\_inout PVOID \*BaseAddress,
\_\_inout PSIZE\_T RegionSize,
\_\_in ULONG FreeType
);PsLookupProcessByProcessId函数获取进程EPROCESS结构,再通过ObOpenObjectByPointer获取进程句柄,第二个参数填入申请得到的内存地址的二级指针,第三个参数NULL,第四个参数填入你要申请内存的大小的指针,第五个参数填入MEM\_COMMIT(提交内存),第六个参数填入你想要申请的内存保护类型,填入PAGE\_READWRITE就行,代码如下:st = ZwAllocateVirtualMemory(hProcess,
&pVirsualAddr,
0,
®ionSize,
MEM\_COMMIT,
PAGE\_READWRITE);KeStackAttachProcess 附加上目标进程后使用 RtlCopyMemory把DLL路径拷贝进去就行了,代码如下:KeStackAttachProcess(pTargetProcess, &kapcstate);
RtlZeroMemory(pVirsualAddr, regionSize);
RtlCopyMemory(pVirsualAddr, path,strlen(path));CreateRemoteThread函数,所以我们需要用一个系统函数NtCreateThreadEx函数,但是这个函数是未公开的,所以我们需要通过特征码去定位这个函数地址,和第二步的方法差不多,这里我直接给出NtCreateThreadEx函数原型和查找函数地址代码:typedef NTSTATUS (\*ZwCreateThreadEx)(
PHANDLE ThreadHandle,
ACCESS\_MASK DesiredAccess,
POBJECT\_ATTRIBUTES ObjectAttributes,
HANDLE ProcessHandle,
PVOID StartRoutine,
PVOID StartContext,
ULONG CreateThreadFlags,
SIZE\_T ZeroBits,
SIZE\_T StackSize,
SIZE\_T MaximumStackSize,
PPS\_ATTRIBUTE\_LIST AttributeList
);unsigned char ZwCreateThreadCode[] =
{
0x40,0x55,0x53,0x56,0x57,0x41,0x54,0x41,0x55,0x41,0x56,0x41,0x57,
0x48,0x81,0xec,0x28,0x03,0x00,0x00
};ntoskrnl.exe中,所以我们这里需要通过遍历系统模块列表对比去拿到该模块的地址和大小,代码如下:ULONG\_PTR GetKernelModuleBase(PUCHAR moduleName, PULONG pModuleSize) {
RTL\_PROCESS\_MODULES SysModules = { 0 };
PRTL\_PROCESS\_MODULES pModules = &SysModules;
ULONG SystemInformationLength = 0;
//查询系统中所有内核模块,底层也是遍历链表
NTSTATUS status = ZwQuerySystemInformation(SystemModuleInformation, pModules, sizeof(RTL\_PROCESS\_MODULES), &SystemInformationLength);
if (status == STATUS\_INFO\_LENGTH\_MISMATCH) {
pModules = ExAllocatePool(NonPagedPool, SystemInformationLength + sizeof(RTL\_PROCESS\_MODULES));
RtlZeroMemory(pModules, SystemInformationLength + sizeof(RTL\_PROCESS\_MODULES));
status = ZwQuerySystemInformation(SystemModuleInformation, pModules, SystemInformationLength + sizeof(RTL\_PROCESS\_MODULES), &SystemInformationLength);
if (!NT\_SUCCESS(status)) {
ExFreePool(pModules);
return 0;
}
}
if (!strcmp("ntoskrnl.exe", moduleName) || !strcmp("ntkrnlpa.exe", moduleName)) {
\*pModuleSize = pModules->Modules[0].ImageSize;
ULONG\_PTR ret = pModules->Modules[0].ImageBase;
if (SystemInformationLength) {
ExFreePool(pModules);
}
return ret;
}
for (ULONG i = 0; i < pModules->NumberOfModules; i++) {
if (strstr(pModules->Modules[i].FullPathName, moduleName)) {
\*pModuleSize = pModules->Modules[i].ImageSize;
ULONG\_PTR ret = pModules->Modules[i].ImageBase;
if (SystemInformationLength) {
ExFreePool(pModules);
}
//返回模块地址
return ret;
}
}
if (SystemInformationLength) {
ExFreePool(pModules);
}
return 0;
}pZwCreatThraedFuncAddr = SearchSpecialCode(pNtoskrnlModulAddr, uNtoskrnlModulSize, ZwCreateThreadCode, 17);
if (pZwCreatThraedFuncAddr)
{
DbgPrintEx(77, 0, "[db]pZwCreatThraedFuncAddr:%llx\n", pZwCreatThraedFuncAddr);
}mycreate = pZwCreatThraedFuncAddr;
st = mycreate(&hThread, THREAD\_ALL\_ACCESS, NULL, hProcess,pLoadLibAddr, pVirsualAddr,0x2, 0, 0, 0, NULL);
DbgPrintEx(77, 0, "[db]创建线程状态st:%d\n", st);NtResumeThread去恢复线程执行,其NtResumeThread也是未公开的,我们也需要特征码去搜索,当然如果你想线程创建后就执行的话CreateFlag填0就行了,不需要使用NtResumeThread了,NtResumeThread的函数原型以及函数地址搜索代码如下:typedef NTSTATUS
(\*NtResumeThread)(
\_\_in HANDLE ThreadHandle,
\_\_out\_opt PULONG PreviousSuspendCount
);pNtResumeThreadFuncAddr = SearchSpecialCode(pNtoskrnlModulAddr, uNtoskrnlModulSize, NtResumeThreadcode, 14);
if (pNtResumeThreadFuncAddr)
{
DbgPrintEx(77, 0, "[db]pNtResumeThreadFuncAddr:%llx\n", pNtResumeThreadFuncAddr);
}//tool.h
#pragma once
#include <ntifs.h>
#include <string.h>
#include <ntimage.h>
typedef struct \_INITIAL\_TEB {
struct {
PVOID OldStackBase;
PVOID OldStackLimit;
} OldInitialTeb;
PVOID StackBase;
PVOID StackLimit;
PVOID StackAllocationBase;
} INITIAL\_TEB, \* PINITIAL\_TEB;
typedef struct \_RTL\_PROCESS\_MODULE\_INFORMATION {
HANDLE Section; // Not filled in
PVOID MappedBase;
PVOID ImageBase;
ULONG ImageSize;
ULONG Flags;
USHORT LoadOrderIndex;
USHORT InitOrderIndex;
USHORT LoadCount;
USHORT OffsetToFileName;
UCHAR FullPathName[256];
} RTL\_PROCESS\_MODULE\_INFORMATION, \* PRTL\_PROCESS\_MODULE\_INFORMATION;
typedef struct \_RTL\_PROCESS\_MODULES {
ULONG NumberOfModules;
RTL\_PROCESS\_MODULE\_INFORMATION Modules[1];
} RTL\_PROCESS\_MODULES, \* PRTL\_PROCESS\_MODULES;
//0x58 bytes (sizeof)
typedef struct \_PEB\_LDR\_DATA
{
ULONG Length; //0x0
UCHAR Initialized; //0x4
PVOID SsHandle; //0x8
LIST\_ENTRY InLoadOrderModuleList; //0x10
LIST\_ENTRY InMemoryOrderModuleList; //0x20
LIST\_ENTRY InInitializationOrderModuleList; //0x30
PVOID EntryInProgress; //0x40
UCHAR ShutdownInProgress; //0x48
PVOID ShutdownThreadId; //0x50
}PEB\_LDR\_DATA, \* PPEB\_LDR\_DATA;
//0x7c8 bytes (sizeof)
typedef struct \_PEB
{
UCHAR InheritedAddressSpace; //0x0
UCHAR ReadImageFileExecOptions; //0x1
UCHAR BeingDebugged; //0x2
union
{
UCHAR BitField; //0x3
struct
{
UCHAR ImageUsesLargePages : 1; //0x3
UCHAR IsProtectedProcess : 1; //0x3
UCHAR IsImageDynamicallyRelocated : 1; //0x3
UCHAR SkipPatchingUser32Forwarders : 1; //0x3
UCHAR IsPackagedProcess : 1; //0x3
UCHAR IsAppContainer : 1; //0x3
UCHAR IsProtectedProcessLight : 1; //0x3
UCHAR IsLongPathAwareProcess : 1; //0x3
};
};
UCHAR Padding0[4]; //0x4
PVOID Mutant; //0x8
PVOID ImageBaseAddress; //0x10
PEB\_LDR\_DATA\* Ldr; //0x18 //0xc //0x18
}PEB,\*PPEB;
//0x120 bytes (sizeof)
typedef struct \_LDR\_DATA\_TABLE\_ENTRY
{
LIST\_ENTRY InLoadOrderLinks; //0x0
LIST\_ENTRY InMemoryOrderLinks; //0x10
LIST\_ENTRY InInitializationOrderLinks; //0x20
PVOID DllBase; //0x30
PVOID EntryPoint; //0x38
ULONG SizeOfImage; //0x40
UNICODE\_STRING FullDllName; //0x48
UNICODE\_STRING BaseDllName; //0x58 //0x11c
}LDR\_DATA\_TABLE\_ENTRY,\*PLDR\_DATA\_TABLE\_ENTRY;
typedef struct \_PS\_ATTRIBUTE {
ULONG\_PTR Attribute;
SIZE\_T Size;
union {
ULONG\_PTR Value;
PVOID ValuePtr;
} u1;
PSIZE\_T ReturnLength;
} PS\_ATTRIBUTE, \* PPS\_ATTRIBUTE;
typedef struct \_PS\_ATTRIBUTE\_LIST {
SIZE\_T TotalLength;
PS\_ATTRIBUTE Attributes[1];
} PS\_ATTRIBUTE\_LIST, \* PPS\_ATTRIBUTE\_LIST;
PVOID SearchSpecialCode(PVOID pSearchBeginAddr, ULONG ulSearchLength, PUCHAR pSpecialCode, ULONG ulSpecialCodeLength);
NTSYSAPI
NTSTATUS
NTAPI ZwQuerySystemInformation(
IN ULONG SystemInformationClass,
IN OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength
);
typedef NTSTATUS (\*ZwCreateThreadEx)(
PHANDLE ThreadHandle,
ACCESS\_MASK DesiredAccess,
POBJECT\_ATTRIBUTES ObjectAttributes,
HANDLE ProcessHandle,
PVOID StartRoutine,
PVOID StartContext,
ULONG CreateThreadFlags,
SIZE\_T ZeroBits,
SIZE\_T StackSize,
SIZE\_T MaximumStackSize,
PPS\_ATTRIBUTE\_LIST AttributeList
);
typedef NTSTATUS
(\*NtResumeThread)(
\_\_in HANDLE ThreadHandle,
\_\_out\_opt PULONG PreviousSuspendCount
);
EXTERN\_C
PPEB
PsGetProcessPeb(
\_\_in PEPROCESS Process
);
typedef enum \_SYSTEM\_INFORMATION\_CLASS {
SystemBasicInformation,
SystemProcessorInformation, // obsolete...delete
SystemPerformanceInformation,
SystemTimeOfDayInformation,
SystemPathInformation,
SystemProcessInformation,
SystemCallCountInformation,
SystemDeviceInformation,
SystemProcessorPerformanceInformation,
SystemFlagsInformation,
SystemCallTimeInformation,
SystemModuleInformation,
SystemLocksInformation,
SystemStackTraceInformation,
SystemPagedPoolInformation,
SystemNonPagedPoolInformation,
SystemHandleInformation,
SystemObjectInformation,
SystemPageFileInformation,
SystemVdmInstemulInformation,
SystemVdmBopInformation,
SystemFileCacheInformation,
SystemPoolTagInformation,
SystemInterruptInformation,
SystemDpcBehaviorInformation,
SystemFullMemoryInformation,
SystemLoadGdiDriverInformation,
SystemUnloadGdiDriverInformation,
SystemTimeAdjustmentInformation,
SystemSummaryMemoryInformation,
SystemMirrorMemoryInformation,
SystemPerformanceTraceInformation,
SystemObsolete0,
SystemExceptionInformation,
SystemCrashDumpStateInformation,
SystemKernelDebuggerInformation,
SystemContextSwitchInformation,
SystemRegistryQuotaInformation,
SystemExtendServiceTableInformation,
SystemPrioritySeperation,
SystemVerifierAddDriverInformation,
SystemVerifierRemoveDriverInformation,
SystemProcessorIdleInformation,
SystemLegacyDriverInformation,
SystemCurrentTimeZoneInformation,
SystemLookasideInformation,
SystemTimeSlipNotification,
SystemSessionCreate,
SystemSessionDetach,
SystemSessionInformation,
SystemRangeStartInformation,
SystemVerifierInformation,
SystemVerifierThunkExtend,
SystemSessionProcessInformation,
SystemLoadGdiDriverInSystemSpace,
SystemNumaProcessorMap,
SystemPrefetcherInformation,
SystemExtendedProcessInformation,
SystemRecommendedSharedDataAlignment,
SystemComPlusPackage,
SystemNumaAvailableMemory,
SystemProcessorPowerInformation,
SystemEmulationBasicInformation,
SystemEmulationProcessorInformation,
SystemExtendedHandleInformation,
SystemLostDelayedWriteInformation,
SystemBigPoolInformation,
SystemSessionPoolTagInformation,
SystemSessionMappedViewInformation,
SystemHotpatchInformation,
SystemObjectSecurityMode,
SystemWatchdogTimerHandler,
SystemWatchdogTimerInformation,
SystemLogicalProcessorInformation,
SystemWow64SharedInformation,
SystemRegisterFirmwareTableInformationHandler,
SystemFirmwareTableInformation,
SystemModuleInformationEx,
SystemVerifierTriageInformation,
SystemSuperfetchInformation,
SystemMemoryListInformation,
SystemFileCacheInformationEx,
MaxSystemInfoClass // MaxSystemInfoClass should always be the last enum
} SYSTEM\_INFORMATION\_CLASS;
BOOLEAN MDLWriteMemory(PVOID pBaseAddress, PVOID pWriteData, SIZE\_T writeDataSize);
ULONG\_PTR GetKernelModuleBase(PUCHAR moduleName, PULONG pModuleSize);
ULONG64 GetProcessModule(HANDLE hPid,UNICODE\_STRING unModule, PULONG pSize);
NTSTATUS InsertDll(HANDLE hPid, char\* path);//tool.c
#include "tool.h"
BOOLEAN MDLWriteMemory(PVOID pBaseAddress, PVOID pWriteData, SIZE\_T writeDataSize)
{
PMDL pMdl = NULL;
PVOID pNewAddress = NULL;
// 创建 MDL
pMdl = MmCreateMdl(NULL, pBaseAddress, writeDataSize);
if (NULL == pMdl)
{
return FALSE;
}
// 更新 MDL 对物理内存的描述
MmBuildMdlForNonPagedPool(pMdl);
// 映射到虚拟内存中
pNewAddress = MmMapLockedPages(pMdl, KernelMode);
if (NULL == pNewAddress)
{
IoFreeMdl(pMdl);
}
// 写入数据
RtlCopyMemory(pNewAddress, pWriteData, writeDataSize);
// 释放
MmUnmapLockedPages(pNewAddress, pMdl);
IoFreeMdl(pMdl);
return TRUE;
}
ULONG\_PTR GetKernelModuleBase(PUCHAR moduleName, PULONG pModuleSize) {
RTL\_PROCESS\_MODULES SysModules = { 0 };
PRTL\_PROCESS\_MODULES pModules = &SysModules;
ULONG SystemInformationLength = 0;
//查询系统中所有内核模块,底层也是遍历链表
NTSTATUS status = ZwQuerySystemInformation(SystemModuleInformation, pModules, sizeof(RTL\_PROCESS\_MODULES), &SystemInformationLength);
if (status == STATUS\_INFO\_LENGTH\_MISMATCH) {
pModules = ExAllocatePool(NonPagedPool, SystemInformationLength + sizeof(RTL\_PROCESS\_MODULES));
RtlZeroMemory(pModules, SystemInformationLength + sizeof(RTL\_PROCESS\_MODULES));
status = ZwQuerySystemInformation(SystemModuleInformation, pModules, SystemInformationLength + sizeof(RTL\_PROCESS\_MODULES), &SystemInformationLength);
if (!NT\_SUCCESS(status)) {
ExFreePool(pModules);
return 0;
}
}
if (!strcmp("ntoskrnl.exe", moduleName) || !strcmp("ntkrnlpa.exe", moduleName)) {
\*pModuleSize = pModules->Modules[0].ImageSize;
ULONG\_PTR ret = pModules->Modules[0].ImageBase;
if (SystemInformationLength) {
ExFreePool(pModules);
}
return ret;
}
for (ULONG i = 0; i < pModules->NumberOfModules; i++) {
if (strstr(pModules->Modules[i].FullPathName, moduleName)) {
\*pModuleSize = pModules->Modules[i].ImageSize;
ULONG\_PTR ret = pModules->Modules[i].ImageBase;
if (SystemInformationLength) {
ExFreePool(pModules);
}
//返回模块地址
return ret;
}
}
if (SystemInformationLength) {
ExFreePool(pModules);
}
return 0;
}
PVOID SearchSpecialCode(PVOID pSearchBeginAddr, ULONG ulSearchLength, PUCHAR pSpecialCode, ULONG ulSpecialCodeLength)
{
PVOID pDestAddr = NULL;
PUCHAR pBeginAddr = (PUCHAR)pSearchBeginAddr;
PUCHAR pEndAddr = pBeginAddr + ulSearchLength;
PUCHAR i = NULL;
ULONG j = 0;
for (i = pBeginAddr; i <= pEndAddr; i++)
{
// 遍历特征码
for (j = 0; j < ulSpecialCodeLength; j++)
{
// 判断地址是否有效
if (FALSE == MmIsAddressValid((PVOID)(i + j)))
{
break;
}
// 匹配特征码
if (\*(PUCHAR)(i + j) != pSpecialCode[j])
{
break;
}
}
// 匹配成功
if (j >= ulSpecialCodeLength)
{
pDestAddr = (PVOID)i;
break;
}
}
return pDestAddr;
}
ULONG64 GetProcessModule(HANDLE hPid, UNICODE\_STRING unModule,PULONG pSize)
{
PEPROCESS pEprocess = NULL;
NTSTATUS st = STATUS\_SUCCESS;
PPEB pPeb = ExAllocatePool(NonPagedPool,sizeof(pEprocess));
PPEB\_LDR\_DATA pPebLdr = NULL;
PLDR\_DATA\_TABLE\_ENTRY pFirLdrForPebLdr = NULL;
PLDR\_DATA\_TABLE\_ENTRY pDataLdr = NULL;
PLDR\_DATA\_TABLE\_ENTRY pDataLdrTmp = NULL;
KAPC\_STATE kApc;
ULONG64 uRetAddr = 0;
st = PsLookupProcessByProcessId(hPid, &pEprocess);
if (!NT\_SUCCESS(st))
{
ObDereferenceObject(pEprocess);
return;
}
pPeb = PsGetProcessPeb(pEprocess);
KeStackAttachProcess(pEprocess, &kApc);
if (pPeb)
{
if (MmIsAddressValid(&(pPeb->Ldr)))
{
pPebLdr = pPeb->Ldr;
pFirLdrForPebLdr = pPebLdr->InLoadOrderModuleList.Blink;
pDataLdr = pFirLdrForPebLdr->InLoadOrderLinks.Flink;
pDataLdrTmp = pDataLdr;
do
{
DbgPrintEx(77, 0, "[db]%wZ,地址:%llx\n", pDataLdrTmp->BaseDllName, pDataLdrTmp->DllBase);
if (RtlEqualUnicodeString(&(pDataLdrTmp->BaseDllName), &unModule,FALSE))
{
\*pSize = pDataLdrTmp->SizeOfImage;
uRetAddr = (ULONG64)pDataLdrTmp->DllBase;
break;
}
pDataLdrTmp = pDataLdrTmp->InLoadOrderLinks.Flink;
} while (pDataLdrTmp!= pDataLdr);
}
}
KeUnstackDetachProcess(&kApc);
return uRetAddr;
}
NTSTATUS InsertDll(HANDLE hPid, char\* path)
{
PEPROCESS pTargetProcess = NULL;
NTSTATUS st = STATUS\_SUCCESS;
KAPC\_STATE kapcstate;
HANDLE hProcess = 0;
HANDLE hThread = 0;
PVOID pNtoskrnlModulAddr = NULL;
ULONG uNtoskrnlModulSize = 0;
PVOID pKernel32ModulAddr = NULL;
ULONG uKernel32ModulSize = 0;
PVOID pZwCreatThraedFuncAddr = NULL;
PVOID pNtResumeThreadFuncAddr = NULL;
PVOID pLoadLibAddr = NULL;
PVOID pVirsualAddr = NULL;
SIZE\_T regionSize = 0x1000;
ULONG PreviousSuspendCount = 0;
ZwCreateThreadEx mycreate = NULL;
NtResumeThread myresume = NULL;
UNICODE\_STRING unKernel32Name = RTL\_CONSTANT\_STRING(L"KERNEL32.DLL");
st = PsLookupProcessByProcessId(hPid, &pTargetProcess);
if (!NT\_SUCCESS(st))
{
return st;
}
ObOpenObjectByPointer(pTargetProcess,
OBJ\_KERNEL\_HANDLE,
NULL,
PROCESS\_ALL\_ACCESS,
\*PsProcessType,
KernelMode,
&hProcess);
if (!NT\_SUCCESS(st))
{
return st;
}
KeStackAttachProcess(pTargetProcess, &kapcstate);
//NtCreateThread特征码
unsigned char ZwCreateThreadCode[] =
{
0x40,0x55,0x53,0x56,0x57,0x41,0x54,0x41,0x55,0x41,0x56,0x41,0x57,
0x48,0x81,0xec,0x28,0x03,0x00,0x00
};
//ResumeThreadcode特征码
unsigned char NtResumeThreadcode[] =
{
0x40,0x53,0x48,0x83,0xec,0x50,0x48,
0x8b,0xda,0x4c,0x8b,0xd1,0xc7,0x44
};
//LoadLibrary特征码偏移-0x1e
unsigned char loadliboffsetcode[] =
{
0x85, 0xC0, 0x0F, 0x95, 0xC1, 0x33, 0xC0, 0x41, 0x89, 0x09,
0xC3
};
//内核Ntoskrnl地址
pNtoskrnlModulAddr = GetKernelModuleBase("ntoskrnl.exe", &uNtoskrnlModulSize);
if (pNtoskrnlModulAddr)
{
DbgPrintEx(77, 0, "[db]pKernelModulAddr:%llx\n", pNtoskrnlModulAddr);
}
//kernel32.dll地址,为了拿LoadLibrary函数地址
pKernel32ModulAddr = GetProcessModule(hPid, unKernel32Name, &uKernel32ModulSize);
if (pKernel32ModulAddr)
{
DbgPrintEx(77, 0, "[db]pKernel32ModulAddr:%llx\n", pKernel32ModulAddr);
}
//NtCreateThreadEx函数地址
pZwCreatThraedFuncAddr = SearchSpecialCode(pNtoskrnlModulAddr, uNtoskrnlModulSize, ZwCreateThreadCode, 17);
if (pZwCreatThraedFuncAddr)
{
DbgPrintEx(77, 0, "[db]pZwCreatThraedFuncAddr:%llx\n", pZwCreatThraedFuncAddr);
}
//NtResumeThread函数地址
pNtResumeThreadFuncAddr = SearchSpecialCode(pNtoskrnlModulAddr, uNtoskrnlModulSize, NtResumeThreadcode, 14);
if (pNtResumeThreadFuncAddr)
{
DbgPrintEx(77, 0, "[db]pNtResumeThreadFuncAddr:%llx\n", pNtResumeThreadFuncAddr);
}
//LoadLibrary函数地址
pLoadLibAddr = SearchSpecialCode(pKernel32ModulAddr, uKernel32ModulSize, loadliboffsetcode, 11);
pLoadLibAddr = (PUCHAR)pLoadLibAddr + 0x1e;
if (pLoadLibAddr)
{
DbgPrintEx(77, 0, "[db]pLoadLibAddr:%llx\n", pLoadLibAddr);
}
// 使用ZwAllocateVirtualMemory函数在内核地址空间中分配虚拟内存
st = ZwAllocateVirtualMemory(hProcess,
&pVirsualAddr,
0,
®ionSize,
MEM\_COMMIT,
PAGE\_READWRITE);
if (!NT\_SUCCESS(st)) {
DbgPrintEx(77, 0, "[db]内存申请失败: st:%d\n", st);
return st;
}
DbgPrintEx(77, 0, "[db]内存申请成功,st:%d\n", st);
DbgPrintEx(77, 0, "[db]申请到的地址为:%llx\n", pVirsualAddr);
RtlZeroMemory(pVirsualAddr, regionSize);
RtlCopyMemory(pVirsualAddr, path,strlen(path));
//NtCreateThreadEx函数
mycreate = pZwCreatThraedFuncAddr;
//NtResumeThread函数
myresume = pNtResumeThreadFuncAddr;
//创建线程为挂起
st = mycreate(&hThread, THREAD\_ALL\_ACCESS, NULL, hProcess,pLoadLibAddr, pVirsualAddr,0x2, 0, 0, 0, NULL);
DbgPrintEx(77, 0, "[db]创建线程状态st:%d\n", st);
if (NT\_SUCCESS(st))
{
//让线程执行不挂起
st = myresume(hThread, &PreviousSuspendCount);
}
DbgPrintEx(77, 0, "[db]线程调用状态:st:%d\n", st);
st = ZwWaitForSingleObject(
, FALSE, NULL);
if (!NT\_SUCCESS(st))
{
DbgPrintEx(77, 0, "WaitForSingleObject st = %d\n", st);
}
// 使用ZwFreeVirtualMemory函数释放虚拟内存
st = ZwFreeVirtualMemory(hProcess,&pVirsualAddr,®ionSize,MEM\_RELEASE);
if (!NT\_SUCCESS(st)) {
DbgPrintEx(77, 0, "ZwFreeVirtualMemory st = %d\n", st);
}
KeUnstackDetachProcess(&kapcstate);
}//main.c
#include "tool.h"
VOID UnloadDriver(PDRIVER\_OBJECT pDriver)
{
}
NTSTATUS DriverEntry(PDRIVER\_OBJECT pDriver, PUNICODE\_STRING pRegPath)
{
//把C:\\demo.dll注入到进程id为2454的进程中
InsertDll(2464, "C:\\demo.dll");
pDriver->DriverUnload = UnloadDriver;
return STATUS\_SUCCESS;
}// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul\_reason\_for\_call,
LPVOID lpReserved
)
{
switch (ul\_reason\_for\_call)
{
case DLL\_PROCESS\_ATTACH:
{
MessageBoxA(NULL, NULL, NULL, NULL);
break;
}
case DLL\_THREAD\_ATTACH:
case DLL\_THREAD\_DETACH:
case DLL\_PROCESS\_DETACH:
return TRUE;
}
}原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。