如图所示 开始地方就是地址表 用这个办法的好处是不会受到KeServiceDescriptorTableShadow .win32k.ServiceTable被重定位的影响,可以从win32k的基址直接+区段VA获得
代码如下
DWORD FindPeSection( DWORD pModuleBase, PCHAR SectionName )
{
PIMAGE_DOS_HEADER pDosHdr;
PIMAGE_NT_HEADERS pNtHdr;
PIMAGE_SECTION_HEADER pSecHdr;
PIMAGE_EXPORT_DIRECTORY pExtDir;
UINT ui,uj;
PCHAR FunName;
DWORD *dwAddrName;
DWORD *dwAddrFun;
FARPROC pOldFun;
ULONG uAttrib;
pDosHdr = ( PIMAGE_DOS_HEADER )pModuleBase;
if ( IMAGE_DOS_SIGNATURE == pDosHdr->e_magic )
{
pNtHdr = ( PIMAGE_NT_HEADERS )( pModuleBase + pDosHdr->e_lfanew );
if( IMAGE_NT_SIGNATURE == pNtHdr->Signature || IMAGE_NT_SIGNATURE1 == pNtHdr->Signature )
{
pSecHdr = ( PIMAGE_SECTION_HEADER )( pModuleBase + pDosHdr->e_lfanew + sizeof( IMAGE_NT_HEADERS ) );
for ( ui = 0; ui < (UINT)pNtHdr->FileHeader.NumberOfSections; ui++ )
{
if ( !strcmp( pSecHdr->Name, SectionName ) )
// if ( !strcmp( pSecHdr->Name, ".data" ) )
{
dprintf("find it %s",pSecHdr->Name);
return pModuleBase + pSecHdr->VirtualAddress;
}
pSecHdr++;
}
}
}
return 0;
}
二。函数名定位
这个似乎没有多少好办法,解析pdb可以是可以 但是很麻烦
不过还好的是 同一个版本的系统 调用号一样
所以只需要3套 2k xp 2k3的调用号就可以完成hook
pdb办法
SymInitialize初始化
SymSetSearchPath “srv**symbols*
http://msdl.microsoft.com/”
SymLoadModule
SymGetSymFromName
老v曾经发出1个获取shadow地址和函数名称的工具 使用他可以很方便的获取
具体代码可以F5查看

