重写 读Win32 平台上用户级进程(其实就是本线程)的各段寄存器的值,并解析其指向的段的信息

; getSegInfo.asm
; 读Win32 平台上用户级进程(其实就是本线程)的各段寄存器的值,并解析其指向的段的信息
; 是对WOWOCOCK的一个例子程序的改写

include common.asm

.data
strtable tblSregsNames, TXT("cs"), TXT("ds"), TXT("ss"), TXT("es"), TXT("fs"), TXT("gs"), \
         TXT("ldtr"), TXT("tr")

strtable tblTableNames, TXT("gdt"), TXT("ldt")
strtable tblPresent, TXT("NOT present"), TXT("present")
strtable tblGran, TXT("byte"), TXT("4KB")

strtable tblDataSegClass,\
         TXT('不可写数据段'),TXT('不可写数据段, 已访问'),TXT('可写数据段'),TXT('可写数据段, 已访问'),\
         TXT('不可写数据段, 向下扩展'),TXT('不可写数据段, 向下扩展,已访问'),\
         TXT('可写数据段, 向下扩展'),TXT('可写数据段, 向下扩展,已访问')
strtable_cont TXT('不可读代码段'),TXT('不可读代码段, 已访问'),TXT('可读代码段'),TXT('可读代码段, 已访问'),\
         TXT('不可读代码段, 一致性'),TXT('不可读代码段, 一致性, 已访问'),\
         TXT('可读代码段, 一致性'),TXT('可读代码段, 一致性, 已访问')
          
strtable tblSystemClass,TXT('保留'),TXT('16位TSS段(可用)'),TXT('LDT段'),TXT('16位TSS段(忙)'),\
         TXT('16位调用门'),TXT('任务门'), TXT('16位中断门'),TXT('16位陷阱门')         
strtable_cont TXT('保留'),TXT('32位TSS段(可用)'), TXT('保留'),TXT('32位TSS段(忙)') ,\
         TXT('32位调用门'),TXT('保留'), TXT('32位中断门'),TXT('32位陷阱门')

strtable tblClasses, offset tblSystemClass, offset tblDataSegClass ; 二级表
        
        
.code        
PrintSegInfo proc uses ebx esi edi pszBuf, pszSegName, selector
        local   @szBuf[256]:byte
        
        ; 检查有效性
        .if !(selector & 0FFF8H) ;NULL
                invoke  wsprintf,pszBuf,CTXT('%s = %04X --> null', CR, LF),\
                                pszSegName,selector
                ret
        .endif
        
        mov     eax, selector
        mov     edx, eax
        mov     ecx, eax
        mov     ebx, eax
        
        and     eax, 011B       ;get RPL
        and     edx, 0FFF8H     ; get offset in table
        shr     ecx, 3         ; get index into table
        
        shr     ebx, 2          
        and     ebx, 1 ; get table index
        
        invoke  wsprintf,pszBuf,\
                   CTXT('%s = %04X: ti = %d, 指向的段描述符是%s的第%04X个(offset = %04X), rpl = %d', CR, LF),\
                   pszSegName, selector, ebx, tblTableNames[ebx*4], ecx, edx, eax
        
        ;msgbox ,pszBuf

comment ^
lar : load access rights byte 全取出来

lar r16, r/m16  
    r16<-描述符的高32位 masked by FF00H
    (jcw: mask即and 位与)
    
lar r32, r/m32  
    r32<-描述符的高32位 masked by 00FxFF00H

获得指定段选择子对应的段描述符描述的段的存取权限字节。若加载成功,置ZF,否则清ZF。
如果操作数长度是32位的,那么获得的存取权限值包括type, DPL字段,以及S,P,AVL,D/B,G标志,这些
原来都在段描述符的高双字中。

