打开被独占的文件方法(一) -- 寻找打开文件的句柄 打开被独占的文件方法: 被占用文件操作三法 无疑我们中的很多人都会遇到需要读写被其它进程占用的文件的情况,比如说在编写backup 程序或是 trojan 的时候。能从系统中抽出 SAM 文件,或是读取其它某些用标准方法无法成功访问的文件显然是件不错的事情。比如说当用标志 dwShareMode = 0 打开文件时,其它进程就不能对它进行访问了。一个很好的例子就是网络寻呼机程序 Miranda。这个程序在自己工作的时候不允许别人打开自己的数据库。假设我们需要写一个这样的木马,它在感染机器后从数据库中窃走密码,然后删除自身,这个时候就需要解决这个问题。所以我决定写下这篇文章。文章篇幅不大,但里面的内容可能会对某些人有益。那我们就开始吧。 寻找打开文件的句柄 如果文件由某个进程打开,那么这个进程就拥有了它的句柄。在我第二篇关于API 拦截的文章里我讲解了如何搜索需要的句柄并用它打开进程,要访问已打开的文件,我们也可以使用这种方法。我们需要使用 ZwQuerySystemInformation 函数来枚举句柄,将每一个句柄都用 DuplicateHandle 进行复制,确定句柄属于那个文件(ZwQueryInformationFile),如果是要找的文件,就将句柄拷贝。 这些在理论上都讲得通,但在实践中会遇到两处难点。第一,在对打开的 named pipe(工作于block mode)的句柄调用 ZwQueryInformationFile 的时候,调用线程会等待pipe 中的消息,而pipe 中却可能没有消息,也就是说,调用 ZwQueryInformationFile 的线程实际上永久性地挂起了。所以命名文件的获取不用在挑选句柄的主线程中进行,可以启动独立的线程并设置一个 timeout 值来避免挂起。第二,在拷贝句柄后,两个句柄(我们进程的和打开文件进程的)将会指向同一个 FileObject,从而当前的输入输出模式、在文件中的位置以及其它与文件相关的信息就会由两个进程来共享。这时,甚至只是读取文件都会引起读取位置的改变,从而破坏了打开文件程序的正常运行。为了避免这种情形,我们需要需要停止占用文件进程的线程、保存当前位置、拷贝文件、恢复当前位置以及重新启动占用文件的进程。这种方法不能用于许多情形,比如要在运行的系统中拷贝注册表文件,用这种方法就不会成功。 我们先来试着实现对系统中所有已打开文件的句柄的枚举。为枚举句柄,每个句柄都由以下结构体描述: typedef struct _SYSTEM_HANDLE { ULONG uIdPro...