Date:2009.11.15
Author:charme
Index:http://hi.baidu.com/charme000
Email:charme000@gmail.com
很久没有研究技术的东西了,心静不下来。现在稍微好点了,接着以前的主题,希望大家不要厌烦,呼呼!!
为什么说asm是业界利器呢?实际上搞破解和逆向分析的人体会最深了。我以前并不研究什么破解啊什么
的,主要是没兴趣,有时候倒是也逆向一些东西!最近稍微的接触了下,觉得挺有意思的,也不是那么难!但是说到底吧,这里面最根本的实际上还是asm的功底和一些调试技巧!希望不久可以写个拙略的破文出来。
在此特别感谢下啊cr和zapline的帮助。
最近写了篇关于inline hook的整体架构的东西,放空间了(严重鄙视百度的日志篇幅限制,害我分了7篇,丫的!)。师傅说不喜欢看asm,我也没有办法,很俗的说:习惯了,呼呼!
很多人问我:为什么要叫“asm魅力“。呼呼,因为我的名字叫charme(英文意思:魅力)。
昨天一个朋友问我:asm可以写驱动么?当然可以!!!!!
那么这篇呢我们就以这个为主题,我实现一个简单的驱动出来。
原理:
我们简单的自己实现一个调用门,来查询r0状态是一些寄存器的值!
驱动部分------------------------------------------------------------------------------------------------
;名称:MyKmd.asm
;功能:一个很简单的WDM(KDM)驱动程序,为自己的程序提供Ring0。
;说明:需要由“LoadMyKmd.exe”来安装。
;>>>>>>>>>>>>>>>STRUCT>>>>>>>>>>>>>>>>>>>>>>>>>>>>
CALLGATE STRUCT
OFFSETL DW 0
SELECTOR DW 0
DCOUNT DB 0
GTYPE DB 0
OFFSETH DW 0
CALLGATE ENDS
DESCRIPTOR STRUCT
LIMITL DW 0
BASEL DW 0
BASEM DB 0
ATTRIBUTES DW 0
BASEH DB 0
DESCRIPTOR ENDS
;>>>>>>>>>>>>>>>>>equ>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
CODES_SEL = 3E8H
CODE_TYPE = 0CF9AH
GATE_TYPE = 0ECH
;>>>>>>>>>>>>>>>>>Code>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
DriverEntry:
pushfd
pushad
;取得GDTR内容
push edx ;压栈edx,esp-4,构建4字节空间
sgdt [esp-2] ;GDTR是48位,这里利用了技巧,在栈中构建了6字节空间,同时读出GDTR内容
;而且还不破坏堆栈指针,巧巧巧!
pop edx ;全局描述符表基地址这里只关心基址(在高双字,高址),所以出栈即是
mov eax,edx ;存放全局描述符开始地址
;在全句描述符表开始地址存放retn指令机器码, 全句描述符表第一个描述符为空
;表述符,被保留,没被用书上说这个描述符应该全为0这里看出 可以写东西进去。
mov BYTE ptr [edx],0C3H
mov ecx,3E0h ;定位自己的门描述符,
add edx,ecx ;
assume edx:ptr CALLGATE ;让描述符符位置在全局描述符的3E0这个位置
cmp [edx].SELECTOR,CODES_SEL
jz _ToEnd
mov [edx].OFFSETL,ax ;创建门描述符
mov [edx].SELECTOR,CODES_SEL
mov [edx].DCOUNT,0
mov [edx].GTYPE,GATE_TYPE
shr eax,16
mov [edx].OFFSETH,ax
;描述符的偏移地址其实就是上面说到的那个retn指令地址,当call 这个门的时候
;只从堆栈弹出EIP地址,所以CS寄存器没被覆盖,所以还是ring0权限
add edx,8
assume edx:ptr DESCRIPTOR
mov [edx].LIMITL,0FFFFH ;创建自己的代码段描述符
mov [edx].BASEL,0
mov [edx].BASEM,0
mov [edx].ATTRIBUTES,CODE_TYPE
mov [edx].BASEH,0
_ToEnd:
popad
popfd
mov eax,0C0000182h
ret 8
end DriverEntry
这个源文件实际上可以写成一个MyKmd.bat文件,对于其中的批处理,编译的时候按注释处理,忽略。这是一种很好的处理方法。或者你也可以单独的写个bat文件来编译!代码中作了详细的注释。一看就明白!
这其中几处巧妙的地方正是asm得魅力所在,希望大家能够真正的体会出来!
Loader-------------------------------------------------------------------------------
我们也可以写个加载驱动的loader!这里只是演示,就不涉及什么xx的东西了,用最普通的方法来加载。
;名称:LoadMyKmd.asm
;功能:安装驱动程序“MyKmd.sys”使用。
;说明:必须生成“MyKmd.sys”之后才能正确运行。
;编译方式见程序尾部
.data
szError db '装载驱动失败',0
szOK1 db '驱动安装成功',0
szOK db 'OH YEAH.~~!',0
szMyWdm db 'MyKmd.sys',0
szMyWdnName db 'MyKmd',0
szBuffer db MAX_PATH dup (0)
hSCManager dd ?
hService dd ?
.code
start:
invoke OpenSCManager,NULL,NULL,SC_MANAGER_CREATE_SERVICE
.if !eax
invoke MessageBox,0,addr szError,0,MB_ICONERROR or MB_OK
jmp _Err
.endif
mov hSCManager,eax
push ecx
invoke GetFullPathName,addr szMyWdm,sizeof szBuffer,addr szBuffer,esp
pop ecx
invoke CreateService,hSCManager,addr szMyWdnName,addr szMyWdm, \
SERVICE_START or DELETE,SERVICE_KERNEL_DRIVER, \
SERVICE_DEMAND_START,SERVICE_ERROR_IGNORE, \
addr szBuffer,0,0,0,0,0
.if !eax
invoke MessageBox,0,addr szError,0,MB_ICONERROR
jmp _Err
.endif
mov hService,eax
invoke StartService, hService, 0, NULL
invoke DeleteService, hService
invoke CloseServiceHandle, hService
invoke CloseServiceHandle, hSCManager
invoke MessageBox,0,addr szOK1,addr szOK,0
_Err:
invoke ExitProcess,0
end start
现在的话,驱动文件和loader都有了。我们再写个测试程序出来!看看到底能不能出来我们想要的效果!
Test部分:
;程序名:Mytest.asm
;功能:用来测试MyKmd.sys是否正确
.data
szOK db 'Test Ring0',0
CallGate_Sel dd 0
dw 03E3H ;调用门的选择子
szFormat db '通用寄存器:',0Dh,0Ah
db 'EAX=%08X EBX=%08X ECX=%08X EDX=%08X',0Dh,0Ah
db 'ESI=%08X EDI=%08X EBP=%08X ESP=%08X',0Dh,0Ah,0Dh,0Ah
db '段(选择符)寄存器:',0Dh,0Ah
db ' CS=%04X DS=%04X ES=%04X SS=%04X FS=%04X GS==%04X',0Dh,0Ah,0Dh,0Ah
db '指令指针寄存器:EIP=%08X 标志寄存器:EFLAGS=%08X',0Dh,0Ah,0Dh,0Ah
db '控制寄存器:',0Dh,0Ah
db ' CR0=%08X CR1:CPU保留 CR2=%08X CR3=%08X',0Dh,0Ah,0Dh,0Ah
db '系统地址寄存器:',0Dh,0Ah
db ' GDTR=%04X %08X IDTR=%04X %08X TR=%04X LDTR=%04X',0Dh,0Ah,0Dh,0Ah
db '调试寄存器:',0Dh,0Ah
db ' DR0=%08X DR1=%08X DR2=%08X DR3=%08X',0Dh,0Ah
db ' DR4:CPU保留 DR5:CPU保留 DR6=%08X DR7=%08X',0,0
.data?
szBuffer db 500h dup (?)
_ddEAX dd ?
_ddEBX dd ?
_ddECX dd ?
_ddEDX dd ?
_ddESI dd ?
_ddEDI dd ?
_ddEBP dd ?
_ddESP dd ?
_ddCS dd ?
_ddDS dd ?
_ddES dd ?
_ddSS dd ?
_ddFS dd ?
_ddGS dd ?
_ddEIP dd ?
_ddEFLAGS dd ?
_ddCR0 dd ?
;_ddCR1 dd 00000000h ;CPU保留
_ddCR2 dd ?
_ddCR3 dd ?
_dfGDTR dd ? ;低16位是界限
dd ?
_dfIDTR dd ?
dd ?
_ddTR dd ?
_ddLDTR dd ?
_ddDR0 dd ?
_ddDR1 dd ?
_ddDR2 dd ?
_ddDR3 dd ?
;_ddDR4 dd 00000000h ;CPU保留
;_ddDR5 dd 00000000h ;CPU保留
_ddDR6 dd ?
_ddDR7 dd ?
.code
start:
call FWORD ptr CallGate_Sel
;进入ring0
;有兴趣自己也可以创建一个0级堆栈,这里用ring3的堆栈
mov eax,esp ;保存ring0堆栈
mov esp,[esp+4] ;装入ring3堆栈地址
;解释下这里为什么是+4: 因为call调用门会把ss esp cs eip分别放入堆栈,在驱动
;程序里面已经有一句ret 8指令把eip弹出来了。所以这里就得加4以得到ring3堆栈地址
push eax
mov _ddEAX,eax
mov _ddEBX,ebx
mov _ddECX,ecx
mov _ddEDX,edx
mov _ddESI,esi
mov _ddEDI,edi
mov _ddEBP,ebp
mov _ddESP,esp
mov _ddCS,DWORD PTR cs
mov _ddDS,DWORD PTR ds
mov _ddES,DWORD PTR es
mov _ddES,DWORD PTR ss
mov _ddFS,DWORD PTR fs
mov _ddGS,DWORD PTR gs
push eax
pop _ddEIP
pushfd
pop _ddEFLAGS
mov eax,cr0
mov _ddCR0,eax
mov eax,cr2
mov _ddCR2,eax
mov eax,cr3
mov _ddCR3,eax
sgdt FWORD PTR _dfGDTR
sidt FWORD PTR _dfIDTR
xor eax,eax
str ax
mov _ddTR,eax
xor eax,eax
sldt ax
mov _ddLDTR,eax
mov eax,dr0
mov _ddDR0,eax
mov eax,dr1
mov _ddDR1,eax
mov eax,dr2
mov _ddDR2,eax
mov eax,dr3
mov _ddDR3,eax
mov eax,dr6
mov _ddDR6,eax
mov eax,dr7
mov _ddDR7,eax ;ring0下才可以访问的寄存器
pop esp
;;;开发返回ring3
push offset ring3
;正如刚刚所说,已经弹出了eip地址。
;用retf返回肯定出错。所以还是手动帮忙来恢复堆栈,压入ring3下的代码地址
retf
ring3:
mov eax,_dfGDTR
mov ebx,_dfGDTR+4
xchg ax,bx
rol eax,16
mov _dfGDTR,eax
mov _dfGDTR+4,ebx
mov eax,_dfIDTR
mov ebx,_dfIDTR+4
xchg ax,bx
rol eax,16
mov _dfIDTR,eax
mov _dfIDTR+4,ebx
invoke wsprintf,addr szBuffer,addr szFormat,\
_ddEAX,_ddEBX,_ddECX,_ddEDX,\
_ddESI,_ddEDI,_ddEBP,_ddESP,\
_ddCS,_ddSS,_ddDS,_ddES,_ddFS,_ddGS,\
_ddEIP,_ddEFLAGS,\
_ddCR0,_ddCR2,_ddCR3,\
_dfGDTR+4,_dfGDTR,_dfIDTR+4,_dfIDTR,_ddTR,_ddLDTR,\
_ddDR0,_ddDR1,_ddDR2,_ddDR3,_ddDR6,_ddDR7
invoke MessageBox,0,addr szBuffer,addr szOK,0
invoke ExitProcess,0
end start
最终的效果图:
这篇陋文不是要教你怎么写个调用门什么的!要写这样的东西的话,看看combojiang(也不知道拼对了没有,呼呼)大牛的rootkits系列就可以了! 我的目的是想让大家体会下asm的魅力,仅此而已!比起N多大牛的内核驱动程序来说,这个就很简陋了,呼呼!不过现在好多的大牛都简陋的不会写简陋的东西了!
建议:
我个人是这么看的,我并不建议用asm来写驱动,除非你有足够的驾驭能力。
原因1-----asm本身很晦涩,即便他强大。Asm写驱动就有点像用mfc开发gui程序和.net开发gui程序的对比。前者可能在某些方面要强大一点,但是开发速度和效率没有后者强!这个看情况择优!
原因2-----asm写的驱动不好调试。最普遍的就是三精口服液 。
总结:
其实任何的语言无非是规则,高手在于能够充分的理解规则并且试图突破!
对于asm写驱动,前辈已经做了尝试,大家可以到小罗的主页上下载俄罗斯大牛整理的masm开发驱动的开发包KmdKit。相当于ddk一样的东西,很实用!
好了,asm魅力四写完了!就像又完成了一件事情一样!也很开心!
昨天受人委托去辅导一个高中生的去过信息竞赛,不禁感慨一番,里面设计很多的数据结构还有算法的问题,一个动态规划的问题,忙活了我两个小时才写出程序来。看来还是欠火候,希望小妹妹可以一切顺利,也不枉我一番教导啊!呼呼!
- 标 题:asm的魅力(四)
- 作 者:charme
- 时 间:2009-11-15 10:49
- 链 接:http://bbs.pediy.com/showthread.php?t=101257
Asm的魅力(四)
Asm是业界利器-----------------------某人代码:
代码:
代码: