#include "Memory.h"
//W7 x64的PTE基地址
#define PTE_BASE 0xFFFFF68000000000
typedef struct HardwarePteX64 {
ULONG64 valid : 1; //!< [0]
ULONG64 write : 1; //!< [1]
ULONG64 owner : 1; //!< [2]
ULONG64 write_through : 1; //!< [3]
ULONG64 cache_disable : 1; //!< [4]
ULONG64 accessed : 1; //!< [5]
ULONG64 dirty : 1; //!< [6]
ULONG64 large_page : 1; //!< [7]
ULONG64 global : 1; //!< [8]
ULONG64 copy_on_write : 1; //!< [9]
ULONG64 prototype : 1; //!< [10]
ULONG64 reserved0 : 1; //!< [11]
ULONG64 page_frame_number : 36; //!< [12:47]
ULONG64 reserved1 : 4; //!< [48:51]
ULONG64 software_ws_index : 11; //!< [52:62]
ULONG64 no_execute : 1; //!< [63]
}HardwarePte, * PHardwarePte;
ULONG64 GetPTEBase()
{
static ULONG64 pteBase = 0;
if (pteBase)
{
return pteBase;
}
//获取系统版本号
RTL_OSVERSIONINFOEXW version = { 0 };
RtlGetVersion(&version);
//Win7
if (version.dwBuildNumber==7600|| version.dwBuildNumber == 7601)
{
pteBase = PTE_BASE;
}
else if (version.dwBuildNumber>14393)
{
//W10 1607以上
//取函数地址
UNICODE_STRING unName = { 0 };
RtlInitUnicodeString(&unName, L"MmGetVirtualForPhysical");
PUCHAR func= (PUCHAR)MmGetSystemRoutineAddress(&unName);
//取rdx的PDE基址
pteBase=*(PULONG64)(func + 0x22);
}
else
{
pteBase = PTE_BASE;
}
}
ULONG64 GetPTEByVirtualAddress(ULONG64 VirtualAddress)
{
ULONG64 pteBase = GetPTEBase();
//这个是IDA里面的算法
ULONG64 Addr= ((VirtualAddress >> 9) & 0x7FFFFFFFF8) + pteBase;
//1.抹掉高12位 2.除以0x1000 求出在第几个分页 3.乘以8
//ULONG64 Addr2= (((VirtualAddress & 0xFFFFFFFFFFFF) >>12)<<3) + pteBase;
return Addr;
}
ULONG64 GetPDEByVirtualAddress(ULONG64 VirtualAddress)
{
//拿到PTE基地址
ULONG64 pteBase = GetPTEBase();
//拿到PTE
ULONG64 pte = GetPTEByVirtualAddress(VirtualAddress);
//返回PDT
ULONG64 Addr = ((pte >> 9) & 0x7FFFFFFFF8) + pteBase;
return Addr;
}
ULONG64 GetPPEByVirtualAddress(ULONG64 VirtualAddress)
{
//拿到PTE基地址
ULONG64 pteBase = GetPTEBase();
//拿到PDE
ULONG64 pde = GetPDEByVirtualAddress(VirtualAddress);
//返回PDT
ULONG64 Addr = ((pde >> 9) & 0x7FFFFFFFF8) + pteBase;
return Addr;
}
ULONG64 GetPXEByVirtualAddress(ULONG64 VirtualAddress)
{
//拿到PTE基地址
ULONG64 pteBase = GetPTEBase();
//拿到PPE
ULONG64 ppe = GetPPEByVirtualAddress(VirtualAddress);
//返回PDT
ULONG64 Addr = ((ppe >> 9) & 0x7FFFFFFFF8) + pteBase;
return Addr;
}
BOOLEAN SetExecutePage(ULONG64 VirtualAddress, ULONG size)
{
//结束地址
ULONG64 uEndAddr = (VirtualAddress + size) & (~0xFFF);
//清掉后12位 属性位
ULONG64 uStartAddr = VirtualAddress&(~0xFFF);
while (uEndAddr>= uStartAddr)
{
//处理PDE
PHardwarePte pde=GetPDEByVirtualAddress(VirtualAddress);
if (MmIsAddressValid(pde)&&pde->valid)
{
//设置可写 可执行
pde->no_execute = 0;
pde->write = 1;
}
//处理PTE
PHardwarePte pte = GetPTEByVirtualAddress(VirtualAddress);
if (MmIsAddressValid(pte) && pte->valid)
{
//设置可写 可执行
pte->no_execute = 0;
pte->write = 1;
}
//每次递增一个页
uStartAddr += PAGE_SIZE;
}
return TRUE;
}
char shellcode[] = "\x31\xdb\xb3\x30\x29\xdc\x64\x8b\x03\x8b\x40\x0c\x8b"
"\x58\x1c\x8b\x1b\x8b\x1b\x8b\x73\x08\x89\xf7\x89\x3c"
"\x24\x8b\x47\x3c\x01\xc7\x31\xdb\xb3\x78\x01\xdf\x8b"
"\x3f\x8b\x04\x24\x01\xf8\x89\x44\x24\x08\x31\xdb\xb3"
"\x1c\x01\xc3\x8b\x03\x8b\x3c\x24\x01\xf8\x89\x44\x24"
"\x0c\x8b\x44\x24\x08\x31\xdb\xb3\x20\x01\xc3\x8b\x03"
"\x01\xf8\x89\x44\x24\x10\x8b\x44\x24\x08\x31\xdb\xb3"
"\x24\x01\xc3\x8b\x03\x01\xf8\x89\x44\x24\x14\x8b\x44"
"\x24\x08\x31\xdb\xb3\x18\x01\xc3\x8b\x03\x89\x44\x24"
"\x18\x8b\x74\x24\x30\x31\xf6\x89\x74\x24\x30\x8b\x4c"
"\x24\x18\x8b\x2c\x24\x8b\x5c\x24\x10\x8b\x4c\x24\x18"
"\x85\xc9\x74\x5f\x49\x89\x4c\x24\x18\x8b\x34\x8b\x01"
"\xee\x31\xff\x31\xc0\xfc\xac\x84\xc0\x74\x07\xc1\xcf"
"\x0d\x01\xc7\xeb\xf4\x8b\x5c\x24\x14\x66\x8b\x0c\x4b"
"\x8b\x5c\x24\x0c\x8b\x04\x8b\x01\xe8\x8b\x34\x24\x81"
"\xff\xaa\xfc\x0d\x7c\x75\x08\x8d\x74\x24\x20\x89\x06"
"\xeb\xb5\x81\xff\x8e\x4e\x0e\xec\x75\x08\x8d\x74\x24"
"\x24\x89\x06\xeb\xa5\x81\xff\x7e\xd8\xe2\x73\x75\x9d"
"\x8d\x74\x24\x1c\x89\x06\xeb\x95\x89\xe6\x31\xd2\x66"
"\xba\x6c\x6c\x52\x68\x33\x32\x2e\x64\x68\x75\x73\x65"
"\x72\x54\xff\x56\x24\x89\x46\x28\x31\xd2\xb2\x41\x52"
"\x31\xd2\x66\xba\x6f\x78\x66\x52\x68\x61\x67\x65\x42"
"\x68\x4d\x65\x73\x73\x54\x50\xff\x56\x20\x89\x46\x2c"
"\x31\xd2\xb2\x20\x52\x31\xd2\x66\xba\x74\x6f\x66\x52"
"\x68\x69\x79\x61\x6e\x68\x46\x65\x62\x72\x89\xe3\x31"
"\xd2\xb2\x6f\x52\x68\x48\x65\x6c\x6c\x89\xe1\x31\xd2"
"\xb2\x04\x52\x31\xd2\x51\x53\x31\xff\x57\xff\x56\x2c"
"\x89\xf4\x57\xff\x54\x24\x20";
PVOID AllocateMemory(HANDLE pid, SIZE_T size)
{
//获取进程结构体
PEPROCESS Process=NULL;
PVOID BaseAddress = 0;
NTSTATUS status= PsLookupProcessByProcessId(pid, &Process);
if (!NT_SUCCESS(status))
{
return NULL;
}
//判断进程是否退出
if (PsGetProcessExitStatus(Process)!=STATUS_PENDING)
{
ObDereferenceObject(Process);
return NULL;
}
//附加进程
KAPC_STATE kApcState = {0};
KeStackAttachProcess(Process, &kApcState);
//附加 加上获取当前句柄 不会触发句柄保护回调 直接打开句柄会
ZwAllocateVirtualMemory(NtCurrentProcess(), &BaseAddress, 0, &size, MEM_COMMIT, PAGE_READWRITE);
if (NT_SUCCESS(status))
{
RtlZeroMemory(BaseAddress, size);
memcpy(BaseAddress, shellcode, sizeof(shellcode));
//修改PDE和PTE 设置可写和可执行属性
SetExecutePage(BaseAddress, size);
}
KeUnstackDetachProcess(&kApcState);
return BaseAddress;
}
NTSTATUS FreeMemory(HANDLE pid, PVOID BaseAddress, SIZE_T size)
{
//获取进程结构体
PEPROCESS Process = NULL;
NTSTATUS status = PsLookupProcessByProcessId(pid, &Process);
if (!NT_SUCCESS(status))
{
return STATUS_NOT_FOUND;
}
//判断进程是否退出
if (PsGetProcessExitStatus(Process) != STATUS_PENDING)
{
ObDereferenceObject(Process);
return STATUS_UNSUCCESSFUL;
}
//附加进程
KAPC_STATE kApcState = { 0 };
KeStackAttachProcess(Process, &kApcState);
//释放内存
if (BaseAddress)
{
ZwFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, 0, &size, MEM_RESERVE);
}
KeUnstackDetachProcess(&kApcState);
return STATUS_SUCCESS;
}