是我犯的超低级错误,我用的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 加载用户层的模块 方便下断和分析代码)