首页
论坛
课程
招聘
[原创]inline hook SSDT 躲避 Themida 的ThreadHideFromDebugger (学习笔记2)
2008-12-10 15:31 9807

[原创]inline hook SSDT 躲避 Themida 的ThreadHideFromDebugger (学习笔记2)

2008-12-10 15:31
9807
Themida保护的程序会采用ThreadHideFromDebugger来反调试,这个一旦设置,就一直起效,所以对于需要附加的程序就不太好办了,或者有的程序直接调用 int 2e来反调试, 虽然有插件比如 invisible可以躲过,但是需要附加进行调试的程序就不起作用了。

比如我以前写的一个反调试函数

void anti()
{

/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
//NtSetInformationThread 功能设置调试端口为0
//
//
//

        ::GetCurrentThread();
        _asm                                                                // xp系统
        {
                push 0                      //InformationLength
                push 0                      //ThreadInformation
                push 0x11                //11 就是ThreadHideFromDebugger           
                push eax                  //当前线程句柄
                mov eax, 0xe5         //EAX  NtSetInformationThread调用号
                mov edx, esp           //EDX  当前堆栈放
                int 0x2e
                add esp, 0x10
        }

        ::GetCurrentThread();
        _asm                                                                // 2000系统
        {
                push 0
                push 0
                push 0x11
                push eax
                mov eax, 0xc6
                mov edx, esp
                int 0x2e
                add esp, 0x10
        }
}

   为了躲避上面的ANTI         HOOK ssdt是个不错的方法
  下面的原理就是HOOK SSDT 原理是我学习笔记1中的原理, 不过HOOK单元改了下,ring3的拿到RING0要改下= =
     HOOK SSDT 分5步

第一步 申请一个全局变量 用来存放被破坏的指令
第二步 声明一个类型 用来强制转换 调用自己的 POldNtWriteProcessMemroy
第三步 自己的函数
第四步 安装HOOK
第五部 卸载HOOK
其中起关键作用的是下面的代理函数
NTSTATUS __stdcall                           //第三步 自己的函数
MyNtSetInformationThread(
                                                 IN HANDLE ThreadHandle,
                                                 IN THREADINFOCLASS ThreadInformationClass,
                                                 IN PVOID ThreadInformation,
                                                 IN ULONG ThreadInformationLength
                                                 )
{
        if(ThreadInformationClass == 0x11)
        {
                DbgPrint("发现 ANTI DEBUG 行为");
               
                DbgPrint("NtSetInformationThread 参数 %8x %8x %8x %8x ", ThreadHandle, ThreadInformationClass, ThreadInformationClass, ThreadInformationLength); //  打印出参数               
                ThreadInformationClass = (THREADINFOCLASS)0xff;
               
                DbgPrint("参数被我改过后是   %8x %8x %8x %8x ", ThreadHandle, ThreadInformationClass, ThreadInformationClass, ThreadInformationLength);
               
                return STATUS_SUCCESS;      //直接返回成功  这样ANTI就失效了
        }
       
                 //强制转换成函数的形式   
        return        ((SYSNTSETINFORMATIIONTHREAD)OldNtSetInformationThread)(  //  放行
                ThreadHandle,
                ThreadInformationClass,
                ThreadInformation,
                ThreadInformationLength
                );
}

下面是全部的代码   附件中也包含完成的代码
SYS加载有  你只要调用下 anti这个函数 代理函数就会输出参数 并且 改变参数
void * OldNtSetInformationThread;;                       //第一步 申请一个全局变量 用来存放被破坏的指令

//NtSetInformationThread
typedef NTSTATUS (__stdcall *SYSNTSETINFORMATIIONTHREAD)   //第二步 声明一个类型 用来强制转换 调用自己的 POldNtWriteProcessMemroy
(
IN HANDLE ThreadHandle,
IN THREADINFOCLASS ThreadInformationClass,
IN PVOID ThreadInformation,
IN ULONG ThreadInformationLength
);

