祝各位新年快乐 
一边听音乐一边写代码真的很舒服阿很舒服
 
先简单说以下,NP和HS都hook了以下一些SSDT
什么是SSDT?我不想说那些复杂的理论,希望以简单的事实帮助介绍
先向大S道歉,下文如有冒犯,还请大S原谅 

怎么说呢,SSDT本身就是一个地址表,我们当他是个地址簿,也就是写了每个人的地址的记录表
今天,偶想给大S送新年礼物,怎么送到大S家里呢?就得查看地址簿了
上面是这样写的  大S: 游戏达人,外挂高人,破解牛人,脱壳圣人;分身有如月,堀北真希,花泽类,猪的理想;实际上是个阳光宝宝,吃的的白白胖胖的,每天都很开心;家住上海市X区X路X楼,进门左转、左转、再左转,敲门说找S.H.E就行了。
标准SSDT hook的方式就是改变这个地址,HS就是八地址改写成abnlab实验室,如果你照着走就到abnlab实验室了
他们就要检查你了,这么大一箱礼物?是不是带了炸弹阿,识别你的身份阿,但是这样怎么能行呢,经过他们一审核
我的新年礼物岂不是要过年以后才能到了?不行不行
只能先联系大S,大S说家在上海X别墅区X,偶于是就上门了,到了别墅,门卫不让偶进去阿,理由是偶没有邀请函

                         ; MmDeleteTeb(x,x)+Ep ...
.text:004129B3
.text:004129B3 BugCheckParameter1= dword ptr  8
.text:004129B3 arg_4           = dword ptr  0Ch
.text:004129B3
.text:004129B3 ; FUNCTION CHUNK AT .text:00445DD6 SIZE 00000049 BYTES
.text:004129B3
.text:004129B3                 mov     edi, edi
.text:004129B5                 push    ebp
.text:004129B6                 mov     ebp, esp
.text:004129B8                 push    esi
.text:004129B9                 push    edi
.text:004129BA                 mov     eax, large fs:124h
.text:004129C0                 mov     edi, [ebp+BugCheckParameter1]
.text:004129C3                 mov     esi, eax
.text:004129C5                 cmp     [esi+44h], edi
.text:004129C8                 jz      short loc_4129FF
.text:004129CA                 cmp     byte ptr [esi+165h], 0
.text:004129D1                 jnz     loc_445DD6
.text:004129D7                 mov     eax, large fs:994h
.text:004129DD                 test    eax, eax
.text:004129DF                 jnz     loc_445DD6
.text:004129E5                 call    ds:__imp__KeRaiseIrqlToDpcLevel@0 ; KeRaiseIrqlToDpcLevel()
.text:004129EB                 mov     byte ptr [ebp+BugCheckParameter1], al
.text:004129EE                 lea     eax, [esi+14Ch]
.text:004129F4                 push    eax
.text:004129F5                 push    [ebp+BugCheckParameter1]
.text:004129F8                 push    edi
.text:004129F9                 push    esi
.text:004129FA                 call    _KiAttachProcess@16 ; KiAttachProcess(x,x,x,x)
.text:004129FF
.text:004129FF loc_4129FF:                             ; CODE XREF: KeAttachProcess(x)+15j
.text:004129FF                 pop     edi
.text:00412A00                 pop     esi
.text:00412A01                 pop     ebp
.text:00412A02                 retn    4
.text:00412A02 _KeAttachProcess@4 endp

