首页
社区
课程
招聘
[旧帖] [求助]请教关于R3与R0地址转换问题,(处女贴哦,各位大大请给力) 0.00雪花
2011-5-11 17:55 3250

[旧帖] [求助]请教关于R3与R0地址转换问题,(处女贴哦,各位大大请给力) 0.00雪花

2011-5-11 17:55
3250
环境:
干净的 xp sp3 windbg 本地内核调试中.....

现象:
lkd>!process 0 0
...省略无关内容若干...
PROCESS 892f1ab0 SessionId: 0 Cid: 0f7c Peb: 7ffdd000 ParentCid: 0638
DirBase: 0acc0620 ObjectTable: e170f938 HandleCount: 52.
Image: NOTEPAD.EXE
...省略无关内容若干...
lkd>.process 892f1ab0
lkd>!peb
peb at 7ffda000
error 1 InitTypeRead( nt!_PEB at 7ffda000)...
lkd> dt nt!_PEB 7ffda000
   +0x000 InheritedAddressSpace : ??
   +0x001 ReadImageFileExecOptions : ??
   +0x002 BeingDebugged    : ??
   +0x003 SpareBool        : ??
   +0x004 Mutant           : ????
   +0x008 ImageBaseAddress : ????
   +0x00c Ldr              : ????
   +0x010 ProcessParameters : ????
   +0x014 SubSystemData    : ????
   +0x018 ProcessHeap      : ????
   +0x01c FastPebLock      : ????
   +0x020 FastPebLockRoutine : ????
   +0x024 FastPebUnlockRoutine : ????
   +0x028 EnvironmentUpdateCount : ??
   +0x02c KernelCallbackTable : ????
   +0x030 SystemReserved   : [1] ??
   +0x034 AtlThunkSListPtr32 : ??
   +0x038 FreeList         : ????
   +0x03c TlsExpansionCounter : ??
   +0x040 TlsBitmap        : ????
   +0x044 TlsBitmapBits    : [2] ??
   +0x04c ReadOnlySharedMemoryBase : ????
   +0x050 ReadOnlySharedMemoryHeap : ????
   +0x054 ReadOnlyStaticServerData : ????
   +0x058 AnsiCodePageData : ????
   +0x05c OemCodePageData  : ????
   +0x060 UnicodeCaseTableData : ????
   +0x064 NumberOfProcessors : ??
   +0x068 NtGlobalFlag     : ??
   +0x070 CriticalSectionTimeout : _LARGE_INTEGER
   +0x078 HeapSegmentReserve : ??
   +0x07c HeapSegmentCommit : ??
   +0x080 HeapDeCommitTotalFreeThreshold : ??
   +0x084 HeapDeCommitFreeBlockThreshold : ??
   +0x088 NumberOfHeaps    : ??
   +0x08c MaximumNumberOfHeaps : ??
   +0x090 ProcessHeaps     : ????
   +0x094 GdiSharedHandleTable : ????
   +0x098 ProcessStarterHelper : ????
   +0x09c GdiDCAttributeList : ??
   +0x0a0 LoaderLock       : ????
   +0x0a4 OSMajorVersion   : ??
   +0x0a8 OSMinorVersion   : ??
   +0x0ac OSBuildNumber    : ??
   +0x0ae OSCSDVersion     : ??
   +0x0b0 OSPlatformId     : ??
   +0x0b4 ImageSubsystem   : ??
   +0x0b8 ImageSubsystemMajorVersion : ??
   +0x0bc ImageSubsystemMinorVersion : ??
   +0x0c0 ImageProcessAffinityMask : ??
   +0x0c4 GdiHandleBuffer  : [34] ??
   +0x14c PostProcessInitRoutine : ????
   +0x150 TlsExpansionBitmap : ????
   +0x154 TlsExpansionBitmapBits : [32] ??
   +0x1d4 SessionId        : ??
   +0x1d8 AppCompatFlags   : _ULARGE_INTEGER
   +0x1e0 AppCompatFlagsUser : _ULARGE_INTEGER
   +0x1e8 pShimData        : ????
   +0x1ec AppCompatInfo    : ????
   +0x1f0 CSDVersion       : _UNICODE_STRING
   +0x1f8 ActivationContextData : ????
   +0x1fc ProcessAssemblyStorageMap : ????
   +0x200 SystemDefaultActivationContextData : ????
   +0x204 SystemAssemblyStorageMap : ????
   +0x208 MinimumStackCommit : ??
