欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

TsFltMgr.sys系統(tǒng)藍屏的原因分析(小心QQ電腦管家)

  發(fā)布時間:2015-03-13 14:36:01   作者:佚名   我要評論
經(jīng)過互聯(lián)網(wǎng)查詢,和不斷摸索,最后發(fā)現(xiàn)居然是可惡的QQ軟件管家惹的禍,進安全模式果斷卸載QQ軟件管家后,再重新啟動,系統(tǒng)全然正常了

同事一WindowsXP系統(tǒng),正常執(zhí)行,關(guān)閉后,第二天無法啟動,詳細癥狀為:

(1)安全模式以及帶網(wǎng)絡功能的安全模式都能夠進入;
(2)正常模式,還沒出現(xiàn)WindowXP滾動欄就開始重新啟動;
(3)進安全模式,禁用自己主動重新啟動后,再正常啟動,出現(xiàn)藍屏,報TsFltMgr.sys內(nèi)存錯誤!

經(jīng)過互聯(lián)網(wǎng)查詢,和不斷摸索,最后發(fā)現(xiàn)居然是可惡的QQ軟件管家惹的禍,進安全模式果斷卸載QQ軟件管家后,再重新啟動,系統(tǒng)全然正常了。

以下轉(zhuǎn)載了一篇分析QQ電腦管家的文章,請參考:

QQ電腦管家中的TsFltMgr Hook框架分析

新版的QQ電腦管家中多了一個名字叫TsFltMgr.sys的驅(qū)動(應該是Sysnap大牛開發(fā)的,膜拜),對該驅(qū)動進行了一些簡單的分析,看見了一套美麗的Hook框架,發(fā)出來與大家分享。分析不正確的地方請多多包涵。
首先TsFltMgr掛鉤了KiFastCallEntry函數(shù),Hook點在這里:

代碼:


復制代碼
代碼如下:

kd> u KiFastCallEntry+e3
nt!KiFastCallEntry+0xe3:
8053dbb3 c1e902 shr ecx,2
-------------------------------------------------------------------------
8053dbb6 90 nop
8053dbb7 90 nop
8053dbb8 90 nop
8053dbb9 e962170c77 jmp TsFltMgr+0x2320 (f75ff320)
-------------------------------------------------------------------------
8053dbbe 0f83a8010000 jae nt!KiSystemCallExit2+0x9f (8053dd6c)
8053dbc4 f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
8053dbc6 ffd3 call ebx

原始的KiFastCallEntry在 shr ecx, 2 指令后面應該是 mov edi,esp;cmp esi, MmUserProbeAddress,共8個字節(jié),在這里被 TsFltMgr 替換成了3個nop和一個jmp。

該jmp會跳轉(zhuǎn)到 KiFastCallEntry_Detour 函數(shù)中,KiFastCallEntry_Detour 函數(shù)代碼例如以下:

代碼:


復制代碼
代碼如下:

// 保存現(xiàn)場
pushfd
pushad </p> <p>// 調(diào)用 KiFastCallEntry_Filter 函數(shù),實現(xiàn)過濾
push edi // 本次系統(tǒng)調(diào)用相應的SysCall Table的地址(SSDT或SSDTShadow的地址)
push ebx // 本次系統(tǒng)調(diào)用在SysCall Table中相應的內(nèi)核函數(shù)地址
push eax // 本次系統(tǒng)調(diào)用相應的內(nèi)核函數(shù)在SysCall Table中的功能號
call KiFastCallEntry_Filter // 調(diào)用KiFastCallEntry_Filter,實現(xiàn)過濾
mov [esp+10h], eax // 更改本次調(diào)用相應的內(nèi)核函數(shù)地址!</p> <p>// 恢復現(xiàn)場
popad
popfd</p> <p>// 運行 KiFastCallEntry 函數(shù)中被替換掉的指令,并跳回原函數(shù)
mov edi,esp
cmp esi, g_7fff0000
push g_JmpBack
ret

