Archive for the ‘平台’ Category

DLL转发

动态链接库的静态链接导致程序的DLL劫持漏洞-借助QQ程序xGraphic32.dll描述

[编程交流]DLL转发技术,实现程序隐藏与自启动(下)

#GDT

http://book.51cto.com/art/200812/103206.htm

段描述符表基址保存在gdtr寄存器中,gdtr寄存器由base32和limit16两个字段组成,limit最大值是0xFFFF,而每个段描述符占8字节,因此段描述符表中最多只能有8192((0xFFFF+1)/8)个段描述符。另一方面段寄存器中保存着段选择子,也因为每个段描述符占8字节,因此只需要前13位保存其在段描述符表中的索引号(前13位+后3位置0也能很快定位其偏移量),后3位则可以用作其他用途(1位TI指示段描述符在GDT还是LDT中,2位CPL指示当前特权级)。

r gdtr查看gdtr中保存的GDT基址。

dg (Display Selector)
The dg command shows the segment descriptor for the specified selector.

Syntax
dg FirstSelector [LastSelector]

Parameters
FirstSelector
Specifies the hexadecimal selector value of the first selector to be displayed.
LastSelector
Specifies the hexadecimal selector value of the last selector to be displayed. If this is omitted, only one selector will be displayed.

更多请参考WinDbg帮助手册,如dg 0 8显示前两个段描述符。

内存访问

代码访问内存是通过古老的段+偏移的方式确定内存地址(逻辑地址--->线性地址),保护模式下段寄存器中保存的并不是段的基址,而是16位的段选择子,由段描述符表的索引号(即高13位,低3位置0时就是偏移量了)+1位 TI+2位RPL组成。其中CS寄存器的低两位保存着当前正在执行的代码所在的段的特权级(CPL),而段描述符表中又保存着DPL,因此用户空间和系统空间得以分离。举例来说,Ring3下某进程访问Ring0中的数据,CPU会先从CS寄存器中取得CPL=3,然后比较要访问的数据所在段的段描述符DPL=0,当不满足CPL<=DPL时,为访问违例。

CPU取指也需要访问内存,但应该不会通过段寄存器--->段描述符表--->比较CPL和DPL这么复杂,而是由硬件完成,因此独立的一段代码段应该在一致CPL/RPL中。要跳转到非一致的代码段必须通过系统机制(【原创】rootkit ring3进ring0之门系列[一] -- 调用门【求助】关于异常发生后保护模式下权限转移疑惑)。

段选择子

用比喻类比说明CPU的特权级DPL - CPL - RPL

段描述符伪代码:

union
{
    struct
    {
        unsigned short Segment Limit 0...15
        unsigned short Base Address 0...15
    }
    int 32
}
union
{
    struct
    {
        unsigend char Base Address 16...23
        unsigend char TYPE 4bit/S 1bit/DPL 2bit/P 1bit (先定义的在低位)
        unsigend char Segment Limit 16...19 4bit/AVL 1bit/Reserved 1bit/D/B 1bit/G 1bit (先定义的在低位)
        unsigend char Base Address 24...31
    }
    int 32
}

段描述符

#逻辑地址—>线性地址—>物理地址

#逻辑地址--->线性地址--->物理地址
http://blog.csdn.net/do2jiang/article/details/4512417
http://hi.baidu.com/iaaie/blog/item/3b34ce26266c403cc9955900.html

逻辑地址--->线性地址:Intel为了向后兼容其段式内存管理而设计,Windows虚拟内存空间中的地址即逻辑地址,Windows将逻辑地址到线性地址的映射设计为线性关系,只使用段地址进行GDT和LDT的选择,及访问控制。其GDTR、LDTR寄存器中保存的是线性地址。

线性地址--->物理地址:Intel页式管理,CR3寄存器中保存的是物理地址。

一次转译过程:程序中访问某地址(逻辑地址)--->查GDT(假设是GDT),GDTR中保存的是线性地址,因此也要查询其物理地址--->CR3中是物理地址,因此能定位页目录表的物理地址--->PDE(前20位)中存放是PTE的物理地址,因此能查询到GDTR的物理地址。剩下的不写了。

关于句柄表

记得《Windows核心编程》中说过,一个进程的句柄直接给另一个进程使用很有可能会出错,因为句柄就是个索引值嘛,可能在另一个进程中这个索引值就指向它打开的其它内核对象了。

悲催的没仔细研究,想当然的认为句柄值应该是从小到大,根据打开内核对象的次序依次分配的。尤其是在父进程创建子进程的过程中,父进程可继承的句柄值应该先挑出来,然后在子进程中依次重新分配。结果不然。假设父进程有512个句柄值,只有第512个句柄值可继承,那么子进程中该句柄值还是512*4(之前我想当然的以为是子进程初始句柄值+4,即能分配的最小的句柄值)!也就是说从父进程中继承来的句柄,其索引值在子进程中是不会变的!

无觅相关文章插件,快速提升流量