22 12
发新话题
打印

无驱动执行Ring0代码和执行程序

无驱动执行Ring0代码和执行程序

文章作者:zzzEVAzzz
复制内容到剪贴板
代码:
//************************************************************************
// 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);
}
附件: 您所在的用户组无法下载或查看附件

TOP

猪猪:
你有试验 是否可以正确执行

写一下  利用方法 ok?

TOP

同意楼上得想法哈

TOP

我使用vc编译的时候老提示 很多错误
包括好几个 函数类型的转换
猪猪:
你有编译吗?

TOP

代码可以正确 编译!
自己糊涂  保存为cpp文件编译的!
保存为.c 编译即可!

里面的ntdll.lib
vc 没有这个库

需要从ddk中取得

我这里附上  此文件!

在换行符附近 我的vc还报错误!  可能换行符没写正确!
最后把那个#define的函数  都写成一行了!呵呵 知识贫穷啊!


还有一个重要问题就是
为什么在
// 获取系统核心模块ntoskrnl.exe的基址
  pKernel = GetModuleBase(Kernel);
这个地方 取得的是NULL呢
没有取到地址!

[ 本帖最后由 wuna66320 于 2007-2-23 12:10 编辑 ]
附件: 您所在的用户组无法下载或查看附件

TOP

回复 #5 wuna66320 的帖子

楼上的兄弟,这个我也没有编译过。不过你的问题我可以帮你看看,等待一下。。

TOP

好的! thanks!

TOP

// 获取系统核心模块ntoskrnl.exe的基址
  pKernel = GetModuleBase(Kernel);
这个地方 取得的是NULL呢
没有取到地址!

我这边测试成功,

取到了结果.0x804d1000
是ntoskrnl.exe在内核的加载地址KernelBase
本帖最近评分记录

TOP

运行时出现问题:
Ring0Code+0x18c我机器上显示是这个地方出的问题

代码是(*buffer)++;

就找到这些 

好像是栈溢出

TOP

你使用的是什么操作系统?
我使用的xp2

TOP

XP SP2

TOP

这个程序好像是在windows 2000下的....

TOP

我使用win 2000的虚拟机器 也是一样 取得的 地址都是 0
郁闷!

TOP

引用:
原帖由 wuna66320 于 2007-2-25 14:24 发表
我使用win 2000的虚拟机器 也是一样 取得的 地址都是 0
郁闷!
编译好的程序我刚刚加进去了。你可以直接下载编译好的。

感谢 逆水寒 编译此程序。

TOP

这个我也编译出来了! 问题是 他好像没有执行ListProcessInfo  函数!
在xp2  中没有把琏表里面的 进程信息打印出来!
C:\Documents and Settings\Administrator>E:\编译后的Ring0\Ring0.exe

-=< Run Ring0 Code Without Driver Demo >=-
C:\Documents and Settings\Administrator>

在我的虚拟机器win2000里执行更是可怕 直接蓝屏重起!

[ 本帖最后由 wuna66320 于 2007-2-25 15:52 编辑 ]

TOP

 22 12
发新话题