這里須要注意的是 call KiFastCallEntry_Filter 之后的 mov [esp+10h], eax。之前保存現(xiàn)場時的指令pushad會導致寄存器EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI依次入棧,并通過后面的popad指令恢復這些寄存器的值。因此此處的mov [esp+10h], eax實際上是用 KiFastCallEntry_Filter 函數(shù)的返回值來改寫堆棧中保存的ebx的值,即改寫本次系統(tǒng)調(diào)用相應的內(nèi)核函數(shù)地址。

KiFastCallEntry_Filter 是真正實現(xiàn)過濾的函數(shù),該函數(shù)的參數(shù)和返回值上文已經(jīng)說明了,其詳細實現(xiàn)分析整理后,C語言描寫敘述例如以下:

代碼:


復制代碼
代碼如下:

ULONG __stdcall KiFastCallEntry_Filter(ULONG ulSyscallId, ULONG ulSyscallAddr, PULONG pulSyscallTable)
{
PFAKE_SYSCALL pFakeSysCall = NULL;</p> <p> if ( ulSyscallId >= 0x400 )
return ulSyscallAddr;</p> <p> if ( pulSyscallTable == g_KiServiceTable && ulSyscallId <= g_ServiceNum/* 0x11c */ )
{
pFakeSysCall = g_FakeSysCallTable[ulSyscallId]; // SSDT
}
else if (pulSyscallTable == g_KeServiceDescriptorTable &&
g_KeServiceDescriptorTable && ulSyscallId <= g_ServiceNum/* 0x11c */)
{
pFakeSysCall = g_FakeSysCallTable[ulSyscallId]; // SSDT
}
else if (pulSyscallTable == g_W32pServiceTableAddr && ulSyscallId <= g_ShadowServiceNum/* 0x29b */)
{
pFakeSysCall = g_FakeSysCallTable[ulSyscallId + 1024]; // ShadowSSDT
}</p> <p> if ( pFakeSysCall && pFakeSysCall->ulFakeSysCallAddr )
{
pFakeSysCall->ulOrigSysCallAddr = ulSyscallAddr;
return pFakeSysCall->ulFakeSysCallAddr;
}
return ulSyscallAddr;
}

這里須要說明的是,TsFltMgr內(nèi)部有一張表,暫且命名為 g_FakeSysCallTable,該表中存放的是指向 FAKE_SYSCALL 結(jié)構(gòu)的指針。表中的每個 FAKE_SYSCALL 結(jié)構(gòu)相應一個系統(tǒng)調(diào)用,表的前半部分相應SSDT中的系統(tǒng)調(diào)用,1024項以后相應ShadowSSDT里的系統(tǒng)調(diào)用。

當中 FAKE_SYSCALL 結(jié)構(gòu)大致例如以下(當中非常多域的作用沒弄明確):

代碼:


復制代碼
代碼如下:

typedef struct __FAKE_SYSCALL__ {
ULONG xxx1;
ULONG ulSyscallId; // 該系統(tǒng)調(diào)用的功能號
ULONG xxx3;
ULONG ulTableIndex;
ULONG xxx5;
ULONG ulCountForPreWork;
ULONG ulCountForPostWork;
ULONG xxx8;
ULONG ulOrigSysCallAddr; // 真實的系統(tǒng)調(diào)用地址
ULONG ulFakeSysCallAddr; // 假的系統(tǒng)調(diào)用地址
ULONG xxx11;
ULONG xxx12;
ULONG xxx13;
……
} FAKE_SYSCALL, *PFAKE_SYSCALL, **PPFAKE_SYSCALL;

因此 KiFastCallEntry_Filter 函數(shù)的所做的就是依據(jù)系統(tǒng)調(diào)用的功能號在 g_FakeSysCallTable 中索引出相應的 pFakeSysCall 對象,然后推斷該系統(tǒng)調(diào)用是否須要hook,假設(shè)須要則將真實的系統(tǒng)調(diào)用地址保存到 pFakeSysCall->ulOrigSysCallAddr 中,并將 pFakeSysCall->ulFakeSysCallAddr 作為假系統(tǒng)調(diào)用的地址返回。

這樣的調(diào)用過程中動態(tài)獲取真實系統(tǒng)調(diào)用地址的方法使 TsFltMgr 的Hook框架有較高的兼容性,比如不會使載入順序晚于TsFltMgr的驅(qū)動中的SSDT Hook失效,比如QQ電腦管家本身帶的TSKsp.sys驅(qū)動。

