首页
社区
课程
招聘
[旧帖] [原创]通过各种门进行ring3到ring0的切换测试程序 0.00雪花
发表于: 2012-3-10 01:10 4236

[旧帖] [原创]通过各种门进行ring3到ring0的切换测试程序 0.00雪花

2012-3-10 01:10
4236
标 题: 【原创】通过各种门进行ring3到ring0的切换测试程序(新人申请个邀请码进来学习)
作 者: XiaoWen
时 间: 2012-03-10,01:10:10
链 接: http://bbs.pediy.com/showthread.php?t=147670

    学习调用门、中断门、陷阱门、任务门时,经常要进行各种的系统描述符、门描述符、TSS描述符的计算和进入Windbg手工填写来测试各种的逻辑代码,最头痛的就是常常要喝上“三精口服液”,虚拟机伤不起、电脑更伤不起,更何况是我们幼小的心灵;
    为了方便以后回顾这方面知识,进行一些测试,或者想进ring0进行测试,故写了这个门测试小程序;学习过门的可以拿来作为测试或者复习用用;
    在这个行业,作为新手学习这些领域,不足之处还请多多提点下;
     程序里已有很多注释,这里就不提及了,主要是可测试各种门及由ring3->ring0切换、ring0->ring0切换、ring3->ring3切换的测试,附上源码;

为了方便初学者,补上几张演示图:

1.打开Windbg->file->kernel debug->local->确定,然后如图输入,查看第一个CPU的GDT地址(因为程序里设置了SetThreadAffinityMask(GetCurrentThread(),CURRENT_CPU_1);)


2.运行测试程序,生成调用门ring3->ring0的描述符(第一个需要手动的原因是让自身进入ring0,然后就可以让程序有权限自动修改GDT、IDT表信息了)


3.利用生成的描述符,进入Windbg修改GDT(程序里所用的选择子为0xb3,所以在GDT表里的偏移为0xb0)


4.回到运行中的控制台程序,直接按回车确定(会跳到CallGate ring3->ring0的函数执行你自己编的代码)



5.其中涉及的基础知识还请查看那本《80x86汇编语言程序设计教程》的保护模式部分

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 0
支持
分享
最新回复 (17)
雪    币: 27
活跃值: (796)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
2
做个记号!
2012-3-10 10:26
0
雪    币: 4
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
同意楼主,值得学习
2012-3-10 11:02
0
雪    币: 31
活跃值: (48)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4
顶贴留名,有空下载研究,希望适合初学者。
2012-3-10 11:24
0
雪    币: 71
活跃值: (58)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
xiaowenXW兄:牛呀!呵呵~ ~
2012-3-10 14:21
0
雪    币: 15
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
为什么要进入ring0啊?
2012-3-10 19:58
0
雪    币: 32
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
出入此道,学习了
2012-3-11 02:35
0
雪    币: 32
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
mark~~
2012-3-11 09:18
0
雪    币: 8264
活跃值: (18375)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
9
老大,“打开windbg,手动把该调用门描述符填到GDT表里“ 这一步如何做,能不能说详细点,谢谢:)
2012-3-11 09:57
0
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
已经补上基本的测试步骤了~
2012-3-11 23:23
0
雪    币: 8264
活跃值: (18375)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
11
hah,非常感谢!
2012-3-12 11:48
0
雪    币: 7
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
做好基础   支持
2012-3-12 14:46
0
雪    币: 8264
活跃值: (18375)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
13
还是出不来,老是报错,访问拒绝。。。。
我的系统WINXP,CPU4核,程序运行后不知为什么关系设置里还是4个CPU,但调试发现SetThreadAffinityMask返回值为8,应该调用成功了啊,手动改为CPU 0,并且在WINDBG里手动更改了GDT,运行还是报错。。。。
报错的地方在远转移这里 Call fword ptr [eax] ,手动更改GDT为0040ec01  001b3b30 一样会报错,为什么?
2012-3-12 17:30
0
雪    币: 209
活跃值: (808)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
为什么不直接写驱动进入内核?
2012-3-12 18:25
0
雪    币: 2323
活跃值: (4113)
能力值: ( LV12,RANK:530 )
在线值:
发帖
回帖
粉丝
15
门很强大,学习~~
2012-3-12 18:41
0
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
1.注意这里我自己设的是0xb3,所以在设定的CPU的GDT表里的偏移0xb0处修改
*(WORD*)&buff[4]=0xb3;                //&0xFFF8后为b0,在GDT表里的偏移
__asm
{
mov eax,gateType        //通过堆栈传递参数
push eax
lea eax,buff
call fword ptr [eax]        //通过手动修改GDT时的门描述符,会跳到Ring0Func函数开始执行
}

2.SetThreadAffinityMask(GetCurrentThread(),CURRENT_CPU_1);
注意这里还是不要用这个宏了,直接用1,2,4,8掩码作参数,程序里面这里的宏貌似定义错误了
Windbg里的命令:!pcr 0    对应第一个CPU      掩码用1
我的查到是GDT: 8003f000