Memory read error 7ffda208

疑问:
(1).process 命令的作用.
.process 命令切换到应用程序的地址空间,那为什么我依然不能访问输入进程892f1ab0的地址0x7ffda000?
(2)除了通过.process切换地址空间,如何才能在不调试 NOTEPAD.EXE 的情况下查看 它的PEB,
也就是如何才能将一个PE独立地址空间内的地址转换为在lkd>提示符下可以访问的地址
也就是R3的地址如何转换成R0的地址
或者这种方式不可行?

各位大大,小生这里有些啰嗦了...可是还觉得没说明白...期待您的解答,先行谢过

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

收藏
点赞0
打赏
分享
最新回复 (13)
雪    币: 690
活跃值: (40)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
virusest 2 2011-5-11 23:20
2
0
1>.process 就是 切换到当前进程的环境
  你之所以不能访问peb是因为没加载用户模块的pdb,使用.process /p /r _eprocess的地址
2>r3的线性地址转换到r0的物理地址,这个要理解CPU的分页和分段机制。我简单说下分页机制,当cpu要访问一个线性地址时,cpu的页处理器(80386往后)会把32位的线性地址分成3部分,0-11位为偏移,12-21位为页表,22-31位为页目录。页目录的物理地址位于cr3寄存器,当你切换到某个进程的环境时, 在windbg里输入 r cr3,可获取当前进程的页目录,或者使用dt -r nt!_eprocess 进程eprocess的地址,就可以看到在_kprocess的偏移0x18处有个DirectoryTableBase,他的值也就是该进程的页目录,和r cr3显示的一样。 有了页目录后,该页目录指向一个包含1024项的页表,而32位线性地址的12-21位为页表索引,cpu再从页表中找到对应的页表项,而该页表项指定了该进程被映射到实际物理内存的页面地址,当cpu知道页面地址后,再把32位线性地址的0-11位偏移地址加到该页面的首地址后获取该线性地址对应的实际物理地址,然后从该物理地址中取得数据。其实这种转换cpu有专门的处理单元,无需程序员了解。如果你想知道他是怎么回事的话,可以按照上面的步骤自己算。
举个例子,假如cpu要访问0x20021406处的内容,把该地址转换成二进制就是 00100000000000100001010000000110,其中,0-11位为offset即0x406, 页表为0X21,页目录为0x80,cpu先从页目录的地址搜索页表的地址,找到页表基址后,从该页表搜索第0x21项,从该项中获取页面的基址,有了页面后加上偏移就可找到实际的物理内存地址。页表和页面的映射关系是由系统内核完成的,内核维护这张表,并负责在进程初始化时把这张表加载到内存。如果了解页目录的话,页目录的10位中,有一位为P(present flag)标志位,该位为1,表示该映射表在内存中,否则,cpu把该线性地址保存到cr2寄存中,并生成一个页异常(#GP),当然内核是不会让该事发生的,因为在cpu启用分页机制前,内核会将改页表加载到内存中。

其实,这里面还有很多事,比如cpu为了快速访问一个线性地址,或者多次访问同一个线性地址,会将改映射信息保存在内部的一个tlb缓存区当中,这样cpu就不用多次查表访问同一个线性地址,可实现快速访问内存。当进程环境切换后,该缓存区的内容会被清空。

还有在windbg里也能看到这种页寻址的办法,输入 !pte 线性地址 ,则会显示出页目录(PDE)和页表(PTE)的地址。如:
kd> !pte 5004
                    VA 00005004  
PDE at C0600000            PTE at C0000028
contains 0000000002B40067  contains 0000000000000000
pfn 2b40      ---DA--UWEV   not valid

其实这些东西在任何一本讲内核原理的书中都会介绍。如《深入理解Linux内核》,我看的是英文原版,国内的书我好像在潘爱民老师的《Windows内核原理与实现》里看到过。
雪    币: 79
活跃值: (40)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
wParma 1 2011-5-12 00:36
3
0
感谢virusest大神的精彩解答.
第一个问题已经通过加/r顺利解决
第二个问题我在换算地址的时候有些疑惑还请virusest大神赐教,
现象:DirectoryTableBase 指向的数据全是0,具体操作如下:
lkd> !process 0 0
........省略无关数据若干.....
PROCESS 88a47c30  SessionId: 0  Cid: 0f50    Peb: 7ffde000  ParentCid: 067c
    DirBase: 0b0003c0  ObjectTable: e380c838  HandleCount: 171.
    Image: plugin-container.exe
........省略无关数据若干.....

lkd> .process /r 871b9da0
Implicit process is now 871b9da0

lkd> dt -r nt!_KPROCESS 888c4da0
........省略无关数据若干.....
   +0x018 DirectoryTableBase : [2] 0xb000380
........省略无关数据若干.....

现在我要换算0x7ffdf000(这个地址就是进程871b9da0的PEB)

lkd> !peb
PEB at 7ffdf000

按照偏移的含义
000000000000   offset =0
1111011111       页表 =  0x3df
0001111111      

lkd>  dd 0xb000380+3df
0b00075f  00000000 00000000 00000000 00000000
0b00076f  00000000 00000000 00000000 00000000
0b00077f  00000000 00000000 00000000 00000000
0b00078f  00000000 00000000 00000000 00000000
0b00079f  00000000 00000000 00000000 00000000
0b0007af  00000000 00000000 00000000 00000000
0b0007bf  00000000 00000000 00000000 00000000
0b0007cf  00000000 00000000 00000000 00000000


悲剧了...算不下去了...
雪    币: 278
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
流氓刚 2011-5-12 05:39
4
0
内存计算器.rar1
上传的附件:
雪    币: 79
活跃值: (40)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
wParma 1 2011-5-12 10:25
5
0
[QUOTE=流氓刚;957687] 内存计算器.rar1[/QUOTE]

但是我木有kx,不能下载....
雪    币: 79
活跃值: (40)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
wParma 1 2011-5-12 22:10
6
0
不能沉啊各位大大....偶还没明白呢...
雪    币: 125
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
trueme 2011-5-14 10:32
7
0
呵呵,那个页目录显示出来的是物理地址吧。不能这么搞!你用!pte先看看页目录地址撒,或者直接通过虚拟地址
雪    币: 690
活跃值: (40)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
virusest 2 2011-5-14 17:27
8
0
你这样算是不对的,下来我详细说下虚拟地址的转换。

首先,来看下内核为一个进程建立页目录和页表以及线性空间的函数。这个函数原型是:
VOID
MiInitMachineDependent (
    IN PLOADER_PARAMETER_BLOCK LoaderBlock
    )

位于init386.c的762行,这个函数太长了,挑选部分如下:
   PointerPte = MiGetPdeAddress (PDE_BASE);
    PdePageNumber = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte);

    CurrentProcess = PsGetCurrentProcess ();

