Hook Specials 9 : Talk out inline hook of kernel on three fronts
Step 1: principle of Inline hook
This is common statement of inline hooke about modify flow of function is executed,And conquer the field that control function and filter to operate.We can replace anyplace of original commands to our jump commands in theory,Some peoples really do it to hide for check inline hook ,Do it before flow of function and command is very famillar, even this inline hook don't have generality and stability. The article talk to realized two general inline
principle of Inline hook: Analyse a few command of function's start and They is copied to saved, After our command is called to original command be replaced. If execute original function, must after our function is finished and executed a few command of be saved front on address of return our command later.
The whole process of the inline hook in this,Check function and Get address fucntion is amonged to only call function.
The article talk two inline hook at these point.
Explain three-point:
1、Balance stack is top,Parameter popdown yet.
2、Whether WP bit control processor of CR0 allow to memory's page of only read is writed. When value is zero ,Protection mechanism is forbidden.
3、Lifting interrupt level to DISPATCH_LEVEL, Prohibit interrupt of thread change-over generated.
(Two) Use inline hook
Inline hook divide into two types:
(1)inline export function, ObReferenceObjectByHandle is selected for example。
(2)inline not export function,KiInsertQueueApc is selected for example.
First a few bytes of export function can be viewed with windbg.However Not-export function need confirm to a few bytes oneself,during many questions is noticed.When we understand the article ,You feel very simple about inline hook.
Next through two examples to explain that how use inline hook.
1、inline hook ObReferenceObjectByHandle,Proctect process
ObReferenceObjectByHandle is included export function of ntoskrnl.exe and frequently be used on kernel.
NtCreateProcess need call ObReferenceObjectByHandle for create process, NtTerminateProcess need call ObReferenceObjectByHandle,Because of it that we protect and disabled create process with hook.
Effect : Already ran Notepad can't finish to use task management
Flow:
HookObReferenceObjectByHandle------DetourMyObReferenceObjectByHa ndle----------UnHookObReferenceObjectByHandle
Core code:
//=======================================inline HOOK ObReferenceObjectByHandle===========================
//ObReferenceObjectByHandle is export function of ntoskrnl.exe,First five bytes is hooked.
//Bytes type data unsigned char
ULONG CR0VALUE;
BYTE OriginalBytes[5]={0}; //Save first five bytes of original function
BYTE JmpAddress[5]={0xE9,0,0,0,0}; //Jump's address of hook
extern POBJECT_TYPE *PsProcessType;
NTKERNELAPI NTSTATUS ObReferenceObjectByHandle(
IN HANDLE Handle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_TYPE ObjectType OPTIONAL,
IN KPROCESSOR_MODE AccessMode,
OUT PVOID *Object,
OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL
);
//HOOK function
NTSTATUS DetourMyObReferenceObjectByHandle(
IN HANDLE Handle,
IN ACCESS_MASK DesiredAccess
IN POBJECT_TYPE ObjectType OPTIONAL,
IN KPROCESSOR_MODE AccessMode,
OUT PVOID *Object,
OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL);
//
//hook flow HookObReferenceObjectByHandle---DetourMyObReferenceObjectByHandle---UnHookObReferenceObjectByHandle
void HookObReferenceObjectByHandle()
{
//Evaluation front defined array
KIRQL Irql;
KdPrint(("[ObReferenceObjectByHandle] :0x%x",ObReferenceObjectByHandle)); //address confirm
//Save first five bypes of function
RtlCopyMemory(OriginalBytes,(BYTE *)ObReferenceObjectByHandle,5);
//Save first five bytes's offset of new function
*(ULONG *)(JmpAddress+1)=(ULONG)DetourMyObReferenceObjectByHandle-((ULONG)ObReferenceObjectByHandle+5);
//Start inline hook
//Close to write-protect of memory
_asm
{
push eax
mov eax, cr0
mov CR0VALUE, eax
and eax, 0fffeffffh
mov cr0, eax
pop eax
}
//Lifting interrupt level of IRQL
Irql=KeRaiseIrqlToDpcLevel();
//Write Jmp to five bytes of function
RtlCopyMemory((BYTE *)ObReferenceObjectByHandle,JmpAddress,5);
//Recover Irql
KeLowerIrql(Irql);
//Open write-protect of memory
__asm
{
push eax
mov eax, CR0VALUE
mov cr0, eax
pop eax
}
}
_declspec (naked) NTSTATUS OriginalObReferenceObjectByHandle(IN HANDLE Handle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_TYPE ObjectType OPTIONAL,
IN KPROCESSOR_MODE AccessMode,
OUT PVOID *Object,
OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
{
_asm
{
mov edi,edi
push ebp
mov ebp,esp
mov eax,ObReferenceObjectByHandle
add eax,5
jmp eax
}
}
NTSTATUS DetourMyObReferenceObjectByHandle(
IN HANDLE Handle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_TYPE ObjectType OPTIONAL,
IN KPROCESSOR_MODE AccessMode,
OUT PVOID *Object,
OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
{
NTSTATUS status;
//Call original
status=OriginalObReferenceObjectByHandle(Handle,DesiredAccess,ObjectType,AccessMode,Object,HandleInformation);
if((status==STATUS_SUCCESS)&&(DesiredAccess==1))
{
if(ObjectType== *PsProcessType)
{
if( _stricmp((char *)((ULONG)(*Object)+0x174),"notepad.exe")==0)
{
ObDereferenceObject(*Object);
return STATUS_INVALID_HANDLE;
}
}
}
return status;
}
void UnHookObReferenceObjectByHandle()
{
//Write back five bytes to original again
KIRQL Irql;
//Close write-protect
_asm
{
push eax
mov eax, cr0
mov CR0VALUE, eax
and eax, 0fffeffffh
mov cr0, eax
pop eax
}
//Lifting IRQL to Dpc
Irql=KeRaiseIrqlToDpcLevel();
RtlCopyMemory((BYTE *)ObReferenceObjectByHandle,OriginalBytes,5);
KeLowerIrql(Irql);
//Open write-protect
__asm
{
push eax
mov eax, CR0VALUE
mov cr0, eax
pop eax
}
}
After driver is loaded, program of finished notepad as follow:
(image one)
In more detail:
1、ObReferenceObjectByHandle analyse
NTSTATUS
ObReferenceObjectByHandle(
IN HANDLE Handle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_TYPE ObjectType OPTIONAL,
IN KPROCESSOR_MODE AccessMode,
OUT PVOID *Object,
OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL
);
Function prototype as above,Get pointer of object by handle,return:
STATUS_SUCCESS succed call
STATUS_OBJECT_TYPE_MISMATCH
STATUS_ACCESS_DENIED limite not enough
STATUS_INVALID_HANDLE invalid handle
Call NtTerminateProcess need call ObReferenceObjectByHandle,So we protect process through return value of function is modified.But NtCreateProcess call same this functiong . If don't distinguish,Create process prohibit yet.How distinguish who call it, we can reference WRK, I found to through the second paramter - DesiredAccess can be judged, Create and finish process is different about the second paramter ,PROCESS_CREATE_PROCESS和PROCESS_TERMINATE,Question away.
PspCreateProcess on WRK-v1.2\base\ntos\ps\create.c
Call ObReferenceObjectByHandle code:
Status = ObReferenceObjectByHandle (ParentProcess,
PROCESS_CREATE_PROCESS,
PsProcessType,
PreviousMode,
&Parent,
NULL);
NtTerminateProcess on WRK-v1.2\base\ntos\ps\psdelete.c
Call ObReferenceObjectByHandle code:
st = ObReferenceObjectByHandle (ProcessHandle,
PROCESS_TERMINATE,
PsProcessType,
KeGetPreviousModeByThread(&Self->Tcb),
&Process,
NULL);
DesiredAccess description:
#define PROCESS_TERMINATE (0x0001) // winnt
#define PROCESS_CREATE_THREAD (0x0002) // winnt
#define PROCESS_SET_SESSIONID (0x0004) // winnt
#define PROCESS_VM_OPERATION (0x0008) // winnt
#define PROCESS_VM_READ (0x0010) // winnt
#define PROCESS_VM_WRITE (0x0020) // winnt
// begin_ntddk begin_wdm begin_ntifs
#define PROCESS_DUP_HANDLE (0x0040) // winnt
// end_ntddk end_wdm end_ntifs
#define PROCESS_CREATE_PROCESS (0x0080) // winnt
#define PROCESS_SET_QUOTA (0x0100) // winnt
#define PROCESS_SET_INFORMATION (0x0200) // winnt
#define PROCESS_QUERY_INFORMATION (0x0400) // winnt
#define PROCESS_SET_PORT (0x0800)
#define PROCESS_SUSPEND_RESUME (0x0800) // winnt
2、Call Function's description
We call a function only to write function's name on C language,But infact do it:
Push paramter of fuction to stack and return address of function, call function , open up space of stack and register local variable for new function,
Recover stack keep stack balance
(_stdcall)assembly code:
Push paramter 4
Push paramter 3
Push paramter 2
Push paramter 1
Call function, call command finish two operate in the same time,one is return push stack,two jump to entry address of be called function
Push ebp
Mov ebp,esp
Sub esp, XX ;Open stack fram space
……
Add esp ,XX
Pop ebp
Retn ;recove stack balance
stack details :
ESP
Local variable
EBP
return address
paramter 1
paramter 2
paramter 3
paramter 4
The stack is mad from high to low address.
Paramter pass to EBP,aligned use four bytes
paramter 4----------------------EBP+0x14
paramter 3----------------------EBP+0x10
paramter 2----------------------EBP+0xc
paramter 1--------------------- EBP+0x8
Get local variable through Ebp-XX
So inline hook notice stack balance , brokn stack will breakdown function.
My thinking usual has three steps about inline hook:
HOOK function ----- DetourMy handle function ---------- UnHook function
Modify result of function return or handle among data, then call original function. When we handle original function that already hook, So i construction a original function, Paramter alreday press-in stack before hook in the side, Announce function type is _declspec (naked).。
It is hard to understand about function call stack frame, I is hard to explain everything , Welcome authority talk with me.
2、inline hook KiInsertQueueApc cope kill process for APC
KiInsertQueueAPc is non-export on kernel,Under code may is used to universally template of non-export function inline, Everybody can modify it by need, Principle already is analysed because of inline ObReferenceObject, This part don't analyse by me, Use this yet - Hook function ---DetourMy function --- UnHook function
Croe code:
//===================inline hook KiInsertQueueApc====================
//KiInsertQueueApc is non-export on kernel, Position it from KeInsertQueueApc
//Modify front five bytes of KiInsertQueueApc
//Thinking of handle function: apc-->kthread---apc_state--eprocess--process's name
//HookKiInsertQueueApc---DetourMyKiInsertQueueApc---UnHookKiInsertQueueApc
ULONG CR0VALUE;
ULONG g_KiInsertQueueApc;
BYTE JmpAddress[5]={0xE9,0,0,0,0}; //Jump HOOK function's address
BYTE OriginalBytes[5]={0}; //Save front five bytes of original function
VOID FASTCALL DetourMyKiInsertQueueApc(IN PKAPC Apc,IN KPRIORITY Increment);
VOID WPOFF()
{
_asm
{
push eax
mov eax, cr0
mov CR0VALUE, eax
and eax, 0fffeffffh
mov cr0, eax
pop eax
cli
};
}
VOID WPON()
{
__asm
{
sti
push eax
mov eax, CR0VALUE
mov cr0, eax
pop eax
};
}
//1、Get KiInsertQueueApc address
ULONG GetFunctionAddr( IN PCWSTR FunctionName) //PCWSTR const pointer , point 16 bit UNICODE
{
UNICODE_STRING UniCodeFunctionName;
RtlInitUnicodeString( &UniCodeFunctionName, FunctionName );
return (ULONG)MmGetSystemRoutineAddress( &UniCodeFunctionName );
}
ULONG GetKiInsertQueueApcAddr()
{
ULONG sp_code1=0x28,sp_code2=0xe8,sp_code3=0xd88a; //Signature, sp_code3 windbg show error, That is d88a
ULONG address=0;
PUCHAR addr;
PUCHAR p;
addr=(PUCHAR)GetFunctionAddr(L"KeInsertQueueApc");
for(p=addr;p<p+PAGE_SIZE;p++)
{
if((*(p-1)==sp_code1)&&(*p==sp_code2)&&(*(PUSHORT)(p+5)==sp_code3))
{
address=*(PULONG)(p+1)+(ULONG)(p+5);
break;
}
}
KdPrint(("[KeInsertQueueApc] addr %x\n",(ULONG)addr));
KdPrint(("[KiInsertQueueApc] address %x\n",address));
return address;
}
VOID HookKiInsertQueueApc()
{
KIRQL Irql;
g_KiInsertQueueApc=GetKiInsertQueueApcAddr();
KdPrint(("[KiInsertQueueApc] KiInsertQueueApc %x\n",g_KiInsertQueueApc));
// Save front bytes of original function保存原函数的前字节内容
RtlCopyMemory (OriginalBytes, (BYTE*)g_KiInsertQueueApc, 5);
//Offset address of new function to original function
*( (ULONG*)(JmpAddress + 1) ) = (ULONG)DetourMyKiInsertQueueApc - (ULONG)g_KiInsertQueueApc - 5;
// Prohibit write-protect of systerm, Lifting IRQL to DPC
WPOFF();
Irql = KeRaiseIrqlToDpcLevel();
//inline hook function
RtlCopyMemory ( (BYTE*)g_KiInsertQueueApc, JmpAddress, 5 );
// recover write-protect , lower IRQL
KeLowerIrql(Irql);
WPON();
}
//Original function
_declspec (naked) VOID FASTCALL OriginalKiInsertQueueApc(IN PKAPC Apc,IN KPRIORITY Increment)
{
_asm
{
//front five bytes
mov edi,edi
push ebp
mov ebp,esp
mov eax,g_KiInsertQueueApc
add eax,5
jmp eax
}
}
//Handle function
//apc--kthread--apc_state--eprocess
VOID FASTCALL DetourMyKiInsertQueueApc(IN PKAPC Apc,IN KPRIORITY Increment)
{
ULONG thread;
ULONG process;
if(MmIsAddressValid((PULONG)((ULONG)Apc+0x008))) //address confirm KAPC structure +008 ---> kthread
thread=*((PULONG)((ULONG)Apc+0x008));
else
return ;
if(MmIsAddressValid((PULONG)((ULONG)thread+0x044))) //kthread+30-->KAPC_STATE+10-->eprocess
process=*((PULONG)((ULONG)thread+0x044));
else
return ;
if(MmIsAddressValid((PULONG)((ULONG)process+0x174))) //eprocess+174---->process's name
{
if((_stricmp((char *)((ULONG)process+0x174),"notepad.exe")==0)&&(Increment==2))
{
return ;
}
else
OriginalKiInsertQueueApc(Apc,Increment);
}
else
return;
}
//Unload function
VOID UnHookKiInsertQueueApc()
{
KIRQL Irql;
WPOFF();
Irql = KeRaiseIrqlToDpcLevel();
//inline hook function
RtlCopyMemory ( (BYTE*)g_KiInsertQueueApc, OriginalBytes, 5);
// Recover write-protect , lower IRQL
KeLowerIrql(Irql);
WPON();
}
Reply some questions:
1、Search Signature
Seach with kernel debug of windbg:
uf KeInsertQueueApc
nt!KeInsertQueueApc+0x3b:
804e6d0a 8b450c mov eax,dword ptr [ebp+0Ch]
804e6d0d 8b5514 mov edx,dword ptr [ebp+14h]
804e6d10 894724 mov dword ptr [edi+24h],eax
804e6d13 8b4510 mov eax,dword ptr [ebp+10h]
804e6d16 8bcf mov ecx,edi
804e6d18 894728 mov dword ptr [edi+28h],eax
804e6d1b e8523fffff call nt!KiInsertQueueApc (804dac72)
804e6d20 8ad8 (error) mov bl,al
Signature : sp_code1=0x28 sp_code2=0xe8 sp_code3=0xd88a(windbg's display is error, that is d88a
)
The way is method of through already export function position non-export function,That is generality. In detail see code.
2、Get course of EPRocess
Apc-----kthread-----apc_stateeprocess
dt _KAPC offset 0x008 point KTHREAD
dt _KTHREAD offset 0x034 point KAPC_STATE
dt _KAPC_STATE offset 0x10 point EPROCESS
dt _EPROCESS offset 0x174 point process's name
(three)Summanry
Many people is difficult about inline hook and handle it to is troubles. But i belive to watch my article, You must not think so,Only careful for inline hook and notice details no different with other hook.
The code use hard code, Complie in sp3+VMware, Please modify by system oneself. Welcome reader talk with me.
Step 1: principle of Inline hook
This is common statement of inline hooke about modify flow of function is executed,And conquer the field that control function and filter to operate.We can replace anyplace of original commands to our jump commands in theory,Some peoples really do it to hide for check inline hook ,Do it before flow of function and command is very famillar, even this inline hook don't have generality and stability. The article talk to realized two general inline
principle of Inline hook: Analyse a few command of function's start and They is copied to saved, After our command is called to original command be replaced. If execute original function, must after our function is finished and executed a few command of be saved front on address of return our command later.
The whole process of the inline hook in this,Check function and Get address fucntion is amonged to only call function.
The article talk two inline hook at these point.
Explain three-point:
1、Balance stack is top,Parameter popdown yet.
2、Whether WP bit control processor of CR0 allow to memory's page of only read is writed. When value is zero ,Protection mechanism is forbidden.
3、Lifting interrupt level to DISPATCH_LEVEL, Prohibit interrupt of thread change-over generated.
(Two) Use inline hook
Inline hook divide into two types:
(1)inline export function, ObReferenceObjectByHandle is selected for example。
(2)inline not export function,KiInsertQueueApc is selected for example.
First a few bytes of export function can be viewed with windbg.However Not-export function need confirm to a few bytes oneself,during many questions is noticed.When we understand the article ,You feel very simple about inline hook.
Next through two examples to explain that how use inline hook.
1、inline hook ObReferenceObjectByHandle,Proctect process
ObReferenceObjectByHandle is included export function of ntoskrnl.exe and frequently be used on kernel.
NtCreateProcess need call ObReferenceObjectByHandle for create process, NtTerminateProcess need call ObReferenceObjectByHandle,Because of it that we protect and disabled create process with hook.
Effect : Already ran Notepad can't finish to use task management
Flow:
HookObReferenceObjectByHandle------DetourMyObReferenceObjectByHa ndle----------UnHookObReferenceObjectByHandle
Core code:
//=======================================inline HOOK ObReferenceObjectByHandle===========================
//ObReferenceObjectByHandle is export function of ntoskrnl.exe,First five bytes is hooked.
//Bytes type data unsigned char
ULONG CR0VALUE;
BYTE OriginalBytes[5]={0}; //Save first five bytes of original function
BYTE JmpAddress[5]={0xE9,0,0,0,0}; //Jump's address of hook
extern POBJECT_TYPE *PsProcessType;
NTKERNELAPI NTSTATUS ObReferenceObjectByHandle(
IN HANDLE Handle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_TYPE ObjectType OPTIONAL,
IN KPROCESSOR_MODE AccessMode,
OUT PVOID *Object,
OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL
);
//HOOK function
NTSTATUS DetourMyObReferenceObjectByHandle(
IN HANDLE Handle,
IN ACCESS_MASK DesiredAccess
IN POBJECT_TYPE ObjectType OPTIONAL,
IN KPROCESSOR_MODE AccessMode,
OUT PVOID *Object,
OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL);
//
//hook flow HookObReferenceObjectByHandle---DetourMyObReferenceObjectByHandle---UnHookObReferenceObjectByHandle
void HookObReferenceObjectByHandle()
{
//Evaluation front defined array
KIRQL Irql;
KdPrint(("[ObReferenceObjectByHandle] :0x%x",ObReferenceObjectByHandle)); //address confirm
//Save first five bypes of function
RtlCopyMemory(OriginalBytes,(BYTE *)ObReferenceObjectByHandle,5);
//Save first five bytes's offset of new function
*(ULONG *)(JmpAddress+1)=(ULONG)DetourMyObReferenceObjectByHandle-((ULONG)ObReferenceObjectByHandle+5);
//Start inline hook
//Close to write-protect of memory
_asm
{
push eax
mov eax, cr0
mov CR0VALUE, eax
and eax, 0fffeffffh
mov cr0, eax
pop eax
}
//Lifting interrupt level of IRQL
Irql=KeRaiseIrqlToDpcLevel();
//Write Jmp to five bytes of function
RtlCopyMemory((BYTE *)ObReferenceObjectByHandle,JmpAddress,5);
//Recover Irql
KeLowerIrql(Irql);
//Open write-protect of memory
__asm
{
push eax
mov eax, CR0VALUE
mov cr0, eax
pop eax
}
}
_declspec (naked) NTSTATUS OriginalObReferenceObjectByHandle(IN HANDLE Handle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_TYPE ObjectType OPTIONAL,
IN KPROCESSOR_MODE AccessMode,
OUT PVOID *Object,
OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
{
_asm
{
mov edi,edi
push ebp
mov ebp,esp
mov eax,ObReferenceObjectByHandle
add eax,5
jmp eax
}
}
NTSTATUS DetourMyObReferenceObjectByHandle(
IN HANDLE Handle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_TYPE ObjectType OPTIONAL,
IN KPROCESSOR_MODE AccessMode,
OUT PVOID *Object,
OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
{
NTSTATUS status;
//Call original
status=OriginalObReferenceObjectByHandle(Handle,DesiredAccess,ObjectType,AccessMode,Object,HandleInformation);
if((status==STATUS_SUCCESS)&&(DesiredAccess==1))
{
if(ObjectType== *PsProcessType)
{
if( _stricmp((char *)((ULONG)(*Object)+0x174),"notepad.exe")==0)
{
ObDereferenceObject(*Object);
return STATUS_INVALID_HANDLE;
}
}
}
return status;
}
void UnHookObReferenceObjectByHandle()
{
//Write back five bytes to original again
KIRQL Irql;
//Close write-protect
_asm
{
push eax
mov eax, cr0
mov CR0VALUE, eax
and eax, 0fffeffffh
mov cr0, eax
pop eax
}
//Lifting IRQL to Dpc
Irql=KeRaiseIrqlToDpcLevel();
RtlCopyMemory((BYTE *)ObReferenceObjectByHandle,OriginalBytes,5);
KeLowerIrql(Irql);
//Open write-protect
__asm
{
push eax
mov eax, CR0VALUE
mov cr0, eax
pop eax
}
}
After driver is loaded, program of finished notepad as follow:
(image one)
In more detail:
1、ObReferenceObjectByHandle analyse
NTSTATUS
ObReferenceObjectByHandle(
IN HANDLE Handle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_TYPE ObjectType OPTIONAL,
IN KPROCESSOR_MODE AccessMode,
OUT PVOID *Object,
OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL
);
Function prototype as above,Get pointer of object by handle,return:
STATUS_SUCCESS succed call
STATUS_OBJECT_TYPE_MISMATCH
STATUS_ACCESS_DENIED limite not enough
STATUS_INVALID_HANDLE invalid handle
Call NtTerminateProcess need call ObReferenceObjectByHandle,So we protect process through return value of function is modified.But NtCreateProcess call same this functiong . If don't distinguish,Create process prohibit yet.How distinguish who call it, we can reference WRK, I found to through the second paramter - DesiredAccess can be judged, Create and finish process is different about the second paramter ,PROCESS_CREATE_PROCESS和PROCESS_TERMINATE,Question away.
PspCreateProcess on WRK-v1.2\base\ntos\ps\create.c
Call ObReferenceObjectByHandle code:
Status = ObReferenceObjectByHandle (ParentProcess,
PROCESS_CREATE_PROCESS,
PsProcessType,
PreviousMode,
&Parent,
NULL);
NtTerminateProcess on WRK-v1.2\base\ntos\ps\psdelete.c
Call ObReferenceObjectByHandle code:
st = ObReferenceObjectByHandle (ProcessHandle,
PROCESS_TERMINATE,
PsProcessType,
KeGetPreviousModeByThread(&Self->Tcb),
&Process,
NULL);
DesiredAccess description:
#define PROCESS_TERMINATE (0x0001) // winnt
#define PROCESS_CREATE_THREAD (0x0002) // winnt
#define PROCESS_SET_SESSIONID (0x0004) // winnt
#define PROCESS_VM_OPERATION (0x0008) // winnt
#define PROCESS_VM_READ (0x0010) // winnt
#define PROCESS_VM_WRITE (0x0020) // winnt
// begin_ntddk begin_wdm begin_ntifs
#define PROCESS_DUP_HANDLE (0x0040) // winnt
// end_ntddk end_wdm end_ntifs
#define PROCESS_CREATE_PROCESS (0x0080) // winnt
#define PROCESS_SET_QUOTA (0x0100) // winnt
#define PROCESS_SET_INFORMATION (0x0200) // winnt
#define PROCESS_QUERY_INFORMATION (0x0400) // winnt
#define PROCESS_SET_PORT (0x0800)
#define PROCESS_SUSPEND_RESUME (0x0800) // winnt
2、Call Function's description
We call a function only to write function's name on C language,But infact do it:
Push paramter of fuction to stack and return address of function, call function , open up space of stack and register local variable for new function,
Recover stack keep stack balance
(_stdcall)assembly code:
Push paramter 4
Push paramter 3
Push paramter 2
Push paramter 1
Call function, call command finish two operate in the same time,one is return push stack,two jump to entry address of be called function
Push ebp
Mov ebp,esp
Sub esp, XX ;Open stack fram space
……
Add esp ,XX
Pop ebp
Retn ;recove stack balance
stack details :
ESP
Local variable
EBP
return address
paramter 1
paramter 2
paramter 3
paramter 4
The stack is mad from high to low address.
Paramter pass to EBP,aligned use four bytes
paramter 4----------------------EBP+0x14
paramter 3----------------------EBP+0x10
paramter 2----------------------EBP+0xc
paramter 1--------------------- EBP+0x8
Get local variable through Ebp-XX
So inline hook notice stack balance , brokn stack will breakdown function.
My thinking usual has three steps about inline hook:
HOOK function ----- DetourMy handle function ---------- UnHook function
Modify result of function return or handle among data, then call original function. When we handle original function that already hook, So i construction a original function, Paramter alreday press-in stack before hook in the side, Announce function type is _declspec (naked).。
It is hard to understand about function call stack frame, I is hard to explain everything , Welcome authority talk with me.
2、inline hook KiInsertQueueApc cope kill process for APC
KiInsertQueueAPc is non-export on kernel,Under code may is used to universally template of non-export function inline, Everybody can modify it by need, Principle already is analysed because of inline ObReferenceObject, This part don't analyse by me, Use this yet - Hook function ---DetourMy function --- UnHook function
Croe code:
//===================inline hook KiInsertQueueApc====================
//KiInsertQueueApc is non-export on kernel, Position it from KeInsertQueueApc
//Modify front five bytes of KiInsertQueueApc
//Thinking of handle function: apc-->kthread---apc_state--eprocess--process's name
//HookKiInsertQueueApc---DetourMyKiInsertQueueApc---UnHookKiInsertQueueApc
ULONG CR0VALUE;
ULONG g_KiInsertQueueApc;
BYTE JmpAddress[5]={0xE9,0,0,0,0}; //Jump HOOK function's address
BYTE OriginalBytes[5]={0}; //Save front five bytes of original function
VOID FASTCALL DetourMyKiInsertQueueApc(IN PKAPC Apc,IN KPRIORITY Increment);
VOID WPOFF()
{
_asm
{
push eax
mov eax, cr0
mov CR0VALUE, eax
and eax, 0fffeffffh
mov cr0, eax
pop eax
cli
};
}
VOID WPON()
{
__asm
{
sti
push eax
mov eax, CR0VALUE
mov cr0, eax
pop eax
};
}
//1、Get KiInsertQueueApc address
ULONG GetFunctionAddr( IN PCWSTR FunctionName) //PCWSTR const pointer , point 16 bit UNICODE
{
UNICODE_STRING UniCodeFunctionName;
RtlInitUnicodeString( &UniCodeFunctionName, FunctionName );
return (ULONG)MmGetSystemRoutineAddress( &UniCodeFunctionName );
}
ULONG GetKiInsertQueueApcAddr()
{
ULONG sp_code1=0x28,sp_code2=0xe8,sp_code3=0xd88a; //Signature, sp_code3 windbg show error, That is d88a
ULONG address=0;
PUCHAR addr;
PUCHAR p;
addr=(PUCHAR)GetFunctionAddr(L"KeInsertQueueApc");
for(p=addr;p<p+PAGE_SIZE;p++)
{
if((*(p-1)==sp_code1)&&(*p==sp_code2)&&(*(PUSHORT)(p+5)==sp_code3))
{
address=*(PULONG)(p+1)+(ULONG)(p+5);
break;
}
}
KdPrint(("[KeInsertQueueApc] addr %x\n",(ULONG)addr));
KdPrint(("[KiInsertQueueApc] address %x\n",address));
return address;
}
VOID HookKiInsertQueueApc()
{
KIRQL Irql;
g_KiInsertQueueApc=GetKiInsertQueueApcAddr();
KdPrint(("[KiInsertQueueApc] KiInsertQueueApc %x\n",g_KiInsertQueueApc));
// Save front bytes of original function保存原函数的前字节内容
RtlCopyMemory (OriginalBytes, (BYTE*)g_KiInsertQueueApc, 5);
//Offset address of new function to original function
*( (ULONG*)(JmpAddress + 1) ) = (ULONG)DetourMyKiInsertQueueApc - (ULONG)g_KiInsertQueueApc - 5;
// Prohibit write-protect of systerm, Lifting IRQL to DPC
WPOFF();
Irql = KeRaiseIrqlToDpcLevel();
//inline hook function
RtlCopyMemory ( (BYTE*)g_KiInsertQueueApc, JmpAddress, 5 );
// recover write-protect , lower IRQL
KeLowerIrql(Irql);
WPON();
}
//Original function
_declspec (naked) VOID FASTCALL OriginalKiInsertQueueApc(IN PKAPC Apc,IN KPRIORITY Increment)
{
_asm
{
//front five bytes
mov edi,edi
push ebp
mov ebp,esp
mov eax,g_KiInsertQueueApc
add eax,5
jmp eax
}
}
//Handle function
//apc--kthread--apc_state--eprocess
VOID FASTCALL DetourMyKiInsertQueueApc(IN PKAPC Apc,IN KPRIORITY Increment)
{
ULONG thread;
ULONG process;
if(MmIsAddressValid((PULONG)((ULONG)Apc+0x008))) //address confirm KAPC structure +008 ---> kthread
thread=*((PULONG)((ULONG)Apc+0x008));
else
return ;
if(MmIsAddressValid((PULONG)((ULONG)thread+0x044))) //kthread+30-->KAPC_STATE+10-->eprocess
process=*((PULONG)((ULONG)thread+0x044));
else
return ;
if(MmIsAddressValid((PULONG)((ULONG)process+0x174))) //eprocess+174---->process's name
{
if((_stricmp((char *)((ULONG)process+0x174),"notepad.exe")==0)&&(Increment==2))
{
return ;
}
else
OriginalKiInsertQueueApc(Apc,Increment);
}
else
return;
}
//Unload function
VOID UnHookKiInsertQueueApc()
{
KIRQL Irql;
WPOFF();
Irql = KeRaiseIrqlToDpcLevel();
//inline hook function
RtlCopyMemory ( (BYTE*)g_KiInsertQueueApc, OriginalBytes, 5);
// Recover write-protect , lower IRQL
KeLowerIrql(Irql);
WPON();
}
Reply some questions:
1、Search Signature
Seach with kernel debug of windbg:
uf KeInsertQueueApc
nt!KeInsertQueueApc+0x3b:
804e6d0a 8b450c mov eax,dword ptr [ebp+0Ch]
804e6d0d 8b5514 mov edx,dword ptr [ebp+14h]
804e6d10 894724 mov dword ptr [edi+24h],eax
804e6d13 8b4510 mov eax,dword ptr [ebp+10h]
804e6d16 8bcf mov ecx,edi
804e6d18 894728 mov dword ptr [edi+28h],eax
804e6d1b e8523fffff call nt!KiInsertQueueApc (804dac72)
804e6d20 8ad8 (error) mov bl,al
Signature : sp_code1=0x28 sp_code2=0xe8 sp_code3=0xd88a(windbg's display is error, that is d88a
)
The way is method of through already export function position non-export function,That is generality. In detail see code.
2、Get course of EPRocess
Apc-----kthread-----apc_stateeprocess
dt _KAPC offset 0x008 point KTHREAD
dt _KTHREAD offset 0x034 point KAPC_STATE
dt _KAPC_STATE offset 0x10 point EPROCESS
dt _EPROCESS offset 0x174 point process's name
(three)Summanry
Many people is difficult about inline hook and handle it to is troubles. But i belive to watch my article, You must not think so,Only careful for inline hook and notice details no different with other hook.
The code use hard code, Complie in sp3+VMware, Please modify by system oneself. Welcome reader talk with me.
No comments:
Post a Comment