今天与大家一起见证怎么废了QQProtect.sys。
环境:
QQ版本:2013正式版 sp2(8178)
调试工具:windbg 6.12
操作系统:xp sp3 32bit
其他工具:lordpe
一直很纳闷,你一个QQ干嘛还要上个保护驱动那?这种行为让楼主很不爽。已知QQProtect会启动内核线程、注册内核通知回调例程、SSDT hook, SSDTShadow hook, inline hook。
打算用 QQProtect来练练手,正好好久没玩内核了,快生疏了。
本篇共分为4部分:
1. kill 内核线程
2. 恢复SSDT hook,inline hook
3. 摘除内核通知回调例程
4. 恢复SSDTShadow hook
当然以上的操作都是使用windbg做的。一起来调戏QQProtect吧。
使用APC KILL内核线程
QQ的保护驱动创建了一些内核线程。楼主找到QQ的内核线程
获取system进程的EPROCESS地址
代码:
0: kd> !process 0 0 system
PROCESS 867b5830 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000
DirBase: 06ca0020 ObjectTable: e1002e40 HandleCount: 401.
Image: System
在获取QQProtect驱动的起始地址和结束地址
代码:
0: kd> lm m qq*
start end module name
eee0c000 eee36680 QQProtect (deferred)
遍历进程的线程链,找到起始地址在QQProtect模块空间的线程
获取需要的字段在结构中的偏移
代码:
0: kd> r @$t0=@@(#FIELD_OFFSET(nt!_EPROCESS, ThreadListHead))
0: kd> r @$t1= @@(#FIELD_OFFSET(nt!_ETHREAD, ThreadListEntry))
0: kd> r @$t2=@@(#FIELD_OFFSET(nt!_ETHREAD, StartAddress))
遍历线程链,找到QQ的内核线程
代码:
0: kd> !list "-t nt!_LIST_ENTRY.FLink -e -x \"r @$t3=@$extret-@$t1; r @$t4= @$t3+@$t2; r @$t5=poi(@$t4);.if(@@((unsigned long)@$t5>(unsigned long)0xeee0c000 && (unsigned long)@$t5<(unsigned long)0xeee36680)){r @$t3;dt -b nt!_ETHREAD Cid. @$t3; dds @$t4 l1;}; \" 867b5830+@$t0"
r @$t3=@$extret-@$t1; r @$t4= @$t3+@$t2; r @$t5=poi(@$t4);.if(@@((unsigned long)@$t5>(unsigned long)0xeee0c000 && (unsigned long)@$t5<(unsigned long)0xeee36680)){r @$t3;dt -b nt!_ETHREAD Cid. @$t3; dds @$t4 l1;};
$t3=86699130 //ETHREAD地址
+0x1ec Cid :
+0x000 UniqueProcess : 0x00000004 //进程ID
+0x004 UniqueThread : 0x00000160 //线程ID
86699354 eee11a0c QQProtect+0x5a0c //线程的起始地址
r @$t3=@$extret-@$t1; r @$t4= @$t3+@$t2; r @$t5=poi(@$t4);.if(@@((unsigned long)@$t5>(unsigned long)0xeee0c000 && (unsigned long)@$t5<(unsigned long)0xeee36680)){r @$t3;dt -b nt!_ETHREAD Cid. @$t3; dds @$t4 l1;};
$t3=862de020
+0x1ec Cid :
+0x000 UniqueProcess : 0x00000004
+0x004 UniqueThread : 0x00000164
862de244 eee22626 QQProtect+0x16626
通过上面的查找,找到了两个QQProtect的内核线程。找到了线程,接下来该怎么办呢?我们知道用户态线程直接强杀就OK了,但是内核线程强杀是不行的。通常使用APC。使用APC机制结束掉线程。
找到方法,那下一步就是实施了。由于不能调用系统API构建APC,只能手动构建和插入APC了。
第一步先找一块用来构建APC的内存。就在QQProtect中找一处吧。
先看一下QQProtect模块的区段信息
代码:
0: kd> !dh -s eee0c000
SECTION HEADER #1
.text name
1B516 virtual size
480 virtual address
1B580 size of raw data
480 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
68000020 flags
Code
Not Paged
(no align specified)
Execute Read
SECTION HEADER #2
.rdata name
3A8C virtual size
1BA00 virtual address
3B00 size of raw data
1BA00 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
48000040 flags
Initialized Data
Not Paged
(no align specified)
Read Only
Debug Directories(1)
Type Size Address Pointer
cv 8f 1e868 1e868 Format: RSDS, guid, 1, f:\qqprotectdrvbuild\qqbuilder_qd3.5.1_drv2.9\basic_qqprotectdrv_vob\qqprotectdrv\objfre_wxp_x86\i386\QQProtectSYS.pdb
SECTION HEADER #3
.data name
82AC virtual size
1F500 virtual address
8300 size of raw data
1F500 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
C8000040 flags
Initialized Data
Not Paged //不分页内存
(no align specified)
Read Write
SECTION HEADER #4
INIT name
CC6 virtual size
27800 virtual address
D00 size of raw data
27800 file pointer to raw data
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
E2000020 flags
Code
Discardable //可废弃的,初始化完成后,内核可以回收这块内存。
//但是由于内核的页粒度为0x1000,INIT段的开始处一部分内存与.data段在同一块内存页中,那此段的前0x200个字节就是理想的APC数据块载体了
(no align specified)
Execute Read Write
标签: QQ2013
顶一下
(1)
50%
踩一下
(1)
50%