.text:004189DB ; __stdcall KeStackAttachProcess(x, x)
.text:004189DB                 public _KeStackAttachProcess@8
.text:004189DB _KeStackAttachProcess@8 proc near       ; CODE XREF: MmAttachSession(x,x)+58p
.text:004189DB                                         ; MiAttachToSecureProcessInSession(x)+43p ...
.text:004189DB
.text:004189DB arg_0           = dword ptr  8
.text:004189DB arg_4           = dword ptr  0Ch
.text:004189DB
.text:004189DB                 mov     edi, edi
.text:004189DD                 push    ebp
.text:004189DE                 mov     ebp, esp
.text:004189E0                 push    esi
.text:004189E1                 push    edi
.text:004189E2                 mov     eax, large fs:124h
.text:004189E8                 mov     esi, eax
.text:004189EA                 mov     eax, large fs:994h
.text:004189F0                 test    eax, eax
.text:004189F2                 jnz     loc_445DF1
.text:004189F8                 mov     edi, [ebp+arg_0]
.text:004189FB                 cmp     [esi+44h], edi
.text:004189FE                 jz      short loc_418A34
.text:00418A00                 call    ds:__imp__KeRaiseIrqlToDpcLevel@0 ; KeRaiseIrqlToDpcLevel()
.text:00418A06                 cmp     byte ptr [esi+165h], 0
.text:00418A0D                 mov     byte ptr [ebp+arg_0], al
.text:00418A10                 jnz     loc_445E0D
.text:00418A16                 lea     eax, [esi+14Ch]
.text:00418A1C                 push    eax
.text:00418A1D                 push    [ebp+arg_0]
.text:00418A20                 push    edi
.text:00418A21                 push    esi
.text:00418A22                 call    _KiAttachProcess@16 ; KiAttachProcess(x,x,x,x)
.text:00418A27                 mov     eax, [ebp+arg_4]
.text:00418A2A                 and     dword ptr [eax+10h], 0
.text:00418A2E
.text:00418A2E loc_418A2E:                             ; CODE XREF: KeStackAttachProcess(x,x)+63j
.text:00418A2E                                         ; KeAttachProcess(x)+33467j
.text:00418A2E                 pop     edi
.text:00418A2F                 pop     esi
.text:00418A30                 pop     ebp
.text:00418A31                 retn    8

我们有以下办法
1.直接执行函数+5字节处
这样可以,但是有其他问题,如果NP把函数hook改到函数中间或者末尾,我们很难定位
2.执行底层函数KiAttachProcess
KiAttachProcess(EPROCESS *Process,Irql)

.text:00412855 ; __stdcall KiAttachProcess(x, x, x, x)
.text:00412855 _KiAttachProcess@16 proc near           ; CODE XREF: KeAttachProcess(x)+47p
.text:00412855                                         ; KeStackAttachProcess(x,x)+47p ...
.text:00412855
.text:00412855 arg_0           = dword ptr  8
.text:00412855 arg_4           = dword ptr  0Ch
.text:00412855 arg_8           = byte ptr  10h
.text:00412855 arg_C           = dword ptr  14h
.text:00412855
.text:00412855 ; FUNCTION CHUNK AT .text:00445D4F SIZE 0000001E BYTES
.text:00412855 ; FUNCTION CHUNK AT .text:00445D72 SIZE 00000064 BYTES
.text:00412855
.text:00412855                 mov     edi, edi
.text:00412857                 push    ebp
.text:00412858                 mov     ebp, esp
.text:0041285A                 push    ebx
.text:0041285B                 mov     ebx, [ebp+arg_4]
.text:0041285E                 inc     word ptr [ebx+60h]
.text:00412862                 push    esi
.text:00412863                 mov     esi, [ebp+arg_0]
.text:00412866                 push    edi
.text:00412867                 push    [ebp+arg_C]
.text:0041286A                 lea     edi, [esi+34h]
.text:0041286D                 push    edi
.text:0041286E                 call    _KiMoveApcState@8 ; KiMoveApcState(x,x)
.text:00412873                 mov     [edi+4], edi
.text:00412876                 mov     [edi], edi
.text:00412878                 lea     eax, [esi+3Ch]
.text:0041287B                 mov     [eax+4], eax
.text:0041287E                 mov     [eax], eax
.text:00412880                 lea     eax, [esi+14Ch]
.text:00412886                 cmp     [ebp+arg_C], eax
.text:00412889                 mov     [esi+44h], ebx
.text:0041288C                 mov     byte ptr [esi+48h], 0
.text:00412890                 mov     byte ptr [esi+49h], 0
.text:00412894                 mov     byte ptr [esi+4Ah], 0
.text:00412898                 jnz     short loc_4128AD
.text:0041289A                 mov     [esi+138h], eax
.text:004128A0                 mov     [esi+13Ch], edi
.text:004128A6                 mov     byte ptr [esi+165h], 1
.text:004128AD
.text:004128AD loc_4128AD:                             ; CODE XREF: KiAttachProcess(x,x,x,x)+43j
.text:004128AD                 cmp     byte ptr [ebx+65h], 0
.text:004128B1                 jnz     loc_445D72
.text:004128B7                 lea     esi, [ebx+40h]
.text:004128BA
.text:004128BA loc_4128BA:                             ; CODE XREF: KiAttachProcess(x,x,x,x)+33513j
.text:004128BA                 mov     eax, [esi]
.text:004128BC                 cmp     eax, esi
.text:004128BE                 jnz     loc_445D4F
.text:004128C4                 mov     eax, [ebp+arg_C]
.text:004128C7                 push    dword ptr [eax+10h]
.text:004128CA                 push    ebx
.text:004128CB                 call    _KiSwapProcess@8 ; KiSwapProcess(x,x)
.text:004128D0                 mov     cl, [ebp+arg_8]
.text:004128D3                 call    @KiUnlockDispatcherDatabase@4 ; KiUnlockDispatcherDatabase(x)
.text:004128D8
.text:004128D8 loc_4128D8:                             ; CODE XREF: .text:00445D6Dj
.text:004128D8                                         ; KiAttachProcess(x,x,x,x)+3357Cj
.text:004128D8                 pop     edi
.text:004128D9                 pop     esi
.text:004128DA                 pop     ebx
.text:004128DB                 pop     ebp
.text:004128DC                 retn    10h
.text:004128DC _KiAttachProcess@16 endp
.text:004128DC

