Page 1 of 1

Driver development \ get Service Descriptor Table functions

Posted: Sun Jul 07, 2013 1:35 pm
by madd0r
Hi there,

i have made a small modification of one of User_Russian's great driver examples (http://www.purebasic.fr/english/viewtop ... evelopment)

to show how to get dynamically the index number from the Service Descriptor Table of known functions. You can use this to generally detect SDT hooks or make it easily to hook SDT functions, or just as kind of getprocaddress.

btw. sry for my bad english and messy code ;X


http://s14.directupload.net/images/130707/ilkicvt3.png

Code: Select all

 Declare DriverEntry(*DriverObject, *RegistryPath)

XIncludeFile #PB_Compiler_Home+"DDK\ntddk.pbi"
XIncludeFile #PB_Compiler_Home+"DDK\ntstatus.pbi"

CompilerSelect #PB_Compiler_Processor
  CompilerCase #PB_Processor_x86 
    Import "ntoskrnl.lib"
  CompilerCase #PB_Processor_x64   
    ImportC "ntoskrnl.lib"
CompilerEndSelect

  IoCompleteRequest(*IRP, PriorityBoost)
  RtlInitUnicodeString(*UString, *String)
  IoCreateDevice(*DriverObject, DeviceExtensionSize, *UDeviceName, DeviceType, DeviceCharacteristics, Exclusive, *DeviceObject)
  IoDeleteDevice(*DeviceObject)
  IoCreateSymbolicLink(*SymbolicLinkName, *DeviceName)
  IoDeleteSymbolicLink(*SymbolicLinkName)
  ZwQuerySystemInformation(SysInfoClass, *SysInfo, SysInfoLength.l, *ReturnLength)
  ExAllocatePool(PoolType, NumBytes)
  ExFreePool(*Point)
  *KeServiceDescriptorTable.SERVICE_DESCRIPTOR_TABLE As "__imp__KeServiceDescriptorTable"
 
EndImport

ImportC "ntoskrnl.lib"
	DbgPrint(*String)
	strstr(*Stringx, *SearchFor)
	_stricmp(*str1,*str2)
	_snprintf(STRx,count.l,*format,arg)
	strcat ( *destination,*source)
	strcpy ( *destination, *source );
EndImport

#IOCTL_READ_PORT_UCHAR	 = $200 
#IOCTL_WRITE_PORT_UCHAR	 = $400


*A=@DriverEntry()
!jmp [p_A]