再试试看吧,我的机子所有门所有ring之间的切换都亲自测试通过的
2012-3-12 22:48
0
雪    币: 8264
活跃值: (18375)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
17
[QUOTE=xiaowenXW;1052645]1.注意这里我自己设的是0xb3,所以在设定的CPU的GDT表里的偏移0xb0处修改
*(WORD*)&buff[4]=0xb3;                //&0xFFF8后为b0,在GDT表里的偏移
__asm
{
mov eax,gateType        //通过堆栈传递参数
push eax
lea eax,...[/QUOTE]

谢谢热心解答,我不是怀疑你哈,只是想搞清楚为什么在我机子上不成功?不知是不是我理解有误,看了combojiang大大的贴http://bbs.pediy.com/showthread.php?t=62263,我理解如下:远程转移系统只读取高16位,即这里的00b3,然后将它做为选择子在GDT表里找到对应的调用门描述符,0040EC01 00083B30 ,所以实际跳转地址为0008:00403b30(0008段为ring0权限)
2012-3-13 11:11
0
雪    币: 8264
活跃值: (18375)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
18
是我犯的超低级错误,我用的ED命令来写,所以数据弄倒了,正常数据应该是00083b30 0040ec01,这次可以正常进入R0了,不过老是蓝屏,经调试发现蓝屏出在00402036处,信息如下
FAULTING_IP:
Gate+2036
00402036 8a4205          mov     al,byte ptr [edx+5]

MM_INTERNAL_CODE:  0

DEFAULT_BUCKET_ID:  INTEL_CPU_MICROCODE_ZERO

BUGCHECK_STR:  0x50

PROCESS_NAME:  Gate.exe

TRAP_FRAME:  f69b9c8c -- (.trap 0xfffffffff69b9c8c)
ErrCode = 00000000
eax=00000821 ebx=7ffd4000 ecx=00000001 edx=ffc07008 esi=0012fec8 edi=f69b9d58
eip=00402036 esp=f69b9d00 ebp=f69b9d58 iopl=0         nv up ei ng nz na po cy
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010283
Gate+0x2036:
00402036 8a4205          mov     al,byte ptr [edx+5]        ds:0023:ffc0700d=??
Resetting default scope

mov     al,byte ptr [edx+5] 这条指令对应源码为“填充门描述符到GDT”的函数FillGateDescInGdt里
if(pgd->present==0) 语句,  是读取pgd->present位错误,访问违规(这时已经在R0了,CS=0008),暂还没找到原因,继续研究。
另外通过学习有了一些收获也分享下
一开始我就有两个疑问:
1、R3下把参数压入堆栈,传递给R0下使用,以前模糊记得R0和R3下的堆栈地址是不一样的,怎么能通过堆栈来传递参数?
2、CS由001B切换为0008后,原来00403b30的代码还在00403b30?在我原来印象里每个进程都有独立的4G虚拟空间,虽然每个进程代码加载基址一般在00401000,但他们实际的内存物理地址并不一样,并不冲突,这里进行r3到r0切换后,00403b30地址的内容还是原来的内容吗?
经过搜索资料和调试终于找到了答案
第一个问题详见 lly鹅 的保护模式四
http://bbs.pediy.com/showthread.php?t=63057 ,对于代码跳转的步骤写得很详细,这么好的文章居然没人回复,遗憾,问题的答案是新堆栈会把旧堆栈的参数拷贝过去,拷贝的数量由调用门定义,这里就是0040EC01末尾的01,代表拷贝参数1个
第二个问题        参见上贴和combojiang的任务门 http://bbs.pediy.com/showthread.php?t=62510
答案是每个任务都有个TSS结构,这里面有个重要的寄存器值CR3,也就是通过它系统能找到虚拟地址对应的物理地址,而在同一任务里这个东东是不变的,也就是同一任务里进行R3到R0的切换,虚拟地址对应的物理地址还是不变的,变的只是CS和SS,特权的变化,所以即使进到R0,00403b30的代码还是原来的代码

另外还有个问题想求助大家
如果跟踪调试这种r3/r0切换的程序?
用od调试不行, 远调用CALL FAR FWORD PTR DS:[EAX] 步进直接返回结果
windbg双机调试应用程序也不行
因为涉及到R0,应该只有windbg双机调试系统(或驱动)的办法可行,但用它调试驱动挺方便,调试应用程序不知道怎么弄?下断点无效
如 sxe ld gate 或者bu gate!0040402b  都断不来,查资料说切换到对应进程,.process  xxxxx   然后下断也没用,后来只能在下面代码里加一句int 3 ,总算可以了,调试时可以打开寄存器窗口和堆栈数据(windbg的堆栈还是没有OD好用,直接看堆栈数据用内存窗口比较好,输入ESP),对R3/R0切换时,观察寄存器的变化和新堆栈数据更有助于理解上面的两个问题。
void __declspec(naked)Ring0Func()                        //Ring0函数,返回要弹4或5个参数(没传参时)
{
        DWORD gateType;                                                                                        //门类型参数
        __asm
        {
                mov eax,[esp+0x8]                                                                        //通过堆栈接受参数
                mov gateType,eax
                  int 3
        }

2012-4-5
经过网上搜索资料和尝试,终于知道怎么在内核模式下调试用户层程序了
1、!process 0 0
2、.process /i /p  xxxx   (注:一定要/i参数)
3、 输入g运行,它会自动中断在目标用户层空间,这时就可以用bp bu下断点(最好先输入
.reload /f /user 加载用户层的模块 方便下断和分析代码)
2012-4-1 10:42
0
游客
登录 | 注册 方可回帖
返回
//