#if defined(_X86PAE_)

    PrototypePte.u.Soft.PageFileHigh = MI_PTE_LOOKUP_NEEDED;

    _asm {
        mov     eax, cr3
        mov     DirBase, eax
    }

    //
    // Note cr3 must be 32-byte aligned.
    //

    ASSERT ((DirBase & 0x1f) == 0);

    //
    // Initialize the PaeTop for this process right away.
    //

    RtlCopyMemory ((PVOID) &MiSystemPaeVa,
                   (PVOID) (KSEG0_BASE | DirBase),
                   sizeof (MiSystemPaeVa));

    CurrentProcess->PaeTop = &MiSystemPaeVa;

#else

    DirBase = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte) << PAGE_SHIFT;

#endif

    CurrentProcess->Pcb.DirectoryTableBase[0] = DirBase;
    KeSweepDcache (FALSE);

    //
    // Unmap the low 2Gb of memory.
    //

    PointerPde = MiGetPdeAddress (0);
    LastPte = MiGetPdeAddress (KSEG0_BASE);

    MiZeroMemoryPte (PointerPde, LastPte - PointerPde);


第一句:PointerPte = MiGetPdeAddress (PDE_BASE);这句获得一个页表的指针。
PDE_BASE是页目录的基址,这个宏的定义如下:(i386.h 1968行)
#define PDE_BASE_X86    0xc0300000
#define PDE_BASE_X86PAE 0xc0600000

