layout: wiki
title: 騰訊管家攻防驅(qū)動(dòng)分析-TsFltMgr
categories: WindowsDriver
description: 騰訊管家攻防驅(qū)動(dòng)分析-TsFltMgr
keywords:
url: https://lichao890427.github.io/ https://github.com/lichao890427/
-
TsFltMgr.sys分析
- 一慎冤、驅(qū)動(dòng)入口DriverEntry
- 二禾怠、驅(qū)動(dòng)接口Interface
- 三、基礎(chǔ)庫(kù)
-
四铆铆、InlineHook KiFastCallEntry
- 4.1 獲取SSDT/SSSDT/Hook點(diǎn)
- 4.2 從KiSystemService獲取KiFastCallEntry
- 4.3 獲取SSSDT信息
- 4.4 初始化InlineHook KiFastCallEntry跳轉(zhuǎn)表
- 4.5 獲取系統(tǒng)服務(wù)號(hào)的2種方式
- 4.6 InlineHook過(guò)程
- 4.7 構(gòu)造InlineHook跳轉(zhuǎn)后的執(zhí)行語(yǔ)句
- 4.8 強(qiáng)制單核互斥執(zhí)行指定Procedure
- 4.9 進(jìn)行SSDT hook
- 4.10 對(duì)重要回調(diào)(進(jìn)程回調(diào)揍很、線程回調(diào)、映像加載回調(diào))的掛鉤
- 4.11 Hook KeUserModeCallback
- 4.12 交換內(nèi)存
- 4.13 獲取函數(shù)Iat偏移
- 4.14 另一種方式獲取ShadowSSDT信息
TsFltMgr.sys分析
??該驅(qū)動(dòng)為qq管家函數(shù)過(guò)濾驅(qū)動(dòng)呈昔,提供SSDT达椰、SSSDT、進(jìn)程和線程回調(diào)等過(guò)濾操作跛溉,導(dǎo)出接口給TsKsp.sys使用焊切,2者共同做函數(shù)過(guò)濾操作,TsFltMgr提供設(shè)置函數(shù)過(guò)濾的框架芳室,而實(shí)際攔截過(guò)程在TsKsp中专肪。設(shè)備名\Device\TsFltMgr ,符號(hào)名\DosDevices\TsFltMgr 。加密手段:Rabbit算法、MD5算法切威。通過(guò)InlineHook KifastCallEntry實(shí)現(xiàn)掛鉤砚殿。
一芽死、驅(qū)動(dòng)入口DriverEntry
- 創(chuàng)建\Device\TSSysKit設(shè)備和\DosDevices\TSSysKit符號(hào)鏈接
- 設(shè)置DeviceExtension為通信接口(Interface函數(shù)指針)
- 分別注冊(cè)IRP_MJ_CREATE乏梁、IRP_MJ_CLOSE、IRP_MJ_DEVICE_CONTROL关贵、IRP_MJ_SHUTDOWN(關(guān)機(jī)回調(diào))派遣例程為遇骑,CreateCloseDispatch、DeviceIoControlDispatch揖曾、ShutdownDispatch
- 注冊(cè)”Boot驅(qū)動(dòng)加載結(jié)束”回調(diào)DriverReinitializationRoutine
- 為注冊(cè)表日志記錄分配資源RegLogSpace
- 檢查當(dāng)前系統(tǒng)是否為注冊(cè)表version鍵指定的系統(tǒng)落萎,如果在列表中則在掛鉤KiFastCallEntry時(shí)需要做額外工作
- 設(shè)置注冊(cè)表鍵IsBsod為1,用于檢測(cè)該驅(qū)動(dòng)是否引起藍(lán)屏(正常關(guān)機(jī)置0)
- 獲取系統(tǒng)BuildNumber
- 分配和設(shè)置”內(nèi)核Api代理”結(jié)構(gòu)
- 掛鉤KiFastCallEntry
- 掛鉤重要回調(diào)
- 啟動(dòng)注冊(cè)表日志記錄
- 掛鉤KeUserModeCallback
- 記錄當(dāng)前配置
1.1 過(guò)濾模型
[圖片上傳失敗...(image-a25680-1516663378349)]
- Ntdll.NtCreateFile通過(guò)Sysenter調(diào)用進(jìn)入nt.KiFastCallEntry
- 在nt.KiFastCallEntry 執(zhí)行call ebx(原始為nt.NtCreateFile)前跳到TsFltMgr. InlineKiFastCallEntry
- 執(zhí)行進(jìn)入TsFltMgr.HookFilter炭剪,在這里通過(guò)ServiceMapTable表映射到對(duì)應(yīng)Dproxy元素练链,將Dproxy->ProxyNtCreateFile設(shè)置到ebx,將其設(shè)置為ebx
- Nt.KiFastCallEntry執(zhí)行call ebx奴拦,進(jìn)入ProxyNtCreateFile
- 構(gòu)造FilterPacket結(jié)構(gòu)(用于承載參數(shù)媒鼓、原始api和PostFilterFunc執(zhí)行的所有過(guò)濾函數(shù)都用到),依次執(zhí)行Dproxy->PrevFilterSlot的16個(gè)過(guò)濾函數(shù)(PrevFilter是Tsksp事先設(shè)置好的)
- 依次執(zhí)行單個(gè)Tsksp.PrevFilter错妖,進(jìn)行真正的過(guò)濾或?qū)acket. PostFilterSlot進(jìn)行設(shè)置
- 返回TsFltMgr.ProxyNtCreateFile绿鸣,執(zhí)行nt.NtCreateFile
- 執(zhí)行packet. PostFilterSlot的16個(gè)過(guò)濾函數(shù)(Tsksp)
- 返回nt.KiFastCallEntry
1.2 檢查當(dāng)前系統(tǒng)是否為默認(rèn)掛鉤系統(tǒng)
BOOLEAN IsUnSupportedSystem()
{
/*注:\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\TSKS version
存放沒(méi)有預(yù)存 函數(shù)調(diào)用號(hào)ServiceIndex 的系統(tǒng)版本列表 格式:
BuildNumber1;BuildNumber2;...
對(duì)于這些版本在進(jìn)行SSDT Hook時(shí),會(huì)臨時(shí)取得服務(wù)號(hào)
*/
NTSTATUS status;
ULONG BuildNumber = 0,MajorVersion,MinorVersion;
const int BufSize = 1024;
ULONG Size,Type;
WCHAR BuildNumberStr[10] = {0};
BOOLEAN Match = FALSE;
UNICODE_STRING UBuildNumber;
WCHAR* Buffer = (WCHAR*)ExAllocatePool(NonPagedPool,BufSize);
status = GetRegDataWithSizeAndType(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\TSKSP",L"version",
Buffer,BufSize,&Size,&Type);
if(NT_SUCCESS(status) && Type == REG_SZ && Size)
{
Buffer[510] = 0;
RtlInitUnicodeString(&UBuildNumber,BuildNumberStr);
PsGetVersion(&MajorVersion,&MinorVersion,&BuildNumber,NULL);
RtlIntegerToUnicodeString(BuildNumber,10,&UBuildNumber);
if(wcsstr((wchar_t*)Buffer,UBuildNumber.Buffer))
Match = TRUE;
}
ExFreePool(Buffer);
return Match;
}
1.3 打開(kāi)TsFltMgr日志記錄
??在無(wú)保護(hù)情況下為\REGISTRY\MACHINE\SYSTEM\CurrentControlSet\Services\TsFltMgr添加TsDbgLog鍵站玄,內(nèi)容設(shè)置為目標(biāo)文件路徑(例如??\C:\TsDbgLog.txt)枚驻,如果不存在會(huì)自動(dòng)創(chuàng)建文件濒旦,重啟生效株旷。內(nèi)容示例:
[0x00000000] 2015.09.27 20:05:24.109 TS TsFltMgr DbgHelper
[0x00000001] 2015.09.27 20:06:13.750 [Sysnap DbgLog] Block--> TableIndex 0, Process spoolsv.exe[1800]
[0x00000002] 2015.09.27 20:10:35.156 [Sysnap DbgLog] Block--> TableIndex 4, Process regedit.exe[2296]
[0x00000003] 2015.09.27 20:13:46.500 [Sysnap DbgLog] Block--> TableIndex 4, Process regedit.exe[2296]
- DriverReinitializationRoutine中做初始化,此時(shí)最后一個(gè)boot驅(qū)動(dòng)初始化完畢
- 在執(zhí)行KiFastCallEntry hook時(shí)再次嘗試啟動(dòng)打印日志線程
- ExecPrevSlotFunc中尔邓,如果存在過(guò)濾函數(shù)進(jìn)行了放行和攔截晾剖,都會(huì)打印日志
1.4 控制信息
禁止hook
??\REGISTRY\MACHINE\SYSTEM\CurrentControlSet\Services\TsFltMgr dws=1
??\REGISTRY\MACHINE\SYSTEM\CurrentControlSet\services\QQSysMon\DWS dws!=0強(qiáng)制SSDT hook
??\REGISTRY\MACHINE\SYSTEM\CurrentControlSet\Services\TsFltMgr thm=1關(guān)機(jī)回調(diào)
??設(shè)置\REGISTRY\MACHINE\SYSTEM\CurrentControlSet\Services\TsFltMgr IsBsod=0,以便下次啟動(dòng)檢測(cè)是否TsFltMgr引起藍(lán)屏
1.5 全局表
BuildNumber:
Win2000
2195 1
WinXp
2600 2
WinServer2003
3790 3
WinVista
6000 4
6001 5
6002 6
Win7
7600 7
7601 8
Win8
8102 9
8250 10
8400 11
8432 12
8441 12
8520 13
Win8.1
9200 14
9600 15
Win10
9841 16
9860 17
9926 18
10041 19
10049 20
未知 0
enum
{
WIN2000=1,
WINXP,
WINXPSP3,
WINVISTA,
WINVISTASP1,
WINVISTASP2,
WIN7,
WIN7SP1,
WIN8_8102,
WIN8_8250,
WIN8_8400,
WIN8_8432,
WIN8_8441=WIN8_8432,
WIN8_8520,
WIN81_9200,
WIN81_9600,
WIN10_9841,
WIN10_9860,
WIN10_9926,
WIN10_10041,
WIN10_10049,
BUILDMAX,
};
enum
{
SSDT=0,
SSSDT=1,
END=2,
CALLBACK=3,
};
#define APINUMBER 105
struct SProxy
{
ULONG ServiceTableType;//0:SSDT 1:Shadow SSDT 2:結(jié)束符
PWCHAR ApiName;//函數(shù)名
ULONG ProxyFunc;//代理函數(shù)地址
ULONG ServiceIndex[BUILDMAX];
ULONG IndexInTable;//在全局表中的索引
};
struct DProxy
{
ULONG ServiceTableType;//0:SSDT 1:Shadow SSDT 2:結(jié)束符 3:回調(diào)函數(shù)
ULONG ServiceIndex;//服務(wù)號(hào)
PWCHAR ApiName;//函數(shù)名
ULONG TableIndex;//自定義序號(hào)
BOOLEAN IsInitialized;
ULONG PrevFilterRefCount;//引用計(jì)數(shù)
ULONG PostFilterRefCount;//引用計(jì)數(shù)
ULONG OriginFuncAddr;//原始函數(shù)地址
ULONG ProxyFuncAddr;//代理函數(shù)地址
PVOID Log;//用于記錄日志
KEVENT Lock;
BOOLEAN DisablePrevFilter;//關(guān)閉Filter
ULONG UsedSlotCount;// 當(dāng)前使用的Slot個(gè)數(shù)
FILTER_SLOT PrevFilterSlot[16];//過(guò)濾函數(shù)結(jié)構(gòu)
};
struct FILTER_SLOT
{
ULONG Tag;
ULONG CallCount;
ULONG DeleteCount;
KTIMER Timer;
ULONG Filter;
};
struct FilterPacket
{
ULONG CurrentSlot;//當(dāng)前Filter序號(hào)
ULONG ParamNumber;//參數(shù)個(gè)數(shù)
ULONG Params[12];//參數(shù)
ULONG TagSlot[16];//標(biāo)志過(guò)濾函數(shù)用梯嗽,也可用于傳遞修改參數(shù)
NTSTATUS Status;//執(zhí)行結(jié)果
ULONG OriginFuncAddr;//原始函數(shù)
ULONG IndexInTable;//在DProxyTable中的索引
ULONG Access;//訪問(wèn)權(quán)限
ULONG PostFilterSlot[16];//過(guò)濾函數(shù)
ULONG UsedSlotCount;//當(dāng)前使用的Slot個(gè)數(shù)
};
TsFltMgr有3張表與函數(shù)過(guò)濾相關(guān):
靜態(tài)Api代理表SProxy SProxyTable[APINUMBER+1] 用于初始化后面2個(gè)表
動(dòng)態(tài)Api代理表DProxy* DProxyTable[APINUMBER+1] 用于Proxy*函數(shù)中進(jìn)行實(shí)際過(guò)濾操作 方便用SProxy指定的序號(hào)配置
DProxy* ServiceMapTable[2][1024] 用于InlineHook KiFastCallEntry改變ebx齿尽,映射ServiceIndex到Proxy*函數(shù)。函數(shù)前1024個(gè)用于存儲(chǔ)SSDT函數(shù)灯节,后1024用于存儲(chǔ)SSSDT函數(shù)
可以用簡(jiǎn)單的python命令自動(dòng)獲取到g_ProxyApiTable內(nèi)容
addr=0x25200
index=0
while index < 106:
if Dword(addr) == 0:
type="SSDT"
elif Dword(addr) == 1:
type="SSSDT"
else:
type="END"
ApiName=GetString(Dword(addr+4),-1,ASCSTR_UNICODE)
ProxyFunc="Proxy"+ApiName
print "{\n\t%s,L\"%s\",%s,\n\t{" %(type,ApiName,ProxyFunc)
print "\t\t%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d" %(Dword(addr+12),Dword(addr+16),Dword(addr+20),Dword(addr+24),Dword(addr+28),Dword(addr+32),Dword(addr+36),Dword(addr+40),Dword(addr+44),Dword(addr+48),Dword(addr+52),Dword(addr+56),Dword(addr+60),Dword(addr+64),Dword(addr+68),Dword(addr+72),Dword(addr+76),Dword(addr+80),Dword(addr+84),Dword(addr+88),Dword(addr+92))
print "\t},%d\n}," %(Dword(addr+96))
addr=addr+100
index=index+1
struct SProxy SProxyTable[APINUMBER+1] =
{
{
SSDT,L"ZwCreateKey",ProxyZwCreateKey,
{
1023,35,41,43,64,64,64,70,70,347,351,351,350,350,350,354,355,355,356,359,359
},0
},
{
SSDT,L"ZwTerminateProcess",ProxyZwTerminateProcess,
{
1023,224,257,266,338,334,334,370,370,35,35,35,35,35,35,35,36,36,36,36,36
},1
},
{
SSDT,L"ZwSetInformationFile",ProxyZwSetInformationFile,
{
1023,194,224,233,305,301,301,329,329,78,79,79,78,78,78,81,82,82,82,82,82
},2
},
{
SSDT,L"ZwWriteFile",ProxyZwWriteFile,
{
1023,237,274,284,359,355,355,396,396,4,5,5,5,5,5,6,7,7,7,7,7
},3
},
{
SSDT,L"ZwSetValueKey",ProxyZwSetValueKey,
{
1023,215,247,256,328,324,324,358,358,48,48,48,48,48,48,49,50,50,50,50,50
},4
},
{
SSDT,L"ZwWriteVirtualMemory",ProxyZwWriteVirtualMemory,
{
1023,240,277,287,362,358,358,399,399,1,2,2,2,2,2,3,4,4,4,4,4
},5
},
{
SSDT,L"ZwCreateFile",ProxyZwCreateFile,
{
1023,32,37,39,60,60,60,66,66,351,356,356,355,355,355,360,361,361,362,365,365
},6
},
{
SSDT,L"ZwOpenProcess",ProxyZwOpenProcess,
{
1023,106,122,128,194,194,194,190,190,220,222,222,221,221,221,224,225,225,226,227,227
},7
},
{
SSDT,L"ZwDeleteKey",ProxyZwDeleteKey,
{
1023,53,63,66,123,123,123,103,103,310,314,314,313,313,313,317,318,318,319,321,321
},8
},
{
SSDT,L"ZwDeleteValueKey",ProxyZwDeleteValueKey,
{
1023,55,65,68,126,126,126,106,106,307,311,311,310,310,310,314,315,315,316,318,318
},9
},
{
SSDT,L"ZwRequestWaitReplyPort",ProxyZwRequestWaitReplyPort,
{
1023,176,200,208,275,276,276,299,299,108,110,110,109,109,109,112,113,113,114,114,114
},10
},
{
SSDT,L"ZwQueryValueKey",ProxyZwQueryValueKey,
{
1023,155,177,185,252,252,252,266,266,143,145,145,144,144,144,147,148,148,149,149,149
},11
},
{
SSDT,L"ZwEnumerateValueKey",ProxyZwEnumerateValueKey,
{
1023,61,73,77,136,136,136,119,119,292,296,296,295,295,295,299,300,300,301,303,303
},12
},
{
SSDT,L"ZwCreateThread",ProxyZwCreateThread,
{
1023,46,53,55,78,78,78,87,87,330,334,334,333,333,333,337,338,338,339,342,342
},13
},
{
SSDT,L"ZwDuplicateObject",ProxyZwDuplicateObject,
{
1023,58,68,71,129,129,129,111,111,300,304,304,303,303,303,307,308,308,309,311,311
},14
},
{
SSDT,L"ZwLoadDriver",ProxyZwLoadDriver,
{
1023,85,97,101,165,165,165,155,155,255,257,257,256,256,256,259,260,260,261,263,263
},15
},
{
SSDT,L"ZwDeviceIoControlFile",ProxyZwDeviceIoControlFile,
{
1023,56,66,69,127,127,127,107,107,304,308,308,307,307,307,311,312,312,313,315,315
},16
},
{
SSDT,L"ZwAlpcSendWaitReceivePort",ProxyZwAlpcSendWaitReceivePort,
{
1023,1023,1023,1023,38,38,38,39,39,381,386,386,385,385,385,390,391,391,393,396,396
},17
},
{
SSDT,L"ZwSetSystemInformation",ProxyZwSetSystemInformation,
{
1023,208,240,249,321,317,317,350,350,56,56,56,56,56,56,57,58,58,58,58,58
},18
},
{
SSDT,L"ZwDeleteFile",ProxyZwDeleteFile,
{
1023,52,62,65,122,122,122,102,102,311,315,315,314,314,314,318,319,319,320,322,322
},19
},
{
SSDT,L"ZwOpenSection",ProxyZwOpenSection,
{
1023,108,125,131,197,197,197,194,194,216,218,218,217,217,217,220,221,221,222,222,222
},20
},
{
SSDT,L"ZwCreateSection",ProxyZwCreateSection,
{
1023,43,50,52,75,75,75,84,84,333,337,337,336,336,336,340,341,341,342,345,345
},21
},
{
SSDT,L"ZwSuspendThread",ProxyZwSuspendThread,
{
1023,221,254,263,335,331,331,367,367,38,38,38,38,38,38,38,39,39,39,39,39
},22
},
{
SSDT,L"ZwTerminateThread",ProxyZwTerminateThread,
{
1023,225,258,267,339,335,335,371,371,34,34,34,34,34,34,34,35,35,35,35,35
},23
},
{
SSDT,L"ZwSystemDebugControl",ProxyZwSystemDebugControl,
{
1023,222,255,264,336,332,332,368,368,37,37,37,37,37,37,37,38,38,38,38,38
},24
},
{
SSDT,L"ZwProtectVirtualMemory",ProxyZwProtectVirtualMemory,
{
1023,1023,137,143,210,210,210,215,215,194,196,196,195,195,195,198,199,199,200,200,200
},38
},
{
SSDT,L"ZwCreateSymbolicLinkObject",ProxyZwCreateSymbolicLinkObject,
{
1023,45,52,54,77,77,77,86,86,331,335,335,334,334,334,338,339,339,340,343,343
},39
},
{
SSDT,L"ZwSetContextThread",ProxyZwSetContextThread,
{
1023,1023,213,221,293,289,289,316,316,91,92,92,91,91,91,94,95,95,95,95,95
},40
},
{
SSDT,L"ZwRenameKey",ProxyZwRenameKey,
{
1023,1023,192,200,267,267,267,290,290,117,119,119,118,118,118,121,122,122,123,123,123
},41
},
{
SSDT,L"ZwOpenThread",ProxyZwOpenThread,
{
1023,111,128,134,201,201,201,198,198,214,214,214,213,213,213,216,217,217,218,218,218
},42
},
{
SSDT,L"ZwGetNextThread",ProxyZwGetNextThread,
{
1023,1023,1023,1023,372,368,368,140,140,271,271,271,270,270,270,273,274,274,275,277,277
},43
},
{
SSDT,L"ZwCreateThreadEx",ProxyZwCreateThreadEx,
{
1023,1023,1023,1023,388,382,382,88,88,333,333,333,332,332,332,336,337,337,338,341,341
},44
},
{
SSDT,L"ZwRestoreKey",ProxyZwRestoreKey,
{
1023,1023,204,212,279,280,280,302,302,105,107,107,106,106,106,109,110,110,111,111,111
},55
},
{
SSDT,L"ZwReplaceKey",ProxyZwReplaceKey,
{
1023,1023,193,201,268,268,268,292,292,115,117,117,116,116,116,119,120,120,121,121,121
},56
},
{
SSDT,L"ZwGetNextProcess",ProxyZwGetNextProcess,
{
1023,1023,1023,1023,371,367,367,139,139,270,272,272,271,271,271,274,275,275,276,278,278
},45
},
{
SSDT,L"ZwUnmapViewOfSection",ProxyZwUnmapViewOfSection,
{
1023,231,267,277,352,348,348,385,385,19,19,19,19,19,19,19,20,20,20,20,20
},46
},
{
SSDT,L"ZwAssignProcessToJobObject",ProxyZwAssignProcessToJobObject,
{
1023,18,19,21,42,42,42,43,43,377,382,382,381,381,381,386,387,387,389,392,392
},47
},
{
SSDT,L"ZwAllocateVirtualMemory",ProxyZwAllocateVirtualMemory,
{
1023,16,17,18,18,18,18,19,19,403,407,407,406,406,406,411,412,412,415,418,418
},57
},
{
SSDT,L"ZwFreeVirtualMemory",ProxyZwFreeVirtualMemory,
{
1023,71,83,87,147,147,147,131,131,278,281,281,280,280,280,284,285,285,286,288,288
},58
},
{
SSSDT,L"NtUserFindWindowEx",ProxyNtUserFindWindowEx,
{
1023,368,378,377,391,391,391,396,396,455,457,458,459,460,459,460,462,466,466,466,467
},25
},
{
SSSDT,L"NtUserBuildHwndList",ProxyNtUserBuildHwndList,
{
1023,302,312,311,322,322,322,323,323,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},26
},
{
SSSDT,L"NtUserQueryWindow",ProxyNtUserQueryWindow,
{
1023,466,483,481,504,504,504,515,515,478,480,481,482,483,482,483,485,489,489,489,490
},27
},
{
SSSDT,L"NtUserGetForegroundWindow",ProxyNtUserGetForegroundWindow,
{
1023,393,404,403,418,418,418,423,423,426,428,429,430,430,429,430,431,435,435,435,435
},28
},
{
SSSDT,L"NtUserWindowFromPoint",ProxyNtUserWindowFromPoint,
{
1023,568,592,588,617,617,617,629,629,640,643,646,648,650,649,652,658,664,665,666,667
},29
},
{
SSSDT,L"NtUserSetParent",ProxyNtUserSetParent,
{
1023,510,529,526,550,550,550,560,560,582,585,587,589,591,590,593,595,601,602,603,604
},30
},
{
SSSDT,L"NtUserSetWindowLong",ProxyNtUserSetWindowLong,
{
1023,525,544,540,566,566,566,578,578,560,562,564,566,567,566,569,571,575,576,576,577
},31
},
{
SSSDT,L"NtUserMoveWindow",ProxyNtUserMoveWindow,
{
1023,449,465,464,484,484,484,495,495,499,501,502,503,504,503,505,507,511,511,511,512
},32
},
{
SSSDT,L"NtUserSetWindowPos",ProxyNtUserSetWindowPos,
{
1023,527,546,542,568,568,568,580,580,558,560,562,564,565,564,567,569,573,574,574,575
},33
},
{
SSSDT,L"NtUserSetWindowPlacement",ProxyNtUserSetWindowPlacement,
{
1023,526,545,541,567,567,567,579,579,559,561,563,565,566,565,568,570,574,575,575,576
},34
},
{
SSSDT,L"NtUserShowWindow",ProxyNtUserShowWindow,
{
1023,536,555,551,579,579,579,591,591,547,549,551,553,554,553,556,558,562,563,563,564
},35
},
{
SSSDT,L"NtUserShowWindowAsync",ProxyNtUserShowWindowAsync,
{
1023,537,556,552,580,580,580,592,592,546,548,550,552,553,552,555,557,561,562,562,563
},36
},
{
SSSDT,L"NtUserSendInput",ProxyNtUserSendInput,
{
1023,481,502,500,525,525,525,536,536,606,609,611,613,615,614,617,619,625,626,627,628
},37
},
{
SSSDT,L"NtUserSetWinEventHook",ProxyNtUserSetWinEventHook,
{
1023,533,552,548,576,576,576,588,588,550,552,554,556,557,556,559,561,565,566,566,567
},49
},
{
SSSDT,L"NtUserClipCursor",ProxyNtUserClipCursor,
{
1023,0,330,329,343,343,343,348,348,333,334,335,335,335,335,337,338,342,342,342,342
},48
},
{
SSSDT,L"NtUserSetWindowsHookEx",ProxyNtUserSetWindowsHookEx,
{
1023,530,549,545,573,573,573,585,585,553,555,557,559,560,559,562,564,568,569,569,570
},50
},
{
SSDT,L"ZwMakeTemporaryObject",ProxyZwMakeTemporaryObject,
{
1023,1023,105,110,174,174,174,164,164,246,248,248,247,247,247,250,251,251,252,254,254
},59
},
{
SSDT,L"ZwCreateUserProcess",ProxyZwCreateUserProcess,
{
1023,1023,1023,1023,1023,383,383,93,93,322,326,326,325,325,325,329,330,330,331,334,334
},60
},
{
SSSDT,L"NtUserMessageCall",ProxyNtUserMessageCall,
{
1023,444,460,459,479,479,479,490,490,504,506,507,508,509,508,510,512,516,516,516,517
},61
},
{
SSSDT,L"NtUserPostMessage",ProxyNtUserPostMessage,
{
1023,459,475,474,497,497,497,508,508,486,488,489,490,491,490,492,494,498,498,498,499
},62
},
{
SSSDT,L"NtUserPostThreadMessage",ProxyNtUserPostThreadMessage,
{
1023,460,476,475,498,498,498,509,509,485,487,488,489,490,489,491,493,497,497,497,498
},63
},
{
SSSDT,L"NtUserBuildHwndList_WIN8",ProxyNtUserBuildHwndList_WIN8,
{
1023,1023,1023,1023,1023,1023,1023,1023,1023,358,359,360,360,360,360,362,363,367,367,367,367
},64
},
{
SSDT,L"ZwFsControlFile",ProxyZwFsControlFile,
{
1023,1023,84,1023,150,150,150,134,134,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},65
},
{
SSSDT,L"NtUserSetImeInfoEx",ProxyNtUserSetImeInfoEx,
{
1023,1023,517,1023,1023,1023,1023,550,550,1023,1023,1023,1023,1023,600,603,605,611,612,613,1023
},66
},
{
SSDT,L"ZwCreateProcessEx",ProxyZwCreateProcessEx,
{
1023,1023,48,50,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},72
},
{
SSSDT,L"NtUserGetRawInputData",ProxyNtUserGetRawInputData,
{
1023,1023,428,1023,1023,1023,1023,448,448,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},67
},
{
SSSDT,L"NtUserGetRawInputBuffer",ProxyNtUserGetRawInputBuffer,
{
1023,1023,427,1023,1023,1023,1023,447,447,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},68
},
{
SSSDT,L"NtUserGetAsyncKeyState",ProxyNtUserGetAsyncKeyState,
{
1023,1023,383,1023,1023,1023,1023,402,402,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},69
},
{
SSSDT,L"NtUserGetKeyState",ProxyNtUserGetKeyState,
{
1023,1023,416,1023,1023,1023,1023,436,436,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},70
},
{
SSSDT,L"NtUserGetKeyboardState",ProxyNtUserGetKeyboardState,
{
1023,1023,414,1023,1023,1023,1023,434,434,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},71
},
{
SSDT,L"ZwQueueApcThread",ProxyZwQueueApcThread,
{
1023,1023,180,1023,1023,1023,1023,269,269,1023,1023,1023,1023,1023,139,142,143,143,144,144,144
},74
},
{
SSDT,L"ZwSetSecurityObject",ProxyZwSetSecurityObject,
{
1023,1023,237,1023,1023,1023,1023,347,347,1023,1023,1023,1023,1023,59,60,61,61,61,61,61
},75
},
{
SSDT,L"ZwOpenFile",ProxyZwOpenFile,
{
1023,1023,116,1023,1023,1023,1023,179,179,1023,1023,1023,1023,1023,232,235,236,236,237,238,238
},76
},
{
SSDT,L"ZwQueueApcThreadEx",ProxyZwQueueApcThreadEx,
{
1023,1023,1023,1023,1023,1023,1023,270,270,1023,1023,1023,1023,1023,138,141,142,142,143,143,143
},77
},
{
SSDT,L"ZwCreateMutant",ProxyZwCreateMutant,
{
1023,1023,43,45,67,67,67,74,74,1023,1023,1023,1023,1023,346,350,351,351,352,355,355
},78
},
{
SSDT,L"ZwQuerySystemInformation",ProxyZwQuerySystemInformation,
{
1023,1023,173,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},79
},
{
SSDT,L"ZwQueryIntervalProfile",ProxyZwQueryIntervalProfile,
{
1023,1023,158,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},80
},
{
SSDT,L"ZwSetInformationProcess",ProxyZwSetInformationProcess,
{
1023,1023,228,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},81
},
{
SSSDT,L"NtGdiAddFontMemResourceEx",ProxyNtGdiAddFontMemResourceEx,
{
1023,1023,4,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},82
},
{
SSDT,L"ZwReplyWaitReceivePortEx",ProxyZwReplyWaitReceivePortEx,
{
1023,1023,196,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},83
},
{
END,L"KeUserModeCallback",ProxyKeUserModeCallback,
{
1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},51
},
{
SSDT,L"ZwOpenKey",ProxyZwOpenKey,
{
1023,1023,119,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},84
},
{
SSDT,L"ZwMapViewOfSection",ProxyZwMapViewOfSection,
{
1023,1023,108,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},85
},
{
SSDT,L"ZwSetIntervalProfile",ProxyZwSetIntervalProfile,
{
1023,1023,231,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},86
},
{
SSSDT,L"NtGdiAddFontResourceW",ProxyNtGdiAddFontResourceW,
{
1023,1023,2,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},87
},
{
SSSDT,L"NtGdiAddRemoteFontToDC",ProxyNtGdiAddRemoteFontToDC,
{
1023,1023,3,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},88
},
{
SSDT,L"ZwQueryInformationProcess",ProxyZwQueryInformationProcess,
{
1023,1023,154,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},89
},
{
SSDT,L"ZwQueryInformationThread",ProxyZwQueryInformationThread,
{
1023,1023,155,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},90
},
{
SSDT,L"ZwCreateProfile",ProxyZwCreateProfile,
{
1023,1023,49,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},91
},
{
SSDT,L"ZwVdmControl",ProxyZwVdmControl,
{
1023,1023,268,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},92
},
{
SSDT,L"ZwCreateProcess",ProxyZwCreateProcess,
{
1023,1023,47,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},93
},
{
SSSDT,L"NtGdiAddEmbFontToDC",ProxyNtGdiAddEmbFontToDC,
{
1023,1023,214,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},94
},
{
SSDT,L"NtDebugActiveProcess",ProxyNtDebugActiveProcess,
{
1023,1023,57,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},95
},
{
SSDT,L"NtAlpcCreatePort",ProxyNtAlpcCreatePort,
{
1023,1023,1023,1023,1023,1023,1023,23,23,1023,1023,1023,1023,1023,401,406,407,407,410,413,413
},96
},
{
SSDT,L"NtCreatePort",ProxyNtCreatePort,
{
1023,1023,46,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},97
},
{
SSDT,L"ZwAdjustPrivilegesToken",ProxyZwAdjustPrivilegesToken,
{
1023,1023,11,1023,1023,1023,1023,12,12,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},98
},
{
SSDT,L"ZwConnectPort",ProxyZwConnectPort,
{
1023,1023,31,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},99
},
{
SSDT,L"ZwSecureConnectPort",ProxyZwSecureConnectPort,
{
1023,1023,210,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},100
},
{
SSDT,L"ZwQueryKey",ProxyZwQueryKey,
{
1023,1023,160,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},101
},
{
SSDT,L"ZwEnumerateKey",ProxyZwEnumerateKey,
{
1023,1023,71,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},102
},
{
SSDT,L"ZwClose",ProxyZwClose,
{
1023,1023,25,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},103
},
{
SSSDT,L"NtUserSystemParametersInfo",ProxyNtUserSystemParametersInfo,
{
1023,1023,559,1023,1023,1023,1023,559,595,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023
},104
},
{
END,NULL,NULL,
{
-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
},105
}
};
1.6 Proxy*函數(shù)模型
NPAGED_LOOKASIDE_LIST FilterLookAside;
BOOLEAN g_EvaluateTime;
//Proxy*函數(shù)模型 3參數(shù)函數(shù)為例
NTSTATUS __stdcall ProxyNtFunc(int param1,int param2,int param3)
{
NTSTATUS status = STATUS_ACCESS_DENIED;
ULONG Result;//自定義結(jié)果
ULONGLONG Time = 0;
DProxy* proxydata = DProxyTable[ENtFunc];
FilterPacket* packet = ExAllocateFromNPagedLookasideList(&FilterLookAside);
if(g_EvaluateTime)
Time = KeQueryInterruptTime();
if(!packet)
{
if(!proxydata->OriginFuncAddr)
return status;
return proxydata->OriginFuncAddr(param1,param2,param3);
}
packet->Params[0] = param1;
packet->Params[1] = param2;
packet->Params[2] = param3;
packet->ParamNumber = 3;
packet->OriginFuncAddr = proxydata->OriginFuncAddr;
packet->IndexInTable = ENtFunc;
InterlockedIncrement(&proxydata->PrevFilterRefCount);
Result = ExecPrevFilter(packet,proxydata);//Prev過(guò)濾
InterlockedDecrement(&proxydata->PrevFilterRefCount);
if(Result == SYSMON_UNHANDLED)
{
if(packet->OriginFuncAddr)
{
status = packet->OriginFuncAddr(param1,param2,param3);
packet->Status = status;
InterlockedIncrement(&proxydata->PostFilterRefCount);
Result = ExecPostFilter(packet);//Post過(guò)濾
InterlockedDecrement(&proxydata->PostFilterRefCount);
}
}
if(Result == SYSMON_HANDLED)
{
status = packet->Status;
}
if(g_EvaluateTime)
EvaluateTime(proxydata,Time);
ExDeleteNPagedLookasideList(packet);
return status;
}
ULONG ExecPrevFilter(FilterPacket* packet,DProxy* proxydata)
{
ULONG Result;
if(!proxydata || !packet || packet->DisablePrevFilter)
return SYSMON_UNHANDLED;
for(int i=0;i<16;i++)
{
if(!proxydata->PrevFilterSlot[i].DeleteCount && proxydata->PrevFilterSlot[i].Filter && proxydata->SlotNum != 0)
{
InterlockedIncrement(&proxydata->PrevFilterSlot[i].CallCount);
packet->CurrentSlot = i;
Result = proxydata->PrevFilterSlot[i].Filter(packet);
InterlockedDecrement(&proxydata->PrevFilterSlot[i].CallCount);
if(packet->Access & 0x10)//如果權(quán)限被設(shè)置為放行
{
TsLogSprintfOutput(SysMonLogPt,"[Sysnap DbgLog] Modify--> TableIndex %d, Process %s[%d] ",
proxydata->TableIndex,PsGetProcessImageFileName(IoGetCurrentProcess()),PsGetCurrentProcessId());
}
switch(Result)
{
case SYSMON_FORBID:
TsLogSprintfOutput(SysMonLogPt,"[Sysnap DbgLog] Block--> TableIndex %d, Process %s[%d] ",
proxydata->TableIndex,PsGetProcessImageFileName(IoGetCurrentProcess()),PsGetCurrentProcessId());
return SYSMON_FORBID;
case SYSMON_HANDLED:
return SYSMON_HANDLED;
case SYSMON_PASS:
case SYSMON_PASS1:
return SYSMON_UNHANDLED;
default:
break;
}
}
}
}
ULONG ExecPostFilter(FilterPacket* packet)
{
ULONG Result;
if(!packet)
return SYSMON_UNHANDLED;
FILTER_SLOT* CurrentSlot = DProxyTable[packet->IndexInTable]->PrevFilterSlot;
for(int i=0;i<16;i++)
{
if(!CurrentSlot [i].DeleteCount)
{
InterlockedIncrement(&CurrentSlot [i].CallCount);
packet->CurrentSlot = i;
Result = packet->PostFilterSlot(packet);
InterlockedDecrement(&CurrentSlot [i].CallCount);
}
switch(Result)
{
case SYSMON_HANDLED:
return SYSMON_HANDLED;
case SYSMON_PASS:
case SYSMON_PASS1:
case SYSMON_FORBID:
return SYSMON_UNHANDLED;
default:
break;
}
}
}
二循头、驅(qū)動(dòng)接口Interface
2.1 DeviceExtension接口
DeviceObject->DeviceExtension結(jié)構(gòu):
+00h TAG=’TSFL’
+14h FARPROC Interface
FARPROC Interface(intindex)
NTSTATUS Interface(int index,FARPROC* outfunc)
{//注意下面的函數(shù)都是自己實(shí)現(xiàn)的穿透函數(shù)
If(!outfunc)
Return STATUS_UNSUCCESSFUL;
switch(index)
{
case 0:
*outfunc = SetEvaluateTime;
Break;
case 1:
*outfunc = DisablePrevFilter;
Break;
case 2:
*outfunc = SetPostFilter;
Break;
case 3:
*outfunc = ExecOriginFromPacket;
Break;
case 4:
*outfunc = AddPrevFilter;
Break;
case 5:
*outfunc = RemovePrevFilter;
Break;
case 6:
*outfunc = GetCurrentHookInfo;
Break;
case 7:
*outfunc = GetDProxyTable;
Break;
default:
*outfunc = NULL;
Break;
}
Return STATUS_SUCESS;
}
2.2 SetEvaluateTime
Void __stdcall SetEvaluateTime(bool EvaluateTime)
{//設(shè)置計(jì)算過(guò)濾函數(shù)執(zhí)行耗時(shí)
g_EvaluateTime = EvaluateTime;
}
2.3 SetDisablePrevFilter
Void __stdcall SetDisablePrevFilter(ULONG Index,BOOLEAN Disable)
{//設(shè)置是否執(zhí)行PrevFilter(同時(shí)也是PostFilter)
If(Index < APINUMBER)
{
If(DProxyTable[Index])
DProxyTable[Index]-> DisablePrevFilter = Disable;
}
}
2.4 SetPostFilter
Void __stdcall SetPostFilter(FilterPacket* Packet,FARPROC Filter,ULONG Tag)
{//設(shè)置PostFilter函數(shù)
If(Packet)
{
Packet->TagSlot[Packet->CurrentSlot] = Tag;//用于修改參數(shù)或區(qū)分Filter
Packet->PostFilterSlot[Packet->CurrentSlot] = Filter;
Packet->SlotCount++;
}
}
2.5 ExecOriginFromPacket
NTSTATUS __stdcall ExecOriginFromPacket(FilterPacket* Packet)
{//執(zhí)行Nt*原始函數(shù)
If(!Packet || !Packet->OriginFuncAddr)
Return STATUS_UNSUCCESSFUL;
_asm
{
Mov eax, Packet->ParamNumber
Test eax,eax
Jbe tag1
Lea ecx,[eax-1]
Test ecx,ecx
Jl tag1
Lea edx,Packet->Params[ecx]//參數(shù)逐個(gè)壓棧
Tag1:
Mov eax,[edx]
Push eax
Sub ecx,1
Sub edx,4
Test ecx,ecx
Jge tag2
Tag2:
Call Packet->OriginFuncAddr
}
}
2.6 AddPrevFilter
NTSTATUS __stdcall ExecOriginFromPacket(FilterPacket* Packet)
{//執(zhí)行Nt*原始函數(shù)
If(!Packet || !Packet->OriginFuncAddr)
Return STATUS_UNSUCCESSFUL;
_asm
{
Mov eax, Packet->ParamNumber
Test eax,eax
Jbe tag1
Lea ecx,[eax-1]
Test ecx,ecx
Jl tag1
Lea edx,Packet->Params[ecx]//參數(shù)逐個(gè)壓棧
Tag1:
Mov eax,[edx]
Push eax
Sub ecx,1
Sub edx,4
Test ecx,ecx
Jge tag2
Tag2:
Call Packet->OriginFuncAddr
}
}
2.7 RemovePrevFilter
void WaitStop(FILTER_SLOT* CurrentSlot)
{
KeInitializeTimer(&CurrentSlot->Timer);
Li.QuadPart = 1000000;
while(CurrentSlot->CallCount)
{
KeSetTimer(&CurrentSlot->Timer,&Li,NULL);
KeWaitForSingleObject(&CurrentSlot->Timer,Executive,KernelMode,FALSE,NULL);
}
KeCancelTimer(&CurrentSlot->Timer);
}
NTSTATUS __fastcall RemovePrevFilter(ULONG Index,FARPROC Filter)
{//從Index對(duì)應(yīng)的函數(shù)過(guò)濾中查找刪除Filter
if(!Filter || Index >= APINUMBER)
return STATUS_UNSUCCESSFUL;
if(!DProxyTable[Index] || !DProxyTable[Index]->IsInitialized)
return STATUS_UNSUCCESSFUL;
for(int i=0;i<16;i++)
{
if(DProxyTable[Index]->PrevFilterSlot[i].Filter == Filter)
{
LARGE_INTEGER Li;
FILTER_SLOT* CurrentSlot = &DProxyTable[Index]->PrevFilterSlot[i];
CurrentSlot->DeleteCount = FALSE;
InterlockedIncrement(&CurrentSlot->DeleteCount);
WaitStop(CurrentSlot);
InterlockedExchange(&CurrentSlot->Filter,NULL);
InterlockedDecrement(&DProxyTable[Index]->UsedSlotCount);
WaitStop(CurrentSlot);
InterlockedDecrement(&CurrentSlot->DeleteCount);
return STATUS_UNSUCCESSFUL;
}
}
return STATUS_UNSUCCESSFUL;
}
2.8 GetCurrentHookInfo
NTSTATUS __stdcall GetCurrentHookInfo(PULONG pLastErrorCode,PULONG pserHookType,PULONG pOsVer,PULONG pHookErrorIndex)
{
if(OsVer && !LastErrorCode && HookErrorIndex == -1)
{
if(pLastErrorCode)
*pLastErrorCode = 0;//獲取系統(tǒng)buildnumber
if(pserHookType)
*pserHookType = serHookType;
if(pOsVer)
*pOsVer = OsVer;
if(pHookErrorIndex)
*pHookErrorIndex = HookErrorIndex;
}
return STATUS_UNSUCCESSFUL;
}
LastErrorCode
0x01 ZwQuerySystemInformation獲取失敗
0x02 KeServiceDescriptorTable獲取失敗
0x04 KeAddSystemServiceTable獲取失敗
0x08 ShadowSSDT獲取失敗
0x10 MmUserProbeAddress獲取失敗
0x20 Int2E校驗(yàn)失敗
InitState
0x01 ZwQuerySystemInformation獲取成功
0x02 KeServiceDescriptorTable獲取成功
0x04 ShadowSSDT獲取成功
0x08 獲取Inline Hook點(diǎn)成功
serHookType 對(duì)KiFastCallEntry做inline hook的類型
0. Nonhook HOOKTYPE_NONE
1. Inlinehook HOOKTYPE_INLINE
2. SSDTHook HOOKTYPE_SSDT
3. 金山共存Inlinehook HOOKTYPE_KSINLINE
OsVer
BuildNumber:
Win2000
2195 1
WinXp
2600 2
WinServer2003
3790 3
WinVista
6000 4
6001 5
6002 6
Win7
7600 7
7601 8
Win8
8102 9
8250 10
8400 11
8432 12
8441 12
8520 13
Win8.1
9200 14
9600 15
Win10
9841 16
9860 17
9926 18
10041 19
10049 20
?? 0
HookErrorIndex
-1
IsBsod
記錄藍(lán)屏
三、基礎(chǔ)庫(kù)
3.1 獲取注冊(cè)表鍵值
NTSTATUS GetRegDataWithType(PWCHAR RegPath,PWCHAR KeyName,PVOID OutData,ULONG BufSize,PULONG OutType)
{
NTSTATUS status;
HANDLE KeyHandle = NULL;
ULONG ResultLength = 0;
OBJECT_ATTRIBUTES Oa;
UNICODE_STRING URegPath,UKeyName;
PVOID ValueInfo;
const int BufSize = sizeof(PKEY_VALUE_PARTIAL_INFORMATION) + sizeof(WCHAR[260]);
if(!RegPath || !KeyName)
return STATUS_INVALID_PARAMETER;
InitializeObjectAttributes(&Oa,&URegPath,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,NULL,NULL);
status = ZwOpenKey(&KeyHandle,KEY_EXECUTE,&Oa);
ValueInfo = ExAllocatePool(NonPagedPool,BufSize);
if(NT_SUCCESS(status) && ValueInfo)
{
RtlZeroMemory(ValueInfo,BufSize);
RtlInitUnicodeString(&UKeyName,KeyName);
status = ZwQueryValueKey(KeyHandle,&UKeyName,KeyValuePartialInformation,ValueInfo,BufSize,&ResultLength);
if(NT_SUCCESS(status))
{
PKEY_VALUE_PARTIAL_INFORMATION Info = (PKEY_VALUE_PARTIAL_INFORMATION)ValueInfo;
if(OutType)
*OutType = Info->Type;
if(OutData)
RtlCopyMemory(OutData,Info->Data,BufSize<Info->DataLength?BufSize:Info->DataLength);
}
}
if(KeyHandle)
ZwClose(KeyHandle);
if(ValueInfo)
ExFreePool(ValueInfo);
return status;
}
NTSTATUS GetRegDataWithSize(PWCHAR RegPath,PWCHAR KeyName,PVOID OutData,ULONG BufSize,PULONG OutSize)
{
NTSTATUS status;
HANDLE KeyHandle = NULL;
ULONG ResultLength = 0;
OBJECT_ATTRIBUTES Oa;
UNICODE_STRING URegPath,UKeyName;
PVOID ValueInfo;
const int BufSize = sizeof(PKEY_VALUE_PARTIAL_INFORMATION) + sizeof(WCHAR[260]);
if(!RegPath || !KeyName)
return STATUS_INVALID_PARAMETER;
InitializeObjectAttributes(&Oa,&URegPath,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,NULL,NULL);
status = ZwOpenKey(&KeyHandle,KEY_EXECUTE,&Oa);
ValueInfo = ExAllocatePool(NonPagedPool,BufSize);
if(NT_SUCCESS(status) && ValueInfo)
{
RtlZeroMemory(ValueInfo,BufSize);
RtlInitUnicodeString(&UKeyName,KeyName);
status = ZwQueryValueKey(KeyHandle,&UKeyName,KeyValuePartialInformation,ValueInfo,BufSize,&ResultLength);
if(NT_SUCCESS(status))
{
PKEY_VALUE_PARTIAL_INFORMATION Info = (PKEY_VALUE_PARTIAL_INFORMATION)ValueInfo;
if(OutSize)
*OutSize = Info->DataLength;
if(OutData)
RtlCopyMemory(OutData,Info->Data,BufSize<Info->DataLength?BufSize:Info->DataLength);
}
}
if(KeyHandle)
ZwClose(KeyHandle);
if(ValueInfo)
ExFreePool(ValueInfo);
return status;
}
NTSTATUS GetRegDataWithSizeAndType(PWCHAR RegPath,PWCHAR KeyName,PVOID OutData,ULONG BufSize,PULONG OutSize,PULONG OutType)
{
NTSTATUS status;
HANDLE KeyHandle = NULL;
ULONG ResultLength = 0;
OBJECT_ATTRIBUTES Oa;
UNICODE_STRING URegPath,UKeyName;
PVOID ValueInfo;
const int BufSize = sizeof(PKEY_VALUE_PARTIAL_INFORMATION) + sizeof(WCHAR[260]);
if(!RegPath || !KeyName)
return STATUS_INVALID_PARAMETER;
InitializeObjectAttributes(&Oa,&URegPath,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,NULL,NULL);
status = ZwOpenKey(&KeyHandle,KEY_EXECUTE,&Oa);
ValueInfo = ExAllocatePool(NonPagedPool,BufSize);
if(NT_SUCCESS(status) && ValueInfo)
{
RtlZeroMemory(ValueInfo,BufSize);
RtlInitUnicodeString(&UKeyName,KeyName);
status = ZwQueryValueKey(KeyHandle,&UKeyName,KeyValuePartialInformation,ValueInfo,BufSize,&ResultLength);
if(NT_SUCCESS(status))
{
PKEY_VALUE_PARTIAL_INFORMATION Info = (PKEY_VALUE_PARTIAL_INFORMATION)ValueInfo;
if(OutSize)
*OutSize = Info->DataLength;
if(OutType)
*OutType = Info->Type;
if(OutData)
RtlCopyMemory(OutData,Info->Data,BufSize<Info->DataLength?BufSize:Info->DataLength);
}
}
if(KeyHandle)
ZwClose(KeyHandle);
if(ValueInfo)
ExFreePool(ValueInfo);
return status;
}
3.2 通過(guò)進(jìn)程名獲取進(jìn)程ID
HANDLE GetProcessIdByName(PWCHAR ProcessName)
{//根據(jù)進(jìn)程名獲取進(jìn)程ID
HANDLE ProcessId = 0;
NTSTATUS status = STATUS_SUCCESS;
SIZE_T size = 512;
UNICODE_STRING UProcessName;
LPVOID Buffer;
RtlInitUnicodeString(&UProcessName,ProcessName);
while(true)
{
Buffer = ExAllocatePool(PagedPool,size);
if(!Buffer)
return 0;
status = ZwQuerySystemInformation(SystemProcessesAndThreadsInformation,Buffer,size,NULL);
if(status != STATUS_INFO_LENGTH_MISMATCH)
break;
ExFreePool(Buffer);
size *= 2;
}
if(!NT_SUCCESS(Buffer))
ExFreePool(Buffer);
PSYSTEM_PROCESS_INFORMATION ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)Buffer;
while(ProcessInfo->NextEntryOffset)
{
ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)((UCHAR*)ProcessInfo + ProcessInfo->NextEntryOffset);
if(RtlEqualUnicodeString(&UProcessName,&ProcessInfo->ImageName,TRUE)
ProcessId = ProcessInfo->UniqueProcessId;
}
ExFreePool(Buffer);
return ProcessId;
}
3.3 Rabbit加密算法
??Q管很多驅(qū)動(dòng)中存在的用于傳輸時(shí)加密的可逆算法使用了Rabbit分組加密算法炎疆,可以分段加解密卡骂,加密過(guò)程和解密過(guò)程一致。根據(jù)驅(qū)動(dòng)中加解密過(guò)程可以得到如下代碼邏輯:
#define ld(x) ((x>>32)&0xFFFFFFFF)
#define hw(x) ((x>>16)&0xFFFF)
#define lw(x) (x&0xFFFF)
#define rotl(x,y) ((x<<y)|(x>>(32-y)))
struct Rabbit
{
unsigned int X[8];
unsigned int C[8];
unsigned int b;
};
bool Rabbit_nextState(Rabbit* rabbit);
bool Rabbit_Init(Rabbit* rabbit);
unsigned int Rabbit_toInt(unsigned char* key,int index);
bool Rabbit_SetKey(unsigned char* key,Rabbit* rabbit);
bool Rabbit_Init(Rabbit* rabbit)
{
if(!rabbit)
return false;
for(int i=0;i<8;i++)
{
rabbit->C[i] = 0;
rabbit->X[i] = 0;
rabbit->b = 0;
}
return true;
}
unsigned int Rabbit_toInt(unsigned char* key,int index)
{
if(!key)
return 0;
return key[index+3]|(key[index+2]<<8)|(key[index+1]<<16)|(key[index+0]<<24);
}
bool Rabbit_SetKey(unsigned char* key,Rabbit* rabbit)
{
if(!key || !rabbit)
return false;
unsigned int K0 = Rabbit_toInt(key,0);
unsigned int K1 = Rabbit_toInt(key,4);
unsigned int K2 = Rabbit_toInt(key,8);
unsigned int K3 = Rabbit_toInt(key,12);
rabbit->X[0] = K3;
rabbit->X[1] = (K0<<16)|(K1>>16);
rabbit->X[2] = K2;
rabbit->X[3] = (K3<<16)|(K0>>16);
rabbit->X[4] = K1;
rabbit->X[5] = (K2<<16)|(K3>>16);
rabbit->X[6] = K0;
rabbit->X[7] = (K1<<16)|(K2>>16);
rabbit->C[0] = (K1<<16)|(K1>>16);
rabbit->C[1] = ((K3&0xFFFF0000)|(K2&0xFFFF));
rabbit->C[2] = (K0<<16)|(K0>>16);
rabbit->C[3] = ((K2&0xFFFF0000)|(K1&0xFFFF));
rabbit->C[4] = (K3<<16)|(K3>>16);
rabbit->C[5] = ((K1&0xFFFF0000)|(K0&0xFFFF));
rabbit->C[6] = (K2<<16)|(K2>>16);
rabbit->C[7] = ((K0&0xFFFF0000)|(K3&0xFFFF));
rabbit->b = 0;
for(int i=0;i<4;i++)
{
Rabbit_nextState(rabbit);
}
for(int i=0;i<8;i++)
{
rabbit->C[i] ^= rabbit->X[(i+4)&7];
}
return true;
}
unsigned int Rabbit_u1(unsigned int n)
{
unsigned int r0 = ((lw(n) * lw(n)) >> 17) + lw(n) * hw(n);
unsigned int r1 = (r0 >> 15) + hw(n) * hw(n);
unsigned int r2 = n * n;
return r1 ^ r2;
// _asm
// {
// mov esi,n
// movzx edx,si
// mov ecx,esi
// shr ecx,0x10
// push edi
// mov eax, edx
// imul eax, edx
// mov edi, ecx
// imul edi, edx
// mov edx, ecx
// imul edx, ecx
// mov ecx, esi
// imul ecx, esi
// shr eax, 11h
// add eax, edi
// shr eax, 0Fh
// add eax, edx
// pop edi
// xor eax, ecx
// }
}
bool Rabbit_nextState(Rabbit* rabbit)
{
unsigned int G[8]={0};
unsigned int c_old[8];
if(!rabbit)
return false;
memcpy(c_old,rabbit->C,sizeof(c_old));
rabbit->C[0] += rabbit->b + 1295307597;
rabbit->C[1] += (rabbit->C[0] < c_old[0]) - 749914925;
rabbit->C[2] += (rabbit->C[1] < c_old[1]) + 886263092;
rabbit->C[3] += (rabbit->C[2] < c_old[2]) + 1295307597;
rabbit->C[4] += (rabbit->C[3] < c_old[3]) - 749914925;
rabbit->C[5] += (rabbit->C[4] < c_old[4]) + 886263092;
rabbit->C[6] += (rabbit->C[5] < c_old[5]) + 1295307597;
rabbit->C[7] += (rabbit->C[6] < c_old[6]) - 749914925;
rabbit->b = rabbit->C[7] < c_old[7];
for(int i=0;i<8;i++)
{
G[i] = Rabbit_u1(rabbit->X[i]+rabbit->C[i]);
}
rabbit->X[0] = G[0] + rotl(G[7],16) + rotl(G[6],16);
rabbit->X[1] = G[1] + rotl(G[0],8) + G[7];
rabbit->X[2] = G[2] + rotl(G[1],16) + rotl(G[0],16);
rabbit->X[3] = G[3] + rotl(G[2],8) + G[1];
rabbit->X[4] = G[4] + rotl(G[3],16) + rotl(G[2],16);
rabbit->X[5] = G[5] + rotl(G[4],8) + G[3];
rabbit->X[6] = G[6] + rotl(G[5],16) + rotl(G[4],16);
rabbit->X[7] = G[7] + rotl(G[6],8) + G[5];
return true;
}
bool Rabbit_toByte(unsigned int s,unsigned char* d)
{
if(!d)
return false;
d[0] = (s>>24)&0xff;
d[1] = (s>>16)&0xff;
d[2] = (s>>8)&0xff;
d[3] = (s)&0xff;
return true;
}
bool Rabbit_EncryptBuf(Rabbit* rabbit,unsigned char* src,int srclen,unsigned char* dst,int dstlen)
{
unsigned int K[4] = {0};
unsigned char v[4] = {0};
if(!rabbit || !src || !dst || srclen>dstlen || srclen<=0)
return false;
for(int i=0;i<srclen;i+=16)
{
Rabbit_nextState(rabbit);
K[0] = rabbit->X[0]^(rabbit->X[5]>>16)^(rabbit->X[3]<<16)^Rabbit_toInt(src,i);
K[1] = rabbit->X[2]^(rabbit->X[5]<<16)^(rabbit->X[7]>>16)^Rabbit_toInt(src,i+4);
K[2] = rabbit->X[4]^(rabbit->X[7]<<16)^(rabbit->X[1]>>16)^Rabbit_toInt(src,i+8);
K[3] = rabbit->X[6]^(rabbit->X[3]>>16)^(rabbit->X[1]<<16)^Rabbit_toInt(src,i+12);
for(int j=0;j<4;j++)
{
Rabbit_toByte(K[j],v);
*(unsigned int*)(dst+i+4*j) = *(unsigned int*)v;
}
}
return true;
}
下面是一個(gè)實(shí)例:
unsigned char encrypt[448] =
{//加密過(guò)的進(jìn)程id
0x30,0xa2,0xf6,0xa4,0xdb,0x6c,0xe9,0xa2,0x4d,0xdd,0x66,0x18,0xd1,0x8e,0xa9,0x8a,
0x1c,0xa2,0xf6,0xa4,0xf3,0x6c,0xe9,0xa2,0x65,0xdd,0x66,0x18,0xc9,0x8e,0xa9,0x8a,
0x08,0xa2,0xf6,0xa4,0x0b,0x6c,0xe9,0xa2,0xb5,0xdd,0x66,0x18,0x09,0x8e,0xa9,0x8a,
0xc8,0xa2,0xf6,0xa4,0x43,0x6c,0xe9,0xa2,0xd5,0xdd,0x66,0x18,0x81,0x89,0xa9,0x8a,
0x4c,0xa5,0xf6,0xa4,0xbf,0x6b,0xe9,0xa2,0x51,0xda,0x66,0x18,0xf5,0x89,0xa9,0x8a,
0xc8,0xa5,0xf6,0xa4,0x43,0x6b,0xe9,0xa2,0xc5,0xda,0x66,0x18,0x6d,0x89,0xa9,0x8a,
0x7c,0xa4,0xf6,0xa4,0x17,0x6a,0xe9,0xa2,0x89,0xdb,0x66,0x18,0x1d,0x88,0xa9,0x8a,
0xc4,0xa4,0xf6,0xa4,0x5f,0x6a,0xe9,0xa2,0xf1,0xdb,0x66,0x18,0x55,0x88,0xa9,0x8a,
0x14,0xa7,0xf6,0xa4,0xe7,0x69,0xe9,0xa2,0x79,0xd8,0x66,0x18,0xdd,0x8b,0xa9,0x8a,
0x04,0xa7,0xf6,0xa4,0xf7,0x69,0xe9,0xa2,0x69,0xd8,0x66,0x18,0xcd,0x8b,0xa9,0x8a,
0xf8,0xa7,0xf6,0xa4,0x13,0x69,0xe9,0xa2,0x85,0xd8,0x66,0x18,0x29,0x8b,0xa9,0x8a,
0xe8,0xa7,0xf6,0xa4,0x2b,0x69,0xe9,0xa2,0xbd,0xd8,0x66,0x18,0x01,0x8b,0xa9,0x8a,
0x64,0xa6,0xf6,0xa4,0x97,0x68,0xe9,0xa2,0x39,0xd9,0x66,0x18,0x85,0x8a,0xa9,0x8a,
0xfc,0xa6,0xf6,0xa4,0x2b,0x68,0xe9,0xa2,0xbd,0xd9,0x66,0x18,0x09,0x8a,0xa9,0x8a,
0xc8,0xa6,0xf6,0xa4,0x43,0x68,0xe9,0xa2,0xd5,0xd9,0x66,0x18,0x5d,0x8a,0xa9,0x8a,
0x80,0xa6,0xf6,0xa4,0x17,0x6e,0xe9,0xa2,0xd1,0xdf,0x66,0x18,0x19,0x8c,0xa9,0x8a,
0x90,0xa0,0xf6,0xa4,0x5f,0x6e,0xe9,0xa2,0x61,0xdf,0x66,0x18,0x81,0x8e,0xa9,0x8a,
0xe0,0xa5,0xf6,0xa4,0x33,0x6b,0xe9,0xa2,0xa5,0xda,0x66,0x18,0xe1,0x88,0xa9,0x8a,
0x80,0xa5,0xf6,0xa4,0xe7,0x6a,0xe9,0xa2,0x6d,0xdb,0x66,0x18,0x15,0x88,0xa9,0x8a,
0xdc,0xa4,0xf6,0xa4,0x3f,0x6a,0xe9,0xa2,0x95,0xd8,0x66,0x18,0x7d,0x8b,0xa9,0x8a,
0xa0,0xa7,0xf6,0xa4,0x77,0x69,0xe9,0xa2,0xed,0xd8,0x66,0x18,0xe9,0x8b,0xa9,0x8a,
0x40,0xa7,0xf6,0xa4,0x8b,0x69,0xe9,0xa2,0xc9,0xdb,0x66,0x18,0x65,0x88,0xa9,0x8a,
0xa4,0xa4,0xf6,0xa4,0x03,0x68,0xe9,0xa2,0x69,0xd9,0x66,0x18,0xd5,0x8a,0xa9,0x8a,
0x78,0xa9,0xf6,0xa4,0x93,0x67,0xe9,0xa2,0x05,0xd6,0x66,0x18,0x91,0x85,0xa9,0x8a,
0x50,0xa9,0xf6,0xa4,0xab,0x67,0xe9,0xa2,0xdd,0xd6,0x66,0x18,0x05,0x84,0xa9,0x8a,
0x0c,0xab,0xf6,0xa4,0x6b,0x62,0xe9,0xa2,0xfd,0xd0,0x66,0x18,0xe9,0x83,0xa9,0x8a,
0xa8,0xaf,0xf6,0xa4,0xb7,0x63,0xe9,0xa2,0xad,0xce,0x66,0x18,0xa1,0x9c,0xa9,0x8a,
0x44,0xb2,0xf6,0xa4,0x7f,0x7c,0xe9,0xa2,0x15,0xca,0x66,0x18,0xb1,0x8d,0xa9,0x8a,
};
unsigned char decrypt[448]={0};//解密到目標(biāo)內(nèi)存
Rabbit rabbit;
Rabbit_Init(&rabbit);//初始化
Rabbit_SetKey((unsigned char*)"0123456789ABCDEF",&rabbit);//加載密鑰
Rabbit_EncryptBuf(&rabbit,encrypt,448,decrypt,448);//加密/解密
/*解密后的進(jìn)程id
00000344 00000358 0000035c 00000360
00000368 00000370 00000374 00000378
0000037c 00000388 000003a4 000003b8
000003bc 000003c0 000003c4 00000430
00000438 0000043c 00000440 00000444
000004bc 000004c0 000004d4 000004dc
00000508 00000594 00000598 000005ac
000005b0 000005dc 000005e0 000005e4
00000660 00000664 00000668 0000066c
00000670 00000674 00000678 0000067c
0000068c 00000690 00000694 00000698
0000069c 000006a8 000006ac 000006b0
00000710 00000714 00000728 00000734
00000788 000007a8 000007ac 000007b8
000007bc 000007c0 000007c4 000007ec
000007f4 00000194 000001c0 000001a8
000001e4 000001dc 00000170 00000330
00000494 000004b0 000004b4 00000550
000004f4 00000564 0000057c 000005a4
000005a8 000005bc 00000684 000006cc
000006d4 000006f4 000006fc 00000658
00000634 00000608 000005d8 000005d4
000005d0 00000780 00000778 00000764
0000080c 00000810 00000814 00000820
00000824 00000828 000008cc 000009b4
00000a78 00000de8 00000eec 00000e58
00000edc 00000c34 000010bc 00001110
00001330 000013fc 00001404 00000000
*/
四形入、InlineHook KiFastCallEntry
- 重置藍(lán)屏死機(jī)計(jì)數(shù) 用于檢測(cè)hook造成的藍(lán)屏
- 獲取SSDT/SSSDT/ hook點(diǎn)
- 分配跳轉(zhuǎn)表ServiceMapTable
- 改寫(xiě)KiFastCallEntry使跳轉(zhuǎn)表生效
- Hook重要回調(diào)
- 開(kāi)啟日志記錄
- Hook KeUserModeCallback
4.1 獲取SSDT/SSSDT/Hook點(diǎn)
ULONG InitState = 0;
ULONG LastErrorCode = 0;
UCHAR int2Ecode1[10] = {0x8B, 0xFC, 0x3B, 0x35, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x83};
UCHAR int2Ecode2[22] = {0x8B, 0xFC, 0xF6, 0x45, 0x72, 0x02, 0x75, 0x06, 0xF6, 0x45, 0x6C,
0x01, 0x74, 0x0C, 0x3B, 0x35, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x83};
ULONG GetHookPoint1()
{//檢測(cè)系統(tǒng)原始KiFastCallEntry
*(ULONG*)(int2Ecode2 + 4) = MmUserProbeAddress;//構(gòu)造cmp esi,dword ptr ds:[MmUserProbeAddress]
if(!MmUserProbeAddress)
return 0;
ULONG ptr = GetKiSystemServiceAddr();//KiFastCallEntry總在KiSystemService之后
if(ptr < NtosBase || ptr > NtosBase+NtosSize)
return 0;
for(int offset = 0;offset < 1024;offset++,ptr++)
{
/*
mov edi,esp
cmp esi,dword ptr ds:[MmUserProbeAddress]
jae ??
*/
if(RtlCompareMemory(ptr,int2Ecode1,sizeof(int2Ecode1)) == sizeof(int2Ecode1))
return ptr;
}
return 0;
}
ULONG GetHookPoint2()
{//檢測(cè)是否被金山inline hook過(guò)得KiFastCallEntry
*(ULONG*)(int2Ecode2 + 16) = MmUserProbeAddress;//構(gòu)造cmp esi,dword ptr ds:[MmUserProbeAddress]
if(!MmUserProbeAddress)
return 0;
ULONG ptr = GetKiSystemServiceAddr();
if(ptr < NtosBase || ptr > NtosBase+NtosSize)
return 0;
for(int offset = 0;offset < 1024;offset++,ptr++)
{
/*
mov edi,esp
test byte ptr[ebp+72h],2
jne $1
test byte ptr[ebp+6Ch],1
je ??
$1:
cmp esi,dword ptr ds:[MmUserProbeAddress]
jae ??
*/
if(RtlCompareMemory(ptr,int2Ecode2,sizeof(int2Ecode2)) == sizeof(int2Ecode2))
return ptr;
}
return 0;
}
ULONG InitState = 0,LastErrorCode = 0,serHookType = 0;
ULONG NtosBase,NtosSize,SSDTBase,SSDTLimit,ShadowSSDTBase,ShadowSSDTLimit,Win32kBase,Win32kSize;
ULONG dwcsrssId;
ULONG BuildIndex;
PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable;
ULONG MmUserProbeAddress;
struct HOOKINFO
{
ULONG InlinePoint;
ULONG JmpBackPoint;
UCHAR OriginCode[8];
};
HOOKINFO HookInfo1={0},HookInfo2={0};
/*
KiFastCallEntry+0xde:
mov ebx,dword ptr [edi+eax*4]
jmp 81f9e3e0
nop => InlinePoint
nop
nop
jmp TsFltMgr+0x2300 (f8517300)
jae nt!KiSystemCallExit2+0x9f (8053e7ec) => JmpBackPoint
rep movs dword ptr es:[edi],dword ptr [esi]
call ebx
OriginCode[8];
8bfc mov edi,esp
3b35549a5580 cmp esi,dword ptr [nt!MmUserProbeAddress]
*/
NTSTATUS PrepareHook()
{
RTL_PROCESS_MODULE_INFORMATION Win32kInfo,NtosInfo;
NTSTATUS status = STATUS_UNSUCCESSFUL;
ULONG ReturnLength = 0;
ULONG OutData;
LPVOID Buffer = NULL;
RtlZeroMemory(&Win32kInfo,sizeof(Win32kInfo));
RtlZeroMemory(&NtosInfo,sizeof(NtosInfo));
InitState = 0;
LastErrorCode = 0;
status = GetRegDataWithType(L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\TsFltMgr",
L"thm", &OutData, 4, 0)
if(NT_SUCCESS(status) && OutData == 1)
serHookType = HOOKTYPE_SSDT;
ZwQuerySystemInformation(SystemModuleInformation,&ReturnLength,0,&ReturnLength);
if(ReturnLength)
Buffer = ExAllocatePool(PagedPool,ReturnLength);
if(Buffer)
status = ZwQuerySystemInformation(SystemModuleInformation,Buffer,ReturnLength,NULL);
if(!NT_SUCCESS(status))
{
ExFreePool(Buffer);
Buffer = NULL;
}
if(Buffer)
{
RtlCopyMemory(&NtosInfo,((PRTL_PROCESS_MODULES)Buffer)->Modules,sizeof(NtosInfo));
ExFreePool(Buffer);
NtosBase = NtosInfo.ImageBase;
NtosSize = NtosInfo.ImageSize;
ULONG FuncAddr = MiLocateExportName(NtosBase,"KeServiceDescriptorTable");
if(FuncAddr && MmIsAddressValid(FuncAddr))
{
PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable = (PKSERVICE_TABLE_DESCRIPTOR)FuncAddr;
SSDTBase = KeServiceDescriptorTable[0].Base;
SSDTLimit = KeServiceDescriptorTable[0].Limit;
InitState |= 2;
dwcsrssId = GetProcessIdByName(L"csrss.exe");
if(GetProcessInfoByFileName("WIN32K.SYS",&Win32kInfo))
{
Win32kBase = Win32kInfo.ImageBase;
Win32kSize = Win32kInfo.ImageSize;
if(NT_SUCCESS(GetShadowSSDTInfo()))
InitState |= 4;
}
UNICODE_STRING UMmUserProbeAddress;
RtlInitUnicodeString(&UMmUserProbeAddress,L"MmUserProbeAddress");
ULONG MmUserProbeAddress = MmGetSystemRoutineAddress(&UMmUserProbeAddress);
if(MmUserProbeAddress && MmIsAddressValid(MmUserProbeAddress))
{
HookInfo1.InlinePoint = GetHookPoint1();
if(HookInfo1.InlinePoint)
HookInfo1.JmpBackPoint = HookInfo1.InlinePoint + 8;
else
{
HookInfo2.InlinePoint = GetHookPoint2();
if(HookInfo2.InlinePoint)
HookInfo2.JmpBackPoint = HookInfo2.InlinePoint + 6;
}
if(HookInfo1.InlinePoint == 0 && HookInfo2.InlinePoint == 0)
{
LastErrorCode |= 0x20;
return status;
}
InitState |= 8;
MmUserProbeAddress = *(ULONG*)MmUserProbeAddress;
status = STATUS_SUCCESS;
}
else
{
LastErrorCode |= 0x10;
}
}
else
{
LastErrorCode |= 2;
}
}
else
{
LastErrorCode |= 1;
}
return status;
}
4.2 從KiSystemService獲取KiFastCallEntry
struct IDTR
{
USHORT IDTLimit;
PKIDTENTRY IDTBase;
};
ULONG GetKiSystemServiceAddr()
{
IDTR idt = {0};
RTL_PROCESS_MODULE_INFORMATION NtosInfo,Win32kInfo;
RtlZeroMemory(&NtosInfo,sizeof(NtosInfo));
__sidt(&idt);
if(idt.IDTBase)
{
KIDTENTRY int2e = idt.IDTBase[0x2E];
if(MmIsAddressValid(int2e))
return MAKEULONG(int2e.ExtendedOffset,int2e.Offset);
}
return 0;
}
4.3 獲取SSSDT信息
NTSTATUS GetShadowSSDTInfo()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PVOID pt = MiLocateExportName(NtosBase, "KeAddSystemServiceTable");
PMDL mdl = NULL;
if(pt && !MmIsAddressValid(pt))
{//頁(yè)換出
mdl = MmCreateMdl(NULL,pt,0x1000);
if(mdl)
{
MmProbeAndLockPages(mdl,KernelMode,IoReadAccess);
}
}
if(!pt || !MmIsAddressValid(pt))
{
LastErrorCode |= 4;
goto END;
}
switch(BuildIndex)
{
case WIN2000:
case WINXP:
case WINXPSP3:
case WINVISTA:
case WINVISTASP1:
case WINVISTASP2:
case WIN7:
case WIN7SP1:
for(int i=0;i<256;i++)
{
if(MmIsAddressValid(pt) && *(USHORT*)pt == 0x888D)
{//8d88603f5580 lea ecx,nt!KeServiceDescriptorTableShadow
PKSERVICE_TABLE_DESCRIPTOR Table = *(ULONG*)(pt+2);
ShadowSSDTBase = Table[1].Base;
ShadowSSDTLimit = Table[1].Limit;
status = STATUS_SUCCESS;
}
}
break;
case WIN8_8102:
case WIN8_8250:
case WIN81_9200:
case WIN81_9600:
for(int i=0;i<256;i++)
{
if(MmIsAddressValid(pt) && *(USHORT*)pt == 0xB983)
{//83b9603f558083 cmp dword ptr nt!KeServiceDescriptorTableShadow
PKSERVICE_TABLE_DESCRIPTOR Table = *(ULONG*)(pt+2);
if(KeServiceDescriptorTable == Table)
{
ShadowSSDTBase = Table[1].Base;
ShadowSSDTLimit = Table[1].Limit;
status = STATUS_SUCCESS;
}
}
}
break;
case WIN10_9841:
case WIN10_9860:
case WIN10_9926:
case WIN10_10041:
case WIN10_10049:
for(int i=0;i<256;i++)
{
if(MmIsAddressValid(pt) && *(USHORT*)pt == 0x3D83)
{//833d90d28d8100 cmp dword ptr [nt!KeServiceDescriptorTableShadow+0x10],0
PKSERVICE_TABLE_DESCRIPTOR Table = *(ULONG*)(pt+2) - 16;
if(KeServiceDescriptorTable == Table)
{
ShadowSSDTBase = Table[1].Base;
ShadowSSDTLimit = Table[1].Limit;
status = STATUS_SUCCESS;
}
}
}
break;
}
if(!ShadowSSDTBase)
LastErrorCode |= 8;
END:
if(mdl)
{
MmUnlockPages(mdl);
IoFreeMdl(mdl);
}
}
4.4 初始化InlineHook KiFastCallEntry跳轉(zhuǎn)表
BOOLEAN InitProxyTable()
{
ULONG BuildIndex = GetBuildNumberAsIndex();
for(int i = 0;i < APINUMBER;i++)
{
for(int j = 0;j < BUILDMAX;j++)
{
if(SProxyTable[i].ServiceIndex[j] == 0)
SProxyTable[i].ServiceIndex[j] = 1023;//置為無(wú)效
}
}
if(GetServiceIndex("ZwCreateKey") == -1)
{//不能獲取到服務(wù)號(hào)
if(NtosBase)
{
for(int i = 0;i < APINUMBER;i++)
{
if(SProxyTable[i].ServiceTableType == END)
break;
else if(SProxyTable[i].ServiceTableType == SSDT)
{
if(SProxyTable[i].ApiName)
{
UNICODE_STRING UApiName;
ANSI_STRING AApiName;
RtlInitUnicodeString(&UApiName,SProxyTable[i].ApiName);
if(NT_SUCCESS(RtlUnicodeStringToAnsiString(&AApiName,&UApiName,TRUE)))
{
GetServiceIndexFromNtos(AApiName.Buffer);
RtlFreeAnsiString(AApiName);
}
}
}
}
}
}
else
{//能獲取到服務(wù)號(hào) 由于SProxyTable已存服務(wù)號(hào)全跨,所以下面代碼本身無(wú)效
for(int i = 0;i < APINUMBER;i++)
{
if(SProxyTable[i].ServiceTableType == END)
break;
if(SProxyTable[i].ServiceTableType == SSDT)
{
if(SProxyTable[i].ApiName)
{
UNICODE_STRING UApiName;
ANSI_STRING AApiName;
RtlInitUnicodeString(&UApiName,SProxyTable[i].ApiName);
if(NT_SUCCESS(RtlUnicodeStringToAnsiString(&AApiName,&UApiName,TRUE)))
{
ULONG Index = GetServiceIndexFromNtdll(AApiName.Buffer);
if(Index != -1)
SProxyTable[i].ServiceIndex[BuildIndex] = Index;
RtlFreeAnsiString(AApiName);
}
}
}
}
}
return TRUE;
}
int AllocHookTable()
{//已知系統(tǒng)情況下初始化代理表,直接使用ServiceIndex
ULONG BuildIndex = GetBuildNumberAsIndex();
DProxy* Proxydata = NULL;
ULONG Count = 0;//未成功布置的代理函數(shù)個(gè)數(shù)
if(BuildIndex >= 0 && BuildIndex < BUILDMAX)
{
InitProxyTable();
for(int i=0;i<APINUMBER;i++)
{
if(SProxyTable[i].ServiceTableType == END)
break;
if(SProxyTable[i].ServiceIndex[BuildIndex] != 1023)
{
if(SProxyTable[i].ApiName && SProxyTable[i].ProxyFunc && SProxyTable[i].IndexInTable < APINUMBER)
{
Proxydata = (DProxy*)ExAllocatePool(NonPagedPool,sizeof(DProxy));
if(Proxydata)
{
Proxydata->IsInitialized = FALSE;
Proxydata->ApiName = SProxyTable[i].ApiName;
Proxydata->TableIndex = SProxyTable[i].IndexInTable;
Proxydata->ProxyFuncAddr = SProxyTable[i].ProxyFunc;
Proxydata->ServiceIndex = -1;
KeInitializeEvent(Proxydata->Lock,SynchronizationEvent,FALSE);
DProxyTable[SProxyTable[i].IndexInTable] = Proxydata;
ULONG ServiceType = SProxyTable[i].ServiceTableType;
ULONG ServiceIndex = SProxyTable[i].ServiceIndex[BuildIndex];
if(ServiceType >= 2 || ServiceIndex== -1 || ServiceIndex >= 1024)
{
Count++;
}
else
{
ServiceMapTable[ServiceType][ServiceIndex] = Proxydata;
Proxydata->ServiceTableType = ServiceType;
Proxydata->ServiceIndex = ServiceIndex;
}
}
}
}
}
return Count;
}
return APINUMBER;//返回未成功代理的個(gè)數(shù)
}
int AllocHookTableU()
{//未知系統(tǒng)情況下初始化代理表亿遂,臨時(shí)從Ntos模塊獲取ServiceIndex
if(!NtosBase)
return 0;//返回成功布置代理的個(gè)數(shù)
for(int i=0;i<APINUMBER;i++)
{
if(SProxyTable[i].ServiceTableType == END)
break;
else if(SProxyTable[i].ServiceTableType == SSDT)
{
if(SProxyTable[i].ApiName)
{
PUNICODE_STRING UApiName;
ANSI_STRING AApiName;
ULONG Index = -1;
RtlInitUnicodeString(&UApiName,SProxyTable[i].ApiName);
if(NT_SUCCESS(RtlUnicodeStringToAnsiString(&AApiName,&UApiName,TRUE)))
{
Index = GetServiceIndexFromNtos(AApiName.Buffer);
RtlFreeAnsiString(&AApiName);
}
if(Index != -1)
{
if(SProxyTable[i].ApiName && SProxyTable[i].ProxyFunc && SProxyTable[i].IndexInTable < APINUMBER)
{
Proxydata = (DProxy*)ExAllocatePool(NonPagedPool,sizeof(DProxy));
if(Proxydata)
{
Proxydata->IsInitialized = FALSE;
Proxydata->ApiName = SProxyTable[i].ApiName;
Proxydata->TableIndex = SProxyTable[i].IndexInTable;
Proxydata->ProxyFuncAddr = SProxyTable[i].ProxyFunc;
Proxydata->ServiceIndex = -1;
KeInitializeEvent(Proxydata->Lock,SynchronizationEvent,FALSE);
DProxyTable[SProxyTable[i].IndexInTable] = Proxydata;
ULONG ServiceType = SProxyTable[i].ServiceTableType;
ULONG ServiceIndex = SProxyTable[i].ServiceIndex[BuildIndex];
if(ServiceType >= 2 || ServiceIndex== -1 || ServiceIndex >= 1024)
{
Count++;
ServiceMapTable[ServiceType][ServiceIndex] = Proxydata;
Proxydata->ServiceTableType = ServiceType;
Proxydata->ServiceIndex = ServiceIndex;
}
}
}
}
}
}
}
return Count;
}
4.5 獲取系統(tǒng)服務(wù)號(hào)的2種方式
ULONG GetServiceIndexFromNtdll(PCHAR ApiName)
{
ULONG result = -1;
RTL_PROCESS_MODULE_INFORMATION ProcessInfo;
ULONG Index;
RtlZeroMemory(&ProcessInfo,sizeof(ProcessInfo));
if(GetProcessInfoByFileName("ntdll.dll",&ProcessInfo) && ProcessInfo.ImageBase && ApiName)
{
Index = MiLocateExportName(ProcessInfo.ImageBase,ApiName);
if(Index)
{
result = *(ULONG*)(Index+1);
}
}
return result;
}
ULONG GetServiceIndexFromNtos(PCHAR ApiName)
{
ULONG result = -1;
ULONG Index = MiLocateExportName(ProcessInfo.ImageBase,ApiName);
if(Index)
{
result = *(ULONG*)(Index+1);
}
if(Index & 0xFFFFC000)
{
result = -1;
}
return result;
}
4.6 InlineHook過(guò)程
NTSTATUS DoInlineHook()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
ULONG MajorVersion = 0,MinorVersion = 0,BuildNumber = 0;
PsGetVersion(&MajorVersion,&MinorVersion,&BuildNumber,NULL);
if(serHookType == HOOKTYPE_SSDT || !(InitState & 8))//外部hook或沒(méi)找到hook掛載點(diǎn)
return status;
if(HookInfo1.InlinePoint)
{//如果為默認(rèn)方式hook
if(GetBuildNumberAsIndex() >= WINVISTA)
status = ModifyAndHook(HookInfo1.InlinePoint,InlineKiFastCallEntry1);
else
status = ModifyAndHook(HookInfo1.InlinePoint,InlineKiFastCallEntry2);
if(NT_SUCCESS(status))
serHookType = HOOKTYPE_INLINE;
}
else if(HookInfo2.InlinePoint)
{//如果為金山共存方式hook
if(GetBuildNumberAsIndex() >= WINVISTA)
status = ModifyAndHookK(HookInfo2.InlinePoint,InlineKiFastCallEntry3);
else
status = ModifyAndHookK(HookInfo2.InlinePoint,InlineKiFastCallEntry4);
if(NT_SUCCESS(status))
serHookType = HOOKTYPE_KSINLINE;
}
if(NT_SUCCESS(status))
{
for(int i=0;i<APINUMBER;i++)
{
if(DProxyTable[i] != 0 && (DProxyTable[i]->ServiceTableType == SSDT || DProxyTable[i]->ServiceTableType == SSSDT))
DProxyTable[i]->IsInitialized = TRUE;
}
}
}
NTSTATUS DoInlineHookU()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
ULONG MajorVersion = 0,MinorVersion = 0,BuildNumber = 0;
PsGetVersion(&MajorVersion,&MinorVersion,&BuildNumber,NULL);
if(serHookType == HOOKTYPE_SSDT || !(InitState & 8))//采用外部hook或沒(méi)找到hook掛載點(diǎn)
return status;
if(HookInfo1.InlinePoint)
{//如果為默認(rèn)方式hook
if(GetBuildNumberAsIndex() >= WINVISTA)
status = ModifyAndHook(HookInfo1.InlinePoint,InlineKiFastCallEntry1);
else
status = ModifyAndHook(HookInfo1.InlinePoint,InlineKiFastCallEntry2);
if(NT_SUCCESS(status))
serHookType = HOOKTYPE_INLINE;
}
else if(HookInfo2.InlinePoint)
{//如果為金山共存方式hook
if(GetBuildNumberAsIndex() >= WINVISTA)
status = ModifyAndHookK(HookInfo2.InlinePoint,InlineKiFastCallEntry3);
else
status = ModifyAndHookK(HookInfo2.InlinePoint,InlineKiFastCallEntry4);
if(NT_SUCCESS(status))
serHookType = HOOKTYPE_KSINLINE;
}
if(NT_SUCCESS(status))
{
for(int i=0;i<APINUMBER;i++)
{
if(DProxyTable[i] != 0 && (DProxyTable[i]->ServiceTableType == SSDT || DProxyTable[i]->ServiceTableType == SSSDT))
DProxyTable[i]->IsInitialized = TRUE;
}
}
}
NTSTATUS ModifyAndHook(ULONG InlinePoint,FARPROC JmpToFunc)
{//HOOKTYPE_INLINE 更改KiFastCallEntry
NTSTATUS status;
PVOID MappedAddress = NULL;
if(!InlinePoint || !InlineHookFunc)
return STATUS_UNSUCCESSFUL;
PMDL mdl = GetWritablePage(InlinePoint,16,&MappedAddress);
/*
改寫(xiě) 為
mov edi,esp nop
cmp esp,dword ptr ds:[?] nop
nop
jmp ?
*/
if(!mdl)
return STATUS_UNSUCCESSFUL;
ULONG data[3] = {InlinePoint,JmpToFunc,MappedAddress};
status = MakeJmp(data,DoHook);
MmUnlockPages(mdl);
IoFreeMdl(mdl);
return status;
}
NTSTATUS ModifyAndHookK(ULONG InlinePoint,FARPROC JmpToFunc)
{//HOOKTYPE_KSINLINE 更改KiFastCallEntry
NTSTATUS status;
PVOID MappedAddress = NULL;
if(!InlinePoint || !InlineHookFunc)
return STATUS_UNSUCCESSFUL;
PMDL mdl = GetWritablePage(InlinePoint,16,&MappedAddress);
if(!mdl)
return STATUS_UNSUCCESSFUL;
ULONG data[3] = {InlinePoint,JmpToFunc,MappedAddress};
status = MakeJmp(data,DoHookK);
MmUnlockPages(mdl);
IoFreeMdl(mdl);
return status;
}
NTSTATUS DoHook(ULONG* data)
{//HOOKTYPE_INLINE
ULONGLONG shellcode;
if(!data)
return STATUS_UNSUCCESSFUL;
*(ULONGLONG*)(HookInfo1.OriginCode) = *(ULONGLONG*)data[0];//保存原始8字節(jié)
*(ULONG*)((UCHAR*)&shellcode+4) = data[1] - data[0] - 8;//填寫(xiě)偏移 jmp offset
*(ULONG*)((UCHAR*)&shellcode) = 0xE9909090;//寫(xiě)入新8字節(jié)
/*
構(gòu)造
nop
nop
nop
jmp ????
*/
InterlockedCompareExchange64((LONGLONG*)data[2],shellcode,*(LONGLONG*)data[2]);
return STATUS_SUCCESS;
}
NTSTATUS DoHookK(ULONG* data)
{//HOOKTYPE_KSINLINE
ULONGLONG shellcode;
if(!data)
return STATUS_UNSUCCESSFUL;
*(ULONGLONG*)(HookInfo1.OriginCode) = *(ULONGLONG*)data[0];//保存原始8字節(jié)
*(USHORT*)((UCHAR*)&shellcode+6) = 0x0675;
*(ULONG*)((UCHAR*)&shellcode+2) = data[1] - data[0] - 8;//填寫(xiě)偏移 jmp offset
*(ULONG*)((UCHAR*)&shellcode) = 0xE990;//寫(xiě)入新8字節(jié)
InterlockedCompareExchange64((LONGLONG*)data[2],shellcode,*(LONGLONG*)data[2]);
return STATUS_SUCCESS;
}
PMDL GetWritablePage(PVOID VirtualAddress,ULONG Length,PVOID* pMappedAddress)
{
PMDL mdl = IoAllocateMdl(VirtualAddress,Length,FALSE,TRUE,NULL);
if(mdl)
{
MmProbeAndLockPages(mdl,KernelMode,IoWriteAccess);
PVOID NewAddr = MmGetSystemAddressForMdlSafe (Mdl, NormalPagePriority);
if(!NewAddr)
{
MmUnlockPages(mdl);
IoFreeMdl(mdl);
mdl = NULL;
}
if(NewAddr)
*pMappedAddress = NewAddr;
}
return mdl;
}
4.7 構(gòu)造InlineHook跳轉(zhuǎn)后的執(zhí)行語(yǔ)句
ULONG Filter(ULONG ServiceIndex,ULONG OriginFunc,ULONG Base)
{
if(ServiceIndex >= 1024)
return OriginFunc;
ULONG TableType;
if(Base == SSDTBase && ServiceIndex <= SSDTLimit)
{
TableType = SSDT;
}
else if(KeServiceDescriptorTable && KeServiceDescriptorTable->Base == Base && ServiceIndex <= SSDTLimit)
{
TableType = SSDT;
}
else if(Base == ShadowSSDTBase && ServiceIndex <= ShadowSSDTLimit)
{
TableType = SSSDT;
}
else
{
return OriginFunc;
}
if(ServiceMapTable[TableType][ServiceIndex])
{
ULONG NewAddr = ServiceMapTable[TableType][ServiceIndex]->ProxyFuncAddr;
if(NewAddr)
{
ServiceMapTable[TableType][ServiceIndex]->OriginFuncAddr = OriginFunc;
return NewAddr;
}
}
return OriginFunc;
}
void __declspec(naked) InlineKiFastCallEntry1()
{
/* HOOKTYPE_INLINE >=VISTA
輸入
eax=ServiceIndex
edx=OriginFunc
edi=SSDTBase
輸出
edx=FuncAddr 最終函數(shù)調(diào)用地址
*/
_asm
{
pushf;
pusha;
push edi;
push edx;
push eax;
call Filter;
mov [esp+0x14],eax;//改棧中的edx
popa;
popf;
mov edi,esp;
cmp esi,MmUserProbeAddress;
push dword ptr HookInfo1.JmpBackPoint;
retn;//跳回JmpBackPoint
}
}
void __declspec(naked) InlineKiFastCallEntry2()
{
/* HOOKTYPE_INLINE <VISTA
輸入
eax=ServiceIndex
edx=OriginFunc
edi=SSDTBase
輸出
ebx=FuncAddr 最終函數(shù)調(diào)用地址
*/
_asm
{
pushf;
pusha;
push edi;
push edx;
push eax;
call Filter;
mov [esp+0x10],eax;//改棧中的ebx
popa;
popf;
mov edi,esp;
cmp esi,MmUserProbeAddress;
push dword ptr HookInfo1.JmpBackPoint;
retn;
}
}
void __declspec(naked) InlineKiFastCallEntry3()
{
/* HOOKTYPE_KSINLINE <VISTA
輸入
eax=ServiceIndex
edx=OriginFunc
edi=SSDTBase
輸出
edx=FuncAddr 最終函數(shù)調(diào)用地址 (KiFastCallEntry后面mov ebx,edx)
*/
_asm
{
pushf;
pusha;
push edi;
push edx;
push eax;
call Filter;
mov [esp+0x14],eax;//改棧中的edx
popa;
popf;
mov edi,esp;
test byte ptr [ebp+0x72],2;
push dword ptr HookInfo2.JmpBackPoint;
retn;//跳回JmpBackPoint
}
}
void __declspec(naked) InlineKiFastCallEntry4()
{
/* HOOKTYPE_KSINLINE <VISTA
輸入
eax=ServiceIndex
edx=OriginFunc
edi=SSDTBase
輸出
ebx=FuncAddr 最終函數(shù)調(diào)用地址
*/
_asm
{
pushf;
pusha;
push edi;
push edx;
push eax;
call Filter;
mov [esp+0x14],eax;//改棧中的edx
popa;
popf;
mov edi,esp;
test byte ptr [ebp+0x72],2;
push dword ptr HookInfo2.JmpBackPoint;
retn;//跳回JmpBackPoint
}
}
4.8 強(qiáng)制單核互斥執(zhí)行指定Procedure
struct SpinData
{
KSPIN_LOCK SpinLock;
ULONG SpinRefCount;
}g_Spin = {0};
KDPC Dpc[32];
void DpcRoutine(PKDPC Dpc,PVOID DeferredContext,PVOID SystemArgument1,PVOID SystemArgument2)
{
KIRQL OldIrql;
SpinData* spin = (SpinData*)DeferredContext;zh
_disable();
OldIrql = KeRaiseIrqlToDpcLevel();
InterlockedIncrement(spin->SpinRefCount);
KeAcquireSpinLockAtDpcLevel(spin->SpinLock);
KeReleaseSpinLockFromDpcLevel(spin->SpinLock);
KeLowerIrql(OldIrql);
_enable();
}
NTSTATUS MakeJmp(ULONG* data,FARPROC addr)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
ULONG ulCurrentCpu = 0;
KIRQL OldIrql,NewIrql;
KAFFINITY CpuAffinity;
if(!addr)
return status;
CpuAffinity = KeQueryActiveProcessors();
for(int i = 0;i < 32;i++)
{
if((CpuAffinity >> i) & 1)
ulCurrentCpu++;
}
if(ulCurrentCpu == 1)//單核
{
_disable();
OldIrql = KeRaiseIrqlToDpcLevel();
status = addr(data);
KeLowerIrql(OldIrql);
_enable();
}
else//多核 將除當(dāng)前cpu以外的cpu用自旋鎖鎖住
{
SpinData* pSpinData = &g_Spin;
ULONG ulNumberOfActiveCpu = 0;
KeInitializeSpinLock(&g_Spin.SpinLock);
for(int i = 0;i < 32;i++)
{
KeInitializeDpc(&Dpc[i],DpcRoutine,&pSpinData);
}
pSpinData->SpinRefCount = 0;
_disable();
NewIrql = KeAcquireSpinLock(&g_Spin.SpinLock);
ulCurrentCpu = KeGetCurrentProcessorNumber();
for(int i = 0;i < 32;i++)
{
if((CpuAffinity >> i) & 1)
ulNumberOfActiveCpu++;
if(i != ulCurrentCpu)
{
KeSetTargetProcessorDpc(Dpc[i],i);
KeSetImportanceDpc(Dpc[i],HighImportance);
KeInsertQueueDpc(Dpc[i],NULL,NULL);
}
KeInitializeDpc(&Dpc[i],DpcRoutine,&pSpinData);
}
//此時(shí)只有一個(gè)核在工作
for(int i = 0;i < 16;i++)//嘗試16次
{
for(int count = 1000000;count > 0;count--);//延時(shí)
if(g_Spin.SpinRefCount == ulNumberOfActiveCpu - 1)//等待DpcRoutine全部執(zhí)行到死鎖
{
status = addr(data);
break;
}
}
KeReleaseSpinLock(&g_Spin.SpinLock,NewIrql);//恢復(fù)多核運(yùn)行
_enable();
}
return status;
}
4.9 進(jìn)行SSDT hook
??在注冊(cè)表Services\TsFltMgr thm=1的情況下浓若,或者Inline hook KiFastCallEntry失敗的情況下渺杉,會(huì)進(jìn)行SSDT表 hook
NTSTATUS BeginSSDTHook()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
int result = -1;
PVOID MappedAddress = NULL;
PMDL mdl = NULL;
if(serHookType == HOOKTYPE_INLINE || serHookType == HOOKTYPE_KSINLINE)//已成功inline hook
return STATUS_UNSUCCESSFUL;
serHookType = HOOKTYPE_SSDT;
for(int i = 0;i <= APINUMBER;i++)
{
if(DProxyTable[i] && DProxyTable[i]->ServiceIndex != -1 && !DProxyTable[i]->IsInitialized)
{
if(DProxyTable[i]->ServiceTableType == SSDT)
{
int index = DProxyTable[i]->ServiceIndex;
if(index != 1023 && DProxyTable[i]->ProxyFunc && SSDTBase)
{
PVOID MappedAddress = NULL;
PMDL mdl = GetWritablePage(SSDTBase,4*SSDTLimit,&MappedAddress);
if(mdl)
{
DProxyTable[i]->OriginFuncAddr = ((ULONG*)SSDTBase)[index];
((ULONG*)MappedAddress)[index] = DProxyTable[i]->ProxyFunc;
MmUnlockPages(mdl);
IoFreeMdl(mdl);
result = index;
}
}
}
else if(DProxyTable[i]->ServiceTableType == SSSDT)
{
int index = DProxyTable[i]->ServiceIndex;
if(index != 1023 && DProxyTable[i]->ProxyFunc && ShadowSSDTBase)
{
HANDLE CurProcessId = PsGetCurrentProcessId();
HANDLE SmssProcessId = GetProcessIdByName(L"smss.exe");
if(!dwcsrssId)//如果沒(méi)有獲取到csrss.exe的id
{
if(CurProcessId == SmssProcessId)//使用smss.exe的SSSDT
{
mdl = GetWritablePage(ShadowSSDTBase,4*ShadowSSDTLimit,&MappedAddress);
if(mdl)
{
DProxyTable[i]->OriginFuncAddr = ((ULONG*)ShadowSSDTBase)[index];
((ULONG*)MappedAddress)[index] = DProxyTable[i]->ProxyFunc;
MmUnlockPages(mdl);
IoFreeMdl(mdl);
result = index;
}
}
}
else
{//附加到csrss.exe
PVOID attachobj = AttachDriverToProcess(dwcsrssId);
if(attachobj)
{
mdl = GetWritablePage(ShadowSSDTBase,4*ShadowSSDTLimit,&MappedAddress);
if(mdl)
{
DProxyTable[i]->OriginFuncAddr = ((ULONG*)ShadowSSDTBase)[index];
((ULONG*)MappedAddress)[index] = DProxyTable[i]->ProxyFunc;
MmUnlockPages(mdl);
IoFreeMdl(mdl);
result = index;
}
DetachDriverFromProcess(attachobj);
}
}
}
}
if(result != -1)
DProxyTable[i]->IsInitialized = TRUE;
}
}
return STATUS_SUCCESS;
}
struct AttachData
{
KAPC_STATE ApcState;
PVOID Process;
};
PVOID AttachDriverToProcess(HANDLE ProcessId)
{
PVOID Process = NULL;
AttachData* Buffer = NULL;
if(ProcessId == PsGetCurrentProcessId())
return 0xEEEEDDDD;//自身標(biāo)識(shí)
if(ProcessId && NT_SUCCESS(PsLookupProcessByProcessId(ProcessId,&Process)))
{
Buffer = (AttachData*)ExAllocatePool(PagedPool,sizeof(AttachData));
if(!Buffer)
{
ObDereferenceObject(Process);
return NULL;
}
Buffer->Process = Process;
KeStackAttachProcess(Process,&Buffer->ApcState)
}
}
NTSTATUS DetachDriverFromProcess(PVOID Buffer)
{
if(Buffer && (ULONG)Buffer != 0xEEEEDDDD)
{
AttachData* data = (AttachData*)Buffer;
KeUnstackDetachProcess(&data->ApcState);
ObDereferenceObject(data->Process);
ExFreePool(Buffer);
}
}
4.10 對(duì)重要回調(diào)(進(jìn)程回調(diào)、線程回調(diào)挪钓、映像加載回調(diào))的掛鉤
/*
Sproxy Index:
普通api使用index 0-0x33 0x37-0x48 0x4A-0x69
52 CreateNotifyRoutine
53 ThreadNofify
54 ImageNotify
73 CreateNotifyRoutine2
*/
enum
{
INDEX_KECALLBACK = 51,
INDEX_PROCESS = 52,
INDEX_THREAD = 53,
INDEX_IMAGE = 54,
INDEX_PROCESSEX = 73,
};
NTSTATUS HookImportantNotify()
{
if(!DProxyTable[INDEX_PROCESS])
{
DProxy* Proxydata = (DProxy*)ExAllocatePool(NonPagedPool,sizeof(DProxy));
if(Proxydata)
{
Proxydata->IsInitialized = FALSE;
Proxydata->ApiName = "ProcessNotify";
Proxydata->TableIndex = INDEX_PROCESS;
Proxydata->ProxyFuncAddr = CreateNotifyRoutine1;
Proxydata->ServiceIndex = -1;
KeInitializeEvent(&Proxydata->Lock,SynchronizationEvent,FALSE);
DProxyTable[INDEX_PROCESS] = Proxydata;
}
}
if(DProxyTable[INDEX_PROCESS] && !DProxyTable[INDEX_PROCESS]->IsInitialized)
{
DProxyTable[INDEX_PROCESS]->ServiceTableType = CALLBACK;
if(NT_SUCCESS(PsSetCreateProcessNotifyRoutine(CreateProcessNotify,FALSE)))
DProxyTable[INDEX_PROCESS]->IsInitialized = TRUE;
}
if(!DProxyTable[INDEX_PROCESSEX])
{
DProxy* Proxydata = (DProxy*)ExAllocatePool(NonPagedPool,sizeof(DProxy));
if(Proxydata)
{
Proxydata->IsInitialized = FALSE;
Proxydata->ApiName = "ProcessNotifyEx";
Proxydata->TableIndex = INDEX_PROCESSEX;
Proxydata->ProxyFuncAddr = CreateNotifyRoutine1Ex;
Proxydata->ServiceIndex = -1;
KeInitializeEvent(&Proxydata->Lock,SynchronizationEvent,FALSE);
DProxyTable[INDEX_PROCESSEX] = Proxydata;
}
}
if(DProxyTable[INDEX_PROCESSEX] && !DProxyTable[INDEX_PROCESSEX]->IsInitialized)
{
DProxyTable[INDEX_PROCESSEX]->ServiceTableType = CALLBACK;
if(NT_SUCCESS(PsSetCreateProcessNotifyRoutineEx(CreateProcessNotifyEx,FALSE)))
DProxyTable[INDEX_PROCESSEX]->IsInitialized = TRUE;
}
if(!DProxyTable[INDEX_THREAD])
{
DProxy* Proxydata = (DProxy*)ExAllocatePool(NonPagedPool,sizeof(DProxy));
if(Proxydata)
{
Proxydata->IsInitialized = FALSE;
Proxydata->ApiName = "ThreadNotify";
Proxydata->TableIndex = INDEX_THREAD;
Proxydata->ProxyFuncAddr = CreateThreadNotify;
Proxydata->ServiceIndex = -1;
KeInitializeEvent(&Proxydata->Lock,SynchronizationEvent,FALSE);
DProxyTable[INDEX_THREAD] = Proxydata;
}
}
if(DProxyTable[INDEX_THREAD] && !DProxyTable[INDEX_THREAD]->IsInitialized)
{
DProxyTable[INDEX_THREAD]->ServiceTableType = CALLBACK;
if(NT_SUCCESS(PsSetCreateThreadNotifyRoutine(CreateThreadNotify,FALSE)))
DProxyTable[INDEX_THREAD]->IsInitialized = TRUE;
}
if(!DProxyTable[INDEX_IMAGE])
{
DProxy* Proxydata = (DProxy*)ExAllocatePool(NonPagedPool,sizeof(DProxy));
if(Proxydata)
{
Proxydata->IsInitialized = FALSE;
Proxydata->ApiName = "ImageNotify";
Proxydata->TableIndex = INDEX_IMAGE;
Proxydata->ProxyFuncAddr = LoadImageNotify;
Proxydata->ServiceIndex = -1;
KeInitializeEvent(&Proxydata->Lock,SynchronizationEvent,FALSE);
DProxyTable[INDEX_IMAGE] = Proxydata;
}
}
if(DProxyTable[INDEX_IMAGE] && !DProxyTable[INDEX_IMAGE]->IsInitialized)
{
DProxyTable[INDEX_IMAGE]->ServiceTableType = CALLBACK;
if(NT_SUCCESS(PsSetLoadImageNotifyRoutine(LoadImageNotify,FALSE)))
DProxyTable[INDEX_IMAGE]->IsInitialized = TRUE;
}
}
4.11 Hook KeUserModeCallback
NTSTATUS HookKeUserModeCallback()
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
if(!Win32kBase)
return status;
OBJECT_ATTRIBUTES Oa;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE SectionHandle = NULL;
ULONG ViewSize = 0;
HANDLE FileHandle = NULL;
PVOID BaseAddress = 0x5000000;
UNICODE_STRING UKeUserModeCallback;
if(!DProxyTable[INDEX_KECALLBACK])
{
DProxy* Proxydata = (DProxy*)ExAllocatePool(NonPagedPool,sizeof(DProxy));
if(Proxydata)
{
Proxydata->IsInitialized = FALSE;
Proxydata->ApiName = "ImageNotify";
Proxydata->TableIndex = INDEX_KECALLBACK;
Proxydata->ProxyFuncAddr = ProxyKeUserModeCallback;
Proxydata->ServiceIndex = -1;
KeInitializeEvent(&Proxydata->Lock,SynchronizationEvent,FALSE);
DProxyTable[INDEX_KECALLBACK] = Proxydata;
}
}
RtlInitUnicodeString(&UKeUserModeCallback,L"\\SystemRoot\\System32\\Win32k.sys");
InitializeObjectAttributes(&Oa,L"KeUserModeCallback",OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE,NULL,NULL);
status = ZwOpenFile(&FileHandle,GENERIC_READ,&Oa,&IoStatusBlock,FILE_SHARE_READ,FILE_SYNCHRONOUS_IO_NONALERT);
if(NT_SUCCESS(status))
{
Oa.ObjectName = NULL;
status = ZwCreateSection(&SectionHandle,SECTION_MAP_EXECUTE,&Oa,NULL,PAGE_WRITECOPY,SEC_IMAGE);
if(NT_SUCCESS(status))
{
status = ZwMapViewOfSection(&SectionHandle,NtCurrentProcess(),&BaseAddress,0,0,NULL,&ViewSize,ViewUnmap,0,PAGE_EXECUTE);
if(!NT_SUCCESS(status))
{
BaseAddress = NULL;
ZwMapViewOfSection(&SectionHandle,NtCurrentProcess(),&BaseAddress,0,0,NULL,&ViewSize,ViewUnmap,0,PAGE_EXECUTE);
}
}
}
if(BaseAddress)
{
if(!DProxyTable[INDEX_KECALLBACK]->IsInitialized)
{
ULONG IatOffset = GetProcOffsetFromIat(BaseAddress);
DProxyTable[INDEX_KECALLBACK]->OriginFuncAddr = ExchangeMem(IatOffset,Win32kBase,ProxyKeUserModeCallback);
if(DProxyTable[INDEX_KECALLBACK]->OriginFuncAddr)
{
DProxyTable[INDEX_KECALLBACK]->IsInitialized;
status = STATUS_SUCCESS;
}
}
ZwUnmapViewOfSection(NtCurrentProcess(),BaseAddress);
}
return status;
}
4.12 交換內(nèi)存
ULONG ExchangeMem(ULONG Offset,ULONG BaseAddress,ULONG NewValue)
{//替換基址BaseAddress 偏移Offset 處的ULONG數(shù)據(jù)是越,返回原始數(shù)據(jù)
HANDLE CurProcessId = PsGetCurrentProcessId();
HANDLE SmssProcessId = GetProcessIdByName(L"smss.exe");
ULONG OriginValue = 0;
PMDL mdl = NULL;
if(!dwcsrssId)//如果沒(méi)有獲取到csrss.exe的id
{
if(CurProcessId == SmssProcessId)//使用smss.exe的SSSDT
{
mdl = GetWritablePage(BaseAddress+Offset,16,&MappedAddress);
if(mdl)
{
OriginValue = InterlockedExchange(MappedAddress,NewValue);
MmUnlockPages(mdl);
IoFreeMdl(mdl);
}
}
}
else
{//附加到csrss.exe
PVOID attachobj = AttachDriverToProcess(dwcsrssId);
if(attachobj)
{
mdl = GetWritablePage(BaseAddress+Offset,4,&MappedAddress);
if(mdl)
{
OriginValue = InterlockedExchange(MappedAddress,NewValue);
MmUnlockPages(mdl);
IoFreeMdl(mdl);
}
DetachDriverFromProcess(attachobj);
}
}
return OriginValue;
}
4.13 獲取函數(shù)Iat偏移
ULONG GetProcOffsetFromIat(PVOID ImageBase,PCHAR ModuleName,PCHAR ApiName)
{//ImageBase當(dāng)前進(jìn)程映像基址 ModuleName導(dǎo)入模塊映像基址 ApiName導(dǎo)入函數(shù)名
ANSI_STRING AApiName;
UNICODE_STRING UApiname;
PIMAGE_IMPORT_DESCRIPTOR ImportModuleDirectory;
ULONG ObjProcAddr;
ULONG Offset = 0;
PCHAR ImportedName;
PIMAGE_THUNK_DATA FunctionNameList;
RtlInitAnsiString(&AApiName,ApiName);
if(!NT_SUCCESS(RtlAnsiStringToUnicodeString(&UApiname,&AApiName,TRUE)))
return 0;
ObjProcAddr = MmGetSystemRoutineAddress(&UApiname);
RtlFreeUnicodeString(&UApiname);
ImportModuleDirectory = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(ImageBase,TRUE,IMAGE_DIRECTORY_ENTRY_IMPORT);
if(!ImportModuleDirectory)
return 0;
for (;(ImportModuleDirectory->Name != 0) && (ImportModuleDirectory->FirstThunk != 0);ImportModuleDirectory++)
{
ImportedName = (PCHAR)ImageBase + ImportModuleDirectory->Name;
if(!stricmp(ModuleName,ImportedName))
{
FunctionNameList = (PIMAGE_THUNK_DATA)((UCHAR*)ImageBase+ImportModuleDirectory->FirstThunk);
while(*FunctionNameList != 0)
{
if((*FunctionNameList) & 0x80000000)
{
if(FunctionNameList->u1.Function == ObjProcAddr)
return (UCHAR*)FunctionNameList - (UCHAR*)ImageBase;
}
else
{
IMAGE_IMPORT_BY_NAME *pe_name = (IMAGE_IMPORT_BY_NAME*)((PCHAR)ImageBase + *FunctionNameList);
if(pe_name->Name[0] == 'K' && !stricmp(pe_name->Name,"KeUserModeCallback"))
return (UCHAR*)FunctionNameList - (UCHAR*)ImageBase;
}
FunctionNameList++;
}
}
}
return 0;
}
4.14 另一種方式獲取ShadowSSDT信息
??當(dāng)常規(guī)方式獲取SSSDT失敗時(shí),會(huì)臨時(shí)設(shè)置ZwSetSystemInformation的過(guò)濾函數(shù)捕獲系統(tǒng)設(shè)置服務(wù)表(SYSTEM_INFORMATION_CLASS =SystemExtendServiceTableInformation)碌上,
void TryAnotherWayToGetShadowSSDT()
{
AddPrevFilter(EZwSetSystemInformation,ZwSetSystemInformationFilter1,0,0,NULL);
}
ULONG OldKeAddSystemServiceTable;
ULONG __stdcall ZwSetSystemInformationFilter1(FilterPacket* Packet)
{//改EAT以獲取SSSDT
if(!ShadowSSDTBase && Packet->Params[0] == SystemExtendServiceTableInformation && !OldKeAddSystemServiceTable)
{
OldKeAddSystemServiceTable = ExchangeEat(NtosBase,NewKeAddSystemServiceTable);
if(OldKeAddSystemServiceTable)
{
Packet->TagSlot[Packet->CurrentSlot] = 0xABCDEEEE;//用于標(biāo)記
Packet->PostFilterSlot[Packet->CurrentSlot] = ZwSetSystemInformationFilter2;
Packet->UsedSlotCount++;
}
}
return SYSMON_PASSTONEXT;
}
ULONG __stdcall ZwSetSystemInformationFilter2(FilterPacket* Packet)
{//獲取之后恢復(fù)EAT
if(Packet->TagSlot[Packet->CurrentSlot] == 0xABCDEEEE)//檢查標(biāo)記
{
if(serHookType != 1 && serHookType != 3)//是否SSDT型Hook
{
BeginSSDTHook();
}
}
return SYSMON_PASSTONEXT;
}
BOOLEAN __stdcall KeAddSystemServiceTable(PULONG_PTR Base,PULONG Count,ULONG Limit,PUCHAR Number,ULONG Index)
{//獲取SSSDT
RTL_PROCESS_MODULE_INFORMATION ProcessInfo;
RtlZeroMemory(&ProcessInfo,sizeof(ProcessInfo));
if(!ShadowSSDTBase && GetProcessInfoByFileName("win32k.sys",&ProcessInfo) &&
Base >= ProcessInfo.ImageBase && Base <= ProcessInfo.ImageBase+ProcessInfo.ImageSize)
{
Win32kBase = ProcessInfo.ImageBase;
Win32kSize = ProcessInfo.ImageSize;
ShadowSSDTBase = Base;
ShadowSSDTLimit = Limit;
ExchangeEat(NtosBase,OldKeAddSystemServiceTable);
}
return OldKeAddSystemServiceTable(Base,Count,Limit,Number,Index);
}
ULONG ExchangeEat(ULONG ImageBase,ULONG NewFunc)
{
PVOID Address = MiLocateExportName(ImageBase,"KeAddSystemServiceTable");
if(Address)
{
return ExchangeMem(0,Address,NewFunc);
}
return 0;
}