Advanced Debugging
About AdvDbg Consult Train Services Products Tools Community Contact  
欢迎光临 高端调试 登录 | 注册 | FAQ
 
  ACPI调试
Linux内核调试
Windows内核调试
 
  调试战役
调试原理
新工具观察
 
  Linux
Windows Vista
Windows
 
  Linux驱动
WDF
WDM
 
  PCI Express
PCI/PCI-X
USB
无线通信协议
 
  64位CPU
ARM
IA-32
  CPU Info Center
 
  ACPI标准
系统认证
Desktop
服务器
 
  Embedded Linux
嵌入式开发工具
VxWorks
WinCE
嵌入式Windows
 
  格蠹调试套件(GDK)
  格蠹学院
  小朱书店
  老雷的微博
  《软件调试》
  《格蠹汇编》
  《软件调试(第二版)》
沪ICP备11027180号-1

Windows内核调试

帖子发起人: jlflyfox   发起时间: 2009-01-22 15:36 下午   回复: 4

Print Search
帖子排序:    
   2009-01-22, 15:36 下午
jlflyfox 离线,最后访问时间: 2009/1/24 22:08:06 jlflyfox

发帖数前25位
注册: 2008-10-28
发 贴: 65
通过调用门访问页表的疑问
Reply Quote

说来也真不好意思,我是把董岩翻译的undocumented windowsNT和Raymond老大的《调试软件》一起阅读的。

前者05年就通读过一次,今年打算温故而知新。

我在阅读第三章内存管理的那个copy on write的时候,我看了那个showdir的例子,通过调用门,让内核调用0x0041xxxx的代码--这个能理解吧

例子中,内核调用下面这个代码

DWORD PageDirectory[ 1024 ];

void _stdcall CFuncGetPageDirectory()
{
    DWORD *PageDir = (DWORD *)0xC0300000;
    int i = 0;

    for (i = 0; i < 1024; i++) {
        PageDirectory[ i ] = PageDir[ i] ;
    }
}

然后执行两次,作者在重点讲述--“会发现两进程页表目录的高半部除两个表项外几乎完全相同”--里面那两个表项,我对这个兴趣不大,我的兴趣在于看0x00400000的两个例子的页表内容是否一样,就是是否都是一个物理页。

我用windbg来看两个calc.exe是没有问题的,见《调试软件》第二章的方法,但我总想自己写程序来验证下。

(注意calc.exe还比较搞笑,我等会说)

于是我修改了下上面那个片断

DWORD PageDirectory[ 1024 ];
DWORD *ppte40 = 0;
DWORD imagebase = 0;
/* C functions calld from the assembly stub */
void _stdcall CFuncGetPageDirectory()
{
 DWORD *PageDir=(DWORD *)0xC0300000;
 
 int i=0;

 for (i=0; i<1024; i++) {
  PageDirectory[ i ]=PageDir[ i ];
  if (i == 1) { //这个1好理解吧,我硬编码的,就是打算阅读00400000的地址
   DWORD pte40 = PageDirectory[ i ];
   pte40 = pte40&0xFFFFF000;
   ppte40 = (DWORD *)pte40;

   imagebase = *ppte40;//这里就bsod了

  }
 }
}

结果执行到ppte40 = (DWORD *)pte40这里bsod了,我很奇怪,为什么能执行PageDirectory[ i ]=PageDir[ i ];,而我的却不行。

阅读dump文件,就是mov edx, [ ecx ]

而ecx就是页表,用windbg来看也是一样的内容,就是程序一访问就bsod。

calc.exe比较搞笑的是,我最初发现两个calc.exe的逻辑地址0x00400000的物理地址内容稍有差别,本来我用write on copy来解释,但也觉得不对,不是exe文件头啊,而用ollyice装载又没有问题啊,后来突然明白了,它的imagebase不是0x00400000,而ollyice似乎把它强行安装到了0x0040000。

说了太多啰嗦话,还是请各位帮我看看那个代码有什么问题么?

 


IP 地址: 已记录   报告
   2009-01-22, 15:39 下午
jlflyfox 离线,最后访问时间: 2009/1/24 22:08:06 jlflyfox

发帖数前25位
注册: 2008-10-28
发 贴: 65
Re: 通过调用门访问页表的疑问
Reply Quote

晕,怎么有图像啊,怎么禁止啊,再贴下代码

void _stdcall CFuncGetPageDirectory()
{
 DWORD *PageDir=(DWORD *)0xC0300000;
 
 int i=0;

 for (i=0; i<1024; i++) {
  PageDirectory[ i ]=PageDir[ i] ;
  if (i == 1) {
   DWORD pte40 = PageDirectory[ i ];
   pte40 = pte40&0xFFFFF000;
   ppte40 = (DWORD *)pte40;
   imagebase = *ppte40;
  }
 }
}


IP 地址: 已记录   报告
   2009-01-24, 11:52 上午
jlflyfox 离线,最后访问时间: 2009/1/24 22:08:06 jlflyfox

发帖数前25位
注册: 2008-10-28
发 贴: 65
Re: 通过调用门访问页表的疑问
Reply Quote
汗,我知道我哪里错误了
DWORD *PageDir = (DWORD *)0xC0300000;
int i = 0;

for (i = 0; i < 1024; i++) {
PageDirectory[ i ] = PageDir[ i] ;
}

这个里面得到的已经是物理地址了,而我自己再用下面访问,就是把物理地址当作逻辑地址来弄,当然就不对了!
pte40 = pte40&0xFFFFF000;
ppte40 = (DWORD *)pte40;
imagebase = *ppte40;

我最后用!pte得到0x00400000的页表的线性地址,0xC0001000,用它硬编码即可了
ppte40 = 0xC0001000;
imagebase = *ppte40;

另外请问下Raymond, 如果不用硬编码,如何程序中得到0x00400000的Pte对应C0001000这个地址
IP 地址: 已记录   报告
   2009-01-24, 15:15 下午
Raymond 离线,最后访问时间: 2020/7/3 3:40:25 格蠹老雷

发帖数前10位
注册: 2005-12-19
发 贴: 1,303
Re: 通过调用门访问页表的疑问
Reply Quote
或许可以这样推算。线性地址的最高10位是页目录表项的索引(PDE的索引),即
lkd> .formats 0x00400000
Evaluate expression:
Hex: 00400000
Decimal: 4194304
Octal: 00020000000
Binary: 00000000 01000000 00000000 00000000
Chars: .@..
Time: Wed Feb 18 16:05:04 1970
Float: low 5.87747e-039 high 0
Double: 2.07226e-317
也就是说0x00400000这个线性地址的PDE索引是1,也就是页目录表中的1号表项。地址空间中0xC0000000开始的是所谓的HyperSpace区域,如果0号页表放在0xC0000000,那么1号页表刚好位于0xC0001000,因为每个页表的大小是4KB。

IP 地址: 已记录   报告
   2009-01-24, 22:10 下午
jlflyfox 离线,最后访问时间: 2009/1/24 22:08:06 jlflyfox

发帖数前25位
注册: 2008-10-28
发 贴: 65
Re: 通过调用门访问页表的疑问
Reply Quote
good!这样推很好,又学习了。
谢谢Raymond!
祝春节快乐哈!
IP 地址: 已记录   报告
高端调试 » 软件调试 » Windows内核调试 » Re: 通过调用门访问页表的疑问

 
Legal Notice Privacy Statement Corporate Governance Corporate Governance
(C)2004-2020 ADVDBG.ORG All Rights Reserved.