首页
社区
课程
招聘
无驱动执行 Ring0 代码
发表于: 2005-1-14 23:18 9238

无驱动执行 Ring0 代码

2005-1-14 23:18
9238
〔转贴〕原作者姓名 free2000fly
介绍
无驱动执行 Ring0 代码的源程序的改写, 使得能在 VC6 及 vc71 下编译

正文
前不久因为有一个加密及直接操纵硬件的问题, 使用直接访问硬件更直接一点, 但操作系统是NT的,
不能用 CIH 的技术, 在网上狂找, 终于在 http://webcrazy.yeah.net 网站上找到了,
但下载下来的源代码怎么折腾就是编译不过, 当然这其中包括了安装 vc6 加 NTDDK2000,
VC71 加 NTDDK2000 (BTW, 我找不到 XPDDK, M$ 开始要钱了).

后来, 一不做二不休, 直接把 DDK 内的函数声明摘录下来放到我的源代码内, 这下行了.
编译通过有了一线曙光, 但是下下来的源码里的有 inp(...) 和 outp(...) 语句, 编译报错;
干脆,直接改成 汇编指令. 现在编译通过了, 运行一切符合预期.

下面是源代码
//////////////////////////////////////////////////////////////////////////// Ring0NT.cpp  // 演示无驱动执行 Ring0 代码, 改编自  http://webcrazy.yeah.net/  网站相关内容 // 能用 VC71 或 VC6 搭配最新 SDK 编译, 同时得有 NTDDK 内的 ntdll.lib 库文件 // 编译方法:  cl Ring0NT.cpp //////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <windows.h>
#include <aclapi.h>
#include <Ntsecapi.h>
//#include <conio.h>

#pragma comment (lib,"ntdll.lib")       // Copy From DDK
#pragma comment (lib,"Kernel32.lib")
#pragma comment (lib,"Advapi32.lib")

/////////////////////////// 从 NTDDK 摘来 ///////////////////////////////////
#ifdef __cplusplus
extern "C" {
#endif
   
typedef long NTSTATUS;
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
   
#define STATUS_SUCCESS              0x00000000
#define OBJ_KERNEL_HANDLE           0x00000200
#define STATUS_ACCESS_DENIED        0xC0000022
#define OBJ_CASE_INSENSITIVE        0x00000040L
   
    typedef struct _OBJECT_ATTRIBUTES {
        ULONG Length;
        HANDLE RootDirectory;
        PUNICODE_STRING ObjectName;
        ULONG Attributes;
        PVOID SecurityDescriptor;
        PVOID SecurityQualityOfService;
    } OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
   
#define InitializeObjectAttributes( p, n, a, r, s ) { \
    (p)->Length = sizeof( OBJECT_ATTRIBUTES );        \
    (p)->RootDirectory = r;                           \
    (p)->Attributes = a;                              \
    (p)->ObjectName = n;                              \
    (p)->SecurityDescriptor = s;                      \
    (p)->SecurityQualityOfService = NULL;             \
    }
   
    NTSYSAPI
        VOID
        NTAPI
        RtlInitUnicodeString(
        PUNICODE_STRING DestinationString,
        PCWSTR SourceString
        );
   
    NTSYSAPI
        NTSTATUS
        NTAPI
        ZwOpenSection(
        OUT PHANDLE SectionHandle,
        IN ACCESS_MASK DesiredAccess,
        IN POBJECT_ATTRIBUTES ObjectAttributes
        );
   
    NTSYSAPI
        NTSTATUS
        NTAPI
        ZwClose(
        IN HANDLE Handle
        );
   
#ifdef __cplusplus
}
#endif
/////////////////////////////////////////////////////////////////////////////

#define ENTERRING0  _asm pushad \
                    _asm pushf \
                    _asm cli

#define LEAVERING0  _asm popf \
                    _asm popad  \
                    _asm retf

typedef struct gdtr {
    unsigned short Limit;
    unsigned short BaseLow;
    unsigned short BaseHigh;
} Gdtr_t, *PGdtr_t;

typedef struct
{
    unsigned short  offset_0_15;
    unsigned short  selector;
   
    unsigned char    param_count : 4;
    unsigned char    some_bits   : 4;
   
    unsigned char    type        : 4;
    unsigned char    app_system  : 1;
    unsigned char    dpl         : 2;
    unsigned char    present     : 1;
   
    unsigned short  offset_16_31;
} CALLGATE_DESCRIPTOR;

