0x00
最近需要实现一个功能,在驱动中创建文件的符号链接。搜了一圈,只能找到 mklink 命令, mklink 命令显然不能在内核调用。
因为大部分的系统调用最终都会调用到内核层的实现,所以整体思路就是搞清楚 mklink 的实现,找到对应的内核接口。
0x01
简单搜索了下系统目录,发现并没有 mklink 文件,因此怀疑 mklink 是 cmd 的内置命令。验证这个想法很简单,直接把 cmd 拖入 IDA,搜索相关字符串(mklink),果然:
双击条目,找到对应的符号再X下,就能找到相关的引用:
看到这个,一般的猜想就是 mklink 是命令名,eMkLink 是对应的命令处理函数。
我们可以验证一把。
使用 windbg 加载 cmd,根据 _MakeLinkStr 的偏移,也就是图一中的 401be8,计算出加载后的真实地址。对这个地址下一个读断点(windbg:ba r命令;gdb:watch命令),之后 F5。在 cmd 中输入 mklink,回车。我们就会发现断点被断下来了,断下的位置是 wcsicmp,也就是在字符串比较,那么只可能是在比较命令字符串,毕竟 cmd 中内置了很多命令,需要一个一个比较。
我们可以先 shift+f11 出来,到达 cmd 的领空,之后一直 f10,记得盯着 cmd 的输出,如果 cmd 有新的输出,那么就说明咱们走过了_。最终可以确定,eMkLink 就是 mklink 的命令处理函数。
0x02
进入 eMkLink 之后,我们跳过 stub 函数,到达 MakeLink 函数。从函数的实现来看除了验证参数之外,一共有以下的几个实现:
MakeSymLink
MakeHardLink
MakeJunction
对应着 mklink 的几个功能。因为这次我们要实现的功能是文件的符号链接,所以我们进入 MakeSymLink 函数。函数的实现很简单,调用了 CreateSymbolicLinkW 函数。从 msdn 上或者 windbg 上都能知道,这个函数从 kernel32(win7)中导出(因为家里的工作机是 win8.1,所以函数是从 kernelbase.dll 中导出的)。那么接着我们就需要开撸CreateSymbolicLinkW。
CreateSymbolicLinkW 的实现也很简单,主要做了路径转换,之后调用 NtCreateFile 与 NtFsControlFile。我们知道 ntdll 中的 Nt* 函数,最终对应 nt 中的 Zw* 函数,nt!Zw* 函数最终执行到 nt!Nt* 函数。
因此对于我们而言,到目前为止,我们已经知道了创建文件符号链接的整个过程,只要在驱动层调用 ZwCreateFile 与 ZwFsControlFile 即可。唯一需要确定的就是调用这两个函数的参数。
本着大家都要动手实践的原则,具体参数的赋值我就不给出了,只说明下关键的一个参数。
在 NtCreateFile 中,CreateOptions 包含了 FILE_OPEN_REPARSE_POINT 属性;在 NtFsControlFile 中,其FsControlCode 值为 FSCTL_SET_REPARSE_POINT。
另外还有一个神坑需要注意:NtFsControlFile 中的 InputBuffer 在末尾不能包含多余的0字节,否则会直接返回 错误。
0x03
重解析点的原理比较简单,有兴趣的可以翻阅 Ntfs 的源码,里面有相关的实现。
另外有部分博客讲的也很好,推荐下面这个博客 NTFS重解析点(Reparse Points)。