S.l.e!ep.¢%

像打了激速一样,以四倍的速度运转,开心的工作
简单、开放、平等的公司文化;尊重个性、自由与个人价值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

编写简单的防杀程序

Posted on 2009-10-18 18:03 S.l.e!ep.¢% 阅读(561) 评论(0)  编辑 收藏 引用 所属分类: Windows WDM

编写简单的防杀程序

HOHO

发现res区现在编程风行哈~  眼看就要开学,偶再不鲜点血就说不过去了  :P
其实是比较老的东西了 不过个人感觉似乎还是有点意义的 :) 
应该能过taskmgr,IceSword(IceSword的线程信息中一个一个线程的杀还是可以干掉这种的,之于如何防IceSword按线程杀以后再讲:)),DarkSpy 1.0.5.0(我没有办法拿到内部版 所以不知道内部版是什么样的情况:P),SnipeSword (截至偶发贴之前的所有版本),GMER 1.0.13.12551(我所能拿到的最新版本)
过不了Rootkit Unhooker的虚拟内存清零(RkU的以后再讲:P),也过不了Simple Taskmgr 1.0.303
事实上,在simple taskmgr 1.0.303(st)中,所有被提及的全能bypass掉(DarkSpy杀st的时候会蓝屏T_T),不过st用的是ring0 inline hook API,暂时不说。

IceSword杀进程是使用NtTerminateProcess(当然是先恢复掉hook咯 :P),DarkSpy似乎是自己实现了一个PspTerminateProcess(但是并没有实现PspTerminateThreadByPointer),SnipeSword也是使用NtTerminateProcess(调用前恢复hook)。

无论是NtTerminateProcess还是PspTerminateProcess,最终都是调用了PspTerminateThreadByPointer(可以通过windows 2k的源代码或者wrk来看到)

以下以wrk中的代码为例,windows 2k中PspTerminateThreadByPointer的参数是两个,wrk中为三个。不过这些我们不需要关心:P

NtTerminateProcess节选如下:


引用:

NTSTATUS
NtTerminateProcess
(
   
__in_opt HANDLE ProcessHandle,
   
__in NTSTATUS ExitStatus
   
)

{

   
//省略...
   
   
st = STATUS_NOTHING_TO_TERMINATE;

   
for (Thread = PsGetNextProcessThread (Process, NULL);
        
Thread != NULL;
        
Thread = PsGetNextProcessThread (Process, Thread)) {

       
st = STATUS_SUCCESS;
       
if (Thread != Self) {
           
PspTerminateThreadByPointer (Thread, ExitStatus, FALSE);
        }
    }
   
   
//省略...

   
return st;
}


PspTerminateProcess(因为PspTerminateProcess相对比较简单,就全复制过来了):


引用:

NTSTATUS
PspTerminateProcess
(
   
PEPROCESS Process,
   
NTSTATUS ExitStatus
   
)

{

   
PETHREAD Thread;
   
NTSTATUS st;

   
PAGED_CODE();


   
if (Process->Flags
   
& PS_PROCESS_FLAGS_BREAK_ON_TERMINATION) {
     
PspCatchCriticalBreak("Terminating critical process 0x%p (%s)\n",
               
Process,
               
Process->ImageFileName);
    }

   
PS_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_PROCESS_DELETE);

   
st = STATUS_NOTHING_TO_TERMINATE;

   
for (Thread = PsGetNextProcessThread (Process, NULL);
        
Thread != NULL;
        
Thread = PsGetNextProcessThread (Process, Thread)) {

       
st = STATUS_SUCCESS;

       
PspTerminateThreadByPointer (Thread, ExitStatus, FALSE);

    }

   
if (st == STATUS_NOTHING_TO_TERMINATE || Process->DebugPort != NULL) {
       
ObClearProcessHandleTable (Process);
       
st = STATUS_SUCCESS;
    }
   
return st;
}