或者执行更加底层函数KiSwapProcess
.text:00404AC4 ; __stdcall KiSwapProcess(x, x)
.text:00404AC4 _KiSwapProcess@8 proc near              ; CODE XREF: KiAttachProcess(x,x,x,x)+76p
.text:00404AC4                                         ; KeDetachProcess()+73p ...
.text:00404AC4
.text:00404AC4 arg_0           = dword ptr  4
.text:00404AC4
.text:00404AC4                 mov     edx, [esp+arg_0]
.text:00404AC8                 xor     eax, eax
.text:00404ACA                 cmp     [edx+20h], ax
.text:00404ACE                 jz      short loc_404AFF
.text:00404AD0                 mov     ecx, ds:0FFDFF03Ch
.text:00404AD6                 mov     eax, [edx+20h]
.text:00404AD9                 mov     [ecx+48h], eax
.text:00404ADC                 mov     eax, [edx+24h]
.text:00404ADF                 mov     [ecx+4Ch], eax
.text:00404AE2                 mov     ecx, ds:0FFDFF038h
.text:00404AE8                 mov     eax, [edx+28h]
.text:00404AEB                 mov     [ecx+108h], eax
.text:00404AF1                 mov     eax, [edx+2Ch]
.text:00404AF4                 mov     [ecx+10Ch], eax
.text:00404AFA                 mov     eax, 48h
.text:00404AFF
.text:00404AFF loc_404AFF:                             ; CODE XREF: KiSwapProcess(x,x)+Aj
.text:00404AFF                 lldt    ax
.text:00404B02                 mov     ecx, ds:0FFDFF040h
.text:00404B08                 mov     edx, [esp+arg_0]
.text:00404B0C                 xor     eax, eax
.text:00404B0E                 mov     gs, ax
.text:00404B10                 mov     eax, [edx+18h]
.text:00404B13                 mov     [ecx+1Ch], eax
.text:00404B16                 mov     cr3, eax
.text:00404B19                 mov     ax, [edx+30h]
.text:00404B1D                 mov     [ecx+66h], ax
.text:00404B21                 retn    8
.text:00404B21 _KiSwapProcess@8 endp
.text:00404B21

我们仔细看代码,就是更改cr3
我们自己用代码完成-以下代码参考sinister

