注2017年6月25日修改:這個版本想得複雜了,還是改爲python腳本容易實現的方式。見相關blog(ntfs案例一)
目的:
生成一個NTFS文件系統,要求:
1、$MFT至少2個碎片
2、根目錄下建90個以從1開始的數字編號爲名的子目錄,每個子目錄下建80-100個文件,文件編號從1開始編起。
3、有大量文件是由2個或以上碎片組成。(本例多爲2個碎片)
1、shell 腳本如下:
!/bin/sh # Script.sh # # # Created by 張宇 on 2017/3/29. 此腳本已包含後面的命令 # mkdir ~/$1 cd ~/$1 qemu-img create -f raw $1.img 1G qemu-nbd -f raw -c /dev/nbd0 $1.img parted -s /dev/nbd0 mklabel msdos parted -s /dev/nbd0 mkpart -s primary NTFS 128s 100% mkfs.ntfs -f /dev/nbd0p1 mount.ntfs-3g /dev/nbd0p1 /mnt #第一段for,先創建30個子目錄,每個目錄下80-100個文件,大小爲16K-48K,這一段基本連續 for((i=1;i<=3;i++));do mkdir /mnt/$i r1=$(($RANDOM % 20)) for((ii=1;ii<80+$r1;ii++));do r2=$(($RANDOM % 64 + 32)) dd if=/dev/urandom of=/mnt/$i/$ii bs=512 count=$r2 done done #sleep 60 便於讓文件系統flush #sleep 60 mkdir /mnt/padding cd /mnt/padding #填充65000個文件,這樣可以使NTFS $MFT填充到第一個使用的數據區段,從而產生$MFT 碎片。 for((i=1;i<65000;i++));do touch $i done #創建出其他4-90子目錄,這些文件會位於$MFT的第二個片斷或以後 for((i=4;i<=90;i++));do mkdir /mnt/$i r1=$(($RANDOM % 20)) for((ii=1;ii<80+$r1;ii++));do r2=$(($RANDOM % 64 + 32)) dd if=/dev/urandom of=/mnt/$i/$ii bs=512 count=$r2 done done #sleep 60 #第二段for,使用dd把第一段for創建出的文件,從0-16K的位置,寫入48K-80K,基本保證>約2個碎片,子目錄3下的文件是第一段$MFT下的文件,3之後的爲$MFT第二個片斷。 for((i=3;i<=90;i++));do cd /mnt/$i for ii in `ls`;do r2=$(($RANDOM % 64 + 96)) r3=$(($RANDOM % 32)) dd if=/dev/urandom of=/mnt/$i/$ii bs=512 seek=$r3 count=$r2 done done #刪除padding,以免目錄結構太臃腫 rm -rf /mnt/padding cd /mnt find . -type f -print|xargs md5sum -b |tr a-z A-Z 1>~/$1/md5.list for i in `find . -type f`;do ntfscluster -f -F $i /dev/nbd0p1;done 1>~/$1/file.info 2>/dev/null
2、在shell中執行如下命令:
qemu-img create -f raw test2.img 1G qemu-nbd -f raw -c /dev/nbd0 test2.img fdisk /dev/nbd0 #此命令交互,目的爲/dev/nbd0分個區,不想交互,可使用parted加參數 mkfs.ntfs -f /dev/nbd0p1 mount.ntfs-3g /dev/nbd0p1 /mnt /bin/bash run.sh
3、測試結果是否滿意:
命令一:ntfscluster -f -I 0 /dev/nbd0p1
結果與預想相符,$mft果然爲2個片斷:
Forced to continue.
Dump: /$MFT
0x10 - resident
0x30 - resident
0x80 - non-resident
VCN LCN Length
0 4 16387
16387 20488 1880
0xb0 - non-resident
VCN LCN Length
0 2 2
2 16391 1
命令二:ntfscluster -f -F 1/ /dev/nbd0p1
結果與預想相符,抽樣目錄,也爲2個片斷
Forced to continue.
Unnormalized path 1/
Dump: /1
0x10 - resident
0x30 - resident
0x50 - resident
0x90 - resident
0xa0 - non-resident
VCN LCN Length
0 53328 2
2 49238 1
0xb0 - resident
命令三: ntfscluster -f -F 60/9 /dev/nbd0p1
結果與預想相符,抽樣文件,也爲2個片斷
Forced to continue.
Dump: /60/9
0x10 - resident
0x30 - resident
0x50 - resident
0x80 - non-resident
VCN LCN Length
0 211991 8
8 115298 7
4、生成所有文件的md5 哈希,便於生成考覈答案
cd /mnt find . -type f -print|xargs md5sum -b |tr a-z A-Z
5、生成所有文件的碎片信息,便於生成考覈答案
cd /mnt for i in `find . -type f`;do ntfscluster -f -F $i /dev/nbd0p1;done 2>/dev/null
6、生成目錄的碎片信息,便於生成考覈答案
cd /mnt for i in `find . -type d`;do ntfscluster -f -F $i /dev/nbd0p1;done 2>/dev/null
7、生成元文件的文件記錄信息,便於生成考覈答案
for((i=0;i<16;i++));do ntfscluster -f -I $i /dev/nbd0p1;done 2>/dev/null
或者通過命令:ntfscluster -i -f /dev/nbd0p1,
查看如下值:initialized mft records : 73115
再執行,下面命令即可將所有文件的碎片信息打印出來,再做加工,即可生成考覈答案
for((i=0;i<73115;i++));do ntfscluster -f -I $i /dev/nbd0p1;done 2>/dev/null
ntfs-3g源碼改動:
1、ntfscluster.c 400行while改爲如下,目的是便於輸出結果用grep,sed或awk加工
while ((rec = find_attribute(AT_UNUSED, ctx))) { ntfs_log_info(" 0x%02x - ", (int)le32_to_cpu(rec->type)); if (rec->non_resident) { ntfs_log_info("non-resident\n"); runs = ntfs_mapping_pairs_decompress(vol, rec, NULL); if (runs) { ntfs_log_info(" INODE ATTR RUN# VCN LCN Length\n"); for (i = 0; runs[i].length > 0; i++) { ntfs_log_info(" %8lld 0x%02x %8lld %8lld %8lld %8lld\n", (long long)(ino->mft_no & 0x0000FFFFFFFFFFFFUL), (int)le32_to_cpu(rec->type), (long long)i, (long long)runs[i].vcn, (long long)runs[i].lcn, (long long) runs[i].length); } ntfs_log_info(" [INFO]:0x%02xRuns:%d,Inode:%lld,path:%s\n", (int)le32_to_cpu(rec->type), i, (long long)(ino->mft_no & 0x0000FFFFFFFFFFFFUL), buffer); free(runs); } } else { ntfs_log_info("resident\n"); } }
結果將如下:
Dump: /50/3
0x10 - resident
0x30 - resident
0x50 - resident
0x80 - non-resident
INODE ATTR RUN# VCN LCN Length
69425 0x80 0 0 194588 9
69425 0x80 1 9 217183 8
[INFO]:0x80Runs:2,Inode:69425,path:/50/3
考題及答案生成部分:
1、$MFT:$DATA
2、$MFT:$BITMAP
3、在$MFT第一個片斷中的,擁有$DATA:RUNLIST唯一一條記錄的文件,回答其MD5
4、在$MFT第二個片斷中的,擁有$DATA:RUNLIST兩條記錄的文件,回答其MD5
5、讀取某個擁有至少2個A0屬性的目錄塊的MD5
6、給定一個起始簇號,解釋一個RUNLIST的前3條記錄(樣本中至少有3條記錄)
7、恢復一個刪除的文件 (可生成答案後,刪除某個目錄,再恢復其下面的某個文件即可)