本指令执行时会做的检查同lsl指令,除了对本指令有效的描述符还有调用门。
^
        
        lar     ebx, selector
        .if !zero? ;ZF=0
        ; 选择子可能超出所在表的范围; 指向数据段或非一致代码段且其DPL特权级高于CPL或选择子的RPL级别;
        ; 是以下系统描述符:16位中断门、16位陷阱门、32位中断门、32位陷阱门、保留类型
                invoke  lstrcat,pszBuf, \
                CTXT('    |',CR,LF,'    选择子无效, 或对应的描述符因为其类型或特权级而在当前特权级下不允许被访问',CR,LF,CR,LF)

                ret
                ; 取不到属性字节的选择子更不会取到段偏移上限, 也不会是在当前特权级下可读或可写的代码段或数据段
        .endif
        
        ; got access rights: 输出各种属性信息
        invoke  lstrcat,pszBuf,CTXT('   --> 描述符属性: ',CR,LF)
        
        .if ebx & 8000h ;P
                mov     eax, 1
        .else
                mov     eax, 0
        .endif
        invoke  wsprintf,addr @szBuf,CTXT(TAB,'p = %d, %s',CR,LF),eax,tblPresent[eax*4]
        invoke  lstrcat,pszBuf,addr @szBuf

        ;msgbox ,addr @szBuf
        
        .if ebx & 1000h ;S
                mov     eax, 1
        .else
                mov     eax, 0
        .endif
        mov     esi, tblClasses[eax*4]
        
        mov     edx, ebx
        shr     edx, 8
        and     edx, 0Fh ; TYPE
        
        invoke  wsprintf,addr @szBuf,CTXT(TAB,'s = %d, type = %X, %s; '),\
                        eax, edx, dword ptr [esi+edx*4]
        invoke  lstrcat,pszBuf,addr @szBuf

        ;msgbox ,addr @szBuf
        
        .if ebx & 400000H ; D/B  =32
                invoke  wsprintf,addr @szBuf,CTXT('d/b = %d, 默认操作数长度为%d位; '),1,32
        .else ;16
                invoke  wsprintf,addr @szBuf,CTXT('d/b = %d, 默认操作数长度为%d位; '),0,16
        .endif
        invoke  lstrcat,pszBuf,addr @szBuf
         
        ;msgbox ,addr @szBuf
        
        mov     eax, ebx
        shr     eax, 13
        and     eax, 3  ; DPL
        
        mov     edx, ebx
        shr     edx, 20
        and     edx, 1 ; avl
        invoke  wsprintf,addr @szBuf,\
                        CTXT('dpl = %d',CR,LF,TAB,'avl(软件可利用位) = %d; '),eax,edx
        invoke  lstrcat,pszBuf,addr @szBuf
        
        mov     eax, ebx
        shr     eax, 23
        and     eax, 1
        invoke  wsprintf,addr @szBuf,CTXT('g = %d, 段偏移上限的单位为%s',CR,LF),\
                        eax,tblGran[eax*4]
        invoke  lstrcat,pszBuf,addr @szBuf

        ; 看是不是数据、代码段或是系统段;调用门、任务门没有段偏移上限这个属性
        ;.if ebx & 1000h ; S
        ;       ;get_seg_limit ; code / data seg
        ; .endif
        ; 不用麻烦了,直接执行lsl,看ZF
 
comment ^
lsl: load segment limit 加载指定段选择子关联的段的偏移上限

        lsl r16, r/m16  
            load: r16<-segment limit, selector r/m16
            
        lsl r32, r/m32  
            load: r32<-segment limit, selector r/m32

        若加载成功,获得指定段选择子对应的段描述符经解码后的段限长。若加载成功,置ZF,否则清ZF。
        段限长包含在段描述符的第0和第1字节以及第6字节的低4位中。
        得到的结果是以字节计。若段描述符的段限长粒度为4KB,会先被换算成粒度为1字节的值。
        若操作数长度为16位,计算的结果值是有效的32位值,那么高16位会被截掉,只保留低16位到目的寄存器中。
        
        本指令执行时会做以下检查:
        选择子不是NULL;
        选择子指向的描述符是在GDT或LDT的限长范围内;
        描述符类型是对本指令有效的:所有代码和数据段描述符是有效的。此外还有LDT、Task段描述符;
        若该段不是一致代码段,指令会检查该段描述符在当前特权级(CPL)下是否可见,即CPL、段选择子的RPL是否小于或等于段选择子的DPL。
^       
        ;get seg limit      
        lsl     eax, selector        
        .if !zero? ; 说明是调用门、任务门
                ret
        .endif

        ;got seg limit
        invoke  wsprintf,addr @szBuf,CTXT(TAB,'段内偏移上限为%08X',CR,LF), eax
        invoke  lstrcat,pszBuf,addr @szBuf
        
        ; 是不是数据或代码段,如果是系统段如TSS,则不能使用verr/verw
        .if ! (ebx & 1000h) ; system段
                ret
        .endif