引用:
当调用此函数时先把要切换的进程的内核堆栈数加一(EPROCESS->Stack
Count),并从形参中取得当前线程保存 APC 状态的位置,(ETHREAD->SaveApcState)
得到当前线程 APC 状态(ETHREAD->ApcState),来调用 KiMoveApcState()  函数,将当
前线程APC 状态 (ETHREAD->ApcState) 复制到当前线程 SavedApcState 处保存。然后
将当前线程内核 APC 的 Progress 状态、内核模式 APC 的 Pending 状态、用户模式 
APC 的 Pending 态均设置为 FALSE(ETHREAD->KernelApcInProgress、ETHREAD->Kernel
ApcPending、ETHREAD->UserApcPending),并初始化当前线程内核模式与用户模式 APC 
状态链(ETHREAD->>ApcState.ApcListHead[KernelMode]、ETHREAD->ApcState.ApcList
Head[UserMode]),然后将当前线程所在进程(ETHREAD->ApcState->EPROCESS)设置为
要切换的进程(EPROCESS),比较当前线程保存 APC 状态(ETHREAD->SavedApcState)
是否与形参中(SavedApcState)要输出的保存 APC 态相等,如相等则需要将当前线程
APC 状态与保存 APC 状态(ETHREAD->ApcState、ETHREAD->SavedApcState)分别赋与
当前线程的 ApcStatePointer[0] 与 ApcStatePointer[1],(ApcStatePointer 是 
KAPC_STATE 结构数组而 KAPC_STATE 又是由 LIST_ENTRY 链表描述的)然后在设置当前
线程 APC 状态索引为 1(ETHREAD->ApcStateIndex)。
代码:
KiAttachProcess(EPROCESS *Process,Irql){

//CurThread=fs:124h
//CurProcess=CurThread->ApcState.Process;

if(CurProcess!=Process){
     if(CurProcess->ApcStateIndex || KPCR->DpcRoutineActive)KeBugCheckEx...
     }

//if we already in process's context
if(CurProcess==Process){KiUnlockDispatcherDatabase(Irql);return;}

Process->StackCount++;
KiMoveApcState(&CurThread->ApcState,&CurThread->SavedApcState);

// init lists
CurThread->ApcState.ApcListHead[0].Blink=&CurThread->ApcState.ApcListHead[0];
CurThread->ApcState.ApcListHead[0].Flink=&CurThread->ApcState.ApcListHead[0];
CurThread->ApcState.ApcListHead[1].Blink=&CurThread->ApcState.ApcListHead[1];
CurThread->ApcState.ApcListHead[1].Flink=&CurThread->ApcState.ApcListHead[1];;

//fill curtheads's fields
CurThread->ApcState.Process=Process;

CurThread->ApcState.KernelApcInProgress=0;
CurThread->ApcState.KernelApcPending=0;
CurThread->ApcState.UserApcPending=0;

CurThread->ApcState.ApcStatePointer.SavedApcState=&CurThread->SavedApcState;
CurThread->ApcState.ApcStatePointer.ApcState=&CurThread->ApcState;

CurThread->ApcStateIndex=1;

//if process ready, just swap it...
if(!Process->State)//state==0, ready
     {
     KiSwapProcess(Process,CurThread->SavedApcState.Process);
     KiUnlockDispatcherDatabase(Irql);
     return;
     }

CurThread->State=1; //ready?
CurThread->ProcessReadyQueue=1;

//put Process in Thread's waitlist
CurThread->WaitListEntry.Flink=&Process->ReadyListHead.Flink;
CurThread->WaitListEntry.Blink=Process->ReadyListHead.Blink;

Process->ReadyListHead.Flink->Flink=&CurThread->WaitListEntry.Flink;
Process->ReadyListHead.Blink=&CurThread->WaitListEntry.Flink;

// else, move process to swap list and wait
if(Process->State==1){//idle?
     Process->State=2; //trans
     Process->SwapListEntry.Flink=&KiProcessInSwapListHead.Flink;
     Process->SwapListEntry.Blink=KiProcessInSwapListHead.Blink;
        KiProcessInSwapListHead.Blink=&Process->SwapListEntry.Flink;
     KiSwapEvent.Header.SignalState=1;
     if(KiSwapEvent.Header.WaitListHead.Flink!=&KiSwapEvent.Header.WaitListHead.
Flink)
                    KiWaitTest(&KiSwapEvent,0xa); //fastcall
     }

CurThread->WaitIrql=Irql;
KiSwapThread();
return;
}
引用:
从这个函数可以得到以下结论。进程可以处于以下状态0(准备),1(Idle),2(Tra
ns切换)。这证实了高层次的信息。KiAttachProcess使用了另外两个函数KiSwapProce
ss和KiSwapThread。

/************************* KiSwapProcess ****************************/

