用户操作
[即时聊天] [发私信] [加为好友]
ke vinsID:iiprogram
1189929次访问,排名20好友0人,关注者64
残云收夏暑,新雨带秋岚!
iiprogram的文章
原创 1384 篇
翻译 0 篇
转载 1238 篇
评论 354 篇
Kevins的公告
    留言


自2005年07月20日

Kevins的聯係方式:
unix@yiii.net


天氣預報


最近评论
gxyiye@suho.com:厉害呀 可不可以帮我找回QQ号呀 先谢了 QQ15811744 密保BU CHI
iq263:程序员后花园,累了来看看 http://bbs.iq263.cn/
ccc:到处发,?空驱动能编译成功吗,解决好了在发
ZeroChou:__imp_wcslen , 我之前犯过同样的错误.
ZeroChou:不知道这个有什么用, 老罗好象也写过利用SEH来HOOK API的例程.
文章分类
收藏
相册
1
test
美女
*NUX技术
delphij
hitbsecconf2005
knoppix-std
linux admin
linuxsir
LWN.net
最爱chinaunix
毛德操blog
HOT SITES
cnbeta
et8论坛
eyeos 中文
ntdebugging
rootkit
taiwan.cnet
techeblog
web代理
三联生活周刊
中国传统节日
中日文翻译
国学网
深度
看雪学院
驱动开发网
编程技术和代码下载
80x86 Opcodes
awarenetwork
bo2k-plugins
borland update site
C++/C电子书籍
c++builder 研究
chinaaspx文档
code source
codecomments
codeguru
codegurus
codeproject
coffee个人
cprogramming
crack-warez
CrackZ's Reverse Engineering
csdn
csdnbbs文档简易
dd调试技巧代码
debugman
delphi盒子
dephi goo site
diybl
Doron Holan's Blog: Kernel-Mode Drivers
driverdevelop
driverdevsite
electronicstalk_driver
EliCZ
ext2fsd
Flier's Sky
FWB
icode
itconsult_vc
jiurl系统研究
kernel resource
kernel source
kernel-mode development link
krugle.com
LCC
lookcode
mad hook api
mfc
Michael Howard's Web Log
ms_srv protocol
msdn magazine
network code
newhua_deve
ntkernel.com
osronline
pcvc
planet-source-code
putty code
reactos
RECON
reverse-engineering
samba,cifs,smb
shadowgo 个人blog
smartphone开发
sockaddr.com
Source Code Search Engine
tty64
tutorialdownloads
txakynetwork(driver,firewall)
undocumented.ntinternals
uty oldblog(driver&kernel)
vbs脚本
vccode
VCFORGE
vchelp
vckbase
vc-qq
vczx
vc原动力
vc原动力
vc在线
wasm.ru
webcrazyjp
Windows network services internals
世纪站长
中国站长源码
免费ie代理1
免费代理2
拼搏
操作系统开发研究
服务器开发技术
源代码
源代码下载2
电子书
编程网摘
藏鲸阁
豆豆源码
個人輔站
another blog?
个人blog-3
人气第一的台湾小美女
個人blog
個人技術輔2
资料blog
软件工具下载
0DAY 下载
0DAY-ART
chinaitpwo资料
flash下载
icwin资料
infoxa
MYEBOOK.CN
openvpn
scitech.susx
soft8
source520
tooooold_searcj
torrentreactor.net
VCBOOK
x-force
xpbook
卡饭
文学ebook
核心编程
水电
源码天空
绿色下载
计算机与信息技术杂志
超好电子书籍站
酷客tool
酷客tool
非凡绿色下载
高校教材
硬件系统
hri.sourceforge.net
juniper mannel
资讯安全国内站
艾克索夫實驗室
0GINR
0ginr
0ginr论坛
51tiger.com安全
5eCur!ty Labs
5iliby
6code
77169
aloner
Alter's home page
antiprotect
astalavista
axis#ph4nt0m BLOG
ayarei/
bluehack
c.i.s.r.t
chinafe
CISRT
cncert
cto技术圈-ddos
cvcvxk
darkshell
debugman
debugman_wintools
dm-0day
dummy24
enet安全
eva
FCG
flowercode
FreeWin
friend-hsy
greatdong
h31home
H4x0r's Blog
hackee
heifou team
http://hi.baidu.com/yuange1975
huaidan's blog
icylife
inkings
insigma
internet worm
isip.cn
Juniper-bbs
kendivblog
KIJS
lenmo
loveshell
loveshell
luoluo
LYSOFT
lzx
majun 's blog
micropoint
mj0011
n4ry
NCPh
ne365-virus
neeao's blog
neeao's millow exp
Nethackonline 网络黑客在线
nop
nosec.org
open-bug
open-bug
PANTAO
raystyle
redhyphone union
regeliu
regshot
roncha
sometips
sudami
sysadmin.cn
System Repair Engineer安全检测
System Repair Engineer安全检测
T4NK's blog
team509
techtarget中文
TINK'S BLOG
unpack
unpackcn
uuty
vfocus
vxk
vxk大侠
Windows PowerShell及微软脚本
windowssky
xizi1023 blog
xwind
yiming 管理
yunshu-blog
ZUOJIE
zwell
一蓑烟雨
东来blog
中国x黑客小组
中国信息安全研究小组(CISRG)
中国信息安全组织
中国协议分析网
中国安全信息网-企业安全方案
从c开始
冷漠blog
刘涛涛blog
华夏同盟bbs
南域剑盟
危特网安
大牛蛙
安 翼 网 络
安全中国(RSS)
安全警戒
幻影
当下放下
影子鹰安全
微点blog
成都黑客在线
攻防blog
木马帝国
武汉黑客联盟
源码网
溢出专题study
白细胞
立华软件园安全防线
第八个男人
网安俱乐部
网络安全日志
艾克索夫實驗室.
补天
邪恶八进制
邪恶八进制
邪恶的hackza镜像
邪恶的oldexp
陆麟的主页
飞花堂
鬼仔blog
黑客百宝箱
資訊安全国外站
(kernel,virus code)
0DAY
158apps
62nds virus source
62nds-virus-code
advdbg.com
alexfedoto
allife(RSS)
Alter.Org.UA
anticode(RSS)
ANTIrootkit
antirootkit
ANYSIDE-EXP
anyside-exploit
arteam
astalavista.com
auscert
bifrost
bjwever
Black Hats Manual Software Security Auditing, Cracking,
blackcode.com(RSS)
blackhat mirror
blacksecurity
blogs.borland
bluemicro.digibase
bugtraq
bugtraq2
cert.org
chasenet.org-birfost
codebreakers-journal
community.reverse-engineering
Computer Forensics
computerterrorism
cool linux hack tool site
crackserver
CrackZ's Reverse Engineering
CVC电脑病毒
dark it sec
defcon
determina
dkcs security
DOXARA
eeye_0day_tra
eggheadcafe
elicz
elitehackers
elitehaven
European Hacker Conference
EVA的回收站
Evilcry
Expcode
exploit-1
exploitdatabase
foro.elhacke
Fortinet Security Research Team(RSS)
fredeyk
freexploit
freon-security
frsirt(RSS)
f-secure.weblog
Full Disclosure
full-disclosure
full-disclosure
gmc9
gmer
governmentsecurity(RSS)
h4cky0u
hackcoza
hackerscenter(RSS)
hackersclub
hackersplayground
hackwire(RSS)
haking.pl
he4dev
heapoverflow(RSS)
hexview
hick.org
hitbsecconf
hi-tech.nsys
hsc.fr(RSS)
icst.org.tw(RSS)
igniteds
infosecdaily
infosecwriters
infosyssec
insecure.org
internals
invisiblethings
jav.ch(RSS)
jeffrey.vanderstad
kd-team
l33tsecurity
labs.idefense
lcamtuf.coredump
malware analyze & reverse engineering
Mark Russinovich blog(cool)
markrussinovich
MC AV-Test site
Memory Forensic
metasploit-SHELLCODE(RSS)
microsoft安全(RSS)
milw0rm-shellcode(RSS)
MSDN杂志
msuiche
mtaulty(RSS)
mwcollect
nessus
nessus_plugin
net-security
net-security
network-file-explorers
networksecurityarchive(cool)
neworder.box.sk
neworder.box.sk
ngssoftware(RSS)
nirsoft
niscc.gov.uk(RSS)
NIST
nmd-labs
nnove-exploits
northsecuritylabs
noxusfiles
ntbugtraq
ntcore
nteam.ru
ntsecurity
Obsidis
offensivecomputing
offensivecomputing
omcd
only4gurus
Open Source Vulnerability Database
opennet.ru-exp
openrce(RSS)
openrce
openrce-articles
opensc
open-security
opferman
osvdb
packetstorm(RSS)
phenoelit.de
progenic
pulltheplug
PWDUMP6
Raymond Chen(msdn)
RECON
remoteassessment-exploit-file
remote-exploit
Reverse Compilation Techniques
reverse engineering team
ring 0 debugger
rootkit.com
rootkitunhooker(unreal)
ruder.cdut
RUS-CERT
s0ftpj.org
sabre-security
sabre-security
sec-consult(RSS)
seclist-fulldisclosure
secunia.com
secunia.com
secureworks
secureworks
securiteam
security.ittoolbox
security.nnov.ru
security.org.sg-code
securityarchitects
security-briefings
securitycatalyst(RSS)
securitydot-exploit
securityfocus(RSS)
securityforest
securitylab.ru
security-protocols(RSS)
securityreasonExploitAlert
securitysearch.net
securitytracker
sensepost
spywareinfo
Stanford's stinson
SUCK-O
sweRAT
sysinternals forum
taosecurity
taosecurity.blogspot(cool)
techmeme
techmeme.
tenablesecurity
THC(RSS)
thc.org
The 20 Most Critical Internet Security Vulnerabilities
the Month of Kernel Bugs
The Open Source Vulnerability Database
theaimsgroup bug
thebugs.ws
thenetworksecurity
tibbar(RSS)
tibbar
tippingpoint
topix-tech
triviasecurity
undergroundnews(RSS)
undocumented
undocumented.ntinternals
uninformed
uninformed
uninformed
uninformed.org
US-CERT
virustotal detect
vuln-search
VX Heavens
wd-3(RSS)
websense
WebSense Security Labs
whitehat
wilderssecurity
Win NT, Win 2000, and Win XP Security Tips
Windows network services internals
windowsecurity(RSS)
WOODMANN
woodmann.com
xatrix.org
xzziroz
yorn security
ZDNET_security
zdnet's security
zero day (RSS)
zone-h
zone-h.
反汇编引擎distorm
最新被黑站点
查询windows不明进程
汇编引擎yasm
经典phrack(RSS)
经典ussrback(RSS)
存档
订阅我的博客
XML聚合  FeedSky

