首页
社区
课程
招聘
hook ntoskrnl.exe的奇怪现象(很久不说"奇怪"两个字了
发表于: 2005-4-4 09:58 7563

hook ntoskrnl.exe的奇怪现象(很久不说"奇怪"两个字了

2005-4-4 09:58
7563
通过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/

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (9)
雪    币: 228
活跃值: (119)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
2
大家注意看我下断点的地方(有头像):

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 );
         我在此下断点,并且使用softice察看FunName和pOldFun,发现pOldFun的真正函数名称永远不是FunName.
---太---奇---怪---了---.
         
//return pOldFun;
         上句话被我注释掉了
}

dwAddrName ++;
dwAddrFun ++;
}
}

pSecHdr++;
}
}
}

return NULL;
}

2005-4-4 10:00
0
雪    币: 228
活跃值: (119)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
我这里的情况是ZwCreatefile .ZwReadfile 。。这些函数还对应的上。但是其他函数比如KeWaitForsignleObject.或者Ex系列的。Io系列的在ntoskernl.exe 中简直一团是糨糊。

难道这些函数的实际Export_TABLE 不是在ntoskernl.exe 中吗?

真是太奇怪了!
2005-4-4 10:02
0
雪    币: 221
活跃值: (55)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
没什么奇怪的,先顶一下再说
2005-4-4 11:33
0
雪    币: 228
活跃值: (119)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
呵呵是呀,osr上也没有人提出这个问题,够奇怪的,不过偶只是想隐藏IAT,偶发现一个大老的另外一种方法用一个函数MmGetSystemRoutineAddress就搞定相当于win32 API的GetProcAddress,不过它只能对付hal.dll和ntoskrnl.exe 中的函数。正好。偶也只需要这两个中的函数,MmGetSystemRoutineAddress用免得麻烦了。

不过这个问题还是个问题,希望知道的朋友告诉偶,毕竟这里的都是PE大虾聚餐的地方嘛。谢谢
2005-4-4 13:02
0
雪    币: 1540
活跃值: (2807)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
要用C语言的模式来编译吧,加上Extern "C"试试看

最初由 machoman 发布
呵呵是呀,osr上也没有人提出这个问题,够奇怪的,不过偶只是想隐藏IAT,偶发现一个大老的另外一种方法用一个函数MmGetSystemRoutineAddress就搞定相当于win32 API的GetProcAddress,不过它只能对付hal.dll和ntoskrnl.exe 中的函数。正好。偶也只需要这两个中的函数,MmGetSystemRoutineAddress用免得麻烦了。

不过这个问题还是个问题,希望知道的朋友告诉偶,毕竟这里的都是PE大虾聚餐的地方嘛。谢谢
2005-4-4 15:06
0
雪    币: 1540
活跃值: (2807)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
最初由 machoman 发布
呵呵是呀,osr上也没有人提出这个问题,够奇怪的,不过偶只是想隐藏IAT,偶发现一个大老的另外一种方法用一个函数MmGetSystemRoutineAddress就搞定相当于win32 API的GetProcAddress,不过它只能对付hal.dll和ntoskrnl.exe 中的函数。正好。偶也只需要这两个中的函数,MmGetSystemRoutineAddress用免得麻烦了。

不过这个问题还是个问题,希望知道的朋友告诉偶,毕竟这里的都是PE大虾聚餐的地方嘛。谢谢
2005-4-4 15:19
0
雪    币: 216
活跃值: (370)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
8
开玩笑,又不是每个导出函数都有名字,这个函数能这么写吗?再说了,就算有都有名字,也不见得名字的排列次序跟对应函数的排列次序一样,能这么查找吗?
2005-4-5 10:01
0
雪    币: 228
活跃值: (119)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
9
最初由 limee 发布


http://www.osr.com
要用代理才能上。里边的邮件列表是个宝库呀。
2005-4-5 10:35
0
雪    币: 228
活跃值: (119)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
10
最初由 goldenegg 发布
开玩笑,又不是每个导出函数都有名字,这个函数能这么写吗?再说了,就算有都有名字,也不见得名字的排列次序跟对应函数的排列次序一样,能这么查找吗?

老大发话了。有道理,一语惊醒梦中人呀!
2005-4-5 10:36
0
游客
登录 | 注册 方可回帖
返回
//