仅自己做备忘...
问题1.pspcidtable不是全局变量吗?咋个不能声明直接用?
结论:
因为它没有导出... 其实那个SSDT的结构能用是因为它导出了的...
问题2.(在windbg调试第三篇的补充内容那.....)
问题3.咋个,以及为什么那个HANDLE的值,TableCode的指针和对象体的指针低2位都要是0?
结论:
为了内存对齐~ 这样,内存以4字节一单位划分,指针的值是内存地址 必须能被4整除,所以指针的开始2位必须为0(必须为4的倍数) 搜索内存的时候就以4字节为单位搜索 减少搜索时间
感悟1:
if (*(PUSHORT)cPtr == 0x35FF && *(pOpcode + 6) == 0xE8)
{
pPspCidTable = **(PVOID **)(pOpcode + 2);
break;
}
这个代码是在PsLookUpProcessByProcessId的函数内定位pspcidtable
我反了下这个PsLookUpProcessByProcessId函数
kd> uf nt!PsLookUpProcessByProcessId
nt!PsLookupProcessByProcessId:
......
805ca42e ff35
e0b25580 push dword ptr [nt!PspCidTable (8055b2e0)]
805ca434 e84bb50300 call nt!ExMapHandleToPointer (80605984)
......
大概就是内存特征定位吧 哈哈 红色标注的地方就是pspcidtable的地址拉
也就是说在整个函数中,pspcidtable的地址前面是0xff35 后面是 0xe8
通过这个特征找到0xff35和 0xe8之间的这8字节的数据就是pspcidtable的地址
当然拉看起来不像是吧 内存存放顺序跟我们看的不一样 是以2字节为单位 压栈压进去的
所以逻辑上的顺序和内存上的顺序是正好相反的
所以红色字体以2个字节倒着排过来就是 8055b2e0
我们拿windbg看看
kd> dd pspcidtable
8055b2e0 e1000860 00000002 00000000 00000000
看 果然是pspcidtable的地址 神奇阿~~
感悟2:
记得 <<基于pspCidTable的进程检测技术>>这篇牛文里面说过获取pspcidtable的方法还有一个 就是
KdEnableDebugger->KdInitSystem->KdDebuggerDataBlock
->KDDEBUGGER_DATA32->PspCidTable
这个流程 其实跟那个PsLookUpProcessByProcessId差不多 都是内存定位
但是我们群的牛哥哥说了个更加易用的方法~
#define GetVar( x ) (*(PULONG)((*(PULONG)0xffdff034) + (ULONG)(x)))
PspCidTable = GetVar(0x80);
就这么简单.... 原理很简单... 0xffdff000是KPCR这个结构变量的地址
那么0x34就是KdVersionBlock 成员变量在该结构中的偏移
但是在0xffdff034指向的地方对应有个结构_DBGKD_GET_VERSION64
可惜的是这个结构只有0x28字节大小 但是....嘿嘿 这个结构后面藏着N多超级重要的内核变量
我们的pspcidtable这个变量其实就在这个结构起始位置的0x80字节偏移处~
如此一来 我拿sp3的xp系统调试如下:
kd> dd 0xffdff034
ffdff034 80546b38 8003f400 8003f000 80042000
kd> dd 80546b38+0x80
80546bb8
8055b2e0 00000000 8055d708 00000000
kd> dd pspcidtable
8055b2e0 e1000860 00000002 00000000 00000000
其实0xffdff034指向的地方对应的结构体应该就是传说中的KDDEBUGGER_DATA32这个结构(windbg看了下说没这个符号...)
typedef struct _KDDEBUGGER_DATA32 {
DBGKD_DEBUG_DATA_HEADER32 Header;
ULONG KernBase;
ULONG BreakpointWithStatus; // address of breakpoint
ULONG SavedContext;
USHORT ThCallbackStack; // offset in thread data
USHORT NextCallback; // saved pointer to next callback frame
USHORT FramePointer; // saved frame pointer
USHORT PaeEnabled:1;
ULONG KiCallUserMode; // kernel routine
ULONG KeUserCallbackDispatcher; // address in ntdll
ULONG PsLoadedModuleList;
ULONG PsActiveProcessHead;
ULONG PspCidTable; // <--------- What we need!!
//...
ULONG MmLoadedUserImageList;
} KDDEBUGGER_DATA32, *PKDDEBUGGER_DATA32;
大概就是这样的 呵呵 里面保存着比较重要的变量比如pspcidtable PsActiveProcessHead
PsLoadedModuleList等等 重要的是这个地址貌似是硬编码进去的 也就是说好像只要是NT内核的机器这个地址是不会变的,什么?根据?嘿嘿...
据某老外文献记载:
; Start of the architecturally defined section of the PCR. This section
; may be directly addressed by vendor/platform specific HAL code and will
; not change from version to version of NT.
看没看没 反正我sp3上机器可以 的确是这个地址 没错
__ay.字涉及到的学习资料
http://bbs.pediy.com/showthread.php?p=13746
http://www.0GiNr.com/
http://bbs.pediy.com/showthread.php?t=73028
futo 抹句柄表
Rootkits.com opc0de