Structure SYSTEM_MODULE
  Reserved1.l;
  Reserved2.l;
  *ImageBaseAddress;
  ImageSize.l;
  Flags.l;
  Id.w;
  Rank.w;
  w018.w;
  NameOffset.w;
  Name.s{#MAXIMUM_FILENAME_LENGTH};
EndStructure

Structure SYSTEM_MODULE_INFO 
  ModulesCount.l; 
  Modules.SYSTEM_MODULE[0];
EndStructure

Structure StrippedExport
  *AddressOfName
  *AddressOfFunc
  *LoopOrdinal
  *Ordinal
EndStructure


Macro NTCALL(_function)
  *KeServiceDescriptorTable\ntoskrnl\ServiceTable\ar[_function]
EndMacro



Enumeration
  #SM_SDT_Name_By_Ordinal
  #SM_SDT_Ordinal_By_Name
EndEnumeration

;get the kernel base address 
Procedure.l GetKernelBaseAddress()
  Protected  SystemInfoBufferSize.l,*pSystemInfoBuffer
  Protected *ModulesInfo.SYSTEM_MODULE_INFO
 
  
  ZwQuerySystemInformation(#SystemModuleInformation, @SystemInfoBufferSize, 0, @SystemInfoBufferSize)
  If @SystemInfoBufferSize <> 0 ;

    *pSystemInfoBuffer = ExAllocatePool(#PagedPool, SystemInfoBufferSize*2)
    If *pSystemInfoBuffer <> #Null
      If ZwQuerySystemInformation(#SystemModuleInformation, *pSystemInfoBuffer, SystemInfoBufferSize*2, @SystemInfoBufferSize)= #STATUS_SUCCESS
        
        *ModulesInfo = *pSystemInfoBuffer

        For i = 0 To *ModulesInfo\ModulesCount -1

            ;ntoskrnl.exe single-processor without PAE
            ;ntkrnlmp.exe multi-processor without PAE
            ;ntkrnlpa.exe single-processor With PAE (version 5.0 And higher)
            ;ntkrpamp.exe multi-processor With PAE (version 5.0 And higher)

          If strstr(@*ModulesInfo\Modules[i]\Name,@"ntoskrnl.exe") Or strstr(@*ModulesInfo\Modules[i]\Name,@"ntkrnlmp.exe") Or strstr(@*ModulesInfo\Modules[i]\Name,@"ntkrnlpa.exe") Or strstr(@*ModulesInfo\Modules[i]\Name,@"ntkrpamp.exe") 
            DbgPrint(@*ModulesInfo\Modules[i]\Name)
            ProcedureReturn *ModulesInfo\Modules[i]\ImageBaseAddress
          EndIf
          

        Next
        
      EndIf
     
      ExFreePool(*pSystemInfoBuffer)
    EndIf
  EndIf
  ProcedureReturn 0 
EndProcedure


;get address of exportname or get name of exportaddress
Procedure.l GetExport(*KernelBase,*ExportName,*ExportAddress,*outExport.StrippedExport)
  Protected *DOS_STUB.IMAGE_DOS_HEADER
  Protected *NT_HEADER.IMAGE_NT_HEADERS
  Protected *DATA_HEADER.IMAGE_DATA_DIRECTORY
  Protected *EXPORT.IMAGE_EXPORT_DIRECTORY
  Protected i.l,*addrName,*addrFunc,*addrOrd,*AddressOfName,*AddressOfFunc,*AddressOfOrd
  
  Protected DebugString.s{100}
  Protected OrdinalString.s{8}
  
  *DOS_STUB   = *KernelBase
  *NT_HEADER  = *KernelBase + *DOS_STUB\e_lfanew
  *EXPORT     = *KernelBase + *NT_HEADER\OptionalHeader\DataDirectory[0]\VirtualAddress
  
  *addrName  = *KernelBase + *EXPORT\AddressOfNames         ;start names array
  *addrFunc  = *KernelBase + *EXPORT\AddressOfFunctions     ;start address array
  *addrOrd   = *KernelBase + *EXPORT\AddressOfNameOrdinals  ;start ordinals array
  

  For i = 0 To *EXPORT\NumberOfNames -1
    
      *AddressOfName = *KernelBase + PeekL(*addrName+(i*4))
      AddressOfOrd  =  PeekW(*addrOrd+(i*2)) 
      *AddressOfFunc = *KernelBase + PeekL(*addrFunc+(AddressOfOrd*4)) 
      ;*AddressOfFunc = *KernelBase + PeekL(*addrFunc+(i*4)) 
      
      If *ExportAddress <> 0 And *ExportName = 0
        If *AddressOfFunc = *ExportAddress
          
          *outExport\AddressOfFunc=*AddressOfFunc
          *outExport\AddressOfName=*AddressOfName
          *outExport\LoopOrdinal  =i
          *outExport\Ordinal      =AddressOfOrd
        
          ProcedureReturn 1
        EndIf 
      ElseIf *ExportName <> 0 And *ExportAddress = 0
        If _stricmp(*ExportName,*AddressOfName) = 0
          
          *outExport\AddressOfFunc=*AddressOfFunc
          *outExport\AddressOfName=*AddressOfName
          *outExport\LoopOrdinal  =i
          *outExport\Ordinal      =AddressOfOrd
          
          ProcedureReturn 1
        EndIf 
      EndIf
      
      
      
  Next
    
  ProcedureReturn 0
  
EndProcedure


;searches for the name of an SDT index or searches for an SDT index by entering the function name
Procedure.l GetSdtOrinalFromExportTableEx(*KernelBase,SDTOrdinal.l,*Name,SearchMode)
  Protected *NtCallAddr,i.l
  Protected retExport.StrippedExport
  
  Select SearchMode
      Case #SM_SDT_Name_By_Ordinal
        *NtCallAddr = NTCALL(SDTOrdinal)
        If GetExport(*KernelBase,0,*NtCallAddr,@retExport) = 1
        
          If *NtCallAddr = retExport\AddressOfFunc
            ProcedureReturn retExport\AddressOfName
          Else
            ProcedureReturn 0
          EndIf 
        EndIf 
        
      Case #SM_SDT_Ordinal_By_Name
        If GetExport(*KernelBase,*Name,0,@retExport)  = 1
          For i = 0 To *KeServiceDescriptorTable\ntoskrnl\ServiceLimit-1

            *NtCallAddr = NTCALL(i)
 
            If *NtCallAddr = retExport\AddressOfFunc
                ProcedureReturn i
            EndIf
          Next
        EndIf
    EndSelect
    
  ProcedureReturn 0
    
EndProcedure




;searches for the name of an SDT index or searches for an SDT index by entering the function name
  


Procedure DeviceIoControl(*DeviceObject.DEVICE_OBJECT, *pIrp.IRP)
  Protected ntStatus, *Point, *Stack.IO_STACK_LOCATION
  
  *Stack = *pIrp\Tail\Overlay\CurrentStackLocation
  
  inBuffersize = *Stack\Parameters\DeviceIoControl\InputBufferLength
  outBuffersize = *Stack\Parameters\DeviceIoControl\OutputBufferLength
  
  CtrlBuff   = PeekI(*pIrp\SystemBuffer)
  address = CtrlBuff & $FFFF
  Byte.a    = (CtrlBuff>>16)&255
  
  Code = *Stack\Parameters\DeviceIoControl\IoControlCode
  
  ntStatus = #STATUS_SUCCESS
  
  Select Code
    Case #IOCTL_READ_PORT_UCHAR
   
      *pIrp\IoStatus\Information = 1
      
    Case #IOCTL_WRITE_PORT_UCHAR
  
      *pIrp\IoStatus\Information = 0
      
    Default
      ntStatus = #STATUS_UNSUCCESSFUL
      *pIrp\IoStatus\Information = 0
  EndSelect
  
  
  *pIrp\IoStatus\Status = ntStatus
  IoCompleteRequest(*pIrp, #IO_NO_INCREMENT)
  
  ProcedureReturn ntStatus
EndProcedure

Procedure CreateDispatch(*DeviceObject.DEVICE_OBJECT, *pIrp.IRP)
  *pIrp\IoStatus\Information = 0
  *pIrp\IoStatus\Status = #STATUS_SUCCESS
  IoCompleteRequest(*pIrp, #IO_NO_INCREMENT)
  ProcedureReturn #STATUS_SUCCESS
EndProcedure

Procedure UnloadDriver(*DriverObject.DRIVER_OBJECT)
  Protected uniDOSString.UNICODE_STRING
  RtlInitUnicodeString(@uniDOSString, ?DosDevices)
  IoDeleteSymbolicLink (@uniDOSString)
  IoDeleteDevice(*DriverObject\DeviceObject)
EndProcedure


Procedure DriverEntry(*DriverObject.DRIVER_OBJECT, *RegistryPath.UNICODE_STRING)
  Protected deviceObject.DEVICE_OBJECT
  Protected uniNameString.UNICODE_STRING
  Protected uniDOSString.UNICODE_STRING
  Protected *KernelBase,*CallName
  Protected i.l
  Protected DebugString.s{100}
  Protected OrdinalString.s{8}
  
  RtlInitUnicodeString(@uniNameString, ?Device)
  RtlInitUnicodeString(@uniDOSString, ?DosDevices)
  
  
  
  
  
  DbgPrint(@"DriverEntry")
  
  strcpy(@DebugString,@"Number of functions overall: ")
  _snprintf(@OrdinalString,8,@"%x", *KeServiceDescriptorTable\ntoskrnl\ServiceLimit)
  strCat(@DebugString,@OrdinalString)
  
  DbgPrint(@DebugString)
  
  
  
  *KernelBase  = GetKernelBaseAddress()
  
  If *KernelBase <> 0 
    
    DbgPrint(@"Found KernelBase")
    
    
    ;list all exported functions in SDT
    For i = 0 To *KeServiceDescriptorTable\ntoskrnl\ServiceLimit -1

      *CallName = GetSdtOrinalFromExportTableEx(*KernelBase,i,0,#SM_SDT_Name_By_Ordinal)
      
      If *CallName <> 0 
        
        strcpy(@DebugString,@"Found Call: ")
        strCat(@DebugString,*CallName)
        strCat(@DebugString,@" Ordinal: ")
        _snprintf(@OrdinalString,9,@"0x%x",i)
        strCat(@DebugString,@OrdinalString)
        DbgPrint(@DebugString)
        
     
      Else
        ;DbgPrint(@"No Export present for this  call")
      EndIf  
      
    Next 
    
   strcpy(@DebugString,@"NtQuerySystemInformation")
  ;search for NtQuerySystemInformation 
  *CallName = GetSdtOrinalFromExportTableEx(*KernelBase,0,@DebugString,#SM_SDT_Ordinal_By_Name)
  strcpy(@DebugString,@"Found Index No of NtQuerySystemInformation: ")
  _snprintf(@OrdinalString,9,@"0x%x",*CallName)
  strCat(@DebugString,@OrdinalString)
  DbgPrint(@DebugString)
    
    
    
  EndIf
  

  
  status = IoCreateDevice(*DriverObject, 0, @uniNameString, #FILE_DEVICE_UNKNOWN, 0, #False, @deviceObject)
  If status <> #STATUS_SUCCESS
    ProcedureReturn status
  EndIf
  
  status = IoCreateSymbolicLink(@uniDOSString, @uniNameString)
  If status <> #STATUS_SUCCESS
    IoDeleteDevice(@deviceObject) ; Ìû äîëæíû ñàìè óáèðàòü "õâîñòû" â ðåæèìå ÿäðà!
    ProcedureReturn status
  EndIf
  
  *DriverObject\DriverUnload = @UnloadDriver()
  
  *DriverObject\MajorFunction[#IRP_MJ_CLOSE]  = @CreateDispatch()
  *DriverObject\MajorFunction[#IRP_MJ_CREATE] = @CreateDispatch()
  *DriverObject\MajorFunction[#IRP_MJ_DEVICE_CONTROL] = @DeviceIoControl()
  
  ProcedureReturn #STATUS_SUCCESS
EndProcedure



; 
DataSection
  CompilerSelect #PB_Compiler_Processor
    CompilerCase #PB_Processor_x86 
      Device:
      !du '\Device\driver', 0, 0
      
      DosDevices:
      !du '\DosDevices\driver', 0, 0
      
    CompilerCase #PB_Processor_x64
      Device:
      !du '\Device\driver_x64', 0, 0
      
      DosDevices:
      !du '\DosDevices\driver_x64', 0, 0

  CompilerEndSelect
EndDataSection