原文转载于:http://blog.okbase.net/bruceteen/archive/242.html

上回说到NTFS USN会记录下文件的所有操作,但默认情况下并没有激活这一功能,所以不用担心。在非激活状态,它也只剩下快速查找文件的功能。
这回,假设USN JOURNAL被激活了(你可以用控制台命令fsutil usn,或上回说到的FSCTL_CREATE_USN_JOURNAL来开启这一功能),怎么回窥过去的操作?
为此,写了段代码来进行试验,程序是检索 123.txt 操作历史(记录空间不是无穷大,过旧的信息会被覆盖掉),输出如下

2011-06-24 12:53:53 FILE_CREATE|
  \share\x\新建 文本文档.txt
2011-06-24 12:53:53 FILE_CREATE|CLOSE|
  \share\x\新建 文本文档.txt
2011-06-24 12:53:59 RENAME_OLD_NAME|
  \share\x\新建 文本文档.txt
2011-06-24 12:53:59 RENAME_NEW_NAME|
  \share\x\123.txt
2011-06-24 12:53:59 RENAME_NEW_NAME|CLOSE|
  \share\x\123.txt
2011-06-24 12:55:41 FILE_DELETE|CLOSE|
  \RECYCLER\S-1-5-21-945297121-3308661772-4115227181-3452\Dd3\123.txt

从输出可以看出,先在\share\x目录下创建了"新建 文本文档.txt",后又更名为"123.txt",最后连其父目录一起删进了回收站。

试验代码如下(代码中有好多冗余调用,因为这只是试验代码而已):

#define _CRT_SECURE_NO_WARNINGS
#include <windows.h>
#include <string>
#include <deque>
using namespace std;

