编写驱动的问题调用MmGetSystemRoutineAddress会反回0
以下是驱动的源码。
.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
includelib d:\ntoskrnl.lib
include c:\radasm\masm32\Macros\Strings.mac
;**************************************************************************************************
m2m MACRO M1, M2
push M2
pop M1
ENDM
IOCTL_GET_ZwOpenProcess equ CTL_CODE(FILE_DEVICE_UNKNOWN, 10h, METHOD_BUFFERED, FILE_READ_ACCESS+FILE_WRITE_ACCESS)
IOCTL_GET_ZwProtectVirtualMemory equ CTL_CODE(FILE_DEVICE_UNKNOWN, 11h, METHOD_BUFFERED, FILE_READ_ACCESS+FILE_WRITE_ACCESS)
IOCTL_GET_ZwReadVirtualMemory equ CTL_CODE(FILE_DEVICE_UNKNOWN, 12h, METHOD_BUFFERED, FILE_READ_ACCESS+FILE_WRITE_ACCESS)
IOCTL_GET_ZwWriteVirtualMemory equ CTL_CODE(FILE_DEVICE_UNKNOWN, 13h, METHOD_BUFFERED, FILE_READ_ACCESS+FILE_WRITE_ACCESS)
.data
;保存地址
dwOldNtLoadDriver dd ?
dwAddr dd ?
dwDriverName ANSI_STRING <>
dwOldNtOpenProcess dd ?
dwOldNtProtectVirtualMemory dd ?
dwOldNtReadVirtualMemory dd ?
dwOldNtWriteVirtualMemory dd ?
buffer db 256 dup(?)
.const
CCOUNTED_UNICODE_STRING "\\Device\\devHookApi", g_usDeviceName, 4
CCOUNTED_UNICODE_STRING "\\??\\slHookApi", g_usSymbolicLinkName, 4
CCOUNTED_UNICODE_STRING "ZwLoadDriver", g_ZwLoadDriver, 4
CCOUNTED_UNICODE_STRING "ZwOpenProcess", g_NtOpenProcess, 4
CCOUNTED_UNICODE_STRING "ZwProtectVirtualMemory", g_NtProtectVirtualMemory, 4
CCOUNTED_UNICODE_STRING "ZwReadVirtualMemory", g_NtReadVirtualMemory, 4
CCOUNTED_UNICODE_STRING "ZwWriteVirtualMemory", g_NtWriteVirtualMemory, 4
; 要还原的函数
; NtOpenProcess
; NtProtectVirtualMemory
; NtReadVirtualMemory
; NtWriteVirtualMemory
; NtUserSendInput
;**************************************************************************************************
.code
;让这个函数在NtLoadDriver的调用时被执行以实现监视
NewNtLoadDriver proc lpDriverName:PUNICODE_STRING
pushad
invoke RtlUnicodeStringToAnsiString, addr dwDriverName, lpDriverName,TRUE
invoke DbgPrint, $CTA0("\nDriverName: %s.sys\n"), dwDriverName.Buffer
popad
;调用原函数
push lpDriverName
call dwOldNtLoadDriver
ret
NewNtLoadDriver endp
;**************************************************************************************************
HookFunction proc
pushad
;下面是用KeServiceDescriptorTabled导出符号获得数组的基地址,这个数组中包含有NtXXXX函数的入口地址。
mov eax, KeServiceDescriptorTable
mov esi, [eax]
mov esi, [esi]
;用MmGetSystemRoutineAddress来获得函数ZwLoadDriver的地址。并从这个函数地址后面的第2个字节中取得服务号。从而
;获得以服务号为下标的数组元素。
invoke MmGetSystemRoutineAddress,addr g_ZwLoadDriver
inc eax
movzx ecx,byte ptr[eax]
sal ecx,2
add esi,ecx
mov dwAddr,esi
mov edi,dword ptr[esi]
;保存旧的函数地址。
mov dwOldNtLoadDriver,edi
invoke DbgPrint, $CTA0("dwOldNtLoadDriver:%08X"),edi
mov edi,offset NewNtLoadDriver
;修改入口地址
cli
mov dword ptr[esi],edi
sti
popad
mov eax, STATUS_SUCCESS
ret
HookFunction endp
;**************************************************************************************************
DispatchCreateClose proc pDeviceObject:PDEVICE_OBJECT, pIrp:PIRP
mov eax, pIrp
assume eax:ptr _IRP
mov [eax].IoStatus.Status, STATUS_SUCCESS
and [eax].IoStatus.Information, 0
assume eax:nothing
invoke IoCompleteRequest, pIrp, IO_NO_INCREMENT
mov eax, STATUS_SUCCESS
ret
DispatchCreateClose endp
;**************************************************************************************************
DriverUnload proc pDriverObject:PDRIVER_OBJECT
;必须保存环境,否则后果很严重。在这个函数中恢复被修改的地址。
pushad
mov esi,dwAddr
mov eax,dwOldNtLoadDriver
cli
mov dword ptr[esi],eax
sti
invoke IoDeleteSymbolicLink, addr g_usSymbolicLinkName
mov eax,pDriverObject
invoke IoDeleteDevice, (DRIVER_OBJECT PTR [eax]).DeviceObject
popad
ret
DriverUnload endp
GetServiceDescriptorTableShadowAddress proc uses esi edi ebx
local dwThreadId:DWORD
xor ebx, ebx ; = NULL. Assume ServiceDescriptorTableShadow will be not found
mov eax, KeServiceDescriptorTable
mov esi, [eax]
; Find KTHREAD.ServiceTable field
; For non-GUI threads this field == KeServiceDescriptorTable
; and it points to ServiceDescriptorTable
; For GUI threads
; ServiceDescriptorTableShadow
invoke KeGetCurrentThread
mov edi, 200h-4
.while edi
.break .if dword ptr [eax][edi] == esi
dec edi
.endw
.if edi != 0
; edi = offset to ServiceTable field in KTHREAD structure
mov dwThreadId, 080h
.while dwThreadId < 400h
push eax ; reserve DWORD on stack
invoke PsLookupThreadByThreadId, dwThreadId, esp
pop ecx ; -> ETHREAD/KTHREAD
.if eax == STATUS_SUCCESS
push dword ptr [ecx][edi]
fastcall ObfDereferenceObject, ecx
pop eax
.if eax != esi
mov edx, MmSystemRangeStart
mov edx, [edx]
mov edx, [edx]
.if eax > edx ; some stupid error checking
mov ebx, eax
.break
.endif
.endif
.endif
add dwThreadId, 4
.endw
.endif
mov eax, ebx
ret
GetServiceDescriptorTableShadowAddress endp
_DispatchControl proc uses esi edi ebx,pDeviceObject:PDEVICE_OBJECT, pIrp:PIRP
LOCAL status : NTSTATUS
LOCAL dwBytesReturned
and dwBytesReturned, 0
mov status, STATUS_UNSUCCESSFUL
mov esi, pIrp
assume esi : ptr _IRP
IoGetCurrentIrpStackLocation esi
mov edi, eax
assume edi : ptr IO_STACK_LOCATION
mov eax, [edi].Parameters.DeviceIoControl.IoControlCode
push edi
int 3
.if eax==IOCTL_GET_ZwOpenProcess
invoke getsysFunction,addr g_NtOpenProcess,dwOldNtOpenProcess
此处调用返回正常。
.elseif eax==IOCTL_GET_ZwProtectVirtualMemory
invoke getsysFunction,addr g_NtProtectVirtualMemory,dwOldNtProtectVirtualMemory
此处调用getsysfunction时MmGetSystemRoutineAddress会返回0
.elseif eax==IOCTL_GET_ZwReadVirtualMemory
invoke getsysFunction,addr g_NtReadVirtualMemory,dwOldNtReadVirtualMemory
.elseif eax==IOCTL_GET_ZwWriteVirtualMemory
invoke getsysFunction,addr g_NtWriteVirtualMemory,dwOldNtWriteVirtualMemory
.endif
pop edi
assume edi : ptr IO_STACK_LOCATION
mov esi, pIrp
assume esi : ptr _IRP
m2m [esi].IoStatus.Status, status
m2m [esi].IoStatus.Information, dwBytesReturned
assume esi : nothing
assume edi : nothing
invoke IoCompleteRequest, pIrp, IO_NO_INCREMENT
mov eax, status
ret
_DispatchControl endp
getsysFunction proc funcname:dword,saveaddr:dword
pushad
mov eax, KeServiceDescriptorTable
mov esi, [eax]
mov esi, [esi]
;获得以服务号为下标的数组元素。
invoke MmGetSystemRoutineAddress,funcname
inc eax
movzx ecx,byte ptr[eax]
sal ecx,2
add esi,ecx
mov edi,dword ptr[esi]
;保存旧的函数地址。
mov saveaddr,edi
invoke DbgPrint, $CTA0("%08X"),edi
popad
ret
getsysFunction endp
;**************************************************************************************************
DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING
local status:NTSTATUS
local pDeviceObject:PDEVICE_OBJECT
mov status, STATUS_DEVICE_CONFIGURATION_ERROR
invoke IoCreateDevice, pDriverObject, 0, addr g_usDeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, addr pDeviceObject
.if eax == STATUS_SUCCESS
invoke IoCreateSymbolicLink, addr g_usSymbolicLinkName, addr g_usDeviceName
.if eax == STATUS_SUCCESS
mov eax, pDriverObject
assume eax:ptr DRIVER_OBJECT
mov [eax].DriverUnload, offset DriverUnload
mov [eax].MajorFunction[IRP_MJ_CREATE*(sizeof PVOID)], offset DispatchCreateClose
mov [eax].MajorFunction[IRP_MJ_CLOSE*(sizeof PVOID)], offset DispatchCreateClose
mov [eax].MajorFunction[IRP_MJ_DEVICE_CONTROL*(sizeof PVOID)], offset _DispatchControl
assume eax:nothing
invoke GetServiceDescriptorTableShadowAddress
.if eax != NULL
invoke DbgPrint, $CTA0("ServiceDescriptorTableShadow at address: %08X\n"), eax
.endif
invoke HookFunction
mov status, STATUS_SUCCESS
.else
invoke IoDeleteDevice, pDeviceObject
.endif
.endif
mov eax, status
ret
DriverEntry endp
end DriverEntry
[课程]Linux pwn 探索篇!