void PrintWin32Error( DWORD ErrorCode )
{
    LPVOID lpMsgBuf;
   
    FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
        NULL, ErrorCode,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR) &lpMsgBuf, 0, NULL );
    printf("%s\n", lpMsgBuf );
    LocalFree( lpMsgBuf );
}

ULONG MiniMmGetPhysicalAddress(ULONG virtualaddress)
{
    if(virtualaddress<0x80000000||virtualaddress>=0xA0000000)
        return 0;
    return virtualaddress&0x1FFFF000;
}

VOID SetPhyscialMemorySectionCanBeWrited(HANDLE hSection)
{
   
    PACL pDacl=NULL;
    PACL pNewDacl=NULL;
    PSECURITY_DESCRIPTOR pSD=NULL;
    DWORD dwRes;
    EXPLICIT_ACCESS ea;
   
    if(dwRes=GetSecurityInfo(hSection,SE_KERNEL_OBJECT,DACL_SECURITY_INFORMATION,
        NULL,NULL,&pDacl,NULL,&pSD)!=ERROR_SUCCESS)
    {
        printf( "GetSecurityInfo Error %u\n", dwRes );
        goto CleanUp;
    }
   
    ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
    ea.grfAccessPermissions = 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";
   
   
    if(dwRes=SetEntriesInAcl(1,&ea,pDacl,&pNewDacl)!=ERROR_SUCCESS)
    {
        printf( "SetEntriesInAcl %u\n", dwRes );
        goto CleanUp;
    }
   
    if(dwRes=SetSecurityInfo(hSection,SE_KERNEL_OBJECT,DACL_SECURITY_INFORMATION,NULL,NULL,pNewDacl,NULL)!=ERROR_SUCCESS)
    {
        printf("SetSecurityInfo %u\n",dwRes);
        goto CleanUp;
    }
   
CleanUp:
   
    if(pSD)
        LocalFree(pSD);
    if(pNewDacl)
        LocalFree(pSD);
}

BOOL ExecRing0Proc(ULONG Entry,ULONG seglen)
{
    Gdtr_t gdt;
    __asm sgdt gdt;
   
    ULONG mapAddr=MiniMmGetPhysicalAddress(gdt.BaseHigh<<16U|gdt.BaseLow);
    if(!mapAddr) return 0;
   
    HANDLE   hSection=NULL;
    NTSTATUS status;
    OBJECT_ATTRIBUTES        objectAttributes;
    UNICODE_STRING objName;
    CALLGATE_DESCRIPTOR *cg;
   
    status = STATUS_SUCCESS;
   
    RtlInitUnicodeString(&objName,L"\\Device\\PhysicalMemory");
   
    InitializeObjectAttributes(&objectAttributes,
        &objName,
        OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
        NULL,
        (PSECURITY_DESCRIPTOR) NULL);
   
    status = ZwOpenSection(&hSection,SECTION_MAP_READ|SECTION_MAP_WRITE,&objectAttributes);
   
    if(status == STATUS_ACCESS_DENIED){
        status = ZwOpenSection(&hSection,READ_CONTROL|WRITE_DAC,&objectAttributes);
        SetPhyscialMemorySectionCanBeWrited(hSection);
        ZwClose(hSection);
        status =ZwOpenSection(&hSection,SECTION_MAP_WRITE|SECTION_MAP_WRITE,&objectAttributes);
    }
   
    if(status != STATUS_SUCCESS)
    {
        printf("Error Open PhysicalMemory Section Object,Status:%08X\n",status);
        return 0;
    }
   
    PVOID BaseAddress;
   
    BaseAddress=MapViewOfFile(hSection,
        FILE_MAP_READ|FILE_MAP_WRITE,
        0,
        mapAddr,    //low part
        (gdt.Limit+1));
   
    if(!BaseAddress)
    {
        printf("Error MapViewOfFile:");
        PrintWin32Error(GetLastError());
        return 0;
    }
   
    BOOL setcg=FALSE;
   
    for( cg=(CALLGATE_DESCRIPTOR *)((ULONG)BaseAddress+(gdt.Limit&0xFFF8));
        (ULONG)cg>(ULONG)BaseAddress; cg-- )
    {
        if(cg->type == 0){
            cg->offset_0_15 = LOWORD(Entry);
            cg->selector = 8;
            cg->param_count = 0;
            cg->some_bits = 0;
            cg->type = 0xC;          // 386 call gate
            cg->app_system = 0;      // A system descriptor
            cg->dpl = 3;             // Ring 3 code can call
            cg->present = 1;
            cg->offset_16_31 = HIWORD(Entry);
            setcg=TRUE;
            break;
        }
    }
   
    if(!setcg){
        ZwClose(hSection);
        return 0;
    }
   
    short farcall[3];
   
    farcall[2]=((short)((ULONG)cg-(ULONG)BaseAddress))|3;  //Ring 3 callgate;
   
    if(!VirtualLock((PVOID)Entry,seglen))
    {
        printf("Error VirtualLock:");
        PrintWin32Error(GetLastError());
        return 0;
    }
   
    SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL);
   
    Sleep(0);
   
    _asm call fword ptr [farcall]
        
        SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_NORMAL);
   
    VirtualUnlock((PVOID)Entry,seglen);
   
    //Clear callgate
    *(ULONG *)cg=0;
    *((ULONG *)cg+1)=0;
   
    ZwClose(hSection);
    return TRUE;
}

