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

来源:互联网 发布:证件照ps软件 编辑:程序博客网 时间:2024/05/16 17:44
备份百度空间上的文章
2011-04-15 05:50

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

 

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

;      改写自WOWOCOCK
.686p
.model  flat, stdcall
option  casemap: none

include windows.inc
include kernel32.inc
include user32.inc
includelib kernel32.lib
includelib user32.lib

CR      EQU     0DH
LF      EQU     0AH

.data?
szBuf           db      2048 dup (?)
szBuf2          db      256 dup (?)


.data
_gdt    df      ? ; fword是3个word, 即6个字节,对应df
_idt    df      ?

_cs     dd      ?
_ds     dd      ?
_ss     dd      ?
_es     dd      ?
_fs     dd      ?
_gs     dd      ?                    
_ldt    dd      ?
_tr     dd      ?
regNames dd     offset szCs, offset szDs, offset szSs, offset szEs
        dd      offset szFs, offset szGs, offset szLdtr, offset szTr
 
szCs            db      'CS', 0
szDs            db      'DS', 0
szSs            db      'SS', 0
szEs            db      'ES', 0
szFs            db      'FS', 0
szGs            db      'GS', 0
szLdtr           db     'LDTR', 0
szTr            db      'TR', 0
 
szTitle db      "查看系统寄存器及段的信息", 0

szFmtTables db  "GDT在%08X,上限偏移 = %04X;IDT在%08X,上限偏移 = %04X", CR, LF  
         db     "LDTR = %04X(选择子);TR = %04X(选择子)", CR, LF, CR, LF, 0
szFmtNullSel db '%s = %04X --> 空段', CR, LF, CR, LF, 0

tableIndex dd   offset szInGdt, offset szInLdt
szInGdt         db      'GDT', 0
szInLdt         db      'LDT', 0    
            
szFmtSel db      '%s = %04X;TI = %d,指向的段描述符是在%s的第%04X个,在偏移%04X处;RPL = %d', CR, LF, 0
         
szNoAccessRights db '    |', CR, LF
                 db  '    选择子无效,或者相应的描述符因为类型或是在当前特权级下不允许被访问', CR, LF
                 db  CR, LF, 0

szFmtAccessRights db '   --> 描述符属性:', CR, LF, 0

szNotPresent db '不存在', 0
szPresent db    '存在', 0
tblPresent dd   offset szNotPresent, offset szPresent
szFmtPresent      db '        P = %d,%s', CR, LF, 0

szReserved db   '保留', 0
szAvail16Tss db '16位TSS段(可用)', 0
szLdt   db      'LDT段', 0
szBusy16Tss db  '16位TSS段(忙)', 0
sz16CallGate db '16位调用门', 0
szTaskGate db   '任务门', 0
sz16IntGate db  '16位中断门', 0
sz16TrapGate db '16位陷阱门', 0
szAvail32Tss db '32位TSS段(可用)', 0
szBusy32Tss db  '32位TSS段(忙)', 0
sz32CallGate db '32位调用门', 0
sz32IntGate db  '32位中断门', 0
sz32TrapGate db '32位陷阱门', 0

szRoData db '不可写数据段', 0         ; Ro: read only
szARoData db '不可写数据段,已访问', 0
szWData db '可写数据段', 0
szAWData db '可写数据段,已访问', 0
szERoData db '不可写数据段,向下扩展', 0
szAERoData db '不可写数据段,向下扩展,已访问', 0
szEWData db   '可写数据段,向下扩展', 0
szAEWData db '可写数据段,向下扩展,已访问', 0
szEoCode  db  '不可读代码段', 0       ; Eo: execute only
szAEoCode db  '不可读代码段,已访问', 0
szRCode db    '可读代码段', 0
szARCode db   '可读代码段,已访问', 0
szCEoCode db  '不可读代码段,一致性', 0
szACEoCode db '不可读代码段,一致性,已访问', 0
szCRCode db   '可读代码段,一致性', 0
szACRCode db  '可读代码段,一致性,已访问', 0

