Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html
调用门
问题索引:
1. 调用门的"门"这字的含义。
2. 如果通过这扇门走?
3. 为什么需要调用门?
4. 为何构造call时数组前四位随便写?
5. 调用门构造实验
6. 远调用的特点?
7. 远调用带参数实验
8. 远调用提权实验
9. 权限的CALL指令的门权限检查
10.call调用门提权,iretd降权实验
问题解答:
1. 调用门的"门"这字的含义。
门-通往另外一个世界的通道,同时也是一种控制的阻碍。2. 如果通过这扇门走?
Segment - 段选择子,通过这个段选择子来替换代码段寄存器。
Offset in Segment - 段内偏移,段只能提供基地址,但怎么走还是要看在基地址基础上计算偏移量的。
3. 为什么需要调用门?
方便权限控制,可以不改变R3层的调用方式的基础上改变调用权限来实现控制效果(写好的代码不变,但我可以让你不通过)。
4. 为何构造call时数组前四位随便写?
这四位应该本应该写偏移量的,但是调用门中自带着段内偏移,因此我们并不需要这四位,直接随便填写即可。
5. 调用门构造实验
实验原理:构造调用门,然后执行调用门中指向的函数。
#include "stdafx.h" #include <stdlib.h> __declspec(naked) void callgate(){ __asm{ int 3; retf; } } int main(int argc, char* argv[]) { char buf[6] = {0}; *(int*)&buf[0] = 0x12345678; *(short*)&buf[4] = 0x4b; printf("%x ",callgate); getchar(); __asm{ call fword ptr buf; } system("pause"); return 0; }
windbg进行如下修改
eq 8003f090 00cf9b00`0000ffff (代码段描述符)
eq 8003f048 0040ec00`00901005 (调用门,指向代码段)
6. 远调用的特点?
call far,当使用调用门时,就是远程调用。
远程调用即需要切换环境,至少保存四个值 ret,cs,ss,esp
只要执行远call,其就会切换堆栈(下面实验我们就可以看出)
7. 远调用带参数实验
实验思路:我们在0环读取gdtr表,如果提权成功则可以读取,否则不可以读取。
#include "stdafx.h" #include <stdlib.h> __declspec(naked) void callgate(){ __asm{ int 3; retf 0x4; } } int main(int argc, char* argv[]) { char buf[6] = {0}; *(int*)&buf[0] = 0x12345678; *(short*)&buf[4] = 0x4b; printf("%x ",callgate); getchar(); __asm{ push 0x12345678; call fword ptr buf; } system("pause"); return 0; }
windbg 修改 调用门参数 (承接上个实验)
eq 8003f048 0040ec01`00901005 (添加一个参数)
堆栈如下:
从中我们可以看出,只要通过调用门,其会另其一套堆栈,同时还需要记住参数的压栈顺序,参数是在中间部分。
另外,retf 0x4, 不仅平衡三环的堆栈,也是平衡零环的堆栈。
8. 远调用提权实验
实验思路:我们在0环读取gdtr表,如果提权成功则可以读取,否则不可以读取。
// callgate.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <stdlib.h> int value = 0; __declspec(naked) void callgate(){ __asm{ //int 3; pushad; pushfd; mov eax,dword ptr ds:[0x8003f008]; mov value,eax; popfd; popad; retf 0x4; } } int main(int argc, char* argv[]) { char buf[6] = {0}; *(int*)&buf[0] = 0x12345678; *(short*)&buf[4] = 0x48; printf("%x ",callgate); getchar(); __asm{ push 0x12345678; call fword ptr buf; } printf("%x ",value); system("pause"); return 0; }
实验效果
9. 权限的CALL指令的门权限检查
其需要经过两关来检查:
门检查 max(CPL,RPL) <= DPL
CPL >= 代码段的DPL
10.call调用门提权,iretd降权实验
iretd用于其中断返回的,注意其堆栈的变化。
#include "stdafx.h" #include <stdlib.h> int value = 0; __declspec(naked) void callgate(){ __asm{ //int 3; pushad; pushfd; mov eax,dword ptr ds:[0x8003f008]; mov value,eax; popfd; popad; pop eax; pop ebx; pushfd; push ebx; push eax; iretd; } } int main(int argc, char* argv[]) { char buf[6] = {0}; *(int*)&buf[0] = 0x12345678; *(short*)&buf[4] = 0x48; printf("%x ",callgate); getchar(); __asm{ call fword ptr buf; } printf("%x ",value); system("pause"); return 0; }