|
前言
所有掩护模式索引链接:掩护模式笔记一 掩护模式介绍
在先前的掩护模式笔记七 CALL 长调用与短调用中没有详细分析长调用的实例,接下来补充其须要的相关知识:调用门
调用门
调用门的作用
调用门可以用来提权,通过提权可以实现访问高地址空间等RING0(内核)层才能进行的操纵
调用门和长调用关系
回首先前的笔记可知:
长调用CALL FAR CS:EIP指令要调用的地址是由CS段选择子查GDT得到的调用门 段描述符得来的,后面的EIP不发挥作用
调用门执行流程
- 根据CS的值 查GDT,找到对应的段描述符 这个描述符是一个调用门
- 在调用门描述符中存储另一个代码段的选择子
- 选择子指向的段 段.Base + 偏移地址 就是真正要执行的地址
调用门描述符
对比段描述符
调用门描述符结构
当一个段描述符是一个调用门描述符时,有以下特征:
- S位为0,体现该段描述符为系统段描述符(调用门描述符属于系统段描述符)
- Type域为1100,体现该段描述符为32位调用门
- 低16位到31位由本来的基地址变为存储一个段选择子,该段选择子才和代码真正要调用的地址相关
- 真正要调用的地址 = 段选择子所指向的段.Base + 32位的段中偏移 (段中偏移分为两部分:高位31-16位和低位15-0位)
- 段.Base默认为0,故真正要调用的地址 = 32位的段中偏移
给出段描述符和调用门描述符各部分的对比(上半部分为段描述符,下半部分为调用门描述符):
数据位31-242322212019-161514-131211-87-0寄义BaseGD/B0AVLSeg.LimitPDPLSTypeBase解释基地址粒度默认操纵大小固定为0用于系统软件使用段大小限制有效位特权品级描述符范例段范例基地址数据位31-161514-131211-87-54-0寄义offsetPDPLSType无param.count解释段中偏移有效位特权品级值为0值为1100值为000参数计数数据位31-1615-0寄义Base AdressSegment Limit解释基地址段大小限制数据位31-1615-0寄义selectoroffset解释段选择子段中偏移构造无参调用门描述符
了解了调用门描述符的结构后,尝试本身构造一个无参的调用门描述符,如下:
数据位31-161514-131211-87-54-0寄义offsetPDPLSType无param解释段中偏移有效位特权品级值为0值为1100值为000参数值(二进制)0111011000000000数据位31-1615-0寄义selectoroffset解释段选择子段中偏移值(十六进制)0x00080得到调用门描述符为:0000EC00`00080000
段中偏移临时不明白要调用的代码段,先置0
示例代码
接下来给出一段演示代码:
#include #include __declspec(naked) void callGate(){ _asm{ int 3 //软中断 retf //留意这里长调用对应长返回 } }int main(){ char buff[6]; //*(DWORD*)&buff[0]= 0x12345678; //低地址32位为0x12345678,EIP已废弃,故随便填即可 //*(DWORD*)&buff[4]=0x48; //高地址16位为0x48,段选择子 //也可以换作这种写法 _asm{ mov dword ptr ds:[buff],0x12345678 //低32位赋值废弃EIP lea eax,dword ptr ds:[buff] //将buff地址给EAX add eax,4 //地址+4,即得到高地址 mov word ptr ds:[eax],0x48 //高16位赋值段选择子selector } //使用 调用门 _asm{ call fword ptr ds:[buff] //fword 数据宽度为6字节 } return 0;}代码阐明
代码非常简单,主要分为两部分:
- callGate:调用门真正要调用的函数,先软中断,然后长返回
- main:先构造一个CS:EIP,这里为0x48:0x12345678,然后使用调用门
关于构造CS:EIP,可以观察到赋值后buff在内存中的存储情况:
可以看到CS:EIP在内存中由高地址到低地址存储,为0x004812345678
将门描述符写入GDT
在代码中,CS的也就是段选择子的值为0x48,该选择子指向的GDT的地址为要写入的地址
关于Selector和GDT地址的对应关系在掩护模式笔记三 段描述符和段选择子中已经阐明过了,这里不再赘述
确定门描述符
在写入GDT前,还须要确定要写入的值,前面已经构造好了的门描述符为:0x0000EC00`00080000
但其段中偏移还未确定,于是使用VC++ 6.0检察要调用的代码的地址:
进入debug模式,中断后,选中callGate函数,然后右键→Go to Disassembly(检察反汇编)
可以得到要调用的函数的地址为0x00401020
将得到的要调用的函数地址填入门描述符中对应的offset得到:
- 原:0000EC00`00080000
- 现:0040EC00`00081020
于是得到确定的门描述符为0040EC00`00081020
写入门描述符
确定完门描述符和要写入的地址后,就可以将其写入GDT了,操纵如下:
指令如下:
r gdtr 检察gdtrdq 0x8003f000 以qword检察地址,这里的地址为上面得到的gdtr地址eq 8003f048 0040EC00`00081020 写入门描述符dq 0x8003f000 检察是否写入成功过程图如下:
执行代码
执行代码结果如下:
Windbg获取到了代码中的int 3断点
可以看到此时中断的地址正是门描述符中的偏移地址(要调用的地址 = 段.Base+Offset,Base默认为0,故要调用的地址就直接等于门描述符中的offset)
本来的Ring3(应用)层的int 3断点不会被Windbg所捕获,但这里通过门描述符提权后变为了Ring0(内核层)权限,故会引起Windbg的捕获
可以检察此时的寄存器情况:
r
此时的CS正是前面构造的门描述符中的selector(选择子)
接下来继续单步执行
t
可以看到int 3的下一行代码位retf,也就是callGate函数里的代码中的下一行,由此可以确定调用成功
对比执行前后寄存器
前面只提到了CS段寄存器的变革,现在来总览对比执行前后寄存器的变革:
执行前寄存器情况
在使用调用门的汇编语句处下断点,断下后得到:
得到此时的寄存器情况:
寄存器值ESP12FF2CEBP12FF80CS1BDS23ES23SS23FS3BGS0执行后寄存器情况
得到此时的寄存器情况:
寄存器值ESPB1026DD0EBP12FF80CS08DS23ES23SS10FS30GS0变革对比
寄存器执行前值执行后值是否变革ESP12FF2CB1026DD0√EBP12FF8012FF80×CS1B08√DS2323×ES2323×SS2310√FS3B30√GS00×可以得出变革的寄存器有:ESP、CS、SS、FS
通过调用门提权后,前后寄存器的变革涉及到TSS,这里先记录下变革,详细细节留作之后
构造有参调用门描述符
示例代码
#include #include int a,b,c; __declspec(naked) void callGate(){ _asm{ pushad //将所有32位通用寄存器压入堆栈 pushfd //将32位标志寄存器EFLFAGS压入堆栈 //关于为何是通过ESP+XXX寻址详见后续的堆栈情况阐明 mov eax,[esp+0x24+0x8+0x8] //从堆栈中取出第一个参数 mov dword ptr ds:[a],eax //将取出的参数赋值给全局变量a mov eax,[esp+0x24+0x8+0x4] //从堆栈中取出第二个参数 mov dword ptr ds:,eax //将取出的参数赋值给全局变量b mov eax,[esp+0x24+8+0] //从堆栈中取出第三个参数 mov dword ptr ds:[c],eax //将取出的参数赋值给全局变量c popfd //将所有32位通用寄存器出栈 popad //将所有32位标志寄存器EFLFAGS出栈 retf 0xC//留意这里长调用对应长返回,堆栈平衡 0xC=12=3*4=参数个数*参数的数据宽度(单元字节) } }int main(){ char buff[6]; //*(DWORD*)&buff[0]= 0x12345678; //低地址32位为0x12345678,EIP已废弃,故随便填即可 //*(DWORD*)&buff[4]=0x48; //高地址16位为0x48,段选择子 //也可以换作这种写法 _asm{ mov dword ptr ds:[buff],0x12345678 //低32位赋值废弃EIP lea eax,dword ptr ds:[buff] //将buff地址给EAX add eax,4 //地址+4,即得到高地址 mov word ptr ds:[eax],0x48 //高16位赋值段选择子selector } //使用 调用门 _asm{ push 1 push 2 push 3 call fword ptr ds:[buff] //fword 数据宽度为6字节 } printf("%X\t%X\t%X\n",a,b,c); return 0;}代码阐明
与构造无参调用门描述符相比,主要变革为:
- 在使用调用门前压入了三个参数:1、2、3
- 调用代码作用为:①掩护现场(压入所有通用寄存器和标志寄存器);②从堆栈中取出对应的参数;③将取出的参数赋值给对应的全局变量
- 调用代码最后要平衡堆栈,ret 0xC 0xC=12=3*4=参数个数*参数的数据宽度(单元字节)
- 在调用结束后,输出调用后被赋值的全局变量,验证参数是否成功传递
堆栈情况阐明
堆栈调用情况按执行流程顺序依次阐明:
执行前(压入参数后)
记录下此时的堆栈情况:
地址相对栈顶地址值阐明0012FF20ESP3压入的第三个参数0012FF24ESP+42压入的第二个参数0012FF28ESP+81压入的第一个参数切换到调用代码后
记录下此时的堆栈情况:
地址相对栈顶地址值阐明B9CAFDC4ESP0040D4E8执行后要返回的地址B9CAFDC8ESP+0x41B执行后要恢复的段选择子:CSB9CAFDCCESP+0x83压入的第三个参数B9CAFDD0ESP+0xC2压入的第二个参数B9CAFDD4ESP+0x101压入的第一个参数B9CAFDD8ESP+0x140012FF20执行后要恢复的堆栈寄存器:ESPB9CAFDDCESP+0x1823执行后要恢复的段选择子:SS保存通用寄存器组后
记录下此时的堆栈情况:
地址相对栈顶地址值阐明B9CAFDA4~B9CAFDC0ESP~ESP+0x1C略通用寄存器组B9CAFDC4ESP+0x200040D4E8执行后要返回的地址B9CAFDC8ESP+0x20+0x41B执行后要恢复的段选择子:CSB9CAFDCCESP+0x20+0x83压入的第三个参数B9CAFDD0ESP+0x20+0xC2压入的第二个参数B9CAFDD4ESP+0x20+0x101压入的第一个参数B9CAFDD8ESP+0x20+0x140012FF20执行后要恢复的堆栈寄存器:ESPB9CAFDDCESP+0x20+0x1823执行后要恢复的段选择子:SS保存标志寄存器后
记录下此时的堆栈情况:
地址相对栈顶地址值阐明B9CAFDA0ESP0x202标志寄存器B9CAFDA4~B9CAFDC0ESP+0x4~ESP+0x4+0x1C略通用寄存器组B9CAFDC4ESP+0x4+0x200040D4E8执行后要返回的地址B9CAFDC8ESP+0x4+0x20+0x41B执行后要恢复的段选择子:CSB9CAFDCCESP+0x4+0x20+0x83压入的第三个参数B9CAFDD0ESP+0x4+0x20+0xC2压入的第二个参数B9CAFDD4ESP+0x4+0x20+0x101压入的第一个参数B9CAFDD8ESP+0x4+0x20+0x140012FF20执行后要恢复的堆栈寄存器:ESPB9CAFDDCESP+0x4+0x20+0x1823执行后要恢复的段选择子:SS将门描述符写入GDT
确定门描述符
先确定段中偏移:进入debug模式,中断后,选中callGate函数,然后右键→Go to Disassembly(检察反汇编)
可以得到要调用的函数的地址为0x0040D480
将得到的要调用的函数地址填入门描述符中对应的offset得到:
- 原:0000EC00`00080000
- 现:0040EC00`0008D480
因为此次调用门描述符须要传递三个参数,故修改为:
0040EC03`0008D480
PS:修改了门描述符结构中的param.count,如不熟悉可回首上面的 调用门描述符结构
于是得到确定的门描述符为0040EC03`0008D480
写入门描述符
确定完门描述符和要写入的地址后,就可以将其写入GDT了,操纵如下:
指令如下:
r gdtr 检察gdtrdq 8003f000 以qword检察地址,这里的地址为上面得到的gdtr地址eq 8003f048 0040EC03`0008D480 写入门描述符dq 8003f000 检察是否写入成功过程图如下:
执行代码
执行代码结果如下:
代码执行后,能够准确地输出三个参数,构造有参调用门描述符成功
总结
- 当通过门,权限稳定的时间,只会PUSH两个值:①CS(新的CS的值由调用门决定) ;②返回地址
- 当通过门,权限改变的时间,会PUSH四个值:①SS;② ESP;③ CS ;④ 返回地址 (新的CS的值由调用门决定 新的SS和ESP由TSS提供)
- 通过门调用时,要执行代码的地址由调用门中的选择子决定;使用RETF返回时,由堆栈中压入的返回地址决定
关于TSS的内容留作之后的笔记(* ̄3 ̄)╭
PS:写得比力匆忙,可能会有谬误之处,接待指出
</strong>
来源:http://www.12558.net
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
|