#define PTE_TOP_X86     0xC03FFFFF
#define PDE_TOP_X86     0xC0300FFF

#define PTE_TOP_X86PAE  0xC07FFFFF
#define PDE_TOP_X86PAE  0xC0603FFF

#if !defined (_X86PAE_)
#define PDE_BASE PDE_BASE_X86
#define PTE_TOP  PTE_TOP_X86
#define PDE_TOP  PDE_TOP_X86
#else
#define PDE_BASE PDE_BASE_X86PAE
#define PTE_TOP  PTE_TOP_X86PAE
#define PDE_TOP  PDE_TOP_X86PAE
#endif
#define PTE_BASE 0xc0000000
可以看出,如果CPU支持PAE或者开启了PAE(奔腾往后都支持,默认开启),那么一个进程页目录的基址为0xc0600000,这个在dbg调试的时候也可以看到,如
kd> !pte 0000
                    VA 00000000   (虚拟地址)
PDE at C0600000            PTE at C0000000
contains 0000000002B40067  contains 0000000000000000
pfn 2b40      ---DA--UWEV   not valid

再来看这个MiGetPdeAddress ,他是个宏,定义如下:(mi386.h 1889行)
#define MiGetPdeAddress(va)  ((PMMPTE)(((((ULONG)(va)) >> 22) << 2) + PDE_BASE))

可以看出他是取线性地址的最高10位,再左移2位,加上页目录的基址,得到该线性地址在该进程的 页目录的索引,而该处存放的就是其对应的页表索引,第二句:
PdePageNumber = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte);

MI_GET_PAGE_FRAME_FROM_PTE 这个宏(mi386.h 2542行)的定义如下:
#define MI_GET_PAGE_FRAME_FROM_PTE(PTE) ((PTE)->u.Hard.PageFrameNumber)
他是直接取该页表对应的物理内存的地址。到这里,CPU就可以访问到实际的物理内存了。

剩下的工作就是把cr3寄存器的内容赋给dirbase,再把dirbase赋给进程pcb的DirectoryTableBase项,这个在windbg调试的时候我说过了。后面再把该进程的低2G的用户空间清零。
我举个例子,咱来一步步转换。(我关闭了PAE,关闭方法,网上找,xp sp3)
假如线性地址为7c920000,这个地址一般加载的是进程的ntdll文件,首先把它转换成二进制,我在windbg里做,如下:
kd> .formats 7c920000
Evaluate expression:
  Hex:     7c920000
  Decimal: 2089943040
  Octal:   17444400000
  Binary:  01111100 10010010 00000000 00000000
  Chars:   |...
  Time:    Mon Mar 24 11:44:00 2036
  Float:   low 6.0646e+036 high 0
  Double:  1.03257e-314

可以看到高10位为01111100 10十六进制为0x1f2,
01111100 10 ->0x1F2按照上面的宏,0x1F2在左移2位,为0x7C8,加上PDE的基址C0300000,结果为C03007C8,我们在windbg里看下,如下:
kd> !pte 7c920000
                 VA 7c920000
PDE at C03007C8         PTE at C01F2480
contains 03793067       contains 03791025
pfn 3793  ---DA--UWEV   pfn 3791  ----A--UREV

可以看到,结果是吻合的,下面我们来算页表,按照上面的说法,一个进程的页目录可以达到1024项(2的10次方),而每项都是4字节,所以一个进程的页目录大小为4096bytes(4k),同理,一个页表的大小也为4096bytes(4k),而每一个页目录项对应一个4k大小的页表,所以,页表项的地址可以这么算:
PTE = 页表基址+(页目录项索引 × 一个页表的大小) + (页表索引 × 每一个页表项的大小)