KiSwapProcess(EPROCESS* NewProcess, EPROCESS* OldProcess)
{
// just reload cr3 and small work with TSS

     // TSS=KPCR->TSS;
     // xor eax,eax
     // mov gs,ax
TSS->CR3=NewProcess->DirectoryTableBase;//0x1c
     // mov cr3,NewProcess->DirectoryTableBase
TSS->IopmOffset=NewProcess->IopmOffset;//0x66
if(WORD(NewProcess->LdtDescriptor)==0){lldt 0x00; return;//}
     //GDT=KPCR->GDT;
(QWORD)GDT->0x48=(QWORD)NewProcess->LdtDescriptor;
(QWORD)GDT->0x108=(QWORD)NewProcess->Int21Descriptor;
lldt 0x48;
return;
}

切换进程上下文。正如我所料,这个函数只是重新加载CR3寄存器,再加上一点相关的操作。
例如,用IopmOffset域的值建立TSS中的I/O位图的偏移。还必需将选择子的值加载到ldt(只
用于VDM session)。

/************************* SwapContext ******************************/

SwapContext(NextThread,CurThread,WaitIrql)
{

NextThread.State=ThreadStateRunning; //2
KPCR.DebugActive=NextThread.DebugActive;

cli();

//Save Stack
CurThread.KernelStack=esp;

//Set stack
KPCR.StackLimit=NextThread.StackLimit;
KPCR.StackBase=NextThread.InitialStack;

tmp=NextThread.InitialStack-0x70;
newcr0=cr0&0xfffffff1|NextThread.NpxState|*(tmp+0x6c);
if(newcr0!=cr0)reloadcr0();
if(!*(tmp-0x1c)&0x20000)tmp-=0x10;
TSS=KPCB.TSS;
TSS->ESP0=tmp;

//set pTeb
KPCB.Self=NextThread.pTeb;
esp=NextThread.KernelStack;
sti();

//correct GDT
GDT=KPCB.GDT;
WORD(GDT->0x3a)=NextThread.pTeb;
BYTE(GDT->0x3c)=NextThread.pTeb>>16;
BYTE(GDT->0x3f)=NextThread.pTeb>>24;

//if we must swap processes, do it (like KiSwapProcess)

if(CurThread.ApcState.Process!=NextThread.ApcState.Process)
     {
     //******** like KiSwapProcess
     }

NextThread->ContextSwitches++;

KPCB->KeContextSwitches++;

if(!NextThread->ApcState.KernelApcPending)return 0;

//popf;
// jnz HalRequestSoftwareInterrupt// return 0

return 1;
}

切换堆栈,修正GDT,以使FS寄存器指向TEB。如果线程属于当前进程,则不进行上下文切换
。否则,进行的操作和KiSwapProcess中的大致差不多。
介绍比较多,如果不想看的话可以直接复制代码:lol 
下面的代码完成2个函数模拟,感谢KiSSinGGer大哥写的代码
NTSTATUS
WriteProcessMem( 
  IN HANDLE  hProcess,
  IN PVOID  DstAddr, 
  IN PVOID  SrcAddr,  
  IN ULONG  Size
)
{
  NTSTATUS  Status = STATUS_UNSUCCESSFUL;
  PEPROCESS  Process = NULL;
  KAPC_STATE   ApcState;
  PMDL    pMdl = NULL;
  PCHAR    MemBlock = NULL;
  PCHAR    MappedDstAddr = NULL;
  
  if( SrcAddr == NULL || DstAddr == NULL || Size == 0 )
    return Status;
    
  Status = ObReferenceObjectByHandle(
        hProcess, 
        PROCESS_VM_WRITE|PROCESS_VM_READ, 
        NULL, 
        KernelMode, 
        &Process, 
        NULL
        );
  if( !NT_SUCCESS(Status) )
  {
    DbgMsg( "ObReferenceObjectByHandle Failed.\n" );
    return Status;
  }
  
  //
  // Get Current Process' Memory Block
  //
  
  MemBlock = ExAllocatePoolWithTag( NonPagedPool, Size, '-_-!');
  if( MemBlock == NULL )
  {
    Status = STATUS_UNSUCCESSFUL;
    goto __EXIT2;
  }
  
  __try
  {
    if( MmIsAddressValid(SrcAddr) )
    {
      ProbeForRead( SrcAddr, Size, sizeof(CHAR) );
      RtlCopyMemory( MemBlock, SrcAddr, Size );
    }
    else
    {
      DbgMsg( "SrcAddr not valid.\n" );
      Status = STATUS_UNSUCCESSFUL;
      goto __EXIT2;
    }
  }
  __except(EXCEPTION_EXECUTE_HANDLER)
  {
    
    DbgMsg( "Read SrcAddr raise an exception.\n" );
    Status = STATUS_UNSUCCESSFUL;
    goto __EXIT2;
  }
  
  //
  // Attach to Dst Process
  //
  
  KeStackAttachProcess( &(Process->Pcb), &ApcState);
  
  __try
  {
    pMdl = IoAllocateMdl( DstAddr, Size, FALSE, FALSE, NULL );
    if( pMdl )
    {
      MmProbeAndLockPages (pMdl, KernelMode, IoWriteAccess);
      MappedDstAddr = MmMapLockedPagesSpecifyCache (pMdl,KernelMode,MmCached,NULL,FALSE,NormalPagePriority);
      if( MappedDstAddr )
      {
        RtlCopyMemory( MappedDstAddr, MemBlock, Size );
        Status = STATUS_SUCCESS;
        goto __EXIT1;      
      }
      else
        Status = STATUS_UNSUCCESSFUL;
    }
    else
      Status = STATUS_UNSUCCESSFUL;
  }
  __except(EXCEPTION_EXECUTE_HANDLER)
  {
    DbgMsg( "Process DstAddr raise an exception.\n" );
    Status = STATUS_UNSUCCESSFUL;
    goto __EXIT1;
  }
  
  __EXIT1:
  
  //
  // Detach to Dst Process
  //
  
  KeUnstackDetachProcess( &ApcState );
  if( MappedDstAddr )
  {
    MmUnmapLockedPages( MappedDstAddr, pMdl);
  }
  if( pMdl )
  {
    MmUnlockPages( pMdl );
    IoFreeMdl( pMdl );
  }
  
  __EXIT2:
  if( Process )
  {
    ObDereferenceObject( Process );
  }
  if( MemBlock )
  {
    ExFreePool( MemBlock );
  }
  
  return Status; 
}


NTSTATUS
ReadProcessMem( 
  IN HANDLE  hProcess, 
  IN PVOID  BaseAddr,
  IN PVOID  Buffer,
  IN ULONG  Size
)
{
  NTSTATUS  Status = STATUS_UNSUCCESSFUL;
  PEPROCESS  Process = NULL;
  KAPC_STATE  ApcState;
  PCHAR    MemBlock = NULL;  
  
  
  if( BaseAddr == NULL || Buffer == NULL || Size == 0 )
    return Status;
    
  Status = ObReferenceObjectByHandle(
        hProcess, 
        PROCESS_VM_WRITE|PROCESS_VM_READ, 
        NULL, 
        KernelMode, 
        &Process, 
        NULL
        );
  if( !NT_SUCCESS(Status) )
  {
    DbgMsg( "ObReferenceObjectByHandle Failed.\n" );
    return Status;
  }
  
  MemBlock = ExAllocatePoolWithTag( NonPagedPool, Size, '-_-!');
  if( MemBlock == NULL )
  {
    ObDereferenceObject( Process );
    return STATUS_UNSUCCESSFUL;
  }
  
  KeStackAttachProcess( &(Process->Pcb), &ApcState);
  
  __try
  {
    if( MmIsAddressValid(BaseAddr) )
    {
      ProbeForRead( BaseAddr, Size, sizeof(CHAR) );
      RtlCopyMemory( MemBlock, BaseAddr, Size );
    }
    else
    {
      DbgMsg( "BaseAddr not valid.\n" );
      Status = STATUS_UNSUCCESSFUL;
      goto __EXIT2;
    }
  }
  __except(EXCEPTION_EXECUTE_HANDLER)
  {
    DbgMsg( "Process BaseAddr raise an exception.\n" );
    Status = STATUS_UNSUCCESSFUL;
    goto __EXIT2;
  }

  KeUnstackDetachProcess( &ApcState );
  
  __try
  {
    if( MmIsAddressValid(Buffer) )
    {
      ProbeForWrite( Buffer, Size, sizeof(CHAR));
      RtlCopyMemory( Buffer, MemBlock, Size );
    }
    else
    {
      DbgMsg( "Buffer not valid.\n" );
      Status = STATUS_UNSUCCESSFUL;
      goto __EXIT2;
    }
  }
  __except(EXCEPTION_EXECUTE_HANDLER)
  {
    DbgMsg( "Process Buffer raise an exception.\n" );
    Status = STATUS_UNSUCCESSFUL;
    goto __EXIT2;
  }
  
  
  
  __EXIT2:
  
  KeUnstackDetachProcess( &ApcState );
  
  if( Process )
  {
    ObDereferenceObject( Process );
  }
  if( MemBlock )
  {
    ExFreePool( MemBlock );
  }
  return Status; 
}

下面的代码完成最后一个事情
HANDLE ZwOpenProcess(HANDLE ProcessId)
{
  PEPROCESS Process;
  NTSTATUS St;
  HANDLE hProcess = NULL;

  PsLookupProcessByProcessId(ProcessId, &Process);

  ObOpenObjectByPointer(Process, 0, NULL, 0, NULL, UserMode, &hProcess);

  ObDereferenceObject(Process);

  return hProcess;
}
很好,一些hook函数我们完成了模拟这些内核hook已经对我们不在有意义了

R3部分,这个只有NP才有,我们需要拦截线程创建函数禁止np注入邪恶模块给我们的od
Win32在创建用户态线程的时候,大致流程如下
  CreateThread (kernel32.dll)
  CreateRemoteThread (kernel32.dll)
  NtCreateThread (ntoskrnl.exe)
  PspCreateThread (ntos\ps\create.c:237)
PspCreateThread函数在创建用户态线程时,使用PspUserThreadStartup函数(ntos\ps\
create.c:1639)作为入口函数参数,线程被创建后直接进入此函数。PspUserThreadStartu
p函数对非僵死线程和没有结束的线程初始化其APC;

对于载入和卸载DLL,实际的调用流程如下:
  LoadLibrary (kernel32.dll)
  LoadLibraryEx (kernel32.dll)
  BasepLoadLibraryAsDataFile (kernel32.dll)
  NtMapViewOfSection (ntos\mm\mapview.c:204)

注:Kernel APC与User APC的区别:
         1)前者是在APC_LEVEL上运行,后者是在PASSIVE_LEVEL上运行
          2)只有KTHREAD中的AlertAble或KTHREAD-ApcState-UserApcPending
             为1的情况下,User APC中的Routine才会被执行,Kernel APC没有这个限制
