#include"ntfs.h"
class _MFT_READER
{
#define FILE_LOAD_ERROR 1
#define OUT_OF_MEMORY_ERROR 2
private:
HANDLE hVolume;
BOOT_BLOCK boot_block;
PFILE_RECORD_HEADER MFT;
U32 BytesPerFileRecord;
U32 cnt;
long MFTLength;
int ErrorCode;
void LoadMFT();
long ReadAttribute(FILE* fp, unsigned char* offset, long flag);
void ReadSector(U64 sector, U32 count, void* buffer);
__int64 ReadCluster(unsigned char* point,unsigned char* info);
public:
_MFT_READER
//(WCHAR* drive)
(char* drive)
{
ErrorCode=0;
hVolume = CreateFile(drive, GENERIC_READ,FILE_SHARE_READ | FILE_SHARE_WRITE, 0,OPEN_EXISTING, 0, 0);
ReadFile(hVolume, &boot_block, sizeof(boot_block), &cnt, 0);
if(!GetLastError())
LoadMFT();
else
ErrorCode=FILE_LOAD_ERROR;
}
// void ReLoadMFT(char* drive);
int LastErrorCode(); //최근에 일어난 클래스 내부의 에러를 반환한다.
void MakeBinaryFile(char* filename); //MFT를 Binary 그대로 저장한다.
void MakeTextFile(char* filename, long flag); //MFT 속성을 text 파일로 저장.
};
#include"_MFT_READER.h"
void _MFT_READER::LoadMFT()
{
unsigned __int64 point,i,j,k,temp;
unsigned __int64 HeaderSize;
unsigned __int64 offset;
PFILE_RECORD_HEADER $MFT;
BytesPerFileRecord = boot_block.ClustersPerFileRecord < 0x80? boot_block.ClustersPerFileRecord* boot_block.SectorsPerCluster* boot_block.BytesPerSector : 1 << (0x100 - boot_block.ClustersPerFileRecord);
$MFT = PFILE_RECORD_HEADER(new U8[BytesPerFileRecord]);
if(!$MFT)
{
ErrorCode=OUT_OF_MEMORY_ERROR;
return;
}
ReadSector((boot_block.MftStartLcn) * boot_block.SectorsPerCluster, BytesPerFileRecord / boot_block.BytesPerSector, $MFT);
for(j=1;j<=*((unsigned short*)((unsigned char*)$MFT+6));j++)
{
if( *((char*)$MFT+j*boot_block.BytesPerSector-2)==
*((char*)$MFT+*((unsigned short*)((unsigned char*)$MFT+4)))
&&
*((char*)$MFT+j*boot_block.BytesPerSector-1)==
*((char*)$MFT+*((unsigned short*)((unsigned char*)$MFT+4))+1)
)
{
*((char*)$MFT+j*boot_block.BytesPerSector-2)=
*((char*)$MFT+*((unsigned short*)((unsigned char*)$MFT+4))+2*j);
*((char*)$MFT+j*boot_block.BytesPerSector-1)=
*((char*)$MFT+*((unsigned short*)((unsigned char*)$MFT+4))+2*j+1);
}
}
point=*((unsigned short*)((unsigned char*)$MFT+20));//Offset으로 포인터 이동
while(*((unsigned long*)((unsigned char*)$MFT+point))!=0xFFFFFFFF)
{
/*
*((unsigned char*)MFT+point+9) = Attribute Name Size
Attribute Header size : Resident=24 / Non-resident=64
*/
if(*((unsigned char*)$MFT+point+8))
HeaderSize=64+*((unsigned char*)$MFT+point+9);
else
HeaderSize=24+*((unsigned char*)$MFT+point+9);
switch(*((unsigned long*)((unsigned char*)$MFT+point)))
{
case 0x80://$DATA
MFT=PFILE_RECORD_HEADER(new U8[*((unsigned __int64*)((unsigned char*)$MFT+point+40))]);
if(!MFT)
{
delete $MFT;
ErrorCode=OUT_OF_MEMORY_ERROR;
return;
}
i=*(short*)((unsigned char*)$MFT+point+32);
MFTLength=ReadCluster((unsigned char*)$MFT+point+i,(unsigned char*)MFT);
break;
}
point+=*((unsigned long*)((unsigned char*)$MFT+point+4));
}
delete $MFT;
}
void _MFT_READER::ReadSector(U64 sector, U32 count, void* buffer)
{
ULARGE_INTEGER offset;
OVERLAPPED overlap = {0};
U32 n;
offset.QuadPart = sector * boot_block.BytesPerSector;
overlap.Offset = offset.LowPart;
overlap.OffsetHigh = offset.HighPart;
ReadFile(hVolume, buffer, count * boot_block.BytesPerSector, &n, &overlap);
}
long _MFT_READER::ReadAttribute(FILE* fp, unsigned char* point, long flag)
{
unsigned char* offset=0;
SYSTEMTIME time;
int i,sub_mask;
sub_mask=1;
for(i=1;i<25;i++)
{
if(sub_mask&flag && *(long*)point==0x10*i)
{
if(*((unsigned char*)point+8))
{
if(*((unsigned __int64*)((unsigned char*)point+40)))
offset=(new U8[*((unsigned __int64*)((unsigned char*)point+40))]);
else
offset=0;
if(offset)
ReadCluster(point+(*(short*)((unsigned char*)point+32)),offset);
}
else
{
offset=point+24+*((unsigned char*)point+9);
}
}
sub_mask<<=1;
}
if(!offset)
return *(long*)((unsigned char*)point+4);
if(!((*(long*)point)&0xFFFFFF00))
{
switch(*(long*)point)
{
case 0x10://Standard Information
fprintf(fp,"Attribute type : Standard Information\n");
FileTimeToSystemTime((FILETIME*)offset,&time);
fprintf(fp,"File 생성 %d년 %d월 %d일\n",time.wYear,time.wMonth,time.wDay);
FileTimeToSystemTime((FILETIME*)(offset+8),&time);
fprintf(fp,"File 수정 %d년 %d월 %d일\n",time.wYear,time.wMonth,time.wDay);
FileTimeToSystemTime((FILETIME*)(offset+24),&time);
fprintf(fp,"File 접근 %d년 %d월 %d일\n",time.wYear,time.wMonth,time.wDay);
break;
case 0x20://Attribute List
fprintf(fp,"Attribute type : Attribute list\n");
break;
case 0x30://File Name
fprintf(fp,"Attribute type : File Name\n");
FileTimeToSystemTime((FILETIME*)(offset+8),&time);
fprintf(fp,"File 생성 %d년 %d월 %d일\n",time.wYear,time.wMonth,time.wDay);
FileTimeToSystemTime((FILETIME*)(offset+16),&time);
fprintf(fp,"File 이름 수정 %d년 %d월 %d일\n",time.wYear,time.wMonth,time.wDay);
FileTimeToSystemTime((FILETIME*)(offset+32),&time);
fprintf(fp,"File 접근 %d년 %d월 %d일\n",time.wYear,time.wMonth,time.wDay);
fprintf(fp,"File Name Size : %d\n",*((unsigned char*)offset+64));
fprintf(fp,"File NameSpace : ");
switch(*((unsigned char*)offset+65))
{
case 0:
fprintf(fp,"POSIX\n");
break;
case 1:
fprintf(fp,"Win32\n");
break;
case 2:
fprintf(fp,"DOS\n");
break;
case 3:
fprintf(fp,"Win32 & DOS\n");
break;
default:
fprintf(fp,"Unkown\n");
break;
}
fprintf(fp,"File Name : ");
fwprintf(fp,L"%s",((unsigned char*)offset+66));
fprintf(fp,"\n");
break;
case 0x40://Volume Version
break;
case 0x50://Object ID
break;
case 0x60://Security
break;
}
}
if(*((unsigned char*)point+8))
{
delete offset;
}
if(*(long*)((unsigned char*)point+4))
return *(long*)((unsigned char*)point+4);
else
return 0;
}
//*
__int64 _MFT_READER::ReadCluster(unsigned char* point,unsigned char* info)
{
int i=0,j=0,k;
__int64 offset=0,temp;
__int64 length=0;
while(*(point+i))
{
length=0;
for(k=0;k<(*(point+i)&0x0F);k++)
{
length<<=8;
length+=*((point+i)+(*(point+i)&0x0F)-k);
}
temp=offset; //*오프셋값은 이전 값들과 합계로 계산됨.
offset=0;
for(;k<(*(point+i)&0x0F)+((*(point+i)&0xF0)>>4);k++)
{
offset<<=8;
offset+=*((point+i)+(*(point+i)&0x0F)+((*(point+i)&0xF0)>>4)-k+(*(point+i)&0x0F));
}
//*
if(offset&(0x80<<(8*(((*(point+i)&0xF0)>>4)-1))) && ((*(point+i)&0xF0)>>4)<8)
{
offset=offset^(0x80<<(8*(((*(point+i)&0xF0)>>4)-1)));
offset=-offset;
}
//*/
offset+=temp;
ReadSector(offset * boot_block.SectorsPerCluster,
length * boot_block.SectorsPerCluster,
info+j*boot_block.BytesPerSector*boot_block.SectorsPerCluster);
i+=(*(point+i)&0x0F)+((*(point+i)&0xF0)>>4)+1;
j+=length;
}
return j;
}
//*/
#include"_MFT_READER.h"
void _MFT_READER::MakeBinaryFile(char* filename)
{
FILE* fp;
fp=fopen(filename,"w");
if(!fp)
{
printf("error");
return;
}
fwrite((void*)MFT,BytesPerFileRecord,MFTLength,fp);
fclose(fp);
}
void _MFT_READER::MakeTextFile(char* filename, long flag)
{
FILE *fp=fopen(filename,"w");
long filecounter=0;
long i,j,k;
for(i=0;i<MFTLength*boot_block.BytesPerSector*boot_block.SectorsPerCluster/BytesPerFileRecord;i++)
{
if( ((unsigned char*)MFT+i*BytesPerFileRecord)[0]!='F'
||
((unsigned char*)MFT+i*BytesPerFileRecord)[1]!='I'
||
((unsigned char*)MFT+i*BytesPerFileRecord)[2]!='L'
||
((unsigned char*)MFT+i*BytesPerFileRecord)[3]!='E'
)
continue;
//하위 엔트리 필터링
// if(*((int*)((unsigned char*)MFT+i*BytesPerFileRecord+32)))
// continue;
filecounter++;
fprintf(fp,"MFT's Signaturer : %s\n", ((unsigned char*)MFT+i*BytesPerFileRecord));//+0x27);
fprintf(fp,"Number of this MFT Entry : 0x%02x%02x%02x%02x\n"
, *((unsigned char*)MFT+i*BytesPerFileRecord+47),*((unsigned char*)MFT+i*BytesPerFileRecord+46),
*((unsigned char*)MFT+i*BytesPerFileRecord+45),*((unsigned char*)MFT+i*BytesPerFileRecord+44));
//offset_array
for(j=1;j<=*((unsigned short*)((unsigned char*)MFT+i*BytesPerFileRecord+6));j++)
{
if( *((char*)MFT+i*BytesPerFileRecord+j*boot_block.BytesPerSector-2)==
*((char*)MFT+i*BytesPerFileRecord+*((unsigned short*)((unsigned char*)MFT+i*BytesPerFileRecord+4)))
&&
*((char*)MFT+i*BytesPerFileRecord+j*boot_block.BytesPerSector-1)==
*((char*)MFT+i*BytesPerFileRecord+*((unsigned short*)((unsigned char*)MFT+i*BytesPerFileRecord+4))+1)
)
{
*((char*)MFT+i*BytesPerFileRecord+j*boot_block.BytesPerSector-2)=
*((char*)MFT+i*BytesPerFileRecord+*((unsigned short*)((unsigned char*)MFT+i*BytesPerFileRecord+4))+2*j);
*((char*)MFT+i*BytesPerFileRecord+j*boot_block.BytesPerSector-1)=
*((char*)MFT+i*BytesPerFileRecord+*((unsigned short*)((unsigned char*)MFT+i*BytesPerFileRecord+4))+2*j+1);
}
}
j=*((unsigned short*)((unsigned char*)MFT+i*BytesPerFileRecord+20));//Offset to First Attribute Header
while(!(*((unsigned long*)((unsigned char*)MFT+i*BytesPerFileRecord+j))&0xFFFFFF00))
{
j+=ReadAttribute(fp,(unsigned char*)MFT+i*BytesPerFileRecord+j,flag);
}
fprintf(fp,"\n");
//offset_array
for(j=1;j<=*((unsigned short*)((unsigned char*)MFT+i*BytesPerFileRecord+6));j++)
{
if( *((char*)MFT+i*BytesPerFileRecord+j*boot_block.BytesPerSector-2)==
*((char*)MFT+i*BytesPerFileRecord+*((unsigned short*)((unsigned char*)MFT+i*BytesPerFileRecord+4))+2*j)
&&
*((char*)MFT+i*BytesPerFileRecord+j*boot_block.BytesPerSector-1)==
*((char*)MFT+i*BytesPerFileRecord+*((unsigned short*)((unsigned char*)MFT+i*BytesPerFileRecord+4))+2*j+1)
)
{
*((char*)MFT+i*BytesPerFileRecord+j*boot_block.BytesPerSector-2)=
*((char*)MFT+i*BytesPerFileRecord+*((unsigned short*)((unsigned char*)MFT+i*BytesPerFileRecord+4)));
*((char*)MFT+i*BytesPerFileRecord+j*boot_block.BytesPerSector-1)=
*((char*)MFT+i*BytesPerFileRecord+*((unsigned short*)((unsigned char*)MFT+i*BytesPerFileRecord+4))+1);
}
}
}
fprintf(fp,"Bytes of Files : %d\n",i*BytesPerFileRecord);
fprintf(fp,"A number of Files : %d\n",filecounter);
fclose(fp);
}
int _MFT_READER::LastErrorCode()
{
return ErrorCode;
}