tblDataSegClass       dd      offset szRoData, offset szARoData, offset szWData, offset szAWData
        dd      offset szERoData, offset szAERoData, offset szEWData, offset szAEWData
        dd      offset szEoCode, offset szAEoCode, offset szRCode, offset szARCode
        dd      offset szCEoCode, offset szACEoCode, offset szCRCode, offset szACRCode
        
tblSystemClass        dd      offset szReserved, offset szAvail16Tss, offset szLdt, offset szBusy16Tss
        dd      offset sz16CallGate, offset szTaskGate, offset sz16IntGate, offset sz16TrapGate
        dd      offset szReserved, offset szAvail32Tss, offset szReserved, offset szBusy32Tss
        dd      offset sz32CallGate, offset szReserved, offset sz32IntGate, offset sz32TrapGate
        
tblClasses  dd   offset tblSystemClass, offset tblDataSegClass
szFmtType db    '        S = %d,Type = %X,%s;', 0
szFmtDB     db  'D/B = %d,默认操作数长度为%d位;', 0
szFmtOther  db  'DPL = %d', CR, LF
         db     '        AVL(软件可利用位) = %d;', 0
szFmtG     db   'G = %d, 段偏移上限的单位为%s', CR, LF, 0      
    
szByte  db      '字节', 0
sz4KB   db      '4K字节', 0
tblG    dd      offset szByte, offset sz4KB

szFmtSegLimit   db      '段内偏移上限为%08X', CR, LF, 0
szCannotRead    db      '在当前特权级下不可读;', 0
szCanRead       db      '在当前特权级下可读;', 0
szCannotWrite   db      '在当前特权级下不可写', CR, LF, CR, LF, 0
szCanWrite      db      '在当前特权级下可写', CR, LF, CR, LF, 0

.code
showSegInfo proc uses esi edi ebx segName: dword, selector: dword
        ; 检查有效性
        mov     eax, selector
        and     eax, 0FFF8H
        jnz     @F        ;NULL?
null_sel:
                invoke  wsprintf, offset szBuf2, offset szFmtNullSel, segName, selector
                invoke  lstrcat, offset szBuf, offset szBuf2
                ret

@@:        
        mov     eax, selector
        and     eax, 011B       ;get RPL
        
        mov     edx, selector
        and     edx, 0FFF8H     ; get offset in table
        mov     esi, edx
        shr     esi, 3          ; get index in table
        
        mov     ecx, selector
        and     ecx, 100B
        shr     ecx, 2          ; get table index
 
        invoke  wsprintf, offset szBuf2, offset szFmtSel, segName, selector, ecx, tableIndex[ecx*4], esi, edx, eax
        invoke  lstrcat, offset szBuf, offset szBuf2
        
        lar     esi, selector
        jz      got_access_rights
        
                ; 选择子可能超出所在表的范围; 指向数据段或非一致代码段且其DPL特权级高于CPL或选择子的RPL级别;
                ; 是以下系统描述符:16位中断门、16位陷阱门、32位中断门、32位陷阱门、保留类型
                invoke  lstrcat, offset szBuf, offset szNoAccessRights
                ret
                ; 取不到属性字节的选择子更不会取到段偏移上限, 也不会是在当前特权级下可读或可写的代码段或数据段

got_access_rights: ; 输出各种属性信息
        invoke  lstrcat, offset szBuf, offset szFmtAccessRights
        
        xor     ebx, ebx
        test    esi, 8000H ;P
        setnz   bl
        invoke  wsprintf, offset szBuf2, offset szFmtPresent, ebx, tblPresent[ebx*4]
        invoke  lstrcat, offset szBuf, offset szBuf2
        
        test    esi, 1000h ; S
        setnz   bl
        mov     edi, tblClasses[ebx*4]
        
        mov     eax, esi
        shr     eax, 8
        and     eax, 0Fh ; TYPE
        
        invoke  wsprintf, offset szBuf2, offset szFmtType, ebx, eax, dword ptr [edi+eax*4]
        ;invoke  MessageBox, NULL, offset szBuf2, addr szTitle, MB_OK
        invoke  lstrcat, offset szBuf, offset szBuf2
        
        test    esi, 400000H
        setnz   bl  ; D/B
        test    ebx, ebx
        jz      _16
        
