这题是个文件保护,在Hijack.sys保护C:\windows\system32\360safe.txt成功后把它删掉。
HijackFile.sys的关键代码VM过了,所以只能黑盒之。
刚开始我的虚拟机中C盘是FAT32,还得我转成NTFS的。
然后加载HijackFile.sys,结果蓝掉了...
查看了一下dump,在调用栈中发现了HijackFile.sys的踪迹,根据调用关系直接锁定ntfs.sys进行分析,也算意外收获。
其实就算没有这个意外,多检查一下基本也能发现它动手脚的地方,如果再参考一下sudami的《NTFS文件系统底层挖掘》的话,就更简单了。
检查Hook我用的是Windbg
lkd> !chkimg -d !ntfs
    f82fd55a-f82fd55e  5 bytes - Ntfs!NtfsCheckValidAttributeAccess
  [ 8b ff 55 8b ec:e9 07 89 e0 89 ]
    f82fe1fe-f82fe201  4 bytes - Ntfs!NtfsOpenAttributeInExistingFile+b (+0xca4)
  [ 1e c1 fd ff:3c 5f ec 89 ]
9 errors : !ntfs (f82fd55a-f82fe201)
再细看一下:
第一个钩子:
lkd> u NtfsCheckValidAttributeAccess
Ntfs!NtfsCheckValidAttributeAccess:
f82fd55a e90789e089      jmp     82105e66
f82fd55f 8b4508          mov     eax,dword ptr [ebp+8]
f82fd562 53              push    ebx
f82fd563 56              push    esi
f82fd564 0fb6700b        movzx   esi,byte ptr [eax+0Bh]
lkd> u 82105e66
82105e66 e9d509f973      jmp     f6096840
82105e6b 8bff            mov     edi,edi //可以借用这部分代码跳回去~~
82105e6d 55              push    ebp
82105e6e 8bec            mov     ebp,esp
82105e70 e9ea761f76      jmp     Ntfs!NtfsCheckValidAttributeAccess+0x5 (f82fd55f)
lkd> u f6096840 //这个就是Fake函数了,被VM过
HijackFile+0x1840:
f6096840 8bff            mov     edi,edi
f6096842 55              push    ebp
f6096843 8bec            mov     ebp,esp
第二个钩子:
lkd> u NtfsOpenAttributeInExistingFile
Ntfs!NtfsOpenAttributeInExistingFile:
f82fe1f3 68ac000000      push    0ACh
f82fe1f8 68f0252ff8      push    offset Ntfs!`string'+0x12c (f82f25f0)
f82fe1fd e83c5fec89      call    821c413e //被替换了,这里本应是call Ntfs!_SEH_prolog
f82fe202 8365dc00        and     dword ptr [ebp-24h],0
f82fe206 8b7510          mov     esi,dword ptr [ebp+10h]
lkd> u 821c413e
821c413e e9ed28ed73      jmp     HijackFile+0x1a30 (f6096a30)
821c4143 e9d8611176      jmp     Ntfs!_SEH_prolog (f82da320)

基本上就很明确了。这两个函数
调用NtfsCheckValidAttributeAccess的地方有NtfsOpenFcbById,NtFsOpenExistingPrefixFcb,NtfsOpenFile,NtfsCreateNewFile
NtfsOpenAttributeInExistingFile的地方有NtfsOpenFile,NtFsOpenExistingPrefixFcb,NtfsOpenFile

要打开存在的文件需要调用NtfsOpenFile,而这个函数里有这样两个钩子,所以文件无法打开。
因为不能对它的钩子做任何改动,所以方法无非是能绕就绕,绕不过就自己实现。
对于经常搞Hook的,想到的第一个方法就是以Hook绕过Hook。
对NtfsCheckValidAttributeAccess处的钩子,因为它已经是在函数头了,在这里已经无法再Hook,所以直接查找所有对NtfsCheckValidAttributeAccess的Call,也就是上面四个函数中,替换Call的地址到我们自己的函数中,然后执行覆盖掉的三句指令后再跳到NtfsCheckValidAttributeAccess+5处就可以了(注意看那个Pool的代码,也可以直接修正call到82105e6b,借用sudami的代码跳回去。。。).
对NtfsOpenAttributeInExistingFile处的钩子,因为采用的是替换Call的方法,而前面还有10个字节没有动,所以可以Hook在NtfsOpenAttributeInExistingFile头部,或者NtfsOpenAttributeInExistingFile+5的地方来跳过HijackFile.sys的钩子。
这种方法不难,写过Hook的基本都会,关键是需要得到几个NtfsXx函数的地址,本来自己找挺麻烦的,无非栈回溯而已。但是既然sudami已经帮我们找好了,为什么不用呢?看下面对部分数据的分析(f8844000是HijackFile.sys的加载基址):

代码:
kd> //从f8844000+5000+220处开始才是有用数据,前面是一个反汇编引擎LDasm用的表
f8849200  01010101 00010101 ffff4d09 0000b2f6
f8849210  00000000 00000000 00000000 00000000
f8849220  00000174 000039d8 00000000 f830f0eb //f830f0eb是NtfsOpenFile中call NtfsCreateFcb后的返回地址,可靠
f8849230  805427c4 00000000 f82fe6a0 f830f021 //[f8849230]=NtfsCreateNewFile,不可靠  ,f82fe6a0=NtfsOpenExistingPrefixFcb, f830f021=NtfsOpenFile
f8849240  f82fe1f3 00000000 00000001 00000001 //f82fe1f3=NtfsOpenAttributeInExistingFile
f8849250  00000000 8219cb08 00000000 00000000 //8219cb08指向一个结构,未明确
f8849260  8001003b 00000000 00000000 00000000 //8001003b是OldCr0
f8849270  00000000 00000000 00000000 00000000
kd> 
f8849280  00000001 00000000 82118da8 8209d050 //82118da8未发现有意义数据 , 8209d050未发现有意义数据
f8849290  8206d958 8218bc08 00000000 00000000 //两个FUNCTION_INFO指针
f88492a0  00000000 00000000 00000000 00000000
f88492b0  00000001 0000000f f82fe1fe 00000000 //f82fe1fe是NtfsOpenAttributeInExistingFile中被替换掉的call的位置,用于还原
f88492c0  00000000 00000000 00000000 00000000
f88492d0  00000000 00000000 00000000 00000000
f88492e0  00000000 00000000 00000000 00000000
f88492f0  00000000 00000000 00000000 00000000

[f8844000+5000+290]处的数据的意义
kd> dd 8206d958
8206d958  8211c7a8 f830491f f8845700 f830f0e6
8206d968  00000000 82136ec0 0a060004 20646156
kd> db 8211c7a8 //offset=0处是一个指针,指向加密后的函数名字符串(或者其它编码?)
8211c7a8  44 44 43 38 43 36 42 36-43 45 42 46 44 45 46 44  DDC8C6B6CEBFDEFD  //该字符串总和NtfsCreateFcb相对应
8211c7b8  38 36 34 45 33 36 44 41-32 44 38 36 33 33 44 33  864E36DA2D8633D3
kd> u f830491f //offset=4处是一个地址,指向NtfsCreateFcb
Ntfs!NtfsCreateFcb:
f830491f 6a60            push    60h
f8304921 68c03f2ff8      push    offset Ntfs!`string'+0x1cc (f82f3fc0)
f8304926 e8f559fdff      call    Ntfs!_SEH_prolog (f82da320)
kd> u f8845700 //offset=8处是一个地址,指向Fake函数的地址
HijackFile+0x1700:
f8845700 8bff            mov     edi,edi
f8845702 55              push    ebp
f8845703 8bec            mov     ebp,esp
f8845705 83ec28          sub     esp,28h
kd> u f830f0e6 //offset=0xC处是一个地址,指向Hook点的位置
Ntfs!NtfsOpenFile+0xee:
f830f0e6 e83458ffff      call    Ntfs!NtfsCreateFcb (f830491f)
f830f0eb 8bd8            mov     ebx,eax
f830f0ed 895db8          mov     dword ptr [ebp-48h],ebx
//offset=0x10处是一个标志,表明是否被Hook过
//offset=0x14处是一个指向同样结构的指针
从数据段里能分析出不少东西来~
尽管代码被VM过,但是数据没有,数据段前面是一个反汇编用的表,后面才是有用的数据。看来要WS的话还是连数据也加密了吧,用的时候再解。