以上读取pdb的方法测试使用的可以的
但是实际使用很麻烦
经过分析 我找到了1个比较好的定位办法
我们以SetWindowsHookExA为例子
.text:77D311D1 ; HHOOK __stdcall SetWindowsHookExA(int idHook, HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId)
.text:77D311D1 public _SetWindowsHookExA@16
.text:77D311D1 _SetWindowsHookExA@16 proc near
.text:77D311D1
.text:77D311D1 idHook = dword ptr 8
.text:77D311D1 lpfn = dword ptr 0Ch
.text:77D311D1 hModule = dword ptr 10h
.text:77D311D1 dwThreadId = dword ptr 14h
.text:77D311D1
.text:77D311D1 mov edi, edi
.text:77D311D3 push ebp
.text:77D311D4 mov ebp, esp
.text:77D311D6 push 2 ; int
.text:77D311D8 push [ebp+dwThreadId] ; int
.text:77D311DB push [ebp+hModule] ; hModule
.text:77D311DE push [ebp+lpfn] ; int
.text:77D311E1 push [ebp+idHook] ; int
.text:77D311E4 call _SetWindowsHookExAW@20 ; SetWindowsHookExAW(x,x,x,x,x)
.text:77D311E9 pop ebp
.text:77D311EA retn 10h
.text:77D311EA _SetWindowsHookExA@16 endp
.text:77D2DCFD ; int __stdcall SetWindowsHookExAW(int, int, HMODULE hModule, int, int)
.text:77D2DCFD _SetWindowsHookExAW@20 proc near ; CODE XREF: SetWindowsHookExW(x,x,x,x)+13 p
.text:77D2DCFD ; SetWindowsHookExA(x,x,x,x)+13 p
.text:77D2DCFD
.text:77D2DCFD Filename = word ptr -20Ch
.text:77D2DCFD var_4 = dword ptr -4
.text:77D2DCFD arg_0 = dword ptr 8
.text:77D2DCFD arg_4 = dword ptr 0Ch
.text:77D2DCFD hModule = dword ptr 10h
.text:77D2DCFD arg_C = dword ptr 14h
.text:77D2DCFD arg_10 = dword ptr 18h
.text:77D2DCFD
.text:77D2DCFD mov edi, edi
.text:77D2DCFF push ebp
.text:77D2DD00 mov ebp, esp
.text:77D2DD02 sub esp, 20Ch
.text:77D2DD08 mov eax, ___security_cookie
.text:77D2DD0D push esi
.text:77D2DD0E mov esi, [ebp+hModule]
.text:77D2DD11 test esi, esi
.text:77D2DD13 push edi
.text:77D2DD14 mov edi, [ebp+arg_4]
.text:77D2DD17 mov [ebp+var_4], eax
.text:77D2DD1A jz short loc_77D2DD33
.text:77D2DD1C push 104h ; nSize
.text:77D2DD21 lea eax, [ebp+Filename]
.text:77D2DD27 push eax ; lpFilename
.text:77D2DD28 push esi ; hModule
.text:77D2DD29 call ds:__imp__GetModuleFileNameW@12 ; GetModuleFileNameW(x,x,x)
.text:77D2DD2F test eax, eax
.text:77D2DD31 jz short loc_77D2DD52
.text:77D2DD33
.text:77D2DD33 loc_77D2DD33: ; CODE XREF: SetWindowsHookExAW(x,x,x,x,x)+1D j
.text:77D2DD33 push [ebp+arg_10]
.text:77D2DD36 mov eax, esi
.text:77D2DD38 push edi
.text:77D2DD39 push [ebp+arg_0]
.text:77D2DD3C neg eax
.text:77D2DD3E push [ebp+arg_C]
.text:77D2DD41 sbb eax, eax
.text:77D2DD43 lea ecx, [ebp+Filename]
.text:77D2DD49 and eax, ecx
.text:77D2DD4B push eax
.text:77D2DD4C push esi
.text:77D2DD4D call __SetWindowsHookEx@24 ; _SetWindowsHookEx(x,x,x,x,x,x)
.text:77D2DD52
.text:77D2DD52 loc_77D2DD52: ; CODE XREF: SetWindowsHookExAW(x,x,x,x,x)+34 j
.text:77D2DD52 mov ecx, [ebp+var_4]
.text:77D2DD55 pop edi
.text:77D2DD56 pop esi
.text:77D2DD57 call @__security_check_cookie@4 ; __security_check_cookie(x)
.text:77D2DD5C leave
.text:77D2DD5D retn 14h
.text:77D2DD5D _SetWindowsHookExAW@20 endp
.text:77D2DD5D
.text:77D2DD65 ; __stdcall _SetWindowsHookEx(x, x, x, x, x, x)
.text:77D2DD65 __SetWindowsHookEx@24 proc near ; CODE XREF: SetWindowsHookExAW(x,x,x,x,x)+50 p
.text:77D2DD65
.text:77D2DD65 var_10 = byte ptr -10h
.text:77D2DD65 var_8 = dword ptr -8
.text:77D2DD65 var_4 = dword ptr -4
.text:77D2DD65 arg_0 = dword ptr 8
.text:77D2DD65 arg_4 = dword ptr 0Ch
.text:77D2DD65 arg_8 = dword ptr 10h
.text:77D2DD65 arg_C = dword ptr 14h
.text:77D2DD65 arg_10 = dword ptr 18h
.text:77D2DD65 arg_14 = dword ptr 1Ch
.text:77D2DD65
.text:77D2DD65 mov edi, edi
.text:77D2DD67 push ebp
.text:77D2DD68 mov ebp, esp
.text:77D2DD6A sub esp, 10h
.text:77D2DD6D push [ebp+arg_4]
.text:77D2DD70 and [ebp+var_4], 0
.text:77D2DD74 lea eax, [ebp+var_10]
.text:77D2DD77 push eax
.text:77D2DD78 mov [ebp+var_8], eax
.text:77D2DD7B call ds:__imp__RtlInitUnicodeString@8 ; RtlInitUnicodeString(x,x)
.text:77D2DD81 push [ebp+arg_14]
.text:77D2DD84 push [ebp+arg_10]
.text:77D2DD87 push [ebp+arg_C]
.text:77D2DD8A push [ebp+arg_8]
.text:77D2DD8D push [ebp+var_8]
.text:77D2DD90 push [ebp+arg_0]
.text:77D2DD93 call _NtUserSetWindowsHookEx@24 ; NtUserSetWindowsHookEx(x,x,x,x,x,x)
.text:77D2DD98 leave
.text:77D2DD99 retn 18h
.text:77D2DD99 __SetWindowsHookEx@24 endp
.text:77D2DD99
.text:77D2DDA1 ; __stdcall NtUserSetWindowsHookEx(x, x, x, x, x, x)
.text:77D2DDA1 _NtUserSetWindowsHookEx@24 proc near ; CODE XREF: _SetWindowsHookEx(x,x,x,x,x,x)+2E p
.text:77D2DDA1 mov eax, 1225h
.text:77D2DDA6 mov edx, 7FFE0300h
.text:77D2DDAB call dword ptr [edx]
.text:77D2DDAD retn 18h
.text:77D2DDAD _NtUserSetWindowsHookEx@24 endp
我们看这里 .text:77D2DDA1 mov eax, 1225h
里面有和ssdt一样的调用号 但是有个问题 NtUserSetWindowsHookEx在user32里面没有导出,我们需要多次搜索才行
HHOOK STDCALL NtUserSetWindowsHookEx (HINSTANCE Mod, PUNICODE_STRING UnsafeModuleName, DWORD ThreadId, int HookId, HOOKPROC HookProc, BOOL Ansi)
这个就是原型 不过搜索起来确实是比较麻烦的,不知道还有无其他好办法了
[ 此贴被zhuwg在2007-12-10 20:37重新编辑 ]描述:老v的获取shadow工具
附件:
sysnum.rar (423 K) 下载次数:18
==============================================================
http://www.debugman.com/read.php?tid=755三。如何hook
似乎这个问题并不大,shadow ssdt和ssdt本质上都是1个地址表,最为简单的方法是把你的函数替换地址表的对应项,具体hook代码甚至可以完全照抄ssdt的,这里只说1下几个偶遇到的小问题
1。win32k.sys不是常在内存的,如果不是GUI线程,shadow ssdt地址无效
解决办法:
1。在driverdispatch中hokk
driverdispatch是位于执行driveriocontrol的线程上下文的
我们使用1个GUI线程去driveriocontrol
2。attachtoprocess
通常 我们使用cerss.exe
HANDLE GetCsrPid()
{
HANDLE Process, hObject;
HANDLE CsrId = (HANDLE)0;
OBJECT_ATTRIBUTES obj;
CLIENT_ID cid;
UCHAR Buff[0x100];
POBJECT_NAME_INFORMATION ObjName = (PVOID)&Buff;
PSYSTEM_HANDLE_INFORMATION_EX Handles;
ULONG r;
Handles = GetInfoTable(SystemHandleInformation);
if (!Handles) return CsrId;
for (r = 0; r < Handles->NumberOfHandles; r++)
{
if (Handles->Information[r].ObjectTypeNumber == 21) //Port object
{
InitializeObjectAttributes(&obj, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
cid.UniqueProcess = (HANDLE)Handles->Information[r].ProcessId;
cid.UniqueThread = 0;
if (NT_SUCCESS(NtOpenProcess(&Process, PROCESS_DUP_HANDLE, &obj, &cid)))
{
if (NT_SUCCESS(ZwDuplicateObject(Process,
(HANDLE)Handles->Information[r].Handle,
NtCurrentProcess(),
&hObject,
0, 0, DUPLICATE_SAME_ACCESS)))
{
if (NT_SUCCESS(ZwQueryObject(hObject,
ObjectNameInformation,
ObjName,
0x100, NULL)))
{
if (ObjName->Name.Buffer &&
!wcsncmp(L"\\Windows\\ApiPort", ObjName->Name.Buffer, 20))
{
CsrId = (HANDLE)Handles->Information[r].ProcessId;
}
}
ZwClose(hObject);
}
ZwClose(Process);
}
}
}
ExFreePool(Handles);
return CsrId;
}
然后我们KeAttachProcess
ntStatus = PsLookupProcessByProcessId(GetCsrPid(), &EProcess);
if (!NT_SUCCESS( ntStatus ))
{
DbgPrint("PsLookupProcessByProcessId()\n");
return ntStatus;
}
KeAttachProcess(EProcess);
3.使用MDL映射一块不分页内存,设置成可以写入
不分页内存 ExAllocatePool(NonPagedPool
即为不会被切换到pagefile的内存,是常驻在物理内存的,比较希缺,使用完毕以后记住释放掉
参考regmon的代码
PVOID *
RegmonMapServiceTable(
SERVICE_HOOK_DESCRIPTOR **ServiceIsHooked
)
{
*ServiceIsHooked = (SERVICE_HOOK_DESCRIPTOR*)
ExAllocatePool(NonPagedPool, KeServiceDescriptorTable->TableSize);
if( *ServiceIsHooked )
{
RtlZeroMemory(*ServiceIsHooked, KeServiceDescriptorTable->TableSize);
KeServiceTableMdl = MmCreateMdl(0, KeServiceDescriptorTable->ServiceTable, KeServiceDescriptorTable->TableSize << 2);
if( KeServiceTableMdl )
{
MmBuildMdlForNonPagedPool(KeServiceTableMdl);
KeServiceTableMdl->MdlFlags |= 1;
return (PVOID*)MmMapLockedPages(KeServiceTableMdl, KernelMode);
}
}
return NULL;
};
看起来shadowssdt何hook本身并没有什么难度
只要正确定位了地址,hook起来和ssdt完全一样
unhook不在重复 完全抄ssdt的代码即可
四。checkhook
hook用的人多了 难免出现重复hook的情况 为了实现和别人的东西和平共处,最好hook之前做个检测
hook的方法是固定的,就那么2种 改地址表 或者inline hook,我们分别来对待
1。修改地址表的hook
这个对付起来几乎不用特别对待,只是你保存的OldFunc是其他的程序hook函数所在的地址,判断方法很简单,看看这个地址在不在win32k的模块 里面,和平共处的办法是你的myfunc里面call别人的hook函数,当然 如果你不想要别人的hook了,直接搜索到原始地址call之也是可行的
另外说1下 在别人的函数里面搜索原始地址 用MmIsAddressValid+ismodulewin32k
可以判断(这个办法好像是在mj文章里面看到的 记不清了)
2。inlinehook
这个比较麻烦了 如果是修改前面5个字节还好,直接替换处理都可以不改变
麻烦是函数中间地方被hook,盲目修改可能直接BSOD了,这个需要1个反汇编引擎来帮助分析代码字节长度,海风大大的hooklib很不错 可以完成这个功能
五,简单说1下restore
pWin32k = GetModuleHandle("win32k.sys");
SdtRVA = &KeServiceDescriptorTable->win32k.ServiceTable - pWin32k ;
w32kCopy = LoadPeFile("win32k.sys");
ProcessRelocs(w32kCopy, pWin32k);
memcpy(&KeServiceDescriptorTable->win32k.ServiceTable, w32kCopy + SdtRVA, SdtSize);
不过 其实可以不用ProcessRelocs处理
因为你可以使用lordpe查看1下 win32k.sys的默认基址就是系统加载的基址
可以不需要ProcessRelocs,不过为了更加方便和通用,这么做也可以的
休息去咯---