NTSTATUS __stdcall                           //第三步 自己的函数
MyNtSetInformationThread(
                                                 IN HANDLE ThreadHandle,
                                                 IN THREADINFOCLASS ThreadInformationClass,
                                                 IN PVOID ThreadInformation,
                                                 IN ULONG ThreadInformationLength
                                                 )
{
        if(ThreadInformationClass == 0x11)
        {
                DbgPrint("发现 ANTI DEBUG 行为");
               
                DbgPrint("NtSetInformationThread 参数 %8x %8x %8x %8x ", ThreadHandle, ThreadInformationClass, ThreadInformationClass, ThreadInformationLength); //证明自己存在
               
                ThreadInformationClass = (THREADINFOCLASS)0xff;
               
                DbgPrint("参数被我改过后是   %8x %8x %8x %8x ", ThreadHandle, ThreadInformationClass, ThreadInformationClass, ThreadInformationLength); //证明自己存在
               
                return STATUS_SUCCESS;      //直接返回成功
        }
       
                 //强制转换成函数的形式   
        return        ((SYSNTSETINFORMATIIONTHREAD)OldNtSetInformationThread)(  //  放行
                ThreadHandle,
                ThreadInformationClass,
                ThreadInformation,
                ThreadInformationLength
                );
}

ULONG AddrNtSetInformationThread;
VOID OnUnload(IN PDRIVER_OBJECT DriverObject);
// 驱动程序加载时调用DriverEntry例程
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryString)
{

  DbgPrint("Hook NtSetInformationThread DriverEntry");
  pDriverObj->DriverUnload = OnUnload;

  AddrNtSetInformationThread = *PULONG((ULONG)KeServiceDescriptorTable->ServiceTable + 0xe5 * 4);
  AfxHookCode((void*)AddrNtSetInformationThread, (void*)MyNtSetInformationThread, (void**)&OldNtSetInformationThread,  10);  //第四步 AFXHOOK

// if(驱动加载失败)
//          一定要 AfxUnHookCode  不然驱动加载失败 自己分配的内存代码也就失效了 系统经过这个SSDT也就蓝了
  return STATUS_SUCCESS;
}

//////////////////////////////////////////////////////
VOID OnUnload(IN PDRIVER_OBJECT DriverObject)
{
        AfxUnHookCode((void*)AddrNtSetInformationThread, OldNtSetInformationThread,  10);  //第五部 卸载  驱动卸载一定要还原HOOK 因为驱动卸载了,自己分配的内存也就失效了  所以自己的POldNtWriteProcessMemroy 指向的代码也就没了
        DbgPrint("Unload Hook NtSetInformationThread");
}

下面是RING 0 HOOK 模块
#ifndef __AFXHOOKCODE_H__
#define __AFXHOOKCODE_H__

bool AfxHookCode(void* TargetProc, void* NewProc,void ** l_OldProc, int bytescopy = 5)
{
        *l_OldProc =  ExAllocatePool(NonPagedPool,(bytescopy+5));        // 执行被覆盖的指令 再跳到原来的代码上运行
                                       

        memcpy(*l_OldProc, TargetProc, bytescopy);           // 事先保存被破坏的指令

        __asm{
    cli
    mov  eax,cr0
    and  eax,not 10000h
    mov  cr0,eax
  }

                                           // 我的内存的代码执行完 跳到原来的 代码+破坏的代码的长度 上去
        *((unsigned char*)(*l_OldProc) + bytescopy) = 0xe9;

                           // 我内存代码跳到原来代码上的偏移
    *(unsigned int *)((unsigned char*)(*l_OldProc) +bytescopy + 1)=(unsigned int)(TargetProc) + bytescopy - ( (unsigned int)((*l_OldProc)) + 5 + bytescopy ) ;

                                      //被HOOK的函数头改为jmp
        *(unsigned char*)TargetProc =(unsigned char)0xe9;

                                          //被HOOK的地方跳到我的新过程 接受过滤
        *(unsigned int*)((unsigned int)TargetProc +1) = (unsigned int)NewProc - ( (unsigned int)TargetProc + 5);

  __asm{
    mov  eax,cr0
    or  eax,10000h
    mov  cr0,eax
    sti
  }
        return true;
}