原创 win32调试接口的基本原理 收藏

新一篇: windows driver中的IO_STACK_LOCATION  | 旧一篇: 隐藏内核模块的方法

错的关于windows平台下用户模式调试器的原理 
 
所谓调试器实际上是一个很宽泛的概念,凡是能够以某种形式监控其他程序执行过程的程序,都可以泛称为调试器。在Windows平台上,根据调试器的实现原理大概可以将之分为三类:内核态调试器、用户态调试器和伪代码调试器。     内核态调试器直接工作在操作系统内核一级,在硬件与操作系统之间针对系统核心或驱动进行调试,常见的有SoftICE、WinDbg、WDEB386和i386KD等等;用户态调试器则通过操作系统提供的调试接口,在操作系统和用户态程序之间针对用户态程序进行调试,常见的有各种开发环境如VC/Delphi自带的调试器,OllyDbg等等;伪代码调试器则使用目标系统自定义的调试接口,调试由用户态程序支持的脚本语言或虚拟机代码,常见的如JVM/CLR的调试工具、VB的pcode调试器、Active Script调试器等等。     因为伪代码调试器跟具体系统实现相关性太强,不具备原理层面的通用性,本系列文章尽量不涉及其内容,以后如果有机会可以再讨论一下JVM/CLR/Active Script提供的调试接口;用户态调试器应用最广泛,参考资料也较为完整,我会花较大精力和大家探讨;核心态调试器则跟操作系统结合较为紧密,加上我也不是太熟悉,只能尽力而为了,呵呵。欢迎大家提出批评指正意见和建议 smile     此外强烈推荐John Robbins在MSDN的Bugslayer专栏,以及其所著的<Debugging Applications>一书(中文版《应用程序调试技术》),此书中对调试器从原理到应用都有很全面的讲解。 [1] 用户态调试器结构初探     用户态调试器直接使用Win32 API提供的调试接口,遵循Win32的事件驱动的设计思想,其实现思路非常简单,基本框架伪代码如下:     //启动要调试的进程或挂接调试器到已运行的进程上     CreateProcess(..., DEBUG_PROCESS, ...) or DebugActiveProcess(dwProcessId)     DEBUG_EVENT de;     BOOL bContinue = TRUE;     DWORD dwContinueStatus;     while(bContinue)     {       bContinue = WaitForDebugEvent(&de, INFINITE);       switch(de.dwDebugEventCode)       {       ...       default:         {           dwContinueStatus = DBG_CONTINUE;           break;         }       }       ContinueDebugEvent(de.dwProcessId, de.dwThreadId, dwContinueStatus);     }     在调试器开始调试的时候,会启动被调试程序的新进程或者挂接(attach)到一个已运行进程上,此时Win32系统会启动调试接口的服务器端;然后调试器调用WaitForDebugEvent函数等待调试服务器端的调试事件被引发;调试器根据调试事件进行相应的处理;最后调用ContinueDebugEvent函数请求调试服务器继续执行被调试进程,以等待并处理下一个调试事件。     首先我们大致看看调试接口的服务器端的实现思路:调试服务的服务器端接口实际上是存在于被调试进程的调试端口(Debug Port),此核心对象实现上跟Win32的完成端口类似,都是通过一个核心队列实现的LPC端口。启动调试服务器实际上就是挂接Win32的调试子系统到被调试进程,并在被调试进程内构造调试端口。调试器通过调试端口与Win32的调试子系统通讯;调试子系统响应系统操作所引发的调试事件,并通过调试端口将调试事件分发给核心态/用户态调试器。     建立被调试程序的新进程时,需要在CreateProcess函数的dwCreationFlags参数设置DEBUG_ONLY_THIS_PROCESS或DEBUG_PROCESS标志位,以表示新建的进程需要被调试。CreateProcess函数的调用路径如下     CreateProcessA/CreateProcessW (kernel32.dll)     CreateProcessInternalW (kernel32.dll)     NtCreateProcessEx (ntoskrnl.dll)     PspCreateProcess (ntos\ps\create.c:969)     CreateProcessInternalW函数根据传入的dwCreationFlags参数,决定是否要构造端口核心对象用于调试端口,并设置PEB的相应调试标志;PspCreateProcess会根据传入参数的调试选项和端口对象句柄,选择是否创建目标进程的调试端口;如果要创建则将传入的端口句柄转换成内核对象引用,保存在被调试程序进程的EPROCESS->DebugPort字段里。     Win32 API提供的IsDebuggerPresent函数就是通过判断CreateProcessInternalW函数在PEB中设置的标志位来判断当前进程是否被调试的。IsDebuggerPresent函数伪代码如下:     BOOL IsDebuggerPresent(void)     {       return NtCurrentTeb()->ProcessEnvironmentBlock->BeingDebugged;     }     TEB和PEB的结构可在http://www.ntinternals.net/上找到。     不过此种方法很容易被调试器直接修改PEB内存结构所欺骗,故而有另外一种直接通过检查EPROCESS->DebugPort字段是否被使用,来判断此进程是否正在被调试的方法。以前水木上也有过几次讨论,如blowfish的《检测debugger的方法补遗》一文给出的代码。Windows XP/2003开始由Win32 API提供的 CheckRemoteDebuggerPresent 函数也是使用相同的思路,通过调用 NtQueryInformationProcess 函数查询调试端口实现的,伪代码如下:     BOOL CheckRemoteDebuggerPresent(HANDLE hProcess, PBOOL pbDebuggerPresent)     {       enum PROCESS_INFO_CLASS { ProcessDebugPort = 7 };       if(hProcess && pbDebuggerPresent)       {         HANDLE hPort;         *pbDebuggerPresent = NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessDebugPort, &hPort, sizeof(hPort), NULL)) ? TRUE : FALSE;         return *pbDebuggerPresent;       }       return FALSE;     }     与直接创建被调试程序的新进程不同,调试已启动进程的 DebugActiveProcess 函数首先连接到Win32 系统调试服务器的端口上,然后激活当前正在运行的被调试进程的调试端口。DebugActiveProcess的伪代码如下:     BOOL DebugActiveProcess(DWORD dwProcessId)     {       if(DbgUiConnectToDbg())       {         HANDLE hProcess = ProcessIdToHandle(dwProcessId);         if(hProcess)         {           DbgUiDebugActiveProcess(hProcess);           NtClose(hProcess);         }       }       return FALSE;     }     DbgUiConnectToDbg函数(ntos\dll\dlluistb.c:27)尝试连接核心提供的调试子系统端口(名为"\DbgUiApiPort"),如果成功连接会获得一个端口对象(保存在DbgUiApiPort NtCurrentTeb()->DbgSsReserved[1]),和一个调试状态转换的信号灯句柄(保存在DbgStateChangeSemaphore NtCurrentTeb()->DbgSsReserved[0])用于等待调试事件。伪代码如下:     #define DbgStateChangeSemaphore (NtCurrentTeb()->DbgSsReserved[0])     #define DbgUiApiPort (NtCurrentTeb()->DbgSsReserved[1])     NTSTATUS DbgUiConnectToDbg( VOID )     {       NTSTATUS st = NtConnectPort(&DbgUiApiPort, L"\\DbgUiApiPort", ..., &DbgStateChangeSemaphore);       if(NT_SUCCESS(st))       {         NtRegisterThreadTerminatePort(DbgUiApiPort);       }       else       {         DbgUiApiPort = NULL;       }       return st;     }     如果连接调试子系统成功,则调用NtRegisterThreadTerminatePort函数(ntos\ps\psdelete.c:1202)将调试端口加入到当前线程控制块的终止端口列表(ETHREAD->TerminationPortList)中。在线程结束的之前,会激活此列表中的端口,给调试器一个清理的机会。     DbgUiDebugActiveProcess函数完成具体的激活被调试进程的调试服务器的功能。伪代码如下:     #define DbgUiApiPort (NtCurrentTeb()->DbgSsReserved[1])     void DbgUiDebugActiveProcess(HANDLE hProcess)     {       return NtDebugActiveProcess(DbgUiApiPort) &&              DbgUiIssueRemoteBreakin(hProcess) &&              DbgUiStopDebugging(hProcess);     }     至于这几个函数的具体实现,等后面章节详细分析Win32调试子系统时再详细讲解,呵呵     在被调试进程启动了调试支持后,调试器调用WaitForDebugEvent函数等待调试事件的发生。此函数实际上是对DbgUiWaitStateChange函数(ntos\dll\dlluistb.c:93)的一个简单包装,通过等待DbgUiConnectToDbg函数获得的调试事件信号灯来完成实际功能。如果成功获得调试事件,还会通过NtRequestWaitReplyPort函数(ntos\lpc\lpcsend.c:717)向调试服务器通报DbgUiWaitStateChangeApi消息。     在处理完调试事件后,调试器调用的ContinueDebugEvent函数是DbgUiContinue函数的一个简单包装,也是使用NtRequestWaitReplyPort函数向调试服务器通报DbgUiContinueApi消息。     在完成调试功能后,WinXP/2003还提供了DebugActiveProcessStop函数停止调试。伪代码如下:     BOOL DebugActiveProcessStop(DWORD dwProcessId)     {       HANDLE hProcess = ProcessIdToHandle(dwProcessId);       if(hProcess)       {         CloseAllProcessHandles(dwProcessId);         DbgUiStopDebugging(hProcess);         if(NtClose(hProcess))           return TRUE;       }       return FALSE;     }     DbgUiStopDebugging函数(ntdll.dll)调用ZwRemoveProcessDebug函数(ntoskrnl.exe)关闭指定进程的调试端口,实现上是传入端口句柄和进程句柄,调用0xC7号系统服务完成最终功能。这个暂时就不深入讨论了,就此打住 tongue     在了解这些后,对用户态调试器的实现应该就有了一个框架性的了解:其结构就是一个基于事件的模型,然后通过向调试子系统请求调试事件并完成具体操作。 [2] 调试事件     前面说到 Win32 下的用户态调试器实际上就是一个while循环,循环体内先等待一个调试事件,然后处理之,最后将控制权交还给调试服务器,就好像一个窗口消息循环一样。调试事件的核心实际上就是一个DEBUG_EVENT结构,在WinBase.h文件中定义如下:     typedef struct _DEBUG_EVENT {         DWORD dwDebugEventCode;         DWORD dwProcessId;         DWORD dwThreadId;         union {             EXCEPTION_DEBUG_INFO Exception;             CREATE_THREAD_DEBUG_INFO CreateThread;             CREATE_PROCESS_DEBUG_INFO CreateProcessInfo;             EXIT_THREAD_DEBUG_INFO ExitThread;             EXIT_PROCESS_DEBUG_INFO ExitProcess;             LOAD_DLL_DEBUG_INFO LoadDll;             UNLOAD_DLL_DEBUG_INFO UnloadDll;             OUTPUT_DEBUG_STRING_INFO DebugString;             RIP_INFO RipInfo;         } u;     } DEBUG_EVENT, *LPDEBUG_EVENT;     dwDebugEventCode字段给出此调试事件的类型,dwProcessId和dwThreadId字段分别给出调试事件发生的进程和线程ID号。     调试事件一般有以下几类:     #define EXCEPTION_DEBUG_EVENT 1     #define CREATE_THREAD_DEBUG_EVENT 2     #define CREATE_PROCESS_DEBUG_EVENT 3     #define EXIT_THREAD_DEBUG_EVENT 4     #define EXIT_PROCESS_DEBUG_EVENT 5     #define LOAD_DLL_DEBUG_EVENT 6     #define UNLOAD_DLL_DEBUG_EVENT 7     #define OUTPUT_DEBUG_STRING_EVENT 8     #define RIP_EVENT 9     CREATE_PROCESS_DEBUG_EVENT事件在创建一个新的进程的第一个线程时被引发;相应的EXIT_PROCESS_DEBUG_EVENT事件在被调试的进程结束最后一个线程运行时被引发;每次新建/退出一个线程时会有CREATE_THREAD_DEBUG_EVENT/EXIT_THREAD_DEBUG_EVENT事件被引发;每次载入/卸载一个DLL时会有LOAD_DLL_DEBUG_EVENT/UNLOAD_DLL_DEBUG_EVENT事件被引发;被调试程序使用OutputDebugString函数输出一个调试字符串时调试器会接受到一个OUTPUT_DEBUG_STRING_EVENT事件;异常被引发时调试器会接受到一个第一时间的EXCEPTION_DEBUG_EVENT事件,如果调试器不处理此异常,则进入被调试程序的正常SEH调用链,如果被调试进程也不处理,则会再次引发此事件;RIP_EVENT则一般用于报告错误事件。     一般来说程序的调试事件按照如下顺序被引发:     CREATE_PROCESS_DEBUG_EVENT     LOAD_DLL_DEBUG_EVENT x n // 静态载入的DLL     CREATE_THREAD_DEBUG_EVENT & EXIT_THREAD_DEBUG_EVENT // 多线程程序中成对出现     LOAD_DLL_DEBUG_EVENT & UNLOAD_DLL_DEBUG_EVENT // 动态载入 DLL 时成对出现     EXCEPTION_DEBUG_EVENT x n // 随机出现     OUTPUT_DEBUG_STRING_EVENT x n // 程序写调试信息时出现     EXIT_PROCESS_DEBUG_EVENT     接下来我们详细分析每种调试事件被引发的原因和时机。具体的调试事件内容这里就不罗嗦了,有兴趣写调试器的朋友可以参考MSDN和<Debugging Applications>中相关内容。     首先是建立进程的CREATE_PROCESS_DEBUG_EVENT事件和建立线程的CREATE_THREAD_DEBUG_EVENT事件。这两个事件都是由DbgkCreateThread函数(ntos\dbgk\dbgkproc.h:211)引发的。此函数首先检查当前线程是否是具有调试端口的活动线程;然后检查当前线程是否是进程的创建的第一个线程;如果不是第一个线程,或者调试器是挂接(attach)到一个活动进程上(判断依据是此进程是否占用过用户态的CPU时间),则向调试子系统的调试服务器引发CREATE_THREAD_DEBUG_EVENT事件;否则转而报告CREATE_PROCESS_DEBUG_EVENT事件。     DbgkCreateThread函数伪代码如下:     VOID DbgkCreateThread(PVOID StartAddress)     {       if(!PsGetCurrentProcess()->DebugPort || PsGetCurrentThread()->DeadThread)       {         return;       }       PsLockProcess(Process,KernelMode,PsLockWaitForever); // 锁定进程中所有线程       if(PsGetCurrentProcess()->Pcb.UserTime &&          PsGetCurrentProcess()->CreateProcessReported == FALSE)       {         PsGetCurrentProcess()->CreateProcessReported = TRUE;         // 引发 CREATE_PROCESS_DEBUG_EVENT 事件       }       else       {         // 引发 CREATE_THREAD_DEBUG_EVENT 事件       }       PsUnlockProcess(PsGetCurrentProcess());     }     Win32在创建用户态线程的时候,大致流程如下:     CreateThread (kernel32.dll)     CreateRemoteThread (kernel32.dll)     NtCreateThread (ntoskrnl.exe)     PspCreateThread (ntos\ps\create.c:237)     PspCreateThread函数在创建用户态线程时,使用PspUserThreadStartup函数(ntos\ps\create.c:1639)作为线程入口函数,因此线程被创建后直接进入此函数。PspUserThreadStartup函数对非僵死线程和没有结束的线程初始化其APC;然后调用DbgkCreateThread函数通知调试器采取相应动作;最后将进程的用户态CPU时间设置为1,以标示此进程已启动。对一种特殊线程,非僵死线程但线程启动时已经停止,则直接调用DbgkCreateThread然后立刻调用PspExitThread,以通知调试器采取相应动作。PspUserThreadStartup函数伪代码如下:     VOID PspUserThreadStartup(IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext)     {       if(!PsGetCurrentThread()->DeadThread && !PsGetCurrentThread()->HasTerminated)       {         // 初始化线程 APC       }       else       {         if(!PsGetCurrentThread()->DeadThread)         {           DbgkCreateThread(StartContext);         }         PspExitThread(STATUS_THREAD_IS_TERMINATING);       }       DbgkCreateThread(StartContext);       if(PsGetCurrentProcess()->Pcb.UserTime == 0)       {         PsGetCurrentProcess()->Pcb.UserTime = 1;       }     }     与DbgkCreateThread函数对应的是DbgkExitThread函数(ntos\dbgk\dbgkproc.c:384)和DbgkExitProcess函数(ntos\dbgk\dbgkproc.c:439),分别向调试服务器引发EXIT_THREAD_DEBUG_EVENT和EXIT_PROCESS_DEBUG_EVENT事件。     这两个函数由系统内核退出线程的PspExitThread函数(ntos\ps\psdelete.c:622)在合适的时候调用。PspExitThread函数检测当前进程PCB的线程列表是否只有当前线程一个线程,如果没有其他线程则调用DbgkExitProcess函数,否则调用DbgkExitThread函数。     Win32 系统中载入和卸载DLL,实际的函数调用流程如下:     LoadLibrary (kernel32.dll)     LoadLibraryEx (kernel32.dll)     BasepLoadLibraryAsDataFile (kernel32.dll)     NtMapViewOfSection (ntos\mm\mapview.c:204)     MmMapViewOfSection (ntos\mm\mapview.c:699)     NtMapViewOfSection函数在调用MmMapViewOfSection函数(ntos\mm\mapview.c:699)完成实际的内存文件映射之后,会根据映射节的标记位以及目标进程是否是当前进程,判断是否要调用DbgkMapViewOfSection函数(ntos\dbgk\dbgkproc.c:495),通知调试服务器有新的映象文件被加载。与之对应MmUnmapViewOfSection函数(ntos\mm\umapview.c:88)也在判断标志位和目标进程是否是当前进程后,在函数末尾调用DbgkUnMapViewOfSection函数(ntos\dbgk\dbgkproc.c:567)通知调试服务器有映象文件被卸载。     与前面的几种事件不同,OutputDebugString函数(kernel32.dll)实际上是通过异常实现的。而且有趣的是,这个函数是为数不多的W后缀Unicode版本实现上转而调用A后缀Ansi版本,完成实际功能的例子。OutputDebugStringA函数(kernel32.dll)实际上使用RaiseException函数引发了一个异常号为0x40010006的软件异常,并将字符串的指针和长度作为异常参数传递。     DbgkForwardException函数(ntos\dbgk\dbgkport.c:96)作为实际引发EXCEPTION_DEBUG_EVENT调试事件的函数,在系统的异常分发KiDispatchException函数(ntos\ke\i386\exceptn.c:797)中被调用。KiDispatchException函数根据异常被引发时的状态,分别完成核心和用户态的异常处理工作。     对核心态异常,首先给核心调试程序一个处理机会,然后试图分发到基于帧的SEH异常链去,没有被处理的话则再给核心调试程序一个机会,如果还是没被处理,就只能调用KeBugCheckEx函数(ntos\ke\bugcheck.c:157)蓝屏了,呵呵。     对用户态异常,还是首先试图让核心调试器处理,如果不行才调用DbgkForwardException函数分发,没有被处理的话则多次尝试,如果还是没被处理,就停止线程并报告异常给用户。KiDispatchException函数伪代码如下:     VOID KiDispatchException (IN PEXCEPTION_RECORD ExceptionRecord, IN PKEXCEPTION_FRAME ExceptionFrame,                               IN PKTRAP_FRAME TrapFrame, IN KPROCESSOR_MODE PreviousMode, IN BOOLEAN FirstChance)     {       CONTEXT ContextFrame;       KeContextFromKframes(TrapFrame, ExceptionFrame, &ContextFrame); // 从核心异常帧(Frame)构造异常上下文(Context)       if (ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT) // 处理调试断点 int 3       {         ContextFrame.Eip--;       }       if (PreviousMode == KernelMode)       {         if (FirstChance == TRUE)         {           if (KiDebugRoutine && KiDebugRoutine(..., FALSE) != FALSE) goto Handle1           if(RtlDispatchException(ExceptionRecord, &ContextFrame) == TRUE) goto Handled1;         }         if (KiDebugRoutine && KiDebugRoutine(..., TRUE) != FALSE) goto Handle1         KeBugCheckEx(...); // 核心错误,以可控方式崩溃 -_-b 说白了就是Deadth Blue Screen,呵呵       }       else // PreviousMode = UserMode       {         if (FirstChance == TRUE)         {           if (KiDebugRoutine && KiDebugRoutine(..., FALSE) != FALSE) goto Handle1           if (DbgkForwardException(ExceptionRecord, TRUE, FALSE)) goto Handled2;           // 将异常信息转换到用户模式,并尝试分发         }         if (DbgkForwardException(ExceptionRecord, TRUE, TRUE))         {             goto Handled2;         }         else if (DbgkForwardException(ExceptionRecord, FALSE, TRUE))         {             goto Handled2;         }         else         {             ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);             KeBugCheckEx(...);         }       }     Handled1:       KeContextToKframes(TrapFrame, ExceptionFrame, &ContextFrame,                          ContextFrame.ContextFlags, PreviousMode);     Handled2:     }     DbgkForwardException函数分别针对DebugException和SecondChance参数的三种组合被调用。DebugException为True时向调试端口发送信息,否则向异常端口发送。     至此,我们对几种常见的调试事件的引发机制就大概有了一个了解,下一节将介绍将这些调试事件和最终用户态调试器关联起来的Win32中调试子系统的实现思路。

发表于 @ 2008年06月30日 23:23:00|评论(loading...)|收藏

新一篇: windows driver中的IO_STACK_LOCATION  | 旧一篇: 隐藏内核模块的方法

评论:没有评论。

发表评论  


登录
Csdn Blog version 3.1a
Copyright © Kevins