struct MY_USN_RECORD
{
    DWORDLONG FileReferenceNumber;
    DWORDLONG ParentFileReferenceNumber;
    LARGE_INTEGER TimeStamp;
    DWORD Reason;
    WCHAR FileName[MAX_PATH];
};
HANDLE hVol = INVALID_HANDLE_VALUE;
bool EnumUsnRecord( const char* drvname, std::deque<MY_USN_RECORD>& con )
{
    bool ret = false;

char FileSystemName[MAX_PATH+1];
    DWORD MaximumComponentLength;
    if( GetVolumeInformationA( (std::string(drvname)+":\\").c_str(),0,0,0,&MaximumComponentLength,0,FileSystemName,MAX_PATH+1)
        && 0==strcmp(FileSystemName,"NTFS") ) // 判断是否为 NTFS 格式
    {
        hVol = CreateFileA( (std::string("\\\\.\\")+drvname+":").c_str() // 需要管理员权限,无奈
            , GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
        if( hVol != INVALID_HANDLE_VALUE )
        {
            DWORD br;
            USN_JOURNAL_DATA qujd;
            if( DeviceIoControl( hVol, FSCTL_QUERY_USN_JOURNAL, NULL, 0, &qujd, sizeof(qujd), &br, NULL ) )
            {
                char buffer[0x1000];
                DWORD BytesReturned;
                {
                    READ_USN_JOURNAL_DATA rujd = { 0, -1, 0, 0, 0, qujd.UsnJournalID };
                    for( ; DeviceIoControl(hVol,FSCTL_READ_USN_JOURNAL,&rujd,sizeof(rujd),buffer,_countof(buffer),&BytesReturned,NULL); rujd.StartUsn=*(USN*)&buffer )
                    {
                        DWORD dwRetBytes = BytesReturned - sizeof(USN);
                        PUSN_RECORD UsnRecord = (PUSN_RECORD)((PCHAR)buffer+sizeof(USN));
                        if( dwRetBytes==0 )
                        {
                            ret = true;
                            break;
                        }
                
                        while( dwRetBytes > 0 )
                        {
                            MY_USN_RECORD myur = { UsnRecord->FileReferenceNumber, UsnRecord->ParentFileReferenceNumber, UsnRecord->TimeStamp, UsnRecord->Reason };
                            memcpy( myur.FileName, UsnRecord->FileName, UsnRecord->FileNameLength );
                            myur.FileName[UsnRecord->FileNameLength/2] = L'\0';

con.push_back( myur );
             
                            dwRetBytes -= UsnRecord->RecordLength;
                            UsnRecord = (PUSN_RECORD)( (PCHAR)UsnRecord + UsnRecord->RecordLength );
                        }
                    }
                }
            }

//CloseHandle( hVol );
        }
    }

return ret;
}

#include <set>
int main()
{
    // 获得所有变化记录
    std::deque<MY_USN_RECORD> con;
    EnumUsnRecord( "D", con );

// 搜寻文件名为"test.txt"的文件号(可能有多个)
    std::set<DWORDLONG> con2;
    for( std::deque<MY_USN_RECORD>::const_iterator itor=con.begin(); itor!=con.end(); ++itor )
    {
        const MY_USN_RECORD& mur = *itor;
        if( _wcsicmp(mur.FileName,L"123.txt") == 0 )
        {
            con2.insert( mur.FileReferenceNumber );
        }
    }

// 遍历其历史操作
    setlocale( LC_CTYPE, "chs" );
    for( std::set<DWORDLONG>::const_iterator itor2=con2.begin(); itor2!=con2.end(); ++itor2 )
    {
        for( std::deque<MY_USN_RECORD>::const_iterator itor=con.begin(); itor!=con.end(); ++itor )
        {
            const MY_USN_RECORD& mur = *itor;
            if( *itor2 == mur.FileReferenceNumber )
            {
                FILETIME timestamp;
                FileTimeToLocalFileTime( &(FILETIME&)mur.TimeStamp, &timestamp );
                SYSTEMTIME st;
                FileTimeToSystemTime( &timestamp, &st );
                printf( "%04d-%02d-%02d %02d:%02d:%02d " , st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond );

if( mur.Reason&USN_REASON_DATA_OVERWRITE )
                    printf( "%s|", "DATA_OVERWRITE" );
                if( mur.Reason&USN_REASON_DATA_EXTEND )
                    printf( "%s|", "DATA_EXTEND" );
                if( mur.Reason&USN_REASON_DATA_TRUNCATION )
                    printf( "%s|", "DATA_TRUNCATION" );
                if( mur.Reason&USN_REASON_NAMED_DATA_OVERWRITE )
                    printf( "%s|", "NAMED_DATA_OVERWRITE" );
                if( mur.Reason&USN_REASON_NAMED_DATA_EXTEND )
                    printf( "%s|", "NAMED_DATA_EXTEND" );
                if( mur.Reason&USN_REASON_NAMED_DATA_TRUNCATION )
                    printf( "%s|", "NAMED_DATA_TRUNCATION" );
                if( mur.Reason&USN_REASON_FILE_CREATE )
                    printf( "%s|", "FILE_CREATE" );
                if( mur.Reason&USN_REASON_FILE_DELETE )
                    printf( "%s|", "FILE_DELETE" );
                if( mur.Reason&USN_REASON_EA_CHANGE )
                    printf( "%s|", "EA_CHANGE" );
                if( mur.Reason&USN_REASON_SECURITY_CHANGE )
                    printf( "%s|", "SECURITY_CHANGE" );
                if( mur.Reason&USN_REASON_RENAME_OLD_NAME )
                    printf( "%s|", "RENAME_OLD_NAME" );
                if( mur.Reason&USN_REASON_RENAME_NEW_NAME )
                    printf( "%s|", "RENAME_NEW_NAME" );
                if( mur.Reason&USN_REASON_INDEXABLE_CHANGE )
                    printf( "%s|", "INDEXABLE_CHANGE" );
                if( mur.Reason&USN_REASON_BASIC_INFO_CHANGE )
                    printf( "%s|", "BASIC_INFO_CHANGE" );
                if( mur.Reason&USN_REASON_HARD_LINK_CHANGE )
                    printf( "%s|", "HARD_LINK_CHANGE" );
                if( mur.Reason&USN_REASON_COMPRESSION_CHANGE )
                    printf( "%s|", "COMPRESSION_CHANGE" );
                if( mur.Reason&USN_REASON_ENCRYPTION_CHANGE )
                    printf( "%s|", "ENCRYPTION_CHANGE" );
                if( mur.Reason&USN_REASON_OBJECT_ID_CHANGE )
                    printf( "%s|", "OBJECT_ID_CHANGE" );
                if( mur.Reason&USN_REASON_REPARSE_POINT_CHANGE )
                    printf( "%s|REPARSE_POINT_CHANGE", "" );
                if( mur.Reason&USN_REASON_STREAM_CHANGE )
                    printf( "%s|", "STREAM_CHANGE" );
                if( mur.Reason&USN_REASON_TRANSACTED_CHANGE )
                    printf( "%s|", "TRANSACTED_CHANGE" );
                if( mur.Reason&USN_REASON_CLOSE )
                    printf( "%s|", "CLOSE" );

printf( "\n  " );
                bool PrintFullPath( const MY_USN_RECORD& mur, const std::deque<MY_USN_RECORD>& con );
                PrintFullPath(mur,con);

printf( "\n" );
            }
        }

printf( "\n" );
    }

if( hVol != INVALID_HANDLE_VALUE )
        CloseHandle( hVol );

return 0;
}

bool PrintFullPath( const MY_USN_RECORD& mur, const std::deque<MY_USN_RECORD>& con )
{
    if( (mur.FileReferenceNumber&0x0000FFFFFFFFFFFF) == 5 )
        return true;

std::deque<MY_USN_RECORD>::const_iterator recent = con.end();
    for( std::deque<MY_USN_RECORD>::const_iterator itor=con.begin(); itor!=con.end() && itor->TimeStamp.QuadPart<=mur.TimeStamp.QuadPart; ++itor )
    {
        if( itor->FileReferenceNumber == mur.ParentFileReferenceNumber )
            recent = itor;
    }
    if( recent != con.end() ) // 它的父目录可能也已被删除,所以要先在记录集中找找
    {
        bool r= PrintFullPath(*recent,con);
        printf( "\\%S", mur.FileName );
        return r;
    }

bool GetFullPathByFileReferenceNumber( HANDLE hVol, DWORDLONG FileReferenceNumber );
    bool r = GetFullPathByFileReferenceNumber(hVol,mur.ParentFileReferenceNumber); // 如果记录中没有,再去看看这个文件实际存在否
    if( r )
        printf( "\\%S", mur.FileName );
    else
        printf( "???\\%S", mur.FileName );
    return r;
}

bool GetFullPathByFileReferenceNumber( HANDLE hVol, DWORDLONG FileReferenceNumber ) // 根据文件号获得全路径,上篇文章已经说过,共有3中方法,这是其中之一,代码简单但效率不高
{
    typedef ULONG (__stdcall *PNtCreateFile)(
        PHANDLE FileHandle,
        ULONG DesiredAccess,
        PVOID ObjectAttributes,
        PVOID IoStatusBlock,
        PLARGE_INTEGER AllocationSize,
        ULONG FileAttributes,
        ULONG ShareAccess,
        ULONG CreateDisposition,
        ULONG CreateOptions,
        PVOID EaBuffer,
        ULONG EaLength );
    PNtCreateFile NtCreatefile = (PNtCreateFile)GetProcAddress( GetModuleHandle(L"ntdll.dll"), "NtCreateFile" );

typedef struct _UNICODE_STRING {
        USHORT Length, MaximumLength;
        PWCH Buffer;
    } UNICODE_STRING, *PUNICODE_STRING;
    UNICODE_STRING fidstr = { 8, 8, (PWSTR)&FileReferenceNumber };

typedef struct _OBJECT_ATTRIBUTES {
        ULONG Length;
        HANDLE RootDirectory;
        PUNICODE_STRING ObjectName;
        ULONG Attributes;
        PVOID SecurityDescriptor;
        PVOID SecurityQualityOfService;
    } OBJECT_ATTRIBUTES;
    const ULONG OBJ_CASE_INSENSITIVE = 0x00000040UL;
    OBJECT_ATTRIBUTES oa = { sizeof(OBJECT_ATTRIBUTES), hVol, &fidstr, OBJ_CASE_INSENSITIVE, 0, 0 };
   
    HANDLE hFile;
    ULONG iosb[2];
    const ULONG FILE_OPEN_BY_FILE_ID = 0x00002000UL;
    const ULONG FILE_OPEN            = 0x00000001UL;
    ULONG status = NtCreatefile( &hFile, GENERIC_ALL, &oa, iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, FILE_OPEN_BY_FILE_ID, NULL, 0 );
    if( status == 0 )
    {
        typedef struct _IO_STATUS_BLOCK {
            union {
                NTSTATUS Status;
                PVOID Pointer;
            };
            ULONG_PTR Information;
        } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
        typedef enum _FILE_INFORMATION_CLASS {
            // ……
            FileNameInformation = 9
            // ……
        } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
        typedef NTSTATUS (__stdcall *PNtQueryInformationFile)(
            HANDLE FileHandle,
            PIO_STATUS_BLOCK IoStatusBlock,
            PVOID FileInformation,
            DWORD Length,
            FILE_INFORMATION_CLASS FileInformationClass );
        PNtQueryInformationFile NtQueryInformationFile = (PNtQueryInformationFile)GetProcAddress( GetModuleHandle(L"ntdll.dll"), "NtQueryInformationFile" );

typedef struct _OBJECT_NAME_INFORMATION {
            UNICODE_STRING Name;
        } OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
        IO_STATUS_BLOCK IoStatus;
        size_t allocSize = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH*sizeof(WCHAR);
        POBJECT_NAME_INFORMATION pfni = (POBJECT_NAME_INFORMATION)operator new(allocSize);
        status = NtQueryInformationFile(hFile, &IoStatus, pfni, allocSize, FileNameInformation);
        if( status == 0 )
        {
            printf( "%.*S", pfni->Name.Length/2, &pfni->Name.Buffer );
        }
        operator delete(pfni);

CloseHandle(hFile);
    }

return status == 0;
}

读取NTFS的USN(获取文件的历史操作记录,即使这个文件已被删除)相关推荐

  1. 读取NTFS的USN(快速检索文件)

    有个名叫Everything的软件,搜索文件飞快,看了一下原理,原来NTFS会记录文件的所有操作,也就是说即便文件被删除了,通过USN记录仍然可以知道文件名等部分信息.于是准备写个程序删掉这个信息,但 ...

  2. 读取ntfs的usn

    上回说到NTFS USN会记录下文件的所有操作,但默认情况下并没有激活这一功能,所以不用担心.在非激活状态,它也只剩下快速查找文件的功能. 这回,假设USN JOURNAL被激活了(你可以用控制台命令 ...

  3. 查看历史操作记录(.bash_history)、修改文件时间

    查看历史操作记录: 1.more  ~/.bash_history 修改文件时间: 1.stat XXX.txt 查看文件时间状态: 2.vi XXX.txt 修改文件内容,保存: 3.touch - ...

  4. git删除相关历史提交记录,相关文件保持当前状态

          git删除相关历史提交记录,相关文件保持当前状态 引言   新年新气象,趁着现在新的一年开始项目的事情还不是非常繁忙的时候,多整点下酒菜.这不实战类型的博客记录又开始了!当然实战类型的博客 ...

  5. 怎么查计算机上c盘的历史记录,如何查看电脑历史操作记录

    如何查看电脑历史操作记录 导语:电脑上网所使用的记录,是怎么通过查看的?以下是小编收集的有关电脑入门的知识,希望对您有所帮助. 1.看计算机在哪天运行过,运行了多久 (系统安装在c盘) 找到c:\wi ...

  6. 如何查看手机计算机历史记录,怎么查看电脑历史操作记录

    如何查看电脑历史操作记录? 随便打开我的电脑或者浏览器,然后同时按下Ctrl+H组合键,窗口的左侧就会弹出浏览过的历史记录的小窗口,选择相应的日期之后下拉菜单后,会有浏览的网页记录和我的电脑(下图), ...

  7. Linux下查看历史操作记录

    Linux下查看历史操作记录 2012-04-17 10:23:05 我来说两句 收藏 我要投稿 last命令可以用来查看用户的登陆记录. history命令可以查看命令的执行历史. www.2cto ...

  8. 请教怎么查询ORACLE的历史操作记录!

    请问如何查询ORACLE的历史操作记录!!!!! 我用的是linux oracle 11g r2,想查一下前几天的数据库的历史操作记录,例如对表的insert,delete,update等等的操作记录 ...

  9. python3读取网页_python3+selenium获取页面加载的所有静态资源文件链接操作

    软件版本: python 3.7.2 selenium 3.141.0 pycharm 2018.3.5 具体实现流程如下,废话不多说,直接上代码: from selenium import webd ...

最新文章

  1. 自动填充控件AutoCompleteExtender控件实现代码
  2. 深度聚焦 3 大技术领域,阿里云将重磅亮相首届线上 KubeCon
  3. REVERSE-PRACTICE-BUUCTF-12
  4. ios开发之--调整UISearchBar的输入框的背景颜色
  5. js当中null和{}区别
  6. Vlan与VTP的介绍及工作原理
  7. HashMap的工作原理--重点----数据结构示意图的理解
  8. PHP是迄今为止最好的web平台
  9. 《构建之法》阅读笔记1
  10. 人行征信报告(上)——一代征信报告的变量梳理
  11. VGA接口、DVI接口、HDMI接口
  12. WinEdit10 添加论文引用,XeLaTex编译后论文中的引用变成了【?】
  13. 小程序+spring boot校园交友平台毕业设计-附源码191733
  14. Hack The Box - Access Writeup
  15. Session.CLIENT_ACKNOWLEDGE
  16. 禁用win10自带的微软输入法!
  17. xls和xlsx的区别
  18. Jason数据的访问
  19. 64位处理器_32位和64位的Windows 10和处理器(CPU)有什么区别
  20. 一维矩阵和二维矩阵的前缀和

热门文章

  1. 互联网券商线上开户系统设计与开发技术分享
  2. 101. Domino 10 就要来了
  3. 启动3ds Max报 d3dx9_43.dll丢失 解决方法
  4. 理解O(log2N)和O(Nlog2N)
  5. pb 如何导出csv_打开CSV格式文件?英雄请留步
  6. 如何利用计算机窃取信息,震惊部 · 用非接触的方式,窃取一台电脑上的信息...
  7. 红帽6.4版本安装详细步骤
  8. 华为帐号“一号畅玩”体验,助力游戏用户增长
  9. java 中文编码乱码_Java编码问题复习
  10. 五面拿下阿里飞猪offer,java开发程序员