bool AfxUnHookCode(void* TargetAddress, void * l_SavedCode, unsigned int len)
{

  __asm{
    cli
    mov  eax,cr0
    and  eax,not 10000h
    mov  cr0,eax
  }

  // 恢复HOOK
        memcpy(TargetAddress, l_SavedCode, len);

  __asm{
    mov  eax,cr0
    or  eax,10000h
    mov  cr0,eax
    sti
  }

          return true;
}

#endif

看雪论坛2020激励机制:能力值、活跃值和雪币体系!会员积分、权限和会员发帖、回帖活跃程度关联!

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (10)
雪    币: 250
活跃值: 活跃值 (26)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
weolar 活跃值 10 2008-12-10 16:53
2
0
我又是沙发~~呵呵,顶~~~
雪    币: 55
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xiongyifly 活跃值 2008-12-11 15:33
3
0
这也算inline Hook 吗???
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yulewanglu 活跃值 2008-12-11 17:55
4
0
不错不错 TMD就是强大
雪    币: 221
活跃值: 活跃值 (11)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
梧桐 活跃值 1 2008-12-11 17:59
5
0
毁灭掉一切证据~
雪    币: 459
活跃值: 活跃值 (21)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
qihoocom 活跃值 9 2008-12-11 18:02
6
0
太挫了,下面代码直接绕过你的ANTI-ANTI DEBUG

        st = ObReferenceObjectByHandle (ThreadHandle,
                                        THREAD_SET_INFORMATION,
                                        PsThreadType,
                                        PreviousMode,
                                        &Thread,
                                        NULL);

        if (!NT_SUCCESS (st)) {
            return st;
        }

        PS_SET_BITS (&Thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_HIDEFROMDBG);

        ObDereferenceObject (Thread);
雪    币: 250
活跃值: 活跃值 (26)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
weolar 活跃值 10 2008-12-11 19:02
7
0
又学到一招。现在才知道PS_CROSS_THREAD_FLAGS_HIDEFROMDBG可以用来对调试者隐藏线程。
MJ怎么发现的PS_CROSS_THREAD_FLAGS_HIDEFROMDBG?WRK那么大,能注意到这真不容易~~
那是不是得hook ObReferenceObjectByHandle ,禁止设置 CrossThreadFlags了?
雪    币: 459
活跃值: 活跃值 (21)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
qihoocom 活跃值 9 2008-12-11 20:07
8
0
thread object可以用PsLookupThreadByThreadId法得到

再给你出个狠招~

Set : ProcessObject->DebugObject->Flags  DEBUG_OBJECT_DELETE_PENDING

哈哈,让他Queue Debug Message不成功~
雪    币: 250
活跃值: 活跃值 (26)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
weolar 活跃值 10 2008-12-11 21:00
9
0
#define DEBUG_OBJECT_DELETE_PENDING (0x1) // Debug object is delete pending.
这招够黑~~我也赶快去好好读读wrk。里面的信息太多了,以前直接忽视掉……
雪    币: 6
活跃值: 活跃值 (70)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
crazybug 活跃值 2 2008-12-12 10:13
10
0
都用驱动了,没什么干不了的,还在这块搞来搞去什么攻防,只能说是想象力枯竭~

总之很挫
雪    币: 106
活跃值: 活跃值 (10)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
bujin888 活跃值 4 2008-12-13 07:03
11
0
不知道能不能对付vm1.7反调试附加
游客
登录 | 注册 方可回帖
返回