我之所以不使用广为人知的PsSetCreateProcessNotifyRoutine,PsSetCreateThreadNotifyRoutine
PsSetLoadImageNotifyRoutine。 原因很简单,他们都是插入APC,本质上,其实线程,进程,模块
已经建立或者载入,不过没有开始运行--原因是resume的时候会先执行APC
我们需要从本质上禁止插入邪恶模块,而不是插入1个没有开始运行的模块
当然我也尝试过在apc中无效化模块(故意填充0),但是发现不起作用,邪恶模块还是运行了

还有一个问题是我们不得不关注的运行程序的时候父进程会“帮助”子进程创建子进程的主要线程(因为这个时候子进程还没有线程,所以不可能自己创建),所以这就引出了另外一个问题如何判断这个远程线程创建是注入还是正常的程序运行呢?
简单分析下我们不难发现,二者的区别在于将被创建线程的进程是否还存在其他线程因为我们的代码是在NtCreateThread之前执行的,所以如果是正常运行的程序的话,这个时候它不应当有任何的线程,而线程注入则不同,线程注入的话目标进程应当已经有了至少一个线程(一个主线程和若干个附属线程(或者没有附属线程)
我们需要检查EPROCESS结构的+0x190 ThreadListHead : _LIST_ENTRY
EPROCESS 结构是一个很大的结构,而且不同版本系统结构还不一样
typedef struct _EPROCESS {
/*000*/ BYTE                   Pcb[0x6C];
/*06C*/ NTSTATUS               ExitStatus;
/*070*/ KEVENT                 LockEvent;
/*080*/ DWORD                  LockCount;
/*084*/ DWORD                  dw084;
/*088*/ LARGE_INTEGER          CreateTime;
/*090*/ LARGE_INTEGER          ExitTime;
/*098*/ PVOID                  LockOwner;
/*09C*/ DWORD                  UniqueProcessId;
/*0A0*/ LIST_ENTRY             ActiveProcessLinks; // see PsActiveListHead
/*0A8*/ DWORD                  QuotaPeakPoolUsage[2]; // NP, P
/*0B0*/ DWORD                  QuotaPoolUsage[2]; // NP, P
/*0B8*/ DWORD                  PagefileUsage;
/*0BC*/ DWORD                  CommitCharge;
/*0C0*/ DWORD                  PeakPagefileUsage;
/*0C4*/ DWORD                  PeakVirtualSize;
/*0C8*/ LARGE_INTEGER          VirtualSize;
/*0D0*/ MMSUPPORT              Vm;
/*100*/ LIST_ENTRY             SessionProcessLinks;
/*108*/ DWORD                  dw108[6];
/*120*/ PVOID                  DebugPort;
/*124*/ PVOID                  ExceptionPort;
/*128*/ PVOID                  ObjectTable;
/*12C*/ PVOID                  Token;
/*130*/ FAST_MUTEX             WorkingSetLock;
/*150*/ DWORD                  WorkingSetPage;
/*154*/ BOOLEAN                ProcessOutswapEnabled;
/*155*/ BOOLEAN                ProcessOutswapped;
/*156*/ BOOLEAN                AddressSpaceInitialized;
/*157*/ BOOLEAN                AddressSpaceDeleted;
/*158*/ FAST_MUTEX             AddressCreationLock;
/*178*/ KSPIN_LOCK             HyperSpaceLock;
/*17C*/ DWORD                  ForkInProgress;
/*180*/ WORD                   VmOperation;
/*182*/ BOOLEAN                ForkWasSuccessful;
/*183*/ BYTE                   MmAgressiveWsTrimMask;
/*184*/ DWORD                  VmOperationEvent;
/*188*/ PVOID                  PaeTop;
/*18C*/ DWORD                  LastFaultCount;
/*190*/ DWORD                  ModifiedPageCount;
/*194*/ PVOID                  VadRoot;
/*198*/ PVOID                  VadHint;
/*19C*/ PVOID                  CloneRoot;
/*1A0*/ DWORD                  NumberOfPrivatePages;
/*1A4*/ DWORD                  NumberOfLockedPages;
/*1A8*/ WORD                   NextPageColor;
/*1AA*/ BOOLEAN                ExitProcessCalled;
/*1AB*/ BOOLEAN                CreateProcessReported;
/*1AC*/ HANDLE                 SectionHandle;
/*1B0*/ PVOID                  Peb;
/*1B4*/ PVOID                  SectionBaseAddress;
/*1B8*/ PVOID                  QuotaBlock;
/*1BC*/ NTSTATUS               LastThreadExitStatus;
/*1C0*/ DWORD                  WorkingSetWatch;
/*1C4*/ HANDLE                 Win32WindowStation;
/*1C8*/ DWORD                  InheritedFromUniqueProcessId;
/*1CC*/ ACCESS_MASK            GrantedAccess;
/*1D0*/ DWORD                  DefaultHardErrorProcessing; // HEM_*
/*1D4*/ DWORD                  LdtInformation;
/*1D8*/ PVOID                  VadFreeHint;
/*1DC*/ DWORD                  VdmObjects;
/*1E0*/ PVOID                  DeviceMap;
/*1E4*/ DWORD                  SessionId;
/*1E8*/ LIST_ENTRY             PhysicalVadList;
/*1F0*/ PVOID                  PageDirectoryPte;
/*1F4*/ DWORD                  dw1F4;
/*1F8*/ DWORD                  PaePageDirectoryPage;
/*1FC*/ CHAR                   ImageFileName[16];
/*20C*/ DWORD                  VmTrimFaultValue;
/*210*/ BYTE                   SetTimerResolution;
/*211*/ BYTE                   PriorityClass;
/*212*/ WORD                   SubSystemVersion;
/*214*/ PVOID                  Win32Process;
/*218*/ PVOID                  Job;
/*21C*/ DWORD                  JobStatus;
/*220*/ LIST_ENTRY             JobLinks;
/*228*/ PVOID                  LockedPagesList;
/*22C*/ PVOID                  SecurityPort;
/*230*/ PVOID                  Wow64;
/*234*/ DWORD                  dw234;
/*238*/ IO_COUNTERS            IoCounters;
/*268*/ DWORD                  CommitChargeLimit;
/*26C*/ DWORD                  CommitChargePeak;
/*270*/ LIST_ENTRY             ThreadListHead;
/*278*/ PVOID                  VadPhysicalPagesBitMap;
/*27C*/ DWORD                  VadPhysicalPages;
/*280*/ DWORD                  AweLock;
/*284*/ } EPROCESS, *PEPROCESS;
代码如下
//==========================================
BOOLEAN
ProcessNoThread( PEPROCESS Process)
{
PLIST_ENTRY Entry;
PLIST_ENTRY ThreadListEntry;
PLIST_ENTRY ListHead;

ThreadListEntry = (PLIST_ENTRY)((ULONG)Process + ThreadListHead);
Entry = ThreadListEntry->Flink;
return (Entry==ThreadListEntry);

也就是判断ProcessNoThread了,如果建立进程就通过,反之则拦截

一些结构很复杂很难,偶也不想多写,其实偶也没很明白,更加不敢写,
详细的查阅其他资料把,