直接从分页级结构

时间:2018-03-15 13:46:04

标签: windbg paging virtual-address-space dep

我正在研究Windows 10 x64中的虚拟地址转换。我还读到了PML4,PDP,PDE和PTE,现在我试图通过修改分页结构来改变堆栈的nx位,以便在堆栈中执行代码。

我看到下面的图片描述了PML4E,PDPE,PDE和PTE中的nx-bit:

Paging Structure

假设我们已经使用VMWare创建了一个内核调试Windbg,在客户机中,我们正在使用xdbg64调试一个简单的应用程序。

使用xdbg64附加到目标进程后,现在rsp指向00000089F06FF848。 我更改了程序流程并执行jmp rsp现在,rip指向rsp但由于DEP而提供access_violation exception因此我无法执行任何代码堆栈。 (之前我用xor rax,rax之类的东西更改了堆栈,以便在那里有一个有效的汇编代码。

现在我使用来自主机的Windbg暂停来宾计算机并进行有效翻译,使用.process /f /i ffffa9841d9952c0将显式流程更改为目标流程,然后在按g后,现在我们的{{1} }对翻译有效。

然后我使用以下命令获取PML4E,PDPE,PDE,PTE物理地址:

cr3

above picture开始,第63位用于NX-Bit 然后我得到所有条目(PML4E,PDPE,PDE,PTE),看看有什么。

对于PML4E,它是:

kd> !vtop 0 00000089F06FF848
Amd64VtoP: Virt 00000089`f06ff848, pagedir 34848000
Amd64VtoP: PML4E 34848008
Amd64VtoP: PDPE 3316e138
Amd64VtoP: PDE 340efc18
Amd64VtoP: PTE 31de77f8
Amd64VtoP: Mapped phys 68a6b848
Virtual address 89f06ff848 translates to physical address 68a6b848.
  

转换67 e8 16 33 00 00 00 0a (01100111 11101000 00010110   00110011 00000000 00000000 00000000 0000101 0

  

67 e8 16 33 00 00 00 0b (01100111 11101000 00010110 00110011 00000000   00000000 00000000 0000101 1

(请注意粗体位。)

PDPE是:

kd> !db 34848008
#34848008 67 e8 16 33 00 00 00 0a-00 00 00 00 00 00 00 00 g..3............
#34848018 67 88 77 55 00 00 00 0a-00 00 00 00 00 00 00 00 g.wU............
#34848028 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#34848038 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#34848048 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#34848058 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#34848068 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#34848078 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
  

转换67 f8 0e 34 00 00 00 0a (01100111 11111000 00001110 00110100 00000000 00000000 00000000 0000101 0

  

67 f8 0e 34 00 00 00 0b (01100111 11111000 00001110 00110100 00000000 00000000 00000000 0000101 1

PDE是:

kd> !db 3316e138
#3316e138 67 f8 0e 34 00 00 00 0a-00 00 00 00 00 00 00 00 g..4............
#3316e148 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#3316e158 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#3316e168 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#3316e178 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#3316e188 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#3316e198 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#3316e1a8 00 00 00 00 00 00 00 00-67 f8 0e 34 00 00 00 0a00 00 00 00 00 00 00 00 ................
  

转换67 78 de 31 00 00 00 0a (01100111 01111000 11011110 00110001 00000000 00000000 00000000 0000101 0

  

67 78 de 31 00 00 00 0b (01100111 01111000 11011110 00110001 00000000 00000000 00000000 0000101 1

PTE是:

kd> !db 340efc18
#340efc18 67 78 de 31 00 00 00 0a-00 00 00 00 00 00 00 00 gx.1............
#340efc28 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#340efc38 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#340efc48 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#340efc58 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#340efc68 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#340efc78 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
#340efc88 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

在这种情况下,我没有修改任何东西,因为67 b8 a6 68 00 00 00 81等于01100111 10111000 10100110 01101000 00000000 00000000 00000000 10000001,因为它的最后一位是1.

在最后一步中,我再次运行kd> !db 31de77f8 #31de77f8 67 b8 a6 68 00 00 00 81-00 00 00 00 00 00 00 00 g..h............ #31de7808 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ #31de7818 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ #31de7828 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ #31de7838 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ #31de7848 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ #31de7858 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ #31de7868 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 以查看它是否仍然转换为相同的物理地址,并且我发现它是正确的(指向同一位置。)

然后我按!vtop以测试它是否可以执行堆栈内容但是我看到它仍然会给出相同的错误(access_violation)并且无法执行该地址(g

所以我有以下问题:

  1. 我的修改有什么不对,没有任何影响?

  2. 我听说GDT也有类似NX-Bit的东西阻止了堆栈执行,GDT执行预防和NX-Bit在分页级别之间有什么差异?

  3. 为什么有4级定义nx-bit?是否只更改上述条目之一,如pml4e会影响所有其他条目?

1 个答案:

答案 0 :(得分:0)

  

我的修改有什么不对,没有任何影响?

您应该修补PTE的NX位(这是最重要的位)。

我刚刚将一些代码修补到notepad.exe中,设置了入口点以执行该代码(nops后跟RET):

Notepad with some code

查找记事本:

kd> !process 0 0 notepad.exe PROCESS ffffe000852c5840
    SessionId: 1  Cid: 0108    Peb: 7ff689a4e000  ParentCid: 0d74 FreezeCount 1
    DirBase: 1b1b9000  ObjectTable: ffffc000a6b08280  HandleCount: <Data Not Accessible>
    Image: notepad.exe

切换上下文:

kd> .process /p /i ffffe000852c5840
You need to continue execution (press 'g' <enter>) for the context
to be switched. When the debugger breaks in again, you will be in
the new process context.
kd> g
Break instruction exception - code 80000003 (first chance)
nt!DbgBreakPointWithStatus:
fffff803`f63d1300 cc              int     3

这是RSP(0x64a9b5fdd8)的内容,只是为了确定:

kd> db 64a9b5fdd8 L10
00000064`a9b5fdd8  90 90 90 90 90 90 90 90-c3 c3 c3 c3 c3 c3 c3 c3  ................

检查虚拟到物理:

kd> !vtop 0 00000064a9b5fdd8
Amd64VtoP: Virt 00000064a9b5fdd8, pagedir 000000001b1b9000
Amd64VtoP: PML4E 000000001b1b9000
Amd64VtoP: PDPE 0000000019bbdc90
Amd64VtoP: PDE 00000000416bea68
Amd64VtoP: PTE 00000000501bfaf8
Amd64VtoP: Mapped phys 0000000039fcfdd8
Virtual address 64a9b5fdd8 translates to physical address 39fcfdd8.

仔细检查物理地址:

kd> !db 0000000039fcfdd8 L10
#39fcfdd8 90 90 90 90 90 90 90 90-c3 c3 c3 c3 c3 c3 c3 c3 ................

现在检查PTE:

kd> !dq 00000000501bfaf8 L1
#501bfaf8 82b00000`39fcf867 

将PTE转换为二进制:

kd> .formats 82b00000`39fcf867
Evaluate expression:
  Hex:     82b00000`39fcf867
  Decimal: -9029717251904964505
  Octal:   1012600000007177174147
  Binary:  10000010 10110000 00000000 00000000 00111001 11111100 11111000 01100111
  Chars:   ....9..g
  Time:    ***** Invalid FILETIME
  Float:   low 0.000482503 high -2.58609e-037
  Double:  -9.78598e-296

设置了最高有效位,这意味着NX位已设置,因此我们无法在堆栈上执行。

我们只想删除那个位,所以从技术上讲,只需删除半字节的高位部分(而不是0x82,我们将有0x02):

kd> .formats 02b00000`39fcf867
Evaluate expression:
  Hex:     02b00000`39fcf867
  Decimal: 193654784949811303
  Octal:   0012600000007177174147
  Binary:  00000010 10110000 00000000 00000000 00111001 11111100 11111000 01100111
  Chars:   ....9..g
  Time:    Fri Sep  2 12:34:54.981 2214 (UTC + 1:00)
  Float:   low 0.000482503 high 2.58609e-037
  Double:  9.78598e-296

重写PTE:

kd> !eb 501bfaf8+7 02

重写的PTE:

kd> !db 501bfaf8
#501bfaf8 67 f8 fc 39 00 00 b0 02-

kd> !dq 501bfaf8 L1
#501bfaf8 02b00000`39fcf867

执行:

kd> g

然后在user-land中执行堆栈没问题:)

enter image description here

  

我听说GDT也有类似NX-Bit的东西可以阻止它   堆栈执行,GDT执行预防之间的差异是什么   和寻呼级别的NX-Bit?

嗯,没有像GDT中NX位这样的东西......而且你在x64(仅GS和FS)中没有CS,DS,SS,ES的任何段描述符。

  

为什么有4级定义nx-bit?正在改变其中一个   上面的条目如pml4e会影响所有其他条目吗?

完全:)这可能会产生有趣的副作用,例如将PML4E的U / S位从S(Supervisor)更改为U(User),使用户访问此条目引用的所有页面...