struct _RING0DATA
{
    DWORD mcr0,mcr2,mcr3;
    unsigned short BaseMemory;
    unsigned short ExtendedMemory;
}r0Data;

void __declspec (naked) Ring0Proc1()
{
    ENTERRING0;
    _asm {
        mov eax, cr0
            mov r0Data.mcr0, eax;
        mov eax, cr2
            mov r0Data.mcr2, eax;
        mov eax, cr3
            mov r0Data.mcr3, eax;
    }
    LEAVERING0;
}

void __declspec (naked) Ring0Proc2()
{
    ENTERRING0;

    //------ 求基本内存 ---------------------------------------------
    // outp( 0x70, 0x15 );
    _asm mov al, 15h    ;
    _asm out 70h, al    ;
   
    _asm mov ax,0 ;
    _asm in al,71h ;
    _asm mov r0Data.BaseMemory,ax ;
   
    // outp( 0x70, 0x16 );
    _asm mov al, 16h    ;  
    _asm out 70h, al    ;
    // r0Data.BaseMemory += inp(0x71) << 8;
    _asm xor eax, eax   ;
    _asm in al, 71h     ;
    _asm shl eax, 8h    ;
    _asm add r0Data.BaseMemory, ax  ;

    //------ 求扩展内存 ---------------------------------------------
    // outp( 0x70, 0x17 );
    _asm mov al, 17h    ;
    _asm out 70h, al    ;
    // r0Data.ExtendedMemory = inp( 0x71 );
    _asm xor eax, eax   ;
    _asm in al, 71h     ;
    _asm mov r0Data.ExtendedMemory, ax  ;

    // outp( 0x70, 0x18 );
    _asm mov al, 18h    ;
    _asm out 70h, al    ;
    // r0Data.ExtendedMemory += inp(0x71) << 8;
    _asm xor eax, eax   ;
    _asm in al, 71h     ;
    _asm shl eax, 8h    ;
    _asm add r0Data.ExtendedMemory, ax  ;

    LEAVERING0;
}