可以看到这两个最后都是使用PspTerminateThreadByPointer来按照线程来终止的。

再看看PspTerminateThreadByPointer的代码(节选):


引用:

NTSTATUS
PspTerminateThreadByPointer
(
   
IN PETHREAD Thread,
   
IN NTSTATUS ExitStatus,
   
IN BOOLEAN DirectTerminate
   
)

{
   
//省略...
   
if (DirectTerminate && Thread == PsGetCurrentThread()) {

       
ASSERT (KeGetCurrentIrql() < APC_LEVEL);

       
PS_SET_BITS (&Thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_TERMINATED);

       
PspExitThread (ExitStatus);

    }
else {

       
if (IS_SYSTEM_THREAD (Thread)) {
           
return STATUS_ACCESS_DENIED;
        }

       
//省略...
   
}

   
return Status;
}


也就是说,只要是“他杀”(当前进程(PsGetCurrentThread())不等于参数Thread),那么就会判断IS_SYSTEM_THREAD这个宏 如果为true,就直接返回STATUS_ACCESS_DENIED(拒绝访问)



引用:

#define IS_SYSTEM_THREAD(Thread)  (((Thread)->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_SYSTEM) != 0)


从PspTerminateThreadByPointer的参数表上我们可以知道,Thread是一个PETHREAD类型的数据。
而PETHREAD被定义为*ETHREAD,也就是ETHREAD结构的指针。

ETHREAD结构(来自windbg,结构为xp sp2下的——这个结构在不同系统下不一定相同,CrossThreadFlags在ETHREAD结构中的偏移需要根据系统来判断):



引用:

lkd> dt _ETHREAD
nt
!_ETHREAD
  
+0x000 Tcb              : _KTHREAD
  
+0x1c0 CreateTime       : _LARGE_INTEGER
  
+0x1c0 NestedFaultCount : Pos 0, 2 Bits
  
+0x1c0 ApcNeeded        : Pos 2, 1 Bit
  
+0x1c8 ExitTime         : _LARGE_INTEGER
  
+0x1c8 LpcReplyChain    : _LIST_ENTRY
  
+0x1c8 KeyedWaitChain   : _LIST_ENTRY
  
+0x1d0 ExitStatus       : Int4B
  
+0x1d0 OfsChain         : Ptr32 Void
  
+0x1d4 PostBlockList    : _LIST_ENTRY
  
+0x1dc TerminationPort  : Ptr32 _TERMINATION_PORT
  
+0x1dc ReaperLink       : Ptr32 _ETHREAD
  
+0x1dc KeyedWaitValue   : Ptr32 Void
  
+0x1e0 ActiveTimerListLock : Uint4B
  
+0x1e4 ActiveTimerListHead : _LIST_ENTRY
  
+0x1ec Cid              : _CLIENT_ID
  
+0x1f4 LpcReplySemaphore : _KSEMAPHORE
  
+0x1f4 KeyedWaitSemaphore : _KSEMAPHORE
  
+0x208 LpcReplyMessage  : Ptr32 Void
  
+0x208 LpcWaitingOnPort : Ptr32 Void
  
+0x20c ImpersonationInfo : Ptr32 _PS_IMPERSONATION_INFORMATION
  
+0x210 IrpList          : _LIST_ENTRY
  
+0x218 TopLevelIrp      : Uint4B
  
+0x21c DeviceToVerify   : Ptr32 _DEVICE_OBJECT
  
+0x220 ThreadsProcess   : Ptr32 _EPROCESS
  
+0x224 StartAddress     : Ptr32 Void
  
+0x228 Win32StartAddress : Ptr32 Void
  
+0x228 LpcReceivedMessageId : Uint4B
  
+0x22c ThreadListEntry  : _LIST_ENTRY
  
+0x234 RundownProtect   : _EX_RUNDOWN_REF
  
+0x238 ThreadLock       : _EX_PUSH_LOCK
  
+0x23c LpcReplyMessageId : Uint4B
  
