VB小子玩转驱动程序(10):文件隐藏
作者:胡文亮
注1:本文只适合并针对初级的VB编程爱好者阅读,请所谓的“大牛”飘过。 注2:本文可能会有技术性错误,但是我尽可能保证本文的正确性。 注3:欢迎各位转载,转载最好注明出处和作者。
一般人都是有隐私的,而隐私自然是需要隐藏的。比如张三在外面包了个二奶,和二奶的照片自然要藏好。否则的话,被老婆看见了,老婆要和他离婚;被领导看见了,领导要让他辞职;被无赖看见了,就会被敲诈几桌酒菜钱。在现实中,藏点东西真的比较难,我记得小学时有次数学测验不及格,试卷藏了不到两天就被母亲找到了,结果把我批斗了半宿,还罚了一个月的零花钱(就这么点破事,值得么……)。不过在电脑里藏点东西还算比较容易,挂钩一个函数就可以了。 在Windows NT系统里,用户态用FindFirstFile和FindNextFile枚举文件或者是直接用ntdll.dll中的ZwQueryDirectoryFile,最终会用到SSDT上的NtQueryDirectoryFile。挂钩这个函数即可解决问题,首先看看NtQueryDirectoryFile怎么工作的(转载自华夏黑客同盟): NtQueryDirectoryFile原型:
NTSTATUS 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 FileInformationLength,
IN FILE_INFORMATION_CLASS FileInformationClass,
IN BOOLEAN ReturnSingleEntry,
IN PUNICODE_STRING FileName OPTIONAL,
IN BOOLEAN RestartScan
);
对我们来说重要的参数是FileHandle,FileInformation和FileInformationClass。FileHandle是从NtOpenFile获得的目录对象句柄。FileInformation是一个指针,指向函数要写入需要的数据的已分配内存。FileInformationClass决定写入FileImformation的记录的类型。
FileInformationClass是一个变化的枚举类型,我们只需要其中4个值来枚举目录内容: #define FileDirectoryInformation 1
#define FileFullDirectoryInformation 2
#define FileBothDirectoryInformation 3
#define FileNamesInformation 12
要写入FileInformation的FileDirecoryInformation记录的结构:
typedef struct _FILE_DIRECTORY_INFORMATION {
ULONG NextEntryOffset;
ULONG Unknown;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER EndOfFile;
LARGE_INTEGER AllocationSize;
ULONG FileAttributes;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;
FileFullDirectoryInformation: typedef struct _FILE_FULL_DIRECTORY_INFORMATION {
ULONG NextEntryOffset;
ULONG Unknown;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER EndOfFile;
LARGE_INTEGER AllocationSize;
ULONG FileAttributes;
ULONG FileNameLength;
ULONG EaInformationLength;
WCHAR FileName[1];
} FILE_FULL_DIRECTORY_INFORMATION, *PFILE_FULL_DIRECTORY_INFORMATION;
FileBothDirectoryInformation: typedef struct _FILE_BOTH_DIRECTORY_INFORMATION {
ULONG NextEntryOffset;
ULONG Unknown;
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
LARGE_INTEGER EndOfFile;
LARGE_INTEGER AllocationSize;
ULONG FileAttributes;
ULONG FileNameLength;
ULONG EaInformationLength;
UCHAR AlternateNameLength;
WCHAR AlternateName[12];
WCHAR FileName[1];
} FILE_BOTH_DIRECTORY_INFORMATION, *PFILE_BOTH_DIRECTORY_INFORMATION;
FileNamesInformation: typedef struct _FILE_NAMES_INFORMATION {
ULONG NextEntryOffset;
ULONG Unknown;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_NAMES_INFORMATION, *PFILE_NAMES_INFORMATION;
这个函数在FileInformation中写入这些结构的一个列表。对我们来说在这些结构类型中只有3个变量是重要的。
NextEntryOffset是这个列表中项的偏移地址。第一个项在地址FileInformation+0处,所以第二个项在地址是FileInformation+第一个项的NextEntryOffset。最后一个项的NextEntryOffset是0。
FileName是文件全名。
FileNameLength是文件名长度。
如果我们想要隐藏一个文件,我们需要分别通知这4种类型,对每种类型的返回记录我们需要和我们打算隐藏的文件比较名字。如果我们打算隐藏第一个记录,我们可以把后面的结构向前移动,移动长度为第一个结构的长度,这样会导致第一个记录被改写。如果我们想要隐藏其它任何一个,只需要很容易的改变上一个记录的NextEntryOffset的值就行。如果我们要隐藏最后一个记录就把它的NextEntryOffset改为0,否则NextEntryOffset的值应为我们想要隐藏的那个记录和前一个的NextEntryOffset值的和。然后修改前一个记录的Unknown变量的值,它是下一次搜索的索引。把要隐藏的记录之前一个记录的Unknown变量的值改为我们要隐藏的那个记录的Unkown变量的值即可。如果没有原本应该可见的记录被找到,我们就返回STATUS_NO_SUCH_FILE。 |