對于我的測試系統(tǒng)(XP_SP2),TsFltMgr hook的函數(shù)有:

代碼:


復制代碼
代碼如下:

// SSDT中:
NtCreateFile、NtCreateKey、NtCreateSection、NtCreateSymbolicLinkObject、NtCreateThread、NtDeleteFile、NtDeleteKey、NtDeleteValueKey、NtDeviceIoControlFile、NtDuplicateObject、NtEnumerateValueKey、NtLoadDriver、NtOpenProcess、NtOpenSection、NtProtectVirtualMemory、NtQueryValueKey、NtRequestWaitReplyPort、NtSetContextThread、NtSetInformationFile、NtSetSystemInformation、NtSetValueKey、NtSuspendThread、NtSystemDebugControl、NtTerminateProcess、NtTerminateThread、NtWriteFile、NtWriteVirtualMemory</p> <p>// ShadowSSDT中:
NtUserBuildHwndList、NtUserFindWindowEx、NtUserGetForegroundWindow、NtUserMoveWindow、NtUserQueryWindow、NtUserSendInput、NtUserSetParent、NtUserSetWindowLong、NtUserSetWindowPlacement、NtUserSetWindowPos、NtUserShowWindow、NtUserShowWindowAsync、NtUserWindowFromPoint

全部假系統(tǒng)函數(shù)都有統(tǒng)一的代碼框架,假系統(tǒng)函數(shù)的代碼框架大致例如以下:

代碼:

復制代碼
代碼如下:

NTSTATUS __stdcall FakeNt_XXX(xxx)
{
PFAKE_SYSCALL pFakeSysCall;
ULONG ulXXX = 0;
ULONG ulStatus;
NTSTATUS status;
ULONGLONG ullTickCount;

pFakeSysCall = g_pFakeSysCall_Nt_XXX; // 該系統(tǒng)調(diào)用相應的 pFakeSysCall 對象

status = STATUS_ACCESS_DENIED;
</p> <p> // 貌似是做性能測試時候須要的,實際版本號中 g_bPerformanceTest 為 FALSE
if ( g_bPerformanceTest ) {
ullTickCount = KeQueryInterruptTime();
}</p> <p>
// 系統(tǒng)調(diào)用的調(diào)用前處理!
// +++
InterlockedIncrement(&pFakeSysCall->ulCountForPreWork);
ulStatus = PreWork(&ulXXX, pFakeSysCall);
InterlockedDecrement(&pFakeSysCall->ulCountForPreWork);
// ---

if ( ulStatus != 0xEEEE0004 && ulStatus != 0xEEEE0005)
{
OrigSysCall * pOrigSysCall = pFakeSysCall->ulOrigSysCallAddr;</p> <p> // 調(diào)用原始系統(tǒng)調(diào)用!
if ( pOrigSysCall && NT_SUCCESS(pOrigSysCall(xxx)) )
{
// 系統(tǒng)調(diào)用的調(diào)用后處理!
// +++
InterlockedIncrement(&pFakeSysCall->ulCountForPostWork),
ulStatus = PostWork(&ulXXX),
InterlockedDecrement(&pFakeSysCall->ulCountForPostWork),
// ---
}
}</p> <p> // 0xEEEE0004 應該是拒絕調(diào)用的意思,0xEEEE0005 應該是同意調(diào)用的意思
if (ulStatus == 0xEEEE0005)
status = STATUS_SUCCESS;</p> <p> // PsGetCurrentProcessId 這個調(diào)用的返回值后面并沒實用到,可能是多余的
PsGetCurrentProcessId();</p> <p> // 貌似是做性能測試時候須要的
if ( g_pFakeSysCall_NtTerminateProcess->xxx5 && ullTickCount && g_bPerformanceTest) {
PerformanceTest(&g_pFakeSysCall_NtTerminateProcess->xxx13, ullTickCount);
}</p> <p> return status;
}

以上就是對TsFltMgr Hook框架的一些分析,祝大家元宵快樂~ 

相關(guān)文章

最新評論