+0x240 ReadClusterSize  : Uint4B
  
+0x244 GrantedAccess    : Uint4B
  
+0x248 CrossThreadFlags : Uint4B
  
+0x248 Terminated       : Pos 0, 1 Bit
  
+0x248 DeadThread       : Pos 1, 1 Bit
  
+0x248 HideFromDebugger : Pos 2, 1 Bit
  
+0x248 ActiveImpersonationInfo : Pos 3, 1 Bit
  
+0x248 SystemThread     : Pos 4, 1 Bit
  
+0x248 HardErrorsAreDisabled : Pos 5, 1 Bit
  
+0x248 BreakOnTermination : Pos 6, 1 Bit
  
+0x248 SkipCreationMsg  : Pos 7, 1 Bit
  
+0x248 SkipTerminationMsg : Pos 8, 1 Bit
  
+0x24c SameThreadPassiveFlags : Uint4B
  
+0x24c ActiveExWorker   : Pos 0, 1 Bit
  
+0x24c ExWorkerCanWaitUser : Pos 1, 1 Bit
  
+0x24c MemoryMaker      : Pos 2, 1 Bit
  
+0x250 SameThreadApcFlags : Uint4B
  
+0x250 LpcReceivedMsgIdValid : Pos 0, 1 Bit
  
+0x250 LpcExitThreadCalled : Pos 1, 1 Bit
  
+0x250 AddressSpaceOwner : Pos 2, 1 Bit
  
+0x254 ForwardClusterOnly : UChar
  
+0x255 DisablePageFaultClustering : UChar


理论上都都讲完了,我们来回顾下:

1、不论SnipeSword,IceSword,DarkSpy,又或是GMER(如果我没记错,GMER应该是使用NtTerminateProcess的方法来结束进程的),最终杀进程都要过PspTerminateThreadByPointer
2、PspTerminateThreadByPointer会检查线程的SystemThread标志(ETHREAD结构中CrossThreadFlags的第四位),如果被置为1,就返回拒绝访问(STATUS_ACCESS_DENIED)
3、ETHREAD结构在不同系统中不同,所以我们需要判断操作系统版本(这个我不会在演示代码中出现,交给大家了:P)。

但是我们仍然有一些问题没有解决:

1、进程的ETHREAD结构在内存中的地址是多少?
2、ETHREAD结构存在于系统高2G空间,如何修改?

至于判断系统版本,相信大家都会 :)

1、ETHREAD结构的地址

ntdll.dll导出了一个未文档化的函数——NtQuerySystemInformation,它可以用来查询SystemHandleInformation,查询SystemHandleInformation的返回的数据结构如下(懒得再弄vb的了,直接把C的弄过来,这个可能跟我的代码中的定义有些不同,但是实际上被用到的数据在结构中的偏移是相同的:P):


引用:

typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO {
   
USHORT UniqueProcessId;
   
USHORT CreatorBackTraceIndex;
   
UCHAR ObjectTypeIndex;
   
UCHAR HandleAttributes;
   
USHORT HandleValue;
   
PVOID Object;
   
ULONG GrantedAccess;
}
SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO;

typedef struct _SYSTEM_HANDLE_INFORMATION {
   
ULONG NumberOfHandles;
   
SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[ 1 ];
}
SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;


NumberOfHandles表示返回的数组个数,SYSTEM_HANDLE_TABLE_ENTRY_INFO则是返回的数据。

SYSTEM_HANDLE_TABLE_ENTRY_INFO中的HandleValue是句柄的值,Object便是这个Handle对应的对象(Object,如果Handle类型为线程,那么这个对象就是ETHREAD结构)的地址。

嗯,我想我说的还是比较清楚的。

2、修改物理内存

ntdll.dll还导出了一个函数叫做NtSystemDebugControl,这个函数可以用来操作高2G的内存空间。

剩下的废话不多说了~ 大家看附件把 :)

完整的代码和程序:)

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理