_32:
        invoke  wsprintf, offset szBuf2, offset szFmtDB, ebx, 32
        jmp     short @F
_16:
        invoke  wsprintf, offset szBuf2, offset szFmtDB, ebx, 16
        
@@:
        invoke  lstrcat, offset szBuf, offset szBuf2
         
        mov     eax, esi
        shr     eax, 13
        and     eax, 3  ; DPL
        
        mov     ecx, esi
        shr     ecx, 20
        and     ecx, 1
        invoke  wsprintf, offset szBuf2, offset szFmtOther, eax, ecx
        invoke  lstrcat, offset szBuf, offset szBuf2
        
        mov     eax, esi
        shr     eax, 23
        and     eax, 1
        invoke  wsprintf, offset szBuf2, offset szFmtG, eax, tblG[eax*4]
        invoke  lstrcat, offset szBuf, offset szBuf2
        
        
        ; 看是不是数据、代码段或是系统段;调用门、任务门没有段偏移上限这个属性
        ;test    esi, 1000h ; S
        ;jnz     get_seg_limit ; code / data seg
        ; 不用麻烦了,直接执行,看ZF
        
get_seg_limit:        
        lsl     eax, selector        
        jnz     return  ; 说明是调用门、任务门

got_seg_limit:
        invoke  wsprintf, offset szBuf2, offset szFmtSegLimit, eax
        invoke  lstrcat, offset szBuf, offset szBuf2
        
        ; 是不是数据或代码段,不能是系统段如TSS
        test    esi, 1000h ; S
        jz      return ;  system
            
verify_r_w: ; 在当前特权级下可写不?
        verr    word ptr selector
        jz      can_read
cannot_read:
        invoke  lstrcat, offset szBuf, offset szCannotRead
        jmp     @F
can_read:
        invoke  lstrcat, offset szBuf, offset szCanRead
        
@@:
        verw    word ptr selector
        jz      can_write
cannot_write:
        invoke  lstrcat, offset szBuf, offset szCannotWrite
        jmp     short return
        
can_write:
        invoke  lstrcat, offset szBuf, offset szCanWrite
        
return:
        ret
showSegInfo endp


start:
        sgdt    fword ptr _gdt
        sidt    fword ptr _idt
    
        mov     eax, cs
        mov     _cs, eax
        mov     eax, ds
        mov     _ds, eax
        mov     eax, ss
        mov     _ss, eax
        mov     eax, es
        mov     _es, eax
        mov     eax, fs
        mov     _fs, eax
        mov     eax, gs
        mov     _gs, eax
        
        sldt    word ptr _ldt
        str     word ptr _tr
                
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   ebx, word ptr _idt
        
        invoke  wsprintf, offset szBuf, offset szFmtTables, \
                        dword ptr _gdt+2, eax, dword ptr _idt+2, ebx, \
                        _ldt, _tr
                        
        ;invoke  MessageBox, NULL, offset szBuf, offset szTitle, MB_OK
                        
        ;mov     eax, cs ; 不能用push cs, 因为其等价于sub esp, 4; mov word ptr [esp], cs
        ;push    eax
        
        mov     ecx, 8
        xor     esi, esi
@@:
        push    ecx
        invoke  showSegInfo, regNames[esi*4], _cs[esi*4]
        
        inc     esi
        pop     ecx
        loop    @B
                
        invoke  MessageBox, NULL, offset szBuf, offset szTitle, MB_OK

        ret


        end     start
---------------------------------------------------------------------------------------------------------------------------

相关的东东

---------------------------------------------------------------------------------------------------------------------------
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。

---------------------------------------------------------------------------------------------
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指令,除了对本指令有效的描述符还有调用门。

---------------------------------------------------------------------------------------------
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。

---------------------------------------------------------------------------------------------