void main(void)
{
    ZeroMemory(&r0Data,sizeof(struct _RING0DATA));
    VirtualLock((PVOID)&r0Data,sizeof(struct _RING0DATA));
    ExecRing0Proc((ULONG)Ring0Proc1,0x100);
    ExecRing0Proc((ULONG)Ring0Proc2,0x100);
    VirtualUnlock((PVOID)&r0Data,sizeof(struct _RING0DATA));
    printf("CR0             = %x\n", r0Data.mcr0);
    printf("CR2             = %x\n", r0Data.mcr2);
    printf("CR3             = %x\n", r0Data.mcr3);
    printf("Base memory     = %dK\n", r0Data.BaseMemory);
    printf("Extended memory = %dK\n", r0Data.ExtendedMemory);
}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (13)
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
这个怎么看呀
乱七八糟的
2005-1-14 23:21
0
雪    币: 263
活跃值: (340)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
3
论坛好像对代码支持不好,刚编辑了一下,这下可以看了
2005-1-14 23:28
0
雪    币: 0
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
4
值得佩服!!!!
2005-1-14 23:40
0
雪    币: 260
活跃值: (162)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
这些代码值得消化...楼主辛苦了
2005-1-15 00:56
0
雪    币: 260
活跃值: (81)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
6
好贴!楼主辛苦・!
2005-1-15 01:27
0
雪    币: 6075
活跃值: (2236)
能力值: (RANK:1060 )
在线值:
发帖
回帖
粉丝
7
和ratter那个比实在...
2005-1-15 02:12
0
雪    币: 221
活跃值: (55)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
8
小声问一下,进了ring0一般有什么作用?
比如在软件加密解密方面
2005-1-15 13:39
0
雪    币: 263
活跃值: (340)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
9
要是用的好的话,连操作系统都尽在掌握,用不好,你的系统就over了:D
2005-1-15 15:52
0
雪    币: 2319
活跃值: (565)
能力值: (RANK:300 )
在线值:
发帖
回帖
粉丝
10
值得研究,支持 !
2005-1-15 18:20
0
雪    币: 768
活跃值: (540)
能力值: ( LV13,RANK:460 )
在线值:
发帖
回帖
粉丝
11
强!学习!!
楼主真牛!!:)
2005-1-15 18:49
0
雪    币: 107
活跃值: (54)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
辛苦辛苦
2005-1-16 17:33
0
雪    币: 0
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
13
大家知道,Windows  NT/2000为实现其可靠性,严格将系统划分为内核模式与用户模式,在i386系统中分别对应CPU的Ring0与Ring3级别。Ring0下,可以执行特权级指令,对任何I/O设备都有访问权等等。要实现从用户态进入核心态,即从Ring  3进入Ring  0必须借助CPU的某种门机制,如中断门、调用门等。而Windows  NT/2000提供用户态执行系统服务(Ring  0例程)的此类机制即System  Service的int  2eh中断服务等,严格的参数检查,只能严格的执行Windows  NT/2000提供的服务,而如果想执行用户提供的Ring  0代码(指运行在Ring  0权限的代码),常规方法似乎只有编写设备驱动程序。本文将介绍一种在用户态不借助任何驱动程序执行Ring0代码的方法。  

       Windows  NT/2000将设备驱动程序调入内核区域(常见的位于地址0x80000000上),由DPL为0的GDT项8,即cs为8时实现Ring  0权限。本文通过在系统中构造一个指向我们的代码的调用门(CallGate),实现Ring0代码。基于这个思路,为实现这个目的主要是构造自己的CallGate。CallGate由系统中叫Global  Descriptor  Table(GDT)的全局表指定。GDT地址可由i386指令sgdt获得(sgdt不是特权级指令,普通Ring  3程序均可执行)。GDT地址在Windows  NT/2000保存于KPCR(Processor  Control  Region)结构中(见《再谈Windows  NT/2000环境切换》)。GDT中的CallGate是如下的格式:  

       typedef  struct  
       {  
               unsigned  short    offset_0_15;  
               unsigned  short    selector;  

               unsigned  char        param_count  :  4;  
               unsigned  char        some_bits      :  4;  

               unsigned  char        type                :  4;  
               unsigned  char        app_system    :  1;  
               unsigned  char        dpl                  :  2;  
               unsigned  char        present          :  1;  
         
               unsigned  short    offset_16_31;  
       }  CALLGATE_DESCRIPTOR;  

       GDT位于内核区域,一般用户态的程序是不可能对这段内存区域有直接的访问权。幸运的是Windows  NT/2000提供了一个叫PhysicalMemory的Section内核对象位于\Device的路径下。顾名思义,通过这个Section对象可以对物理内存进行操作。用objdir.exe对这个对象分析如下:  

       C:\NTDDK\bin>objdir  /D  \Device  

       PhysicalMemory                                       
               Section  
               DACL  -   
                     Ace[  0]  -  Grant  -  0xf001f  -  NT  AUTHORITY\SYSTEM  
                                                         Inherit:   
                                                         Access:  0x001F    and    (  D  RCtl  WOwn  WDacl  )  

                     Ace[  1]  -  Grant  -  0x2000d  -  BUILTIN\Administrators  
                                                         Inherit:   
                                                         Access:  0x000D    and    (  RCtl  )  

       从dump出的这个对象DACL的Ace可以看出默认情况下只有SYSTEM用户才有对这个对象的读写权限,即对物理内存有读写能力,而Administrator只有读权限,普通用户根本就没有权限。不过如果我们有Administrator权限就可以通过GetSecurityInfo、SetEntriesInAcl与SetSecurityInfo这些API来修改这个对象的ACE。这也是我提供的代码需要Administrator的原因。实现的代码如下:  

       VOID  SetPhyscialMemorySectionCanBeWrited(HANDLE  hSection)  
       {  

             PACL  pDacl=NULL;  
             PACL  pNewDacl=NULL;  
             PSECURITY_DESCRIPTOR  pSD=NULL;  
             DWORD  dwRes;  
             EXPLICIT_ACCESS  ea;  

             if(dwRes=GetSecurityInfo(hSection,SE_KERNEL_OBJECT,DACL_SECURITY_INFORMATION,  
                                   NULL,NULL,&pDacl,NULL,&pSD)!=ERROR_SUCCESS)  
                   {  
                         printf(  "GetSecurityInfo  Error  %u\n",  dwRes  );  
                         goto  CleanUp;  
                   }  

             ZeroMemory(&ea,  sizeof(EXPLICIT_ACCESS));  
             ea.grfAccessPermissions  =  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";  

             if(dwRes=SetEntriesInAcl(1,&ea,pDacl,&pNewDacl)!=ERROR_SUCCESS)  
                   {  
                         printf(  "SetEntriesInAcl  %u\n",  dwRes  );  
                         goto  CleanUp;  
                   }  

             if(dwRes=SetSecurityInfo(hSection,SE_KERNEL_OBJECT,DACL_SECURITY_INFORMATION,NULL,NULL,pNewDacl,NULL)!=ERROR_SUCCESS)  
                   {  
                         printf("SetSecurityInfo  %u\n",dwRes);  
                         goto  CleanUp;  
                   }  

       CleanUp:  

             if(pSD)  
                   LocalFree(pSD);  
             if(pNewDacl)  
                   LocalFree(pSD);  
       }  

       这段代码对给定HANDLE的对象增加了如下的ACE:   

       PhysicalMemory                                       
               Section  
               DACL  -   
                     Ace[  0]  -  Grant  -  0x2  -  WEBCRAZY\Administrator  
                                                         Inherit:   
                                                         Access:  0x0002        //SECTION_MAP_WRITE  

       这样我们在有Administrator权限的条件下就有了对物理内存的读写能力。但若要修改GDT表实现Ring  0代码。我们将面临着另一个难题,因为sgdt指令获得的GDT地址是虚拟地址(线性地址),我们只有知道GDT表的物理地址后才能通过\Device\PhysicalMemory对象修改GDT表,这就牵涉到了线性地址转化成物理地址的问题。我们先来看一看Windows  NT/2000是如何实现这个的:  

       kd>  u  nt!MmGetPhysicalAddress  l  30  
       ntoskrnl!MmGetPhysicalAddress:  
       801374e0  56                              push        esi  
       801374e1  8b742408                  mov          esi,[esp+0x8]  
       801374e5  33d2                          xor          edx,edx  
       801374e7  81fe00000080          cmp          esi,0x80000000  
       801374ed  722c                          jb        ntoskrnl!MmGetPhysicalAddress+0x2b  (8013751b)  
       801374ef  81fe000000a0          cmp          esi,0xa0000000  
       801374f5  7324                          jnb      ntoskrnl!MmGetPhysicalAddress+0x2b  (8013751b)  
       801374f7  39153ce71780          cmp          [ntoskrnl!MmKseg2Frame  (8017e73c)],edx  
       801374fd  741c                          jz        ntoskrnl!MmGetPhysicalAddress+0x2b  (8013751b)  
       801374ff  8bc6                          mov          eax,esi  
       80137501  c1e80c                      shr          eax,0xc  
       80137504  25ffff0100              and          eax,0x1ffff  
       80137509  6a0c                          push        0xc  
       8013750b  59                              pop          ecx  
       8013750c  e8d3a7fcff              call        ntoskrnl!_allshl  (80101ce4)  
       80137511  81e6ff0f0000          and          esi,0xfff  
       80137517  03c6                          add          eax,esi  
       80137519  eb17                          jmp      ntoskrnl!MmGetPhysicalAddress+0x57  (80137532)  
       8013751b  8bc6                          mov          eax,esi  
       8013751d  c1e80a                      shr          eax,0xa  
       80137520  25fcff3f00              and          eax,0x3ffffc  
       80137525  2d00000040              sub          eax,0x40000000  
       8013752a  8b00                          mov          eax,[eax]  
       8013752c  a801                          test        al,0x1  
       8013752e  7506                          jnz      ntoskrnl!MmGetPhysicalAddress+0x44  (80137536)  
       80137530  33c0                          xor          eax,eax  
       80137532  5e                              pop          esi  
       80137533  c20400                      ret          0x4
2005-1-17 12:30
0
雪    币: 387
活跃值: (236)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
14
看不懂
2005-1-18 08:19
0
游客
登录 | 注册 方可回帖
返回
//