由上面的宏定义知道在关了PAE的情况下页表的基址PTE_BASE为0xc0000000,一个页表项的大小也为4字节。而该线性地址的中间10位为010010 0000十六进制为0x120,所以,该线性地址对应的页表地址为:
PTE = 0xC0000000 + (0x1F2 * 0x1000) + (0x120 * 0x4) = 0xC01F2480.和上面windbg显示的数据是一样的。
在windbg里看下该处的内容为
kd> dd C01F2480
c01f2480  03791025 00000000 00000000 04157025
该页表处的内容为0x03791025 ,其中,如果了解页表结构的话,其高20位为该页表指向的物理内存,为0x3791,再加上线性地址的末12位偏移,所以该线性地址对应的实际物理地址为:0X37910000.
到这里就算完了。

补充:

内核定义的页表的数据结构如下:
typedef struct _MMPTE {
    union  {
        ULONG Long;
        HARDWARE_PTE Flush;
        MMPTE_HARDWARE Hard;
        MMPTE_PROTOTYPE Proto;
        MMPTE_SOFTWARE Soft;
        MMPTE_TRANSITION Trans;
        MMPTE_SUBSECTION Subsect;
        MMPTE_LIST List;
        } u;
} MMPTE;

typedef MMPTE *PMMPTE;

typedef struct _MMPTE_HARDWARE {
    ULONG Valid : 1;
#if defined(NT_UP)
    ULONG Write : 1;       // UP version
#else
    ULONG Writable : 1;    // changed for MP version
#endif
    ULONG Owner : 1;
    ULONG WriteThrough : 1;
    ULONG CacheDisable : 1;
    ULONG Accessed : 1;
    ULONG Dirty : 1;
    ULONG LargePage : 1;
    ULONG Global : 1;
    ULONG CopyOnWrite : 1; // software field
    ULONG Prototype : 1;   // software field
#if defined(NT_UP)
    ULONG reserved : 1;    // software field
#else
    ULONG Write : 1;       // software field - MP change
#endif
    ULONG PageFrameNumber : 20;
} MMPTE_HARDWARE, *PMMPTE_HARDWARE;




可以看出上面那个取物理地址的宏直接取的就是PageFrameNumber ,也就是该地址内容的高20位。
而在!pte命令在还显示了一些大些字母,如D,A,W,U之类的,也在该结构中有所显示。
雪    币: 79
活跃值: (40)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
wParma 1 2011-5-15 22:10
9
0
的确是物理地址...用!dd就可以查看了 感谢trueme童鞋
雪    币: 79
活跃值: (40)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
wParma 1 2011-5-15 22:20
10
0
问题已经解决了 谢谢virusest大神

顺便看了下启用物理地址扩展之后的地址转换方法简单记录下备查.和没有起启用的差距不大.主要有两点差别
(1)多了一张表Page Directory Pointer Table ,同时CR3不再指向PDT 而是指向PDPT
(2)对虚拟地址的解析规则有些差异 现在分为四个部分
    * 2位(位30和位31)的页目录指针表索引,用来索引本地址在页目录指针表中的对应表项。
    * 9位(位21-29)的页目录表索引,用来索引本地址在页目录表中的对应表项。
    * 9位(位12-20)的页表索引,用来索引本地址在页表中的对应表项。
    * 12位(位0-11)的页内偏移,这与以前是相同的。
参考资料 http://bbs.pediy.com/showthread.php?t=67820

还有virusest大神貌似有一点小笔误
"该页表处的内容为0x03791025 ,其中,如果了解页表结构的话,其高20位为该页表指向的物理内存,为0x3791,再加上线性地址的末12位偏移,所以该线性地址对应的实际物理地址为:0X37910000.
到这里就算完了。"
个人认为应该是0X3791000  
雪    币: 690
活跃值: (40)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
virusest 2 2011-5-16 09:00
11
0
恩,那个地址我写错了,你是对的,
还有启用了物理地址扩展之后,那个宏就变了,不再是右移22位,再左移2位,而是右移21位,再左移3位,同时PDE_BASE的值也跟着变。在windbg里调试下就能看到。
雪    币: 38
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yqhzh 2012-6-29 11:46
12
0
很好很强大,顶帖子
雪    币: 38
活跃值: (50)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
troops 2012-11-17 07:24
13
0
支持下……学习
雪    币: 297
活跃值: (120)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
淡定疯着 2012-11-17 10:34
14
0
感谢楼上,把这个帖子翻了出来,嘿嘿
游客
登录 | 注册 方可回帖
返回