Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/bash
- # Global variable to control verbose output
- VERBOSE=0
- # Function to print verbose messages
- verbose_log() {
- if [ "$VERBOSE" -eq 1 ]; then
- echo "$1"
- fi
- }
- # Function to convert hexadecimal string to decimal
- hex_to_dec() {
- echo "$((16#$1))"
- }
- # Function to seek to a specific position in the file
- doseek() {
- local f=$1
- local n=$2
- BLOCKSIZE=512
- na=$((n / BLOCKSIZE))
- nb=$((n % BLOCKSIZE))
- dd if="$f" of=/dev/null bs=$BLOCKSIZE skip=$na 2>/dev/null
- if [ $nb -ne 0 ]; then
- dd if="$f" of=/dev/null bs=1 skip=$nb count=1 2>/dev/null
- fi
- }
- # Function to read a specific number of bytes from a specific position
- readat() {
- local f=$1
- local n=$2
- local s=$3
- doseek "$f" "$n"
- dd if="$f" bs=1 count=$s 2>/dev/null
- }
- # Function to parse the filename attribute
- parseFilename() {
- local s=$1
- ref=$(echo -n "$s" | dd bs=1 count=8 status=none | hexdump -v -e '/1 "%02x"' | rev)
- ref=$(hex_to_dec "$ref")
- flen=$(echo -n "$s" | dd bs=1 skip=64 count=1 status=none | hexdump -v -e '/1 "%02x"' | rev)
- flen=$(hex_to_dec "$flen")
- fn=$(echo -n "$s" | dd bs=1 skip=66 count=$((flen * 2)) status=none | iconv -f UTF-16LE -t UTF-8)
- verbose_log "Parsed filename: $fn with reference $ref"
- echo "$ref $fn"
- }
- # Function to parse the MFT file
- parse_mft() {
- local f=$1
- local bpc=$2
- local mft=$3
- local out=()
- for i in $(seq 0 $(($(echo -n "$mft" | wc -c) / 1024 - 1))); do
- if [ $((i % 791)) -eq 0 ]; then
- echo -ne "\rParsing MFT: $i/$(($(echo -n "$mft" | wc -c) / 1024))" >&2
- fi
- chunk=$(echo -n "$mft" | dd bs=1 skip=$((i * 1024)) count=1024 status=none)
- if [ "$(echo -n "$chunk" | dd bs=1 count=4 status=none)" = "FILE" ]; then
- out+=("$(parse_file "$f" $((i * 1024)) $bpc "$chunk")")
- else
- out+=(0)
- fi
- done
- echo -e "\rParsing MFT: Done! " >&2
- echo "${out[@]}"
- }
- # Function to parse a file record
- parse_file() {
- local f=$1
- local chunkoff=$2
- local bpc=$3
- local chunk=$4
- local magic=$(echo -n "$chunk" | dd bs=1 count=4 status=none | hexdump -v -e '/1 "%02x"' | rev)
- magic=$(hex_to_dec "$magic")
- local usa_ofs=$(echo -n "$chunk" | dd bs=1 skip=4 count=2 status=none | hexdump -v -e '/1 "%02x"' | rev)
- usa_ofs=$(hex_to_dec "$usa_ofs")
- local usa_count=$(echo -n "$chunk" | dd bs=1 skip=6 count=2 status=none | hexdump -v -e '/1 "%02x"' | rev)
- usa_count=$(hex_to_dec "$usa_count")
- local attr_offset=$(echo -n "$chunk" | dd bs=1 skip=20 count=2 status=none | hexdump -v -e '/1 "%02x"' | rev)
- attr_offset=$(hex_to_dec "$attr_offset")
- local attrs=()
- local pos=$attr_offset
- while true; do
- if [ $pos -gt $((1024 - 12)) ]; then
- break
- fi
- type=$(echo -n "$chunk" | dd bs=1 skip=$pos count=4 status=none | hexdump -v -e '/1 "%02x"' | rev)
- type=$(hex_to_dec "$type")
- if [ $type -eq -1 ]; then
- break
- fi
- size=$(echo -n "$chunk" | dd bs=1 skip=$((pos + 4)) count=4 status=none | hexdump -v -e '/1 "%02x"' | rev)
- size=$(hex_to_dec "$size")
- nonres=$(echo -n "$chunk" | dd bs=1 skip=$((pos + 8)) count=1 status=none | hexdump -v -e '/1 "%02x"' | rev)
- nonres=$(hex_to_dec "$nonres")
- namelen=$(echo -n "$chunk" | dd bs=1 skip=$((pos + 9)) count=1 status=none | hexdump -v -e '/1 "%02x"' | rev)
- namelen=$(hex_to_dec "$namelen")
- nameoff=$(echo -n "$chunk" | dd bs=1 skip=$((pos + 10)) count=2 status=none | hexdump -v -e '/1 "%02x"' | rev)
- nameoff=$(hex_to_dec "$nameoff")
- if [ $namelen -ne 0 ]; then
- name=$(echo -n "$chunk" | dd bs=1 skip=$nameoff count=$((namelen * 2)) status=none | iconv -f UTF-16LE -t UTF-8)
- else
- name=""
- fi
- verbose_log "Attribute type: $type, size: $size, non-resident: $nonres, name: $name"
- if [ $type -eq 48 ]; then
- attrs+=("$(parseFilename "$(echo -n "$chunk" | dd bs=1 skip=$pos count=$size status=none)")")
- fi
- pos=$((pos + size))
- done
- echo "${attrs[@]}"
- }
- # Main function
- main() {
- disk=""
- while [[ $# -gt 0 ]]; do
- case $1 in
- -v|--verbose)
- VERBOSE=1
- shift
- ;;
- *)
- disk=$1
- shift
- ;;
- esac
- done
- if [ -z "$disk" ]; then
- echo "Usage: $0 [-v|--verbose] <disk>"
- exit 1
- fi
- verbose_log "Running in verbose mode"
- if ! echo -n "$(readat "$disk" 3 8)" | grep -q "NTFS"; then
- echo "Not an NTFS disk???"
- exit 1
- fi
- bps=$(echo -n "$(readat "$disk" 0xb 2)" | hexdump -v -e '/1 "%02x"' | rev)
- bps=$(hex_to_dec "$bps")
- spc=$(echo -n "$(readat "$disk" 0xd 1)" | hexdump -v -e '/1 "%02x"' | rev)
- spc=$(hex_to_dec "$spc")
- bpc=$((bps * spc))
- mft_clust=$(echo -n "$(readat "$disk" 0x30 8)" | hexdump -v -e '/1 "%02x"' | rev)
- mft_clust=$(hex_to_dec "$mft_clust")
- mftmirr_clust=$(echo -n "$(readat "$disk" 0x38 8)" | hexdump -v -e '/1 "%02x"' | rev)
- mftmirr_clust=$(hex_to_dec "$mftmirr_clust")
- clust_per_mft=$(echo -n "$(readat "$disk" 0x40 1)" | hexdump -v -e '/1 "%02x"' | rev)
- clust_per_mft=$(hex_to_dec "$clust_per_mft")
- verbose_log "Bytes per sector: $bps"
- verbose_log "Sectors per cluster: $spc"
- verbose_log "Bytes per cluster: $bpc"
- verbose_log "MFT cluster: $mft_clust"
- verbose_log "MFT mirror cluster: $mftmirr_clust"
- verbose_log "Clusters per MFT: $clust_per_mft"
- echo "Reading MFT" >&2
- mftbytes=$(readat "$disk" $((mft_clust * bpc)) $((clust_per_mft * bpc)))
- mft=$(parse_mft "$disk" $bpc "$mftbytes")
- for file in $mft; do
- echo "$file"
- done
- }
- if [ "$#" -lt 1 ]; then
- echo "Usage: $0 [-v|--verbose] <disk>"
- exit 1
- fi
- main "$@"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement