KdDisableDebugger 长度70
804f7602 8bff mov edi,edi
804f7604 55 push ebp
804f7605 8bec mov ebp,esp
804f7607 51 push ecx
804f7608 b102 mov cl,2
804f760a ff15f4864d80 call dword ptr [nt!_imp_KfRaiseIrql (804d86f4)]
804f7610 8845ff mov byte ptr [ebp-1],al
804f7613 e81c010000 call nt!KdpPortLock (804f7734) //进入这个里面的函数进行HOOK,直接JMP到下面的804f7670
804f7618 833dc8c8548000 cmp dword ptr [nt!KdDisableCount (8054c8c8)],0
804f761f 753a jne nt!KdDisableDebugger+0x59 (804f765b)
804f7621 a0c1c85480 mov al,byte ptr [nt!KdDebuggerEnabled (8054c8c1)]
804f7626 84c0 test al,al
804f7628 7410 je nt!KdDisableDebugger+0x38 (804f763a)
804f762a 803dfc62548000 cmp byte ptr [nt!KdPitchDebugger (805462fc)],0
804f7631 c605ccc8548001 mov byte ptr [nt!KdPreviouslyEnabled (8054c8cc)],1
804f7638 7407 je nt!KdDisableDebugger+0x3f (804f7641)
804f763a c605ccc8548000 mov byte ptr [nt!KdPreviouslyEnabled (8054c8cc)],0
804f7641 84c0 test al,al
804f7643 7416 je nt!KdDisableDebugger+0x59 (804f765b)
804f7645 e8d47a1600 call nt!KdpSuspendAllBreakpoints (8065f11e) //当执行到这里的时候双机调试会直接断掉
804f764a c705e4325580ec7a4f80 mov dword ptr [nt!KiDebugRoutine (805532e4)],offset nt!KdpStub (804f7aec)
804f7654 c605c1c8548000 mov byte ptr [nt!KdDebuggerEnabled (8054c8c1)],0
804f765b ff05c8c85480 inc dword ptr [nt!KdDisableCount (8054c8c8)]
804f7661 e8de000000 call nt!KdpPortUnlock (804f7744)
804f7666 8a4dff mov cl,byte ptr [ebp-1]
804f7669 ff151c874d80 call dword ptr [nt!_imp_KfLowerIrql (804d871c)]
804f766f c9 leave
804f7670 c3 ret //准备从子函数跳转到这个位置来
思路如下:
下面是call KdpPortLock里面的实现代码
804f78ce b94cbe5480 mov ecx,offset nt!IoStatisticsLock+0x4 (8054be4c)
804f78d3 e988620400 jmp nt!KiAcquireSpinLock (8053db60) nt!KiAcquireSpinLock里面第一行就是一个ret;
没有任何作用
将 jmp nt!KiAcquireSpinLock (8053db60)
改成jmp 804f7670
直接跳转到KdDisableDebugger 里面804f7670 地址,相当于直接返回;
这样应该就可以无视别人去检测KdDisableDebugger里面的代码了
但是……
当我HOOK后,还没直接调用就黑屏
为什么是黑屏,不是蓝屏!!!为什么会黑屏?这问题出的好有个性……
直接贴代码吧!这是一种新的思路,但不知道这种方式是否可行,忘大牛指教,本人技术比较菜,代码可能有点乱,所以随便喷吧……
ULONG JMP_RETADDR = 0;//上一层函数返回的地址
BYTE ByteBuff[4] = {0,0,0,0};//需要恢复的数据
ULONG UlongBuff;
ULONG nWriteAddr;//写入的地址
void __declspec(naked) my_function_detour_Shuangji()
{
//获得调用者的EPROCESS
ANSI_STRING str_1;
ANSI_STRING str_Name;
processEPROCESSB = IoGetCurrentProcess();
//将调用者的进程名保存到str1中
ULONG aaabb;
int naa;
char *pch;
aaabb = (ULONG)processEPROCESSB;
aaabb += 0x174;
pch = (char*)aaabb;
naa = UlongBuff;
//DbgPrint("%s\n",pch);
//改成这样都会直接黑屏
_asm
{
ret
}
//将我们要比对的进程名放入str1和str2
//RtlInitAnsiString(&str_1,TP_EXE);//说明是TP进程访问了这里
////这里判断ESP的值是多少
//ULONG ESPAddr;
//_asm
//{
// mov ESPAddr,esp-4
//}
//if (RtlCompareString(&str_Name,&str_1,TRUE) == 0)
//{
// _asm
// {
// mov eax,JMP_RETADDR
// jmp eax;
// }
//}
//else
//{
// _asm
// {
// mov eax,UlongBuff
// jmp eax;
// }
//}
}
void Pass_Shuangji()
{
BYTE* KdDisableDebuggerAddr = (BYTE*)GetNt_OldAddr(L"KdDisableDebugger");;
PULONG KdpPortLockAddr = NULL;
if(KdDisableDebuggerAddr == NULL)
{
DbgPrint("没有找到KdDisableDebugger地址\n");
return;
}
KdPrint(("KdDisableDebuggerAddr = %X\n"),KdDisableDebuggerAddr);
BYTE* i = NULL;
//找到KdpPortLock的函数地址
for(i = KdDisableDebuggerAddr;i < KdDisableDebuggerAddr+0x70;i++)
{
if( ( *(i-1) == 0xE8 ) &&
( *(i+4) == 0x83 ) &&
( *(i-2) == 0xff ) &&
( *(i-3) == 0x45 ) &&
( *(i-4) == 0x88 )
)
{
int n1 = *(PULONG)i;
KdpPortLockAddr = (PULONG)(i + n1);
KdpPortLockAddr++; //加上*i所占的4字节
DbgPrint("KdpPortLockAddr = %X\n",KdpPortLockAddr);
break;
}
}
if(KdpPortLockAddr == NULL)
{
DbgPrint("没有找到KdpPortLockAddr地址\n");
return;
}
BOOL b = TRUE;
for(i = KdDisableDebuggerAddr;i < KdDisableDebuggerAddr+0x70;i++)
{
if( ( *(i) == 0xC3 ) &&
( *(i-1) == 0xC9 ) &&
( *(i-10) == 0x8A ))
{
DbgPrint("RET的地址 = %X\n",i);
JMP_RETADDR = (ULONG)(i);
b =FALSE;
break;
}
}
if(b)
{
DbgPrint("RET的地址没有找到\n");
return;
}
//要写入的字节
BYTE JmpAddress[4] = {0,0,0,0};
KIRQL Irql;
nWriteAddr = (ULONG)((ULONG)KdpPortLockAddr+6);
ULONG n = ((ULONG)my_function_detour_Shuangji - (ULONG )(nWriteAddr+4));
DbgPrint("nWriteAddr = %X\n",nWriteAddr);
DbgPrint("my_function_detour_Shuangji = %X\n",my_function_detour_Shuangji);
*(PULONG)JmpAddress = n;
//获得原来需要跳转的地址
ULONG m = *(PULONG)nWriteAddr;
UlongBuff = (nWriteAddr + m) + 4;
WPOFF();//去掉页面保护
Irql=KeRaiseIrqlToDpcLevel();
//记录原来的值,用于恢复HOOK
RtlCopyMemory(ByteBuff,(void*)nWriteAddr,4);
//写入
RtlCopyMemory((void*)nWriteAddr,JmpAddress,4);
//恢复Irql
KeLowerIrql(Irql);
WPON();//恢复页面保护
}
void UnShuangji()
{
KIRQL Irql;
WPOFF();//去掉页面保护
Irql=KeRaiseIrqlToDpcLevel();
//恢复原来的值
RtlCopyMemory((void*)nWriteAddr,ByteBuff,4);
//恢复Irql
KeLowerIrql(Irql);
WPON();//恢复页面保护
}
[注意]看雪招聘,专注安全领域的专业人才平台!