Week 11: More scripting
The FAT file system is a file system that allows for saving and deleting files by firstly finding sufficient space on the file system for the file and secondly writing the file to this space and recording the location of the file in the metadata for the file and the cluster chain. The supplied test dd file has several files saved to the file system. Some of these files have been deleted. This lab works through saving files to a USB stick, then deleting files, then formatting a drive and identifying what changes are made to the file system during each of these processes.
Step 1:
The USB stick is formatted to FAT16 with 2048 byte clusters and named mydisk. The Lab5_test.dd image is created by dragging 10 files onto the USB stick.
Step 2:
Find where the final file is located. As the final file saved to the drive is a png and there is only one png file, this can be searched for with the start file signature:
Start Signature: 89 50 4E 47
End Signature: AE 42 60 82
The start of the file is located at 0x5F800 which is 391,168 in decimal
The end of the file is located at 0x5FAF0 which is 391,920 in decimal.
The file is therefore (391,920 – 391,168) = 752 bytes.
The cluster size is 2048.
Therefore, the end of this cluster is at location (391,168 + 2048) = 393,216 or 0x6000
As imaging this 120 MB drive will result in approximately 4MB of data and 115MB of zeros, to make the imaging process quicker and create a small file, calculating the end of the cluster and truncating to that byte is simplest.
Therefore, the USB stick can be imaged from byte 0 to byte 395,264 which is less than 1 percent of the USB stick.
Image the USB stick and name it Lab5_testall.dd
>dcfldd if=/dev/sdb of=Desktop/Lab5_testall.dd bs=1 count=395264 conv=sync,noerror
Step 3:
Open the USB stick in Windows and delete 5 files.
Step 4:
Create a similar dd image of the USB stick named Lab5_testdeleted.dd
>dcfldd if=/dev/sdb of=Desktop/Lab5_testdeleted.dd bs=1 count=395264 conv=sync,noerror
Step 5:
Create 2 text files of the hex of both files so that a comparison can be made to see what has changed in the cluster chain and metadata. Then use the diff command to highlight the differences in the 2 files.
> xxd -c 32 Desktop/Lab5_testall.dd > Desktop/Lab5_testall.txt
> xxd -c 32 Desktop/Lab5_testdeleted.dd > Desktop/Lab5_testdeleted.txt
> diff Desktop/Lab5_testall.txt Desktop/Lab5_testdeleted.txt > Desktop/Lab5_testdiffs.txt
The first change is at byte 0x25 (37) which has changed from 00 to 01.
00c0 0300 8000 2947 8bb5 ea4e 4f20 4e41 4d45 2020 2020 4641 5431 3620 2020 33c9
00c0 0300 8001 2947 8bb5 ea4e 4f20 4e41 4d45 2020 2020 4641 5431 3620 2020 33c9
The next changes are located in the FAT tables – the cluster chains. The deleted files’ cluster chain information has been wiped.
f8ff ffff ffff ffff ffff 0600 0700 ffff 0900 0a00 0b00 0c00 0d00 0e00 ffff 1000
3100 3200 ffff 3400 3500 3600 3700 3800 3900 3a00 3b00 3c00 3d00 3e00 ffff ffff
f8ff ffff ffff ffff ffff 0000 0000 0000 0900 0a00 0b00 0c00 0d00 0e00 ffff 0000
0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ffff
129,130c129,130
< 00001000: f8ff ffff ffff ffff ffff 0600 0700 ffff 0900 0a00 0b00 0c00 0d00 0e00 ffff 1000 ................................
< 00001020: 1100 ffff 1300 ffff 1500 1600 1700 1800 1900 1a00 1b00 ffff 1d00 1e00 1f00 2000 .............................. .
---
> 00001000: f8ff ffff ffff ffff ffff 0000 0000 0000 0900 0a00 0b00 0c00 0d00 0e00 ffff 0000 ................................
> 00001020: 0000 0000 0000 0000 1500 1600 1700 1800 1900 1a00 1b00 ffff 1d00 1e00 1f00 2000 .............................. .
132c132
< 00001060: 3100 3200 ffff 3400 3500 3600 3700 3800 3900 3a00 3b00 3c00 3d00 3e00 ffff ffff 1.2...4.5.6.7.8.9.:.;.<.=.>.....
---
> 00001060: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ffff ................................
3969,3970c3969,3970
< 0001f000: f8ff ffff ffff ffff ffff 0600 0700 ffff 0900 0a00 0b00 0c00 0d00 0e00 ffff 1000 ................................
< 0001f020: 1100 ffff 1300 ffff 1500 1600 1700 1800 1900 1a00 1b00 ffff 1d00 1e00 1f00 2000 .............................. .
---
> 0001f000: f8ff ffff ffff ffff ffff 0000 0000 0000 0900 0a00 0b00 0c00 0d00 0e00 ffff 0000 ................................
> 0001f020: 0000 0000 0000 0000 1500 1600 1700 1800 1900 1a00 1b00 ffff 1d00 1e00 1f00 2000 .............................. .
3972c3972
< 0001f060: 3100 3200 ffff 3400 3500 3600 3700 3800 3900 3a00 3b00 3c00 3d00 3e00 ffff ffff 1.2...4.5.6.7.8.9.:.;.<.=.>.....
---
> 0001f060: 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ffff ................................
7813,7814c7813,7814
< 0003d080: 414d 0069 004e 0069 006f 000f 008b 6e00 2e00 6a00 7000 6700 0000 0000 ffff ffff AM.i.N.i.o....n...j.p.g.........
< 0003d0a0: 4d49 4e49 4f4e 2020 4a50 4720 0078 1b66 4a59 4959 0000 9862 4a59 0500 8915 0000 MINION JPG .x.fJYIY...bJY......
---
> 0003d080: e54d 0069 004e 0069 006f 000f 008b 6e00 2e00 6a00 7000 6700 0000 0000 ffff ffff .M.i.N.i.o....n...j.p.g.........
> 0003d0a0: e549 4e49 4f4e 2020 4a50 4720 0078 1b66 4a59 4a59 0000 9862 4a59 0500 8915 0000 .INION JPG .x.fJYJY...bJY......
7816,7817c7816,7817
< 0003d0e0: 4355 5445 444f 4720 4a50 4720 1884 1d66 4a59 4959 0000 9d62 4a59 0f00 9415 0000 CUTEDOG JPG ...fJYIY...bJY......
< 0003d100: 4652 4f47 2020 2020 4a50 4720 1891 2066 4a59 4959 0000 a462 4a59 1200 750c 0000 FROG JPG .. fJYIY...bJY..u...
---
> 0003d0e0: e555 5445 444f 4720 4a50 4720 1884 1d66 4a59 4a59 0000 9d62 4a59 0f00 9415 0000 .UTEDOG JPG ...fJYJY...bJY......
> 0003d100: e552 4f47 2020 2020 4a50 4720 1891 2066 4a59 4a59 0000 a462 4a59 1200 750c 0000 .ROG JPG .. fJYJY...bJY..u...
7821,7822c7821,7822
< 0003d180: 4d41 4320 2020 2020 4a50 4720 1826 2566 4a59 4959 0000 cb62 4a59 3000 cf14 0000 MAC JPG .&%fJYIY...bJY0.....
< 0003d1a0: 5343 5245 414d 2020 4a50 4720 1828 2666 4a59 4959 0000 d162 4a59 3300 db59 0000 SCREAM JPG .(&fJYIY...bJY3..Y..
---
> 0003d180: e541 4320 2020 2020 4a50 4720 1826 2566 4a59 4a59 0000 cb62 4a59 3000 cf14 0000 .AC JPG .&%fJYJY...bJY0.....
> 0003d1a0: e543 5245 414d 2020 4a50 4720 1828 2666 4a59 4a59 0000 d162 4a59 3300 db59 0000 .CREAM JPG .(&fJYJY...bJY3..Y..
And the metadata line for the first file: MiNion.jpg shows an additional line where the longfilename line would be expected if the name was longer than 8 bytes. However, the name is 6 bytes but this line has been used to record the name because both uppercase and lowercase letters are used in the name. It appears that lowercase names are contained in the metadata line as uppercase letters and are converted to lowercase when displayed. If the filename contains uppercase letters, then an additional metadata line is created to record the correct case for the letters.
414d 0069 004e 0069 006f 000f 008b 6e00 2e00 6a00 7000 6700 0000 0000 ffff ffff AM.i.N.i.o....n...j.p.g.
Followed by the expected metadata line for the MiNion.jpg file.
4d49 4e49 4f4e 2020 4a50 4720 0056 3c98 4959 4959 0000 2061 3e55 0500 8915 0000
e549 4e49 4f4e 2020 4a50 4720 0056 3c98 4959 4959 0000 2061 3e55 0500 8915 0000
Metadata lines for files that have not been deleted are not shown as the lines have not changed in the second dd file. Additionally, the file hex is not shown as deleting a file does not affect the file itself.
Step 6:
Make a copy of the Lab5_testundeleted.dd file and call it Lab5_undeleted.dd.
┌──(root㉿kali)-[~/Desktop]
└─# losetup loop1 Lab5_testall.dd
┌──(root㉿kali)-[~/Desktop]
└─# losetup loop2 Lab5_testdeleted.dd
Ensure all dd files are unmounted and then free all loop devices by using the losetup command:
>losetup -D
Step 7:
Undelete the files:
Open the Lab5_testdeleted.dd file in hexedit and change all the E5 at the start of a metadata line to 5A (Z) except the first E5 in the ‘long’ filename metadata.
Save the changes with F2.
0003D000 4D 59 44 49 53 4B 20 20 20 20 20 08 00 00 00 00 00 00 00 00 00 00 15 66 4A 59 00 00 00 00 00 00 MYDISK ............fJY......
0003D020 42 20 00 49 00 6E 00 66 00 6F 00 0F 00 72 72 00 6D 00 61 00 74 00 69 00 6F 00 00 00 6E 00 00 00 B .I.n.f.o...rr.m.a.t.i.o...n...
0003D040 01 53 00 79 00 73 00 74 00 65 00 0F 00 72 6D 00 20 00 56 00 6F 00 6C 00 75 00 00 00 6D 00 65 00 .S.y.s.t.e...rm. .V.o.l.u...m.e.
0003D060 53 59 53 54 45 4D 7E 31 20 20 20 16 00 2B 14 66 4A 59 4A 59 00 00 15 66 4A 59 02 00 00 00 00 00 SYSTEM~1 ..+.fJYJY...fJY......
0003D080 5A 4D 00 69 00 4E 00 69 00 6F 00 0F 00 8B 6E 00 2E 00 6A 00 70 00 67 00 00 00 00 00 FF FF FF FF ZM.i.N.i.o....n...j.p.g.........
0003D0A0 5A 49 4E 49 4F 4E 20 20 4A 50 47 20 00 78 1B 66 4A 59 4A 59 00 00 98 62 4A 59 05 00 89 15 00 00 ZINION JPG .x.fJYJY...bJY......
0003D0C0 43 41 54 20 20 20 20 20 4A 50 47 20 18 96 1C 66 4A 59 49 59 00 00 9B 62 4A 59 08 00 5A 37 00 00 CAT JPG ...fJYIY...bJY..Z7..
0003D0E0 5A 55 54 45 44 4F 47 20 4A 50 47 20 18 84 1D 66 4A 59 4A 59 00 00 9D 62 4A 59 0F 00 94 15 00 00 ZUTEDOG JPG ...fJYJY...bJY......
0003D100 5A 52 4F 47 20 20 20 20 4A 50 47 20 18 91 20 66 4A 59 4A 59 00 00 A4 62 4A 59 12 00 75 0C 00 00 ZROG JPG .. fJYJY...bJY..u...
0003D120 4D 59 50 44 20 20 20 20 50 44 46 20 18 99 21 66 4A 59 49 59 00 00 AB 62 4A 59 14 00 78 3C 00 00 MYPD PDF ..!fJYIY...bJY..x<..
0003D140 47 49 52 41 46 46 45 20 4A 50 47 20 18 1F 23 66 4A 59 49 59 00 00 C0 62 4A 59 1C 00 EC 82 00 00 GIRAFFE JPG ..#fJYIY...bJY......
0003D160 4C 49 4F 4E 20 20 20 20 42 4D 50 20 18 43 24 66 4A 59 49 59 00 00 C6 62 4A 59 2D 00 FE 15 00 00 LION BMP .C$fJYIY...bJY-.....
0003D180 5A 41 43 20 20 20 20 20 4A 50 47 20 18 26 25 66 4A 59 4A 59 00 00 CB 62 4A 59 30 00 CF 14 00 00 ZAC JPG .&%fJYJY...bJY0.....
0003D1A0 5A 43 52 45 41 4D 20 20 4A 50 47 20 18 28 26 66 4A 59 4A 59 00 00 D1 62 4A 59 33 00 DB 59 00 00 ZCREAM JPG .(&fJYJY...bJY3..Y..
0003D1C0 54 49 4E 59 53 54 41 52 50 4E 47 20 18 07 27 66 4A 59 49 59 00 00 D5 62 4A 59 3F 00 F0 02 00 00 TINYSTARPNG ..'fJYIY...bJY?.....
Open the Lab5testdeleted.dd with losetup.
This is all fairly familiar. The icons have reappeared but the minion (ZINION) filename is in uppercase. It appears that the existence of the ‘long’ filename metadata line is recognized and by default the name is in uppercase.
Change the start of the ‘long’ filename metadata line to 41 (the original value) and reopen the Lab5_testdeleted.dd file with losetup.
The filename has not changed. Clearly more than changing the E5 is required.
It will be useful later to know where the first cluster that is used for saving files to is located. Whilst in the metadata area, search for the first file which is a jpg.
It is found at 0x42800 which is 272,384 in decimal.
By checking the metadata line for the starting cluster of the first jpg, we see that this is cluster 5 (0x42800). So, cluster 5 begins at 272, 384. With a cluster size of 2048, we can now work out with a simple calculation where each file begins if we know the starting cluster.
Step 8:
While seeing the original icons is useful evidence and indicates what the original disk looked like before the files were deleted, the files do not have thumbnails and will not open. Restoring the cluster chain is the next step so that the files will open. However, first we will work through the metadata line so that we understand what each field does.
We shall work through the cat.jpg metadata line.
43 41 54 20 20 20 20 20 4A 50 47 20 18 A6 41 98 49 59 49 59 00 00 8C 7E 21 53 08 00 5A 37 00 00
Name 8 + 4 bytes in big endian
43 41 54 20 20 20 20 20 4A 50 47 20
C A T J P G
Permission Information 4 bytes
18 A6 41 98
Dates 2 bytes in little endian
49 59 = (59 49) = 22857
The decimal conversion is meaningless because the date is made up in 3 parts, year, month and day, by looking at the bits. Therefore, converting to binary is required.
22857 =
01011001 01001001
The first 7 bits is the year added to the base year of 1980.
0101100 = 4 + 8 + 32 = 44 44 + 1980 = 2024
The next 4 bits is the month
1010 = 2 + 8 = 10 October
The final 5 bits is the day
01001 = 2 + 8 = 10 10th October 2024
Step 9:
Extract this information in Bash
Create a new Bash script called meta.sh
The cat.jpg line is located at 0x3D0C0 which is 250048 in decimal. Our script can jump to this line and copy this metadata line into a variable.
Therefore, there should be:
1: an input file name
2: a skipvalue to skip to the desired line
3: a suitable variable name and a command to retrieve the 32 byte line and save it to the variable.
这个命令使用 xxd 工具,从文件的特定位置开始提取一段数据,并以纯十六进制格式输出。让我们分解一下这个命令的含义:
xxd:这是用于查看或转换文件为十六进制格式的命令。
-s $skipvalue:-s 选项用于指定开始偏移量(即从文件的哪个位置开始读取数据)。$skipvalue 是一个变量,表示偏移量(以字节为单位),它是你要跳过的文件开头的字节数。
-l 32:-l 选项指定读取的字节长度。在这个例子中,32 表示读取 32 字节的数据。
-ps:这是两个选项的组合:
-p:表示只输出纯十六进制数,没有地址和 ASCII 信息。
-s:与前面的 -p 结合使用,表示以每行 2 字节(1 字节为2个十六进制字符)输出。
$infilename:这是输入文件的名称,$infilename 是一个变量,表示要读取的文件名。
#!/bin/bash
# This file reads a metadata line in a FAT16 file system and parses the line
infilename=Lab5_testall.dd
skipvalue=250048
metadataline=$(xxd -s $skipvalue -l 32 -ps $infilename)
printf $metadataline
┌──(root㉿kali)-[~/Desktop]
└─# chmod +x meta.sh
┌──(root㉿kali)-[~/Desktop]
└─# ./meta.sh
43415420202020204a50472018961c664a59495900009b624a5908005a37
The line is truncated because it ends in 0000. Not quite what we want. Change the printf statement to:
printf '%s' $metadataline
┌──(root㉿kali)-[~/Desktop]
└─# ./meta.sh
43415420202020204a50472018961c664a59495900009b624a5908005a370000
This prints the line as if it were a string of characters rather than a number. The variable remains in hex format.
Now that the line of metadata is contained in a variable, we can select any byte or bytes withing that variable. Add a line to your script to save the filename and extension into. For this, the ‘cut’ command is used. Note that the cut command reads each character, not each byte, so when reading hex values, FF is one byte byt 2 characters.
-c 1-12:-c 选项指定按字符范围提取数据。1-12 表示从每行的第 1 个字符到第 12 个字符提取。如果一行有多个字符,该命令只会提取这些字符;如果字符数量少于 12,则提取全部字符。
#!/bin/bash
# This file reads a metadata line in a FAT16 file system and parses the line
infilename=Lab5_testall.dd
skipvalue=250048
metadataline=$(xxd -s $skipvalue -l 32 -ps $infilename)
printf "%s" $metadataline
read filename < <(echo $metadataline | cut -c 1-12)
printf "\nThe filename is %s" $filename
┌──(root㉿kali)-[~/Desktop]
└─# ./meta.sh
43415420202020204a50472018961c664a59495900009b624a5908005a370000
The filename is 434154202020
Well, that is technically correct. The filename is in hex format. To print the filename in ASCII we could print it as ASCII or better, we could convert it to ASCII and then print it. That way, the filename is stored in the correct format, as an ASCII string. It may be best to change the variable names so they are more descriptive. For example, filename is in hex, so the ASCII filemname will need a different variable name but perhaps filename is best, Change the variable ‘filename’ to ‘hexfilename’. We can now use ‘filename’ as the ASCII conversion of hexfilename.
xxd:这是用于查看或转换文件为十六进制或从十六进制还原的工具。
-r:-r 选项用于“逆转换”或“还原”。它告诉 xxd 将输入的十六进制数据转换回二进制。
-p:-p 选项用于“纯十六进制模式”。它表示输入或输出时没有地址和 ASCII 信息,仅包含纯十六进制数。该选项适用于数据没有其他格式或注释,只包含连续的十六进制字符的情况。
#!/bin/bash
# This file reads a metadata line in a FAT16 file system and parses the line
infilename=Lab5_testall.dd
skipvalue=250048
metadataline=$(xxd -s $skipvalue -l 32 -ps $infilename)
printf "%s" $metadataline
read hexfilename < <(echo $metadataline | cut -c 1-12)
read filename < <(echo $hexfilename | xxd -r -p)
printf "\nThe filename is %s" $filename
┌──(root㉿kali)-[~/Desktop]
└─# ./meta.sh
43415420202020204a50472018961c664a59495900009b624a5908005a370000
The filename is CAT
If we change the cut command to read 24 bytes, the result is:
#!/bin/bash
# This file reads a metadata line in a FAT16 file system and parses the line
infilename=Lab5_testall.dd
skipvalue=250048
metadataline=$(xxd -s $skipvalue -l 32 -ps $infilename)
printf "%s" $metadataline
read hexfilename < <(echo $metadataline | cut -c 1-24)
read filename < <(echo $hexfilename | xxd -r -p)
printf "\nThe filename is %s" $filename
┌──(root㉿kali)-[~/Desktop]
└─# ./meta.sh
43415420202020204a50472018961c664a59495900009b624a5908005a370000
The filename is CAT
The filename is JPG
Close, but there is a problem. Even though 12 bytes have been saved in ‘filename’, the spaces between CAT and JPG have prevented the final bytes being saved together. The print command runs twice even though there is only one command. Perhaps this is not a bad thing. We need a full stop before the extension so perhaps we can simply read the filename as 2 operations. Read the first 8 bytes and save them into ‘filename’. Then, add a full stop to the end of the filename. Then read the final 4 bytes as ‘extension’ and add it to the filename. To join 2 strings together they can simply be written one after the other. As the full stop is not in a variable, it must be written in quotes. The command to piece all 3 parts of the filename together is therefore:
#!/bin/bash
# This file reads a metadata line in a FAT16 file system and parses the line
infilename=Lab5_testall.dd
skipvalue=250048
metadataline=$(xxd -s $skipvalue -l 32 -ps $infilename)
printf "%s" $metadataline
read hexfilename < <(echo $metadataline | cut -c 1-12)
read filename < <(echo $hexfilename | xxd -r -p)
read hexextension < <(echo $metadataline | cut -c 13-24)
read fileextension < <(echo $hexextension | xxd -r -p)
printf "\nThe filename is %s.%s" $filename $fileextension
┌──(root㉿kali)-[~/Desktop]
└─# ./meta.sh
43415420202020204a50472018961c664a59495900009b624a5908005a370000
The filename is CAT.JPG
Success. We now have the entire filename in a variable.
Step 10:
Read the date and convert it to the correct format.
The date is located at bytes 17 and 18 (33 to 37 for the cut command). We shall just read one date for this lab. The process is:
1: Read the 2 date bytes and convert them to little endian.
2: Convert the 2 bytes to decimal.
3: Conver the decimal 16 bits of binary.
4: Divide the bytes up into 7, 4 and 5 (year, month and day).
5: Convert the binary to decimal – add 1980 to the year.
6: Add the forward slashes to make the date readable.
This is a little tricky. We shall take it slowly. Read the 2 date bytes and change them to little endian.
#!/bin/bash
# This file reads a metadata line in a FAT16 file system and parses the line
infilename=Lab5_testall.dd
skipvalue=250048
# Get metadata
metadataline=$(xxd -s $skipvalue -l 32 -ps $infilename)
printf "%s" $metadataline
# Get name and extension
read hexfilename < <(echo $metadataline | cut -c 1-16)
read filename < <(echo $hexfilename | xxd -r -p)
read hexextension < <(echo $metadataline | cut -c 17-24)
read fileextension < <(echo $hexextension | xxd -r -p)
printf "\nThe filename is %s.%s" $filename $fileextension
# Get date information
read hexfulldate1 < <(echo $metadataline | cut -c 33-34)
read hexfulldate2 < <(echo $metadataline | cut -c 35-36)
hexfulldate=$hexfulldate2$hexfulldate1
printf "\n%s" $hexfulldate
┌──(root㉿kali)-[~/Desktop]
└─# ./meta.sh
43415420202020204a50472018961c664a59495900009b624a5908005a370000
The filename is CAT.JPG
594a
Convert the 2 bytes of hex to 16 bytes of binary. We shall use the ‘bc’ command which is a command to convert between hex and binary. It is not natively part of Linux so we need to install bc.
\$((16#hexfulldate)):这个部分使用了 Bash 的算术扩展。16# 表示该值是一个十六进制数。hexfulldate 是一个变量,它包含一个十六进制数(例如 A1B2C3)。通过 $((16#hexfulldate)),这个十六进制数将被转换为十进制数。
如果只使用 bc 来完成十进制到二进制的转换,可以直接通过终端输入 bc 命令进行转换。以下是具体的步骤:
打开终端,然后启动 bc:
bash
Copy code
bc
设置输入和输出的数制,进行转换:
bash
Copy code
obase=2 # 设置输出为二进制
ibase=10 # 设置输入为十进制
10 # 输入十进制数(在这里以 10 为例)
按 Enter 后,bc 将输出对应的二进制表示:
Copy code
1010
单行命令形式
也可以直接在一行中完成转换,而不需要进入 bc 交互模式。例如,将十进制数 45 转换为二进制:
Copy code
echo "obase=2; ibase=10; 45" | bc
#!/bin/bash
# This file reads a metadata line in a FAT16 file system and parses the line
infilename=Lab5_testall.dd
skipvalue=250048
# Get metadata
metadataline=$(xxd -s $skipvalue -l 32 -ps $infilename)
printf "%s" $metadataline
# Get name and extension
read hexfilename < <(echo $metadataline | cut -c 1-16)
read filename < <(echo $hexfilename | xxd -r -p)
read hexextension < <(echo $metadataline | cut -c 17-24)
read fileextension < <(echo $hexextension | xxd -r -p)
printf "\nThe filename is %s.%s" $filename $fileextension
# Get date information
read hexfulldate1 < <(echo $metadataline | cut -c 33-34)
read hexfulldate2 < <(echo $metadataline | cut -c 35-36)
hexfulldate=$hexfulldate2$hexfulldate1
printf "\nThe full date in hex is %s" $hexfulldate
# Convert hex date to decimal
read decimaldate < <(echo $((16#$hexfulldate)))
printf "\nThe full date in decimal is %s" $decimaldate
# Convert binary
read binarydate < <(echo "obase=2; ibase=10; ${decimaldate}" | bc)
printf "\nThe full date in binary is %s" $binarydate
┌──(root㉿kali)-[~/Desktop]
└─# ./meta.sh
43415420202020204a50472018961c664a59495900009b624a5908005a370000
The filename is CAT.JPG
The full date in hex is 594a
The full date in decimal is 22858
The full date in binary is 101100101001010
It is best to have comments stating what each command does and to print to the screen as you go to ensure the output is what you expect. That way, you will know as soon as a command is not working correctly. To print the hex, decimal and binary to the screen, it is simplest to print them as a string.
We are getting there. The next step is to select the first 7 bits only for the year. I shall call the variable yearbin7 so it is obvious (to me) what it is.
The variable we are parsing is ‘binarydate’. This is 16 zeros and ones. We wish to just extract the first 7 and then convert this to a decimal number with the ‘bc’ command. Note that as 1 is inclusive of 1-6, this is 7 numbers.
数值表示:当 Bash 读取 binarydate 时,如果二进制数的计算结果以数值的形式处理,那么任何不必要的前导零都会被忽略,因为数值前的零在数值上下文中是无意义的。所以读取1-6即可
...
# Get date information
read hexfulldate1 < <(echo $metadataline | cut -c 33-34)
read hexfulldate2 < <(echo $metadataline | cut -c 35-36)
hexfulldate=$hexfulldate2$hexfulldate1
printf "\nThe full date in hex is %s" $hexfulldate
# Convert hex date to decimal
read decimaldate < <(echo $((16#$hexfulldate)))
printf "\nThe full date in decimal is %s" $decimaldate
# Convert dcimal date to binary
read binarydate < <(echo "obase=2; ibase=10; ${decimaldate}" | bc)
printf "\nThe full date in binary is %s" $binarydate
# Get the actual year
read yearbin7 < <(echo $binarydate | cut -c 1-6)
read yeardecimal < <(echo "obase=10; ibase=2; {$yearbin7}" | bc)
actualyear=$(($yeardecimal+1980))
# Get the actual month
read monthbin < <(echo $binarydate | cut -c 7-10)
read monthdecimal < <(echo "obase=10; ibase=2; {$monthbin}" | bc)
# Get the actual day
read daybin < <(echo $binarydate | cut -c 11-15)
read daydecimal < <(echo "obase=10; ibase=2; {$daybin}" | bc)
fullaccessdate=$daydecimal"/"$monthdecimal"/"$actualyear
printf "\nThe Date is %s" $fullaccessdate
┌──(root㉿kali)-[~/Desktop]
└─# ./meta.sh
43415420202020204a50472018961c664a59495900009b624a5908005a370000
The filename is CAT.JPG
The full date in hex is 594a
The full date in decimal is 22858
The full date in binary is 101100101001010
The Date is 10/10/2024
Success! We now have the ‘access date’ in a variable.
Step 11:
Next, we want to read the starting cluster for the file. It will located at 53 54 55 56, 55 56 in advanced of 53 54.
...
# Read the starting cluster and convert to decimal
read hexstartcluster1 < <(echo $metadataline | cut -c 53-54)
read hexstartcluster2 < <(echo $metadataline | cut -c 55-56)
hexstartcluster=$hexstartcluster2$hexstartcluster1
decimalstartcluster=$(printf $((16#$hexstartcluster)))
printf "\nHexstartcluster= %s" $hexstartcluster
printf "\nThe starting cluster is %s" $decimalstartcluster
┌──(root㉿kali)-[~/Desktop]
└─# ./meta.sh
43415420202020204a50472018961c664a59495900009b624a5908005a370000
The filename is CAT.JPG
The full date in hex is 594a
The full date in decimal is 22858
The full date in binary is 101100101001010
The Date is 10/10/2024
Hexstartcluster= 0008
The starting cluster is 8
The leading zeros are ignored in the decimal.
Next, we want to retrieve the size of the file.
Step 12:
Read the size of the file. This requires reading 4 bytes in little endian and converting them to big endian. It should be located at 56 57 58 59 of metadata. Ans, 59 58 57 56 is the right sequence.
...
# Read the size of file
filesize1=$(xxd -s $((skipvalue+28)) -l 1 -ps $infilename)
filesize2=$(xxd -s $((skipvalue+29)) -l 1 -ps $infilename)
filesize3=$(xxd -s $((skipvalue+30)) -l 1 -ps $infilename)
filesize4=$(xxd -s $((skipvalue+31)) -l 1 -ps $infilename)
hexfilesize=$filesize4$filesize3$filesize2$filesize1
decimalfilesize=$(printf $((16#$hexfilesize)))
printf "\nThe file size is %s" $decimalfilesize
┌──(root㉿kali)-[~/Desktop]
└─# ./meta.sh
43415420202020204a50472018961c664a59495900009b624a5908005a370000
The filename is CAT.JPG
The full date in hex is 594a
The full date in decimal is 22858
The full date in binary is 101100101001010
The Date is 10/10/2024
Hexstartcluster= 0008
The starting cluster is 8
The file size is 14170
Now write this information to the screen using printf so that it can be displayed across the screen rather than as a list. Write everything as a string of text. The \t switch is a tab which is useful for printing.
This presents the information nicely but we can enhance this firstly by having a heading for each column and secondly by stating where the file begins – the starting byte location.
Add the headings for the columns:
...
# Print the resulat
printf "Filename \t Access Date \t FIlesize \t Cluster \n"
printf "%s \t \t %s \t %s \t \t %s" $filename $fullaccessdate $decimalfilesize $decimalstartcluster
┌──(root㉿kali)-[~/Desktop]
└─# ./meta.sh
Filename Access Date FIlesize Cluster
CAT 10/10/2024 14170 8
Nearly there. If we can tell the user where the cluster begins, cluster 8 for example, then there is information that could be used to retrieve a file just from the metadata provided the file was not deleted and written over by a later file. Recall that we know were cluster 5 is (byte 272,384) and how big the clusters are (2048 bytes). Add the start cluster value near the beginning of the script as a variable called startcluster, and then add a variable called clustersize.
Now navigate to the end of the script and provide the user with the information of where the file begins and ends.
Step 13:
File locations information.
Add these 2 lines to the script before the printf commands to print to the screen:
...
# Get file start and end byte
filestartbyte=$((startcluster + ((decimalstartcluster-5) * $clustersize )))
fileendbyte=$(($filestartbyte + $decimalfilesize))
# Print the resulat
printf "Filename \t Access Date \t FIlesize \t Cluster \t Start \t End \n"
printf "%s \t \t %s \t %s \t \t %s \t \t%s \t %s" $filename $fullaccessdate $decimalfilesize $decimalstartcluster $filestartbyte $fileendbyte
┌──(root㉿kali)-[~/Desktop]
└─# ./meta.sh
Filename Access Date FIlesize Cluster Start End
CAT 10/10/2024 14170 8 278528 292698
Some experimenting with tabs and spaces is required but the result should be presented nicely to the user. This could easily be directed to a text file as an audit.txt and could include a loop working through each line of metadata so the result is a complete audit.txt file with all file information.
If you’re feeling confident in your script, see if you can carve the cat.jpg file with the information you have retrieved from the metadata. Add the following line to your script but leave 2 blank lines so you don’t disturb your user information.
...
# Restore this file
dcfldd if=$infilename of=$filename bs=1 skip=$filestartbyte count=$decimalfilesize
┌──(root㉿kali)-[~/Desktop]
└─# ./meta.sh
Filename Access Date FIlesize Cluster Start End
14080 blocks (0Mb) written. 14170 8 278528 292698
14170+0 records in
14170+0 records out
The full code is
#!/bin/bash
# This file reads a metadata line in a FAT16 file system and parses the line
infilename=Lab5_testdeleted.dd
skipvalue=250048
startcluster=272384 # No.5 cluster
clustersize=2048
# Get metadata
metadataline=$(xxd -s $skipvalue -l 32 -ps $infilename)
# Get name and extension
read hexfilename < <(echo $metadataline | cut -c 1-16)
read filename < <(echo $hexfilename | xxd -r -p)
read hexextension < <(echo $metadataline | cut -c 17-24)
read fileextension < <(echo $hexextension | xxd -r -p)
# Get date information
read hexfulldate1 < <(echo $metadataline | cut -c 33-34)
read hexfulldate2 < <(echo $metadataline | cut -c 35-36)
hexfulldate=$hexfulldate2$hexfulldate1
# Convert hex date to decimal
read decimaldate < <(echo $((16#$hexfulldate)))
# Convert dcimal date to binary
read binarydate < <(echo "obase=2; ibase=10; ${decimaldate}" | bc)
# Get the actual year
read yearbin7 < <(echo $binarydate | cut -c 1-6)
read yeardecimal < <(echo "obase=10; ibase=2; {$yearbin7}" | bc)
actualyear=$(($yeardecimal+1980))
# Get the actual month
read monthbin < <(echo $binarydate | cut -c 7-10)
read monthdecimal < <(echo "obase=10; ibase=2; {$monthbin}" | bc)
# Get the actual day
read daybin < <(echo $binarydate | cut -c 11-15)
read daydecimal < <(echo "obase=10; ibase=2; {$daybin}" | bc)
fullaccessdate=$daydecimal"/"$monthdecimal"/"$actualyear
# Read the starting cluster and convert to decimal
read hexstartcluster1 < <(echo $metadataline | cut -c 53-54)
read hexstartcluster2 < <(echo $metadataline | cut -c 55-56)
hexstartcluster=$hexstartcluster2$hexstartcluster1
decimalstartcluster=$(printf $((16#$hexstartcluster)))
# Read the size of file
filesize1=$(xxd -s $((skipvalue+28)) -l 1 -ps $infilename)
filesize2=$(xxd -s $((skipvalue+29)) -l 1 -ps $infilename)
filesize3=$(xxd -s $((skipvalue+30)) -l 1 -ps $infilename)
filesize4=$(xxd -s $((skipvalue+31)) -l 1 -ps $infilename)
hexfilesize=$filesize4$filesize3$filesize2$filesize1
decimalfilesize=$(printf $((16#$hexfilesize)))
# Get file start and end byte
filestartbyte=$((startcluster + ((decimalstartcluster-5) * $clustersize )))
fileendbyte=$(($filestartbyte + $decimalfilesize))
# Print the resulat
printf "Filename \t Access Date \t FIlesize \t Cluster \t Start \t End \n"
printf "%s \t \t %s \t %s \t \t %s \t \t%s \t %s" $filename $fullaccessdate $decimalfilesize $decimalstartcluster $filestartbyte $fileendbyte
# Restore this file
dcfldd if=$infilename of=$filename bs=1 skip=$filestartbyte count=$decimalfilesize