阅读:2103回复:17
hook ntoskrnl.exe的奇怪现象(很久不说\"奇怪\"两个字了)
通过hook PE的方式(不是hook ServiceTable),
我参考以下文章的代码,去hook 多个内核函数. 已经可以正确得到ntoskrnl.exe module的基址了, 但是奇怪的事情却发生了. 调试下面这个函数的时候,我为了验证获取的函数名称和函数地址是否匹配,特意注释掉了几句,大家请看. 结果使用softice调试惊讶的发现,FunName和pOldFun完全对应不起来.也就是说,所有几百个函数名称和函数地址全部乱了套. My god! 请问大虾原因何在呢?--太--奇--怪--了--. FARPROC HookFunction( PCHAR pModuleBase, PCHAR HookFunName, FARPROC HookFun ) { PIMAGE_DOS_HEADER pDosHdr; PIMAGE_NT_HEADERS pNtHdr; PIMAGE_SECTION_HEADER pSecHdr; PIMAGE_EXPORT_DIRECTORY pExtDir; UINT ui,uj; PCHAR FunName; DWORD *dwAddrName; DWORD *dwAddrFun; FARPROC pOldFun; ULONG uAttrib; pDosHdr = ( PIMAGE_DOS_HEADER )pModuleBase; if ( IMAGE_DOS_SIGNATURE == pDosHdr->e_magic ) { pNtHdr = ( PIMAGE_NT_HEADERS )( pModuleBase + pDosHdr->e_lfanew ); if( IMAGE_NT_SIGNATURE == pNtHdr->Signature || IMAGE_NT_SIGNATURE1 == pNtHdr->Signature ) { pSecHdr = ( PIMAGE_SECTION_HEADER )( pModuleBase + pDosHdr->e_lfanew + sizeof( IMAGE_NT_HEADERS ) ); for ( ui = 0; ui < (UINT)pNtHdr->FileHeader.NumberOfSections; ui++ ) { if ( !strcmp( pSecHdr->Name, \".edata\" ) ) { pExtDir = ( PIMAGE_EXPORT_DIRECTORY )( pModuleBase + pSecHdr->VirtualAddress ); dwAddrName = ( PDWORD )(pModuleBase + pExtDir->AddressOfNames ); dwAddrFun = ( PDWORD )(pModuleBase + pExtDir->AddressOfFunctions ); for ( uj = 0; uj < (UINT)pExtDir->NumberOfFunctions; uj++ ) { FunName = pModuleBase + *dwAddrName; if( !strcmp( FunName, HookFunName ) ) { DbgPrint(\" HOOK %s()\\n\",FunName); DisableWriteProtect( &uAttrib ); pOldFun = ( FARPROC )( pModuleBase + *dwAddrFun ); //*dwAddrFun = ( PCHAR )HookFun - pModuleBase; 我注释掉这句话,并且在此下断点. EnableWriteProtect( uAttrib ); return pOldFun; } dwAddrName ++; dwAddrFun ++; } } pSecHdr++; } } } return NULL; } 内核级HOOK的几种实现与应用 创建时间:2003-03-26 文章属性:原创 文章来源:http://www.whitecell.org 文章提交:sinister (jiasys_at_21cn.com) 内核级HOOK的几种实现与应用 Author : sinister Email : sinister@whitecell.org HomePage: http://www.whitecell.org 实现内核级 HOOK 对于拦截、分析、跟踪系统内核起着致关重要的作用。实现的方法不同意味着应用侧重点的不同。如想要拦截 NATIVE API 那么可能常用的就是 HOOK SERVICE TABLE 的方法。如果要分析一些系统调用,那么可能想到用 HOOK INT 2E 中断来实现。如果想要拦截或跟踪其他内核 DRIVER 的调用,那么就要用到HOOK PE 的方法来实现。这里我们更注重的是实现,原理方面已有不少高手在网上发表过文章。大家可以结合起来读。下面以我写的几个实例程序来讲解一下各种方法的实现。错误之处还望各位指正。 1、HOOK SERVICE TABLE 方法: 这种方法对于拦截 NATIVE API 来说用的比较多。原理就是通过替换系统导 出的一个 SERVICE TABLE 中相应的 NATIVE API 的地址来达到拦截的目的。 因为此方法较为简单,网上也有不少资料来介绍。所以这里就不给出实例程序了。SERVICE TABLE 的结构如下: typedef struct ServiceDescriptorEntry { unsigned int *ServiceTableBase; unsigned int *ServiceCounterTableBase; unsigned int NumberOfServices; unsigned char *ParamTableBase; } ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t; 2、HOOK INT 2E 方法: 这种方法对于跟踪、分析系统调用来说用的比较多。原理是通过替换 IDT 表中的 INT 2E 中断,使之指向我们自己的中断服务处理例程来实现的。掌握 此方法需要你对保护模式有一定的基础。下面的程序演示了这一过程。 /***************************************************************** 文件名 : WssHookInt2e.c 描述 : 系统调用跟踪 作者 : sinister 最后修改日期 : 2002-11-02 *****************************************************************/ #include \"ntddk.h\" #include \"string.h\" #define DWORD unsigned __int32 #define WORD unsigned __int16 #define BYTE unsigned __int8 #define BOOL __int32 #define LOWORD(l) ((WORD)(l)) #define HIWORD(l) ((WORD)(((DWORD)(l) >> 16) & 0xFFFF)) #define LOBYTE(w) ((BYTE)(w)) #define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF)) #define MAKELONG(a, b) ((LONG) (((WORD) (a)) | ((DWORD) ((WORD) (b))) << 16)) #define SYSTEMCALL 0x2e #define SYSNAME \"System\" #define PROCESSNAMELEN 16 #pragma pack(1) //定义 IDTR typedef struct tagIDTR { WORD IDTLimit; WORD LowIDTbase; WORD HiIDTbase; }IDTR, *PIDTR; //定义 IDT typedef struct tagIDTENTRY{ WORD OffsetLow; WORD selector; BYTE unused_lo; unsigned char unused_hi:5; unsigned char DPL:2; unsigned char P:1; WORD OffsetHigh; } IDTENTRY, *PIDTENTRY; #pragma pack() DWORD OldInt2eService; ULONG ProcessNameOffset; TCHAR ProcessName[PROCESSNAMELEN]; static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject); ULONG GetProcessNameOffset(); VOID GetProcessName( PCHAR Name ); VOID InstallNewInt2e(); VOID UninstallNewInt2e(); VOID __fastcall NativeApiCall() { KIRQL OldIrql; DWORD ServiceID; DWORD ProcessId; __asm mov ServiceID,eax; ProcessId = (DWORD)PsGetCurrentProcessId(); GetProcessName(ProcessName); KeRaiseIrql(HIGH_LEVEL, &OldIrql); // 提升当前的 IRQL 级别防止被中断 switch ( ServiceID ) { case 0x20: DbgPrint(\"NEWINT2E: ProcessName: %s; ProcessID: %d; Native Api: NtCreateFile() \\n\",ProcessName,ProcessId); break; case 0x2b: DbgPrint(\"NEWINT2E: ProcessName: %s; ProcessID: %d; Native Api: NtCreateSection() \\n\",ProcessName,ProcessId); break; case 0x30: DbgPrint(\"NEWINT2E: ProcessName: %s; ProcessID: %d; Native Api: NtCreateToken() \\n\",ProcessName,ProcessId); break; } KeLowerIrql(OldIrql); //恢复原始 IRQL } __declspec(naked) NewInt2eService() { __asm{ pushad pushfd push fs mov bx,0x30 mov fs,bx push ds push es sti call NativeApiCall; // 调用记录函数 cli pop es pop ds pop fs popfd popad jmp OldInt2eService; //跳到原始 INT 2E 继续工作 } } VOID InstallNewInt2e() { IDTR idtr; PIDTENTRY OIdt; PIDTENTRY NIdt; //得到 IDTR 中得段界限与基地址 __asm { sidt idtr; } //得到IDT基地址 OIdt = (PIDTENTRY)MAKELONG(idtr.LowIDTbase,idtr.HiIDTbase); //保存原来的 INT 2E 服务例程 OldInt2eService = MAKELONG(OIdt[SYSTEMCALL].OffsetLow,OIdt[SYSTEMCALL].OffsetHigh); NIdt = &(OIdt[SYSTEMCALL]); __asm { cli lea eax,NewInt2eService; //得到新的 INT 2E 服务例程偏移 mov ebx, NIdt; mov [ebx],ax; //INT 2E 服务例程低 16 位 shr eax,16 //INT 2E 服务例程高 16 位 mov [ebx+6],ax; lidt idtr //装入新的 IDT sti } } VOID UninstallNewInt2e() { IDTR idtr; PIDTENTRY OIdt; PIDTENTRY NIdt; __asm { sidt idtr; } OIdt = (PIDTENTRY)MAKELONG(idtr.LowIDTbase,idtr.HiIDTbase); NIdt = &(OIdt[SYSTEMCALL]); _asm { cli lea eax,OldInt2eService; mov ebx, NIdt; mov [ebx],ax; shr eax,16 mov [ebx+6],ax; lidt idtr sti } } // 驱动入口 NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { UNICODE_STRING nameString, linkString; PDEVICE_OBJECT deviceObject; NTSTATUS status; HANDLE hHandle; int i; //卸载驱动 DriverObject->DriverUnload = DriverUnload; //建立设备 RtlInitUnicodeString( &nameString, L\"\\\\Device\\\\WssHookInt2e\" ); status = IoCreateDevice( DriverObject, 0, &nameString, FILE_DEVICE_UNKNOWN, 0, TRUE, &deviceObject ); if (!NT_SUCCESS( status )) return status; RtlInitUnicodeString( &linkString, L\"\\\\DosDevices\\\\WssHookInt2e\" ); status = IoCreateSymbolicLink (&linkString, &nameString); if (!NT_SUCCESS( status )) { IoDeleteDevice (DriverObject->DeviceObject); return status; } for ( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) { DriverObject->MajorFunction = MydrvDispatch; } DriverObject->DriverUnload = DriverUnload; ProcessNameOffset = GetProcessNameOffset(); InstallNewInt2e(); return STATUS_SUCCESS; } //处理设备对象操作 static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0L; IoCompleteRequest( Irp, 0 ); return Irp->IoStatus.Status; } VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject) { UNICODE_STRING nameString; UninstallNewInt2e(); RtlInitUnicodeString( &nameString, L\"\\\\DosDevices\\\\WssHookInt2e\" ); IoDeleteSymbolicLink(&nameString); IoDeleteDevice(pDriverObject->DeviceObject); return; } ULONG GetProcessNameOffset() { PEPROCESS curproc; int i; curproc = PsGetCurrentProcess(); // // Scan for 12KB, hopping the KPEB never grows that big! // for( i = 0; i < 3*PAGE_SIZE; i++ ) { if( !strncmp( SYSNAME, (PCHAR) curproc + i, strlen(SYSNAME) )) { return i; } } // // Name not found - oh, well // return 0; } VOID GetProcessName( PCHAR Name ) { PEPROCESS curproc; char *nameptr; ULONG i; if( ProcessNameOffset ) { curproc = PsGetCurrentProcess(); nameptr = (PCHAR) curproc + ProcessNameOffset; strncpy( Name, nameptr, 16 ); } else { strcpy( Name, \"???\"); } } 3、 HOOK PE 方法 这种方法对于拦截、分析其他内核驱动的函数调用来说用的比较多。原理 是根据替换 PE 格式导出表中的相应函数来实现的。此方法中需要用到一些小 技巧。如内核模式并没有直接提供类似应用层的 GetModuleHandl()、GetProcAddress() 等函数来获得模块的地址。那么我们就需要自己来编写,这 里用到了一个未公开的函数与结构。ZwQuerySystemInformation 与 SYSTEM_MODULE_INFORMATION 来实现得到模块的基地址。这样我们就可以根据 PE 格式来枚举导出表中的函数来替换了。但这又引出了一个问题,那就是从 WINDOWS 2000 后内核数据的页属性都是只读的,不能更改。内核模式也没有 提供类似应用层的 VirtualProtectEx() 等函数来修改页面属性。那么也需要 我们自己来编写。因为我们是在内核模式所以我们可以通过修改 cr0 寄存器的 的写保护位来达到我们的目的。这样我们所期望的拦截内核模式函数的功能便 得以实现。此方法需要你对 PE 格式有一定的基础。下面的程序演示了这一过程。 /***************************************************************** 文件名 : WssHookPE.c 描述 : 拦截内核函数 作者 : sinister 最后修改日期 : 2002-11-02 *****************************************************************/ #include \"ntddk.h\" #include \"windef.h\" typedef enum _SYSTEM_INFORMATION_CLASS { SystemBasicInformation, SystemProcessorInformation, SystemPerformanceInformation, SystemTimeOfDayInformation, SystemNotImplemented1, SystemProcessesAndThreadsInformation, SystemCallCounts, SystemConfigurationInformation, SystemProcessorTimes, SystemGlobalFlag, SystemNotImplemented2, SystemModuleInformation, SystemLockInformation, SystemNotImplemented3, SystemNotImplemented4, SystemNotImplemented5, SystemHandleInformation, SystemObjectInformation, SystemPagefileInformation, SystemInstructionEmulationCounts, SystemInvalidInfoClass1, SystemCacheInformation, SystemPoolTagInformation, SystemProcessorStatistics, SystemDpcInformation, SystemNotImplemented6, SystemLoadImage, SystemUnloadImage, SystemTimeAdjustment, SystemNotImplemented7, SystemNotImplemented8, SystemNotImplemented9, SystemCrashDumpInformation, SystemExceptionInformation, SystemCrashDumpStateInformation, SystemKernelDebuggerInformation, SystemContextSwitchInformation, SystemRegistryQuotaInformation, SystemLoadAndCallImage, SystemPrioritySeparation, SystemNotImplemented10, SystemNotImplemented11, SystemInvalidInfoClass2, SystemInvalidInfoClass3, SystemTimeZoneInformation, SystemLookasideInformation, SystemSetTimeSlipEvent, SystemCreateSession, SystemDeleteSession, SystemInvalidInfoClass4, SystemRangeStartInformation, SystemVerifierInformation, SystemAddVerifier, SystemSessionProcessesInformation } SYSTEM_INFORMATION_CLASS; typedef struct tagSYSTEM_MODULE_INFORMATION { ULONG Reserved[2]; PVOID Base; ULONG Size; ULONG Flags; USHORT Index; USHORT Unknown; USHORT LoadCount; USHORT ModuleNameOffset; CHAR ImageName[256]; } SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION; #define IMAGE_DOS_SIGNATURE 0x5A4D // MZ #define IMAGE_NT_SIGNATURE 0x50450000 // PE00 #define IMAGE_NT_SIGNATURE1 0x00004550 // 00EP typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header WORD e_magic; // Magic number WORD e_cblp; // Bytes on last page of file WORD e_cp; // Pages in file WORD e_crlc; // Relocations WORD e_cparhdr; // Size of header in paragraphs WORD e_minalloc; // Minimum extra paragraphs needed WORD e_maxalloc; // Maximum extra paragraphs needed WORD e_ss; // Initial (relative) SS value WORD e_sp; // Initial SP value WORD e_csum; // Checksum WORD e_ip; // Initial IP value WORD e_cs; // Initial (relative) CS value WORD e_lfarlc; // File address of relocation table WORD e_ovno; // Overlay number WORD e_res[4]; // Reserved words WORD e_oemid; // OEM identifier (for e_oeminfo) WORD e_oeminfo; // OEM information; e_oemid specific WORD e_res2[10]; // Reserved words LONG e_lfanew; // File address of new exe header } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; typedef struct _IMAGE_FILE_HEADER { WORD Machine; WORD NumberOfSections; DWORD TimeDateStamp; DWORD PointerToSymbolTable; DWORD NumberOfSymbols; WORD SizeOfOptionalHeader; WORD Characteristics; } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; typedef struct _IMAGE_DATA_DIRECTORY { DWORD VirtualAddress; DWORD Size; } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 // // Optional header format. // typedef struct _IMAGE_OPTIONAL_HEADER { // // Standard fields. // WORD Magic; BYTE MajorLinkerVersion; BYTE MinorLinkerVersion; DWORD SizeOfCode; DWORD SizeOfInitializedData; DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; DWORD BaseOfData; // // NT additional fields. // DWORD ImageBase; DWORD SectionAlignment; DWORD FileAlignment; WORD MajorOperatingSystemVersion; WORD MinorOperatingSystemVersion; WORD MajorImageVersion; WORD MinorImageVersion; WORD MajorSubsystemVersion; WORD MinorSubsystemVersion; DWORD Win32VersionValue; DWORD SizeOfImage; DWORD SizeOfHeaders; DWORD CheckSum; WORD Subsystem; WORD DllCharacteristics; DWORD SizeOfStackReserve; DWORD SizeOfStackCommit; DWORD SizeOfHeapReserve; DWORD SizeOfHeapCommit; DWORD LoaderFlags; DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; typedef struct _IMAGE_NT_HEADERS { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER32 OptionalHeader; } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS; typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS; // // Section header format. // #define IMAGE_SIZEOF_SHORT_NAME 8 typedef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; union { DWORD PhysicalAddress; DWORD VirtualSize; } Misc; DWORD VirtualAddress; DWORD SizeOfRawData; DWORD PointerToRawData; DWORD PointerToRelocations; DWORD PointerToLinenumbers; WORD NumberOfRelocations; WORD NumberOfLinenumbers; DWORD Characteristics; } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; #define IMAGE_SIZEOF_SECTION_HEADER 40 // // Export Format // typedef struct _IMAGE_EXPORT_DIRECTORY { DWORD Characteristics; DWORD TimeDateStamp; WORD MajorVersion; WORD MinorVersion; DWORD Name; DWORD Base; DWORD NumberOfFunctions; DWORD NumberOfNames; DWORD AddressOfFunctions; // RVA from base of image DWORD AddressOfNames; // RVA from base of image DWORD AddressOfNameOrdinals; // RVA from base of image } IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY; #define BASEADDRLEN 10 NTSYSAPI NTSTATUS NTAPI ZwQuerySystemInformation( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, IN OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength OPTIONAL ); typedef NTSTATUS (* ZWCREATEFILE)( OUT PHANDLE FileHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PLARGE_INTEGER AllocationSize OPTIONAL, IN ULONG FileAttributes, IN ULONG ShareAccess, IN ULONG CreateDisposition, IN ULONG CreateOptions, IN PVOID EaBuffer OPTIONAL, IN ULONG EaLength ); ZWCREATEFILE OldZwCreateFile; static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject); VOID DisableWriteProtect( PULONG pOldAttr); VOID EnableWriteProtect( ULONG ulOldAttr ); FARPROC HookFunction( PCHAR pModuleBase, PCHAR pHookName, FARPROC pHookFunc ); NTSTATUS HookNtCreateFile( OUT PHANDLE FileHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PLARGE_INTEGER AllocationSize OPTIONAL, IN ULONG FileAttributes, IN ULONG ShareAccess, IN ULONG CreateDisposition, IN ULONG CreateOptions, IN PVOID EaBuffer OPTIONAL, IN ULONG EaLength ); PCHAR MyGetModuleBaseAddress( PCHAR pModuleName ) { PSYSTEM_MODULE_INFORMATION pSysModule; ULONG uReturn; ULONG uCount; PCHAR pBuffer = NULL; PCHAR pName = NULL; NTSTATUS status; UINT ui; CHAR szBuffer[BASEADDRLEN]; PCHAR pBaseAddress; status = ZwQuerySystemInformation( SystemModuleInformation, szBuffer, BASEADDRLEN, &uReturn ); pBuffer = ( PCHAR )ExAllocatePool( NonPagedPool, uReturn ); if ( pBuffer ) { status = ZwQuerySystemInformation( SystemModuleInformation, pBuffer, uReturn, &uReturn ); if( status == STATUS_SUCCESS ) { uCount = ( ULONG )*( ( ULONG * )pBuffer ); pSysModule = ( PSYSTEM_MODULE_INFORMATION )( pBuffer + sizeof( ULONG ) ); for ( ui = 0; ui < uCount; ui++ ) { pName = MyStrchr( pSysModule->ImageName, \'\\\\\' ); if ( !pName ) { pName = pSysModule->ImageName; } else { pName++; } if( !_stricmp( pName, pModuleName ) ) { pBaseAddress = ( PCHAR )pSysModule->Base; ExFreePool( pBuffer ); return pBaseAddress; } pSysModule ++; } } ExFreePool( pBuffer ); } return NULL; } FARPROC HookFunction( PCHAR pModuleBase, PCHAR HookFunName, FARPROC HookFun ) { PIMAGE_DOS_HEADER pDosHdr; PIMAGE_NT_HEADERS pNtHdr; PIMAGE_SECTION_HEADER pSecHdr; PIMAGE_EXPORT_DIRECTORY pExtDir; UINT ui,uj; PCHAR FunName; DWORD *dwAddrName; DWORD *dwAddrFun; FARPROC pOldFun; ULONG uAttrib; pDosHdr = ( PIMAGE_DOS_HEADER )pModuleBase; if ( IMAGE_DOS_SIGNATURE == pDosHdr->e_magic ) { pNtHdr = ( PIMAGE_NT_HEADERS )( pModuleBase + pDosHdr->e_lfanew ); if( IMAGE_NT_SIGNATURE == pNtHdr->Signature || IMAGE_NT_SIGNATURE1 == pNtHdr->Signature ) { pSecHdr = ( PIMAGE_SECTION_HEADER )( pModuleBase + pDosHdr->e_lfanew + sizeof( IMAGE_NT_HEADERS ) ); for ( ui = 0; ui < (UINT)pNtHdr->FileHeader.NumberOfSections; ui++ ) { if ( !strcmp( pSecHdr->Name, \".edata\" ) ) { pExtDir = ( PIMAGE_EXPORT_DIRECTORY )( pModuleBase + pSecHdr->VirtualAddress ); dwAddrName = ( PDWORD )(pModuleBase + pExtDir->AddressOfNames ); dwAddrFun = ( PDWORD )(pModuleBase + pExtDir->AddressOfFunctions ); for ( uj = 0; uj < (UINT)pExtDir->NumberOfFunctions; uj++ ) { FunName = pModuleBase + *dwAddrName; if( !strcmp( FunName, HookFunName ) ) { DbgPrint(\" HOOK %s()\\n\",FunName); DisableWriteProtect( &uAttrib ); pOldFun = ( FARPROC )( pModuleBase + *dwAddrFun ); *dwAddrFun = ( PCHAR )HookFun - pModuleBase; EnableWriteProtect( uAttrib ); return pOldFun; } dwAddrName ++; dwAddrFun ++; } } pSecHdr++; } } } return NULL; } // 驱动入口 NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { UNICODE_STRING nameString, linkString; PDEVICE_OBJECT deviceObject; NTSTATUS status; HANDLE hHandle; PCHAR pModuleAddress; int i; //卸载驱动 DriverObject->DriverUnload = DriverUnload; //建立设备 RtlInitUnicodeString( &nameString, L\"\\\\Device\\\\WssHookPE\" ); status = IoCreateDevice( DriverObject, 0, &nameString, FILE_DEVICE_UNKNOWN, 0, TRUE, &deviceObject ); if (!NT_SUCCESS( status )) return status; RtlInitUnicodeString( &linkString, L\"\\\\DosDevices\\\\WssHookPE\" ); status = IoCreateSymbolicLink (&linkString, &nameString); if (!NT_SUCCESS( status )) { IoDeleteDevice (DriverObject->DeviceObject); return status; } pModuleAddress = MyGetModuleBaseAddress(\"ntoskrnl.exe\"); if ( pModuleAddress == NULL) { DbgPrint(\" MyGetModuleBaseAddress()\\n\"); return 0; } OldZwCreateFile = (ZWCREATEFILE)HookFunction( pModuleAddress, \"ZwCreateFile\",(ZWCREATEFILE)HookNtCreateFile); if ( OldZwCreateFile == NULL) { DbgPrint(\" HOOK FAILED\\n\"); return 0; } DbgPrint(\"HOOK SUCCEED\\n\"); for ( i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) { DriverObject->MajorFunction = MydrvDispatch; } DriverObject->DriverUnload = DriverUnload; return STATUS_SUCCESS; } //处理设备对象操作 static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0L; IoCompleteRequest( Irp, 0 ); return Irp->IoStatus.Status; } VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject) { UNICODE_STRING nameString; PCHAR pModuleAddress; pModuleAddress = MyGetModuleBaseAddress(\"ntoskrnl.exe\"); if ( pModuleAddress == NULL) { DbgPrint(\"MyGetModuleBaseAddress()\\n\"); return ; } OldZwCreateFile = (ZWCREATEFILE)HookFunction( pModuleAddress, \"ZwCreateFile\",(ZWCREATEFILE)OldZwCreateFile); if ( OldZwCreateFile == NULL) { DbgPrint(\" UNHOOK FAILED!\\n\"); return ; } DbgPrint(\"UNHOOK SUCCEED\\n\"); RtlInitUnicodeString( &nameString, L\"\\\\DosDevices\\\\WssHookPE\" ); IoDeleteSymbolicLink(&nameString); IoDeleteDevice(pDriverObject->DeviceObject); return; } NTSTATUS HookNtCreateFile( OUT PHANDLE FileHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PLARGE_INTEGER AllocationSize OPTIONAL, IN ULONG FileAttributes, IN ULONG ShareAccess, IN ULONG CreateDisposition, IN ULONG CreateOptions, IN PVOID EaBuffer OPTIONAL, IN ULONG EaLength ) { NTSTATUS status; DbgPrint(\"Hook ZwCreateFile()\\n\"); status = ((ZWCREATEFILE)(OldZwCreateFile))( FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, AllocationSize, FileAttributes, ShareAccess, CreateDisposition, CreateOptions, EaBuffer, EaLength ); return status; } VOID DisableWriteProtect( PULONG pOldAttr) { ULONG uAttr; _asm { push eax; mov eax, cr0; mov uAttr, eax; and eax, 0FFFEFFFFh; // CR0 16 BIT = 0 mov cr0, eax; pop eax; }; *pOldAttr = uAttr; //保存原有的 CRO 属性 } VOID EnableWriteProtect( ULONG uOldAttr ) { _asm { push eax; mov eax, uOldAttr; //恢复原有 CR0 属性 mov cr0, eax; pop eax; }; } 关于我们: WSS(Whitecell Security Systems),一个非营利性民间技术组织,致力于各种系统安全技术的研究。坚持传统的hacker精神,追求技术的精纯。 WSS 主页:http://www.whitecell.org/ |
|
|
沙发#
发布于:2008-02-02 00:17
Re:hook ntoskrnl.exe的奇怪现象(很久不说\
是这样的名字的导出索引号和导出表中的顺序号不是对应的必须通过 AddressOfNameOrdinals 取出名字的索引号,才能从导出表中获取正确的地址。 |
|
板凳#
发布于:2005-04-29 16:30
导出表通过ord来连接的。
PVOID HookFunction(PVOID pBaseAddress, PCSTR Name, PVOID InFunc, ULONG* OutFunc) { PIMAGE_DOS_HEADER pDosHeader = NULL; PIMAGE_NT_HEADERS pNtHeader = NULL; PIMAGE_DATA_DIRECTORY pDirectory = NULL; PIMAGE_EXPORT_DIRECTORY pExports = NULL; ULONG nSize, Address, i; PULONG pFunctions = NULL; PSHORT pOrdinals = NULL; PULONG pNames = NULL; PVOID pFunction = NULL; ULONG Ordinal = 0; if(pBaseAddress == NULL) return NULL; //Pe pDosHeader = (PIMAGE_DOS_HEADER)pBaseAddress; pNtHeader = (PIMAGE_NT_HEADERS)((PCHAR)pBaseAddress + pDosHeader->e_lfanew); pDirectory = pNtHeader->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_EXPORT; nSize = pDirectory->Size; Address = pDirectory->VirtualAddress; pExports = (PIMAGE_EXPORT_DIRECTORY)((PCHAR)pBaseAddress + Address); //export directory pFunctions = (PULONG)((PCHAR)pBaseAddress + pExports->AddressOfFunctions); pOrdinals = (PSHORT)((PCHAR)pBaseAddress + pExports->AddressOfNameOrdinals); pNames = (PULONG)((PCHAR)pBaseAddress + pExports->AddressOfNames); for(i = 0; i < pExports->NumberOfNames; i++) { Ordinal = pOrdinals; if(pFunctions[Ordinal] < Address || pFunctions[Ordinal] >= Address + nSize) { if(strcmp((PSTR)((PCHAR)pBaseAddress + pNames), Name) == 0) { pFunction = (PCHAR)pBaseAddress + pFunctions[Ordinal]; *OutFunc = (ULONG)pFunction; DisableProtection(); pFunctions[Ordinal] = (ULONG)((ULONG)InFunc - (ULONG)pBaseAddress); EnableProtection(); break; } } } return pFunction; } |
|
|
地板#
发布于:2005-04-26 14:15
请问楼上的老大,你是怎样解决这个问题的啊?
还有你能帮忙看看下面的帖字吗 http://www.driverdevelop.com/forum/html_91174.html?1114496060 |
|
地下室#
发布于:2005-04-26 14:05
不是每个导出函数都有名字,有的只有序号 有道理,我已经调试通过了。 |
|
|
5楼#
发布于:2005-04-07 14:30
有两个疑问 不是每个导出函数都有名字,有的只有序号 名字的排列次序跟对应函数的排列次序不一样,但有个对应表可以查找 为了使效率最高,一般把调用最频繁的函数排在前面,这是由编译器决定的 |
|
|
6楼#
发布于:2005-04-07 14:09
你可以到
http://soft.0zones.com/ 去下载idapro4.7 |
|
|
7楼#
发布于:2005-04-07 14:07
我的idapro是4.7,从驱网下载的。
函数名称的偏移和函数地址的偏移都在一个数组里,可以查的。 |
|
|
8楼#
发布于:2005-04-07 10:02
有两个疑问
(1)是不是每个导出函数都有名字,这个函数能这么写吗? (2)就算有都有名字,也不见得名字的排列次序跟对应函数的排列次序一样,能这么查找吗? _____________________________________________ 请bmyyyud 和idapro5老大其他熟悉PE的兄弟抽宝贵时间帮忙解惑一下,偶对PE是一窍不通. 另:idapro5,你的idapro5软件能够共享一下吗?偶的才version :4。3 |
|
|
9楼#
发布于:2005-04-04 16:39
这么说来,等我再去试验一下.
|
|
|
10楼#
发布于:2005-04-04 14:47
你得到ntoskrnl.exe module的基址是多少
看我的垃圾贴中的\"注释\" http://www.driverdevelop.com/forum/html_89958.html?1112596992 加载基址在xp中和w2k中不一样了 |
|
|
11楼#
发布于:2005-04-04 13:18
在osr找的,因为偶只需要修改IAT而不hook,这几个MmGetSystemRoutineAddress还满好用的。不知道你用过没有?
Re: LoadLibrary & GetProcAddress in KM From: Prasad Dabak <xxx@yahoo.com> Date: Tue, 13 Mar 2001 21:53:40 -0800 (PST) Hello, If you are using Windows 2000, you can dynamically get the address of any NTOSKRNL.EXE or HAL.DLL function using MmGetSystemRoutineAddress function. The function is prototyped in NTDDK.H file. The only parameter which it takes is PUNICODE_STRING pointing to name of the routine. Note, however, it works only for NTOSKRNL.EXE or HAL.DLL routines. The reason is: the code for MmGetSystemRoutineAddress enumerates all the loaded modules in the system and for the module names matching NTOSKRNL/HAL it walks the import tables to locate the address of function. I dont understand, why this function is restricted only to NTOSKRNL/HAL modules. It can always be extended to support any module by adding one more parameter to this function viz. ModuleName. I hope Microsoft will add support for this in future versions of the OS. Alternatively, you can look at the Gary Nebbett\'s \"Windows NT/200 Native API reference\" book page 433, where he has written a kernel mode equivalent of GetProcAddress. Hope this helps. -Prasad --- Anders Fogh wrote: > Hello Matteo, > > As stated in a previous reply there is no documented > and well behaved > way of doing this. If you wanna embelish on hacks, > Dmitri Lehman wrote > a fairly good article which contains a working > solution. I advice that > you proceed with caution using this code - I did > find a few minor bugs > in it. > > http://www.wdj.com/archive/1104/feature.html > > Regards, > Anders Fogh > > > Tuesday, March 13, 2001, 5:53:12 AM, you wrote: > > MP> Is there an equivalent of the Win32 functions: > LoadLibrary and GetProcAddress in kernel mode ? > > MP> Thanks > MP> Matteo > > > MP> --- > xxx@flaffer.com > > > > -- > Best regards, > Anders > mailto:xxx@flaffer.com > > > > xxx@yahoo.com ===== Prasad S. Dabak Director of Engineering, Windows NT/2000 Division Cybermedia Software Private Limited http://www.cybermedia.co.in Co-author of the book \"Undocumented Windows NT\" ISBN 0764545698 __________________________________________________ Do You Yahoo!? Yahoo! Auctions - Buy the things you want at great prices. http://auctions.yahoo.com/ |
|
|
12楼#
发布于:2005-04-04 12:38
我也在好几台机器上试验过。
可能还是通过service table来hook才行。 |
|
|
13楼#
发布于:2005-04-04 09:33
我这里的情况是ZwCreatefile .ZwReadfile 。。这些函数还对应的上。但是其他函数比如KeWaitForsignleObject.或者Ex系列的。Io系列的在ntoskernl.exe 中简直一团是糨糊。
难道这些函数的实际Export_TABLE 不是在ntoskernl.exe 中吗? 真是太奇怪了! |
|
|
14楼#
发布于:2005-04-04 09:26
我到现在还是不明白。
|
|
|
15楼#
发布于:2005-04-04 01:04
真是太奇怪了。找到原因了吗?说来听听,好好学习一下。
|
|
|
16楼#
发布于:2005-03-06 18:14
自己顶一下. :D
|
|
|
17楼#
发布于:2005-03-06 18:12
大家注意看我下断点的地方(有头像):
FARPROC HookFunction( PCHAR pModuleBase, PCHAR HookFunName, FARPROC HookFun ) { PIMAGE_DOS_HEADER pDosHdr; PIMAGE_NT_HEADERS pNtHdr; PIMAGE_SECTION_HEADER pSecHdr; PIMAGE_EXPORT_DIRECTORY pExtDir; UINT ui,uj; PCHAR FunName; DWORD *dwAddrName; DWORD *dwAddrFun; FARPROC pOldFun; ULONG uAttrib; pDosHdr = ( PIMAGE_DOS_HEADER )pModuleBase; if ( IMAGE_DOS_SIGNATURE == pDosHdr->e_magic ) { pNtHdr = ( PIMAGE_NT_HEADERS )( pModuleBase + pDosHdr->e_lfanew ); if( IMAGE_NT_SIGNATURE == pNtHdr->Signature || IMAGE_NT_SIGNATURE1 == pNtHdr->Signature ) { pSecHdr = ( PIMAGE_SECTION_HEADER )( pModuleBase + pDosHdr->e_lfanew + sizeof( IMAGE_NT_HEADERS ) ); for ( ui = 0; ui < (UINT)pNtHdr->FileHeader.NumberOfSections; ui++ ) { if ( !strcmp( pSecHdr->Name, \".edata\" ) ) { pExtDir = ( PIMAGE_EXPORT_DIRECTORY )( pModuleBase + pSecHdr->VirtualAddress ); dwAddrName = ( PDWORD )(pModuleBase + pExtDir->AddressOfNames ); dwAddrFun = ( PDWORD )(pModuleBase + pExtDir->AddressOfFunctions ); for ( uj = 0; uj < (UINT)pExtDir->NumberOfFunctions; uj++ ) { FunName = pModuleBase + *dwAddrName; //if( !strcmp( FunName, HookFunName ) ) :D :D :D :D :D :D :D :D :D :D上句话被我注释掉了 { DbgPrint(\" HOOK %s()\\n\",FunName); DisableWriteProtect( &uAttrib ); pOldFun = ( FARPROC )( pModuleBase + *dwAddrFun ); //*dwAddrFun = ( PCHAR )HookFun - pModuleBase; :D :D :D :D :D :D :D :D :D :D上句话被我注释掉了 EnableWriteProtect( uAttrib ); :D :D :D :D :D :D :D :D :D :D我在此下断点,并且使用softice察看FunName和pOldFun,发现pOldFun的真正函数名称永远不是FunName. ---太---奇---怪---了---. :D :D :D :D :D :D :D :D :D //return pOldFun; :D :D :D :D :D :D :D :D :D :D上句话被我注释掉了 } dwAddrName ++; dwAddrFun ++; } } pSecHdr++; } } } return NULL; } :D |
|
|