方法二:因为知道盟主有一个山寨的ntfs.sys可以用,所以我就想劫持文件系统,不让相关调用走系统的ntfs.sys而走我们这个,这样原来的Hook就失效了。
不过本来文件系统这块就是我的弱项,很多东西还不熟悉,所以在如何挂载新ntfs时搞不下去了,后来偶然跟某同学聊天时得来灵感,于是演变成了这种方法,仍然是重加载ntfs.sys,不过这次是加载系统原版的ntfs.sys,作好重定位之后,直接替换ntfs的DriverObject中的所有MajorFuncion.
这样,所有发往ntfs的调用都不再走原来的ntfs.sys,而走我们重新加载的这个,可以无视ntfs内的任何Code Hook,可以直接在资源管理器中右键删除,当然编程的话用SHFileOperation 就行了.
详情见代码吧,其实主要就是两个函数,一个LoadPE,一个HookDispatchRoutine而已~
我实现上前面两种方法,如果宏观来看的话,也可以算是一种方法吧,代码见这里:


以下方法是YY的,未实现:
方法三:直接磁盘操作法。直接解析NTFS完成删除文件操作,然后刷新缓存。这个可以自己来或者借用一些成熟的ntfs代码来搞,比如ntfs-3g,盟主似乎用这种方法。这个要搞得chkdsk检查没有问题还是挺麻烦啊。
方法四:直接调用ntfs中的底层函数NtfsDeleteFile或发IRP到atapi.这个似乎也很麻烦,因为需要自己搞的东西太多了,所以只能YY一下

还有一个问题不知什么原因:
在我绕过Hook后,本来就应该没有什么阻碍了,文件也可以打开,但是如果保护成功后打开过360safe.txt,用DeleteFile(其实就是ZwSetInformationFile)删除文件就会失败(函数调用成功,但是并没有立刻消失,处于DELETE_PENDING状态),如果保护成功后没有打开过360safe.txt就可以删除成功并立刻消失。也是因为这个原因我的答案才一直推迟没交,因为确实不完美。后来发现不管打没打开过,直接右键(也就是SHFileOperation,FO_DELETE)都可以删除,这个问题困扰我很久,原因未知(莫非和CleanCount之类的计数有关?),路过的牛人指点一下。

水平有限,胡扯这么多,文件系统的知识还得恶补啊~~~
上传的附件 第5题答案.rar