【火哥学习笔记】挂载物理页(实验)

10-10-12分页

前置知识:

为了便于给新的进程挂载物理页,10-10-12分页中,规定了一个线性地址0xc0300000指向的物理地址就是CR3,即PDT表的首地址、Dirbase

我们可以用线性地址0xc0300000 获取PDT表的首地址,还可以用0xc0000000 获取PTT表的首地址

火哥实验代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
char shellcode[] = {0x6a,0,0x6a,0,0x6a,0,0x6a,0,0xe8,0,0,0,0,0xc3};
/* shellcode代码 功能是实现messagebox弹窗
我们的目的就是将线性地址offset1所在的页(也就是0所在的页) 挂载到 shellcode线性地址对应的物理地址上
为什么是offset? 因为分页机制,一个页为4KB 这里使用的是char申请的静态全局变量,不能保证其就在某一页的首部
而如果我们使用malloc申请一个0x1000大的空间(刚好一个页) 就可以满足后文的 call 0;
*/
__declspec(naked) void test()
{
__asm
{
push 0x30;
pop fs;// fs权限修改 默认R0用0x30段选择子
pushad;
pushfd;//保存现场

lea eax,shellcode;
mov ebx,dword ptr ds:[0xc0300000];
test ebx,ebx;
je __PDE; // 看一下PTD表第一项的PTE是否存在 不存在的话
__PTE:
shr eax,12;
and eax,0xfffff;
shl eax,2;
add eax,0xc0000000;
/*
这里是比较巧妙的,自己重温的时候写写草稿
首先是将shellcode的PDT下标 放置到 新线性地址PTT下标的位置来,然后将 shellcode的PTT下标*4 放置到 新线性地址PTT偏移的位置来

①首先我们查PTD表 偏移为0xc00 通过前置知识我们知道查到的是CR3 结果也就是PDT表首地址
②然后"查PTT表" 因为我们存的是shellcode的PDT下标,这里相当于是在查PDT表 但是因为两者计算方式一样,我们得到的是shellcode对应的PTT表首地址
③最后"加偏移" 因为我们存的是shellcode的PTT下标*4,所以这里相当于是在查PTT表,我们的得到的是shellcode对应的物理地址

*/
mov eax,[eax];
mov dword ptr ds:[0xc0000000],eax;
/*
由前置知识可知,线性地址0xc0000000 就是第一项PDE对应的PTT首地址
然后把物理地址的值取出来 替换线性地址0(与offset同) 对应的PTE
*/
jmp __ret;

__PDE:
shr eax,22;
and eax,0x3ff;
shl eax,2;

add eax,0xc0300000;
mov eax,[eax];
mov dword ptr ds:[0xc0300000],eax;
/*感觉火哥这里是有问题的 挂了PDE 还要继续挂PTE 不然进入了正确的PTT表但是没有正确的偏移
自己认为的解决方法是 这里添加一个汇编语句: jmp __PTE;
但是因为大部分程序第一个PTE都存在,而且强制修改为0要蓝屏,就无法验证对错
*/
__ret:
popfd;
popad;//还原现场
retf
}

}

int main()
{
int addr = (int)MessageBox;
int offset1 = ((int) shellcode) & 0xfff;
*((int*)(&shellcode[9])) = addr - (13 + offset1);
char buf[6] = {0,0,0,0,0x48,0};
printf("MessageBox:%X test:%X shellcode:%X\n",MessageBox,test,shellcode);
system("pause");


__asm
{
call fword ptr buf;
push 0x3b;
pop fs;
mov eax,offset1;
call eax;
}

return 0;
}

2-9-9-12 分页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
char shellcode[] = {0x6a,0,0x6a,0,0x6a,0,0x6a,0,0xe8,0,0,0,0,0xc3};
// shellcode代码 功能是实现messagebox弹窗
__declspec(naked) void test()
{
__asm
{
push 0x30;
pop fs;
pushad;
pushfd;

lea eax,shellcode;
mov ebx,0xc0000000;

mov ecx,eax;
shr ecx,30;
and ecx,0x3;
shl ecx,21;
add ebx,ecx; // PDPTE

mov ecx,eax;
shr ecx,21;
and ecx,0x1ff;
shl ecx,12;
add ebx,ecx; // PDE

mov ecx,eax;
shr ecx,12;
and ecx,0x1ff;
shl ecx,3;
add ebx,ecx; // PTE
/*
具体原理同上10-10-12分页
这里默认为线性地址0 有挂物理页 而我们的目标就是修改PTE项
规则为 使用`0xC0000000 + i*0x200000 + j*0x1000 + k*8 ` 就可以获得第`i+1`项`PDPTE`对应的第`j+1`项`PDE`对应的第`k+1`项`PTE`的地址
*/

mov ebx,[ebx];
mov dword ptr ds:[0xc0000000],ebx;

popfd;
popad;
retf
}

}

int main()
{
/*
int* p = (int*)VirtualAlloc(0,0x1000,0x1000 | 0x2000,0x40);
if(p == NULL)
{
printf("分配内存失败\n");
return 0;
}
*p = 1;
*/ //原本以为线性地址0没有挂物理页 想通过这个方法让他先挂上 结果它其实是有挂物理页的
int addr = (int)MessageBox;
int offset1 = ((int) shellcode) & 0xfff;
*((int*)(&shellcode[9])) = addr - (13 + offset1);
char buf[6] = {0,0,0,0,0x48,0};
printf("MessageBox:%X test:%X shellcode:%X\n",MessageBox,test,shellcode);
system("pause");

__asm
{
call fword ptr buf;
push 0x3b;
pop fs;
mov eax,offset1;
call eax;
}

return 0;
}