comment ^
verr/verw: verify a segment for reading or writing

        verr/verw r/m16         ; set ZF=1 if segment specified with r/m16 can be read/written
        verify whether the code or data segment specified with the source operand is readable or writable from the current privilege level(CPL).
        If the segment is accessible and readable (VERR) or writable (VERW), the ZF flag is set; otherwise, the ZF flag is cleared. Code segments are never verified as writable. This check cannot be performed on system segments.
        
        执行完设置ZF的条件如下:
        选择子不是NULL;
        选择子指向的描述符是在GDT或LDT的限长范围内;
        选择子指向的段必须是代码段或数据段(不能是系统段或门);
        该段可读(VERR)或该段是可写的数据段(VERW);
        若该段不是一致代码段,指令会检查该段描述符在当前特权级(CPL)下是否可见,即CPL、段选择子的RPL是否小于或等于段选择子的DPL。
^
        ;verify r w: 在当前特权级下可写不?
        verr    word ptr selector
        .if zero?
                invoke  lstrcat,pszBuf,CTXT('在当前特权级下可读; ')
        .else
                invoke  lstrcat,pszBuf,CTXT('在当前特权级下不可读; ')
        .endif

        verw    word ptr selector
        .if zero?
                invoke  lstrcat,pszBuf,CTXT('在当前特权级下可写', CR, LF)
        .else
                invoke  lstrcat,pszBuf,CTXT('在当前特权级下不可写', CR, LF)
        .endif

        ret
PrintSegInfo endp


start   proc
        local   @gdt:fword,@idt:fword  
        ; fword是3个word, 即6个字节,对应df, 是far指针的意思:32位偏移再加16位段选择子
        local   @sregs[8] ; 各段寄存器的值,按cs,ds,ss,es,fs,gs,ldt,tr顺序存储
        local   @szBuf[2048]:byte
        
        sgdt    fword ptr @gdt
        sidt    fword ptr @idt
        
        mov     @sregs[0*4], cs ;生成的指令是mov word ptr [xxx],cs
        mov     @sregs[1*4], ds
        mov     @sregs[2*4], ss
        mov     @sregs[3*4], es
        mov     @sregs[4*4], fs
        mov     @sregs[5*4], gs
        sldt    word ptr @sregs[6*4]
        str     word ptr @sregs[7*4]
                
comment /* ; 读cs指向的段描述符
        mov     ebx, dword ptr @gdt+2
        mov     eax, cs
        and     eax, 0FFF8H     ;去掉RPL域与TI位
        mov     eax, [ebx+eax] ; 一个段描述符占8个字节, 但这里不用乘以8
        mov     edx, [ebx+eax+4] ; edx: eax
        ; 上面那2条指令执行出现异常,因为gdt为Ring0级
        */
        
        movzx   eax, word ptr @gdt ; 表中最后一个字节的偏移
        movzx   edx, word ptr @idt
        movzx   ecx, word ptr @sregs[6*4] ; 16位零扩展到32位
        movzx   ebx, word ptr @sregs[7*4]
        
        invoke  wsprintf, addr @szBuf,\
CTXT("gdt @ %08X, 上限偏移 = %04X",CR,LF,"idt @ %08X, 上限偏移 = %04X",CR,LF,"ldtr = %04X(selector)",CR,LF,"tr = %04X(selector)",CR,LF,CR,LF),\
                        dword ptr @gdt+2, eax, dword ptr @idt+2, edx, ecx, ebx
                        
        ;msgbox ,addr @szBuf
                        
        ;mov     eax, cs ; 不能用push cs, 因为其等价于sub esp, 4; mov word ptr [esp], cs
        ;push    eax
        xor     ebx, ebx
        .while ebx<8
                invoke  lstrlen, addr @szBuf
                lea     eax, @szBuf[eax]
                movzx   edx, word ptr @sregs[ebx*4] ;16位零扩展到32位
                invoke  PrintSegInfo, eax, tblSregsNames[ebx*4], edx
                invoke  lstrcat, addr @szBuf, CTXT(CR,LF)
                
                inc     ebx
        .endw
                
        msgbox ,addr @szBuf,CTXT("查看系统寄存器及段的信息")

        ret
start   endp


        end     start


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值