как определить версию USN_RECORD для журнала usn?
Хочу узнать принцип всего, и по usn логам следить за добавлением и удалением системных файлов. Я написал кусок кода под windows11, VS2019, Platform Toolset= (v142). Но я обнаружил, что запись->Причина (USN_RECORD) всегда возвращает 0; Кроме того, если я удаляю файл, я отслеживаю, что это искаженное имя файла с $. Например, если я удаляю файл «ABC.TXT», я отслеживаю и обнаруживаю, что возвращается имя файла вроде «$1a2f5.txt». После того, как я погуглил, я обнаружил, что это связано с тем, что USN_RECORD имеет несколько версий, V2, V3, V4, но я не знаю, как определить номер версии. Вот код:
#ifndef VC_EXTRALEAN
#define VC_EXTRALEAN // 从 Windows 头中排除极少使用的资料
#endif
#include <Windows.h>
#include <stdio.h>
#include <string>
#include <iostream>
#include "usn_test.h"
//#define BUFFER_SIZE (1024 * 1024)
constexpr auto BUFFER_SIZE = sizeof(USN) + 0x100000;
HANDLE drive;
USN maxusn;
DWORDLONG gUsnJournalID;
void delete_usn()
{
DELETE_USN_JOURNAL_DATA dujd;
dujd.UsnJournalID = gUsnJournalID;
dujd.DeleteFlags = USN_DELETE_FLAG_DELETE;
DWORD br;
if (DeviceIoControl(drive,
FSCTL_DELETE_USN_JOURNAL,
&dujd,
sizeof(dujd),
nullptr,
0,
&br,
nullptr)
)
{
CloseHandle(drive);
return;
}
CloseHandle(drive);
return;
}
template<typename _T_USN_RECORD>
void check_record(_T_USN_RECORD* record)
{
WCHAR szName[MAX_PATH];
CopyMemory(szName,
((PBYTE)record) + record->FileNameOffset,
record->FileNameLength);
szName[record->FileNameLength / sizeof(WCHAR)] = 0;
std::wcout << szName << L",Reason:" << record->Reason << std::endl;
}
template<>
void check_record(USN_RECORD_V4* record)
{
WCHAR szName[MAX_PATH];
CopyMemory(szName,
((PBYTE)record) + record->Extents->Offset,
record->Extents->Length);
// Let's zero-terminate it
szName[record->Extents->Length / sizeof(WCHAR)] = 0;
std::wcout << szName << L",Reason:" << record->Reason << std::endl;
}
bool create_usn()
{
CREATE_USN_JOURNAL_DATA cujd{};
cujd.MaximumSize = 0; // 0表示使用默认值
cujd.AllocationDelta = 0; // 0表示使用默认值
DWORD br;
if (
DeviceIoControl(drive, // handle to volume
FSCTL_CREATE_USN_JOURNAL, // dwIoControlCode
&cujd, // input buffer
sizeof(cujd), // size of input buffer
nullptr, // lpOutBuffer
0, // nOutBufferSize
&br, // number of bytes returned
nullptr) // OVERLAPPED structure
)
{
return true;
}
auto&& info = "create usn error. Error code: " + std::to_string(GetLastError());
fprintf(stderr, "fileSearcherUSN: %s\n", info.c_str());
return false;
}
template<typename _T_USN_RECORD>
void read_record(DWORDLONG& nextid, void* buffer, _T_USN_RECORD*& record, _T_USN_RECORD*& recordend, const DWORD& bytecount)
{
nextid = *((DWORDLONG*)buffer);
// printf("Next ID: %lu\n", nextid);
record = (_T_USN_RECORD*)((USN*)buffer + 1);
recordend = (_T_USN_RECORD*)(((BYTE*)buffer) + bytecount);
while (record < recordend)
{
check_record(record);
record = (_T_USN_RECORD*)(((BYTE*)record) + record->RecordLength);
}
}
template<>
void read_record(DWORDLONG& nextid, void* buffer, USN_RECORD_V4*& record, USN_RECORD_V4*& recordend, const DWORD& bytecount)
{
nextid = *((DWORDLONG*)buffer);
// printf("Next ID: %lu\n", nextid);
record = (USN_RECORD_V4*)((USN*)buffer + 1);
recordend = (USN_RECORD_V4*)(((BYTE*)buffer) + bytecount);
while (record < recordend)
{
//check_record(record);
record = (USN_RECORD_V4*)(((BYTE*)record) + record->Header.RecordLength);
}
}
int main(int argc, char** argv)
{
//typedef USN_JOURNAL_DATA_V2 USN_JOURNAL_DATA;
#define FILE_END 38
//typedef MFT_ENUM_DATA MFT_ENUM_DATA_V1;
MFT_ENUM_DATA mft_enum_data;
DWORD bytecount = 1;
void* buffer;
USN_RECORD_V3* recordV3;
USN_RECORD_V3* recordendV3;
USN_RECORD_V4* recordV4;
USN_RECORD_V4* recordendV4;
USN_JOURNAL_DATA* journal;
DWORDLONG nextid{};
buffer = new BYTE[BUFFER_SIZE];
if (buffer == NULL)
{
printf("VirtualAlloc: %u\n", GetLastError());
return 0;
}
printf("Opening volume.\n");
drive = CreateFile(L"\\\\?\\h:", GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_FLAG_NO_BUFFERING, NULL);
if (drive == INVALID_HANDLE_VALUE)
{
printf("CreateFile: %u\n", GetLastError());
return 0;
}
if (!create_usn())
{
return -1;
}
printf("Calling FSCTL_QUERY_USN_JOURNAL\n");
if (!DeviceIoControl(drive, FSCTL_QUERY_USN_JOURNAL, NULL, 0, buffer, BUFFER_SIZE, &bytecount, NULL))
{
printf("FSCTL_QUERY_USN_JOURNAL: %u\n", GetLastError());
return 0;
}
// delete_usn();
journal = (USN_JOURNAL_DATA*)buffer;
gUsnJournalID = journal->UsnJournalID;
printf("UsnJournalID: %lu\n", journal->UsnJournalID);
printf("FirstUsn: %lu\n", journal->FirstUsn);
printf("NextUsn: %lu\n", journal->NextUsn);
maxusn = journal->MaxUsn;
mft_enum_data.StartFileReferenceNumber = 0;
mft_enum_data.LowUsn = 0;
mft_enum_data.HighUsn = maxusn;
mft_enum_data.MaxMajorVersion = journal->MaxSupportedMajorVersion;
mft_enum_data.MinMajorVersion = journal->MinSupportedMajorVersion;
for (;;)
{
// printf("=================================================================\n");
// printf("Calling FSCTL_ENUM_USN_DATA\n");
if (!DeviceIoControl(drive, FSCTL_ENUM_USN_DATA, &mft_enum_data, sizeof(mft_enum_data), buffer, BUFFER_SIZE, &bytecount, NULL))
{
auto bRet = GetLastError();
if (bRet != 38)
{
delete_usn();
break;
}
if (bRet == 38)//file to end
{
// break;
Sleep(1000);//wait for new file change
auto oldNextUsn = journal->NextUsn;
if (!DeviceIoControl(drive, FSCTL_QUERY_USN_JOURNAL, NULL, 0, buffer, BUFFER_SIZE, &bytecount, NULL))
{
printf("FSCTL_QUERY_USN_JOURNAL: %u\n", GetLastError());
return 0;
}
journal = (USN_JOURNAL_DATA*)buffer;
if (journal->NextUsn > oldNextUsn)//new file have changed
{
mft_enum_data.StartFileReferenceNumber = 0;
mft_enum_data.LowUsn = oldNextUsn;
mft_enum_data.HighUsn = journal->MaxUsn;
mft_enum_data.MaxMajorVersion = journal->MaxSupportedMajorVersion;
mft_enum_data.MinMajorVersion = journal->MinSupportedMajorVersion;
}
continue;
}
}
// printf("Bytes returned: %u\n", bytecount);
if(mft_enum_data.MinMajorVersion == 4)//it's wrong if i determine version by mft_enum_data.MaxMajorVersion
read_record(nextid, buffer, recordV4, recordendV4, bytecount);
else
read_record(nextid, buffer, recordV3, recordendV3, bytecount);
mft_enum_data.StartFileReferenceNumber = nextid;
}
delete[] buffer;
delete_usn();
}
I have spent 2 weeks for this.google and write a test.day and day.