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