import sys
import struct
from binascii import *
# 부트 섹터의 끝 서명 (FAT32 파티션 유효성 확인용)
bootsector_end_signature = b'\x55\xAA'
# FSINFO 시그니처
fsinfo_signature = b'\x52\x52\x61\x41'
FSINFO_SIGNATURE = b'RRaA'
fsinfo_signature = b'rrAa'
cluster = []
def FAT(fat32_path):
global bootsector_end_signature
global FSINFO_SIGNATURE
global fsinfo_signature
try:
with open(fat32_path, 'rb') as f:
# 부트 섹터 끝에 서명이 있는지 확인
f.seek(510)
test = f.read(2)
if test == bootsector_end_signature:
# MBR 출력
print(f'\n# MBR\n')
print(f'@ Partition 0')
# MBR에서 파티션 정보를 읽기 위해 오프셋 이동
f.seek(446)
# 부트 플래그 확인
boot_flag = f.read(1)
print(f'Boot Flag: 0x{boot_flag.hex()}')
# 시작 CHS 주소
starting_CHS_addr = f.read(3)
hex_starting_CHS_addr = int.from_bytes(starting_CHS_addr, byteorder='little')
print(f'CHS Addr: 0x{hex_starting_CHS_addr:x}')
# 파티션 유형
partition_type = f.read(1)
hex_partition_type = int.from_bytes(partition_type, byteorder='little')
print(f'Part Type: 0x{hex_partition_type:x}')
# 종료 CHS 주소
ending_CHS_addr = f.read(3)
hex_ending_CHS_addr = int.from_bytes(ending_CHS_addr, byteorder='little')
print(f'Ending CHS Addr: 0x{hex_ending_CHS_addr:x}')
# 시작 LBA 주소
starting_LBA_addr = f.read(4)
int_starting_LBA_addr = int.from_bytes(starting_LBA_addr, byteorder='little')
print(f'Starting LBA Addr: {int_starting_LBA_addr} sector')
# 섹터의 크기
size_in_sector = f.read(4)
int_size_in_sector = int.from_bytes(size_in_sector, byteorder='little')
print(f'Size in Sector: 0x{int_size_in_sector:x}\n')
print(f'-----MBR Check Complete-----\n')
# 예약된 영역 정보 출력
print(f'@ Partition 0\n')
print(f'#Reserved Area')
# 예약된 영역의 시작 위치로 이동
f.seek(int_starting_LBA_addr * 512)
# 섹터 위치
print(f'sector: {int_starting_LBA_addr}')
# 점프 부트 코드 (부트 스트랩 로더 시작 코드)
jump_boot_code = f.read(3)
edit_jump_boot_code = ' '.join([jump_boot_code.hex()[i:i+2] for i in range(0, len(jump_boot_code.hex()), 2)])
print(f'Jump Boot Code: {edit_jump_boot_code}')
# OEM ID (제조업체 ID)
oem_id = f.read(8)
str_oem_id = oem_id.decode('ascii')
edit_oem_id = ' '.join([oem_id.hex()[i:i+2] for i in range(0, len(oem_id.hex()), 2)])
print(f'OEM ID (str/hex) : {str_oem_id} / {edit_oem_id}')
# 섹터 당 바이트 수
bp = f.read(2)
int_bp = int.from_bytes(bp, byteorder='little')
print(f'Byte Per Sector: {int_bp}')
# 클러스터 당 섹터 수
sp = f.read(1)
print(f'Sectors Per Cluster: 0x{sp.hex()}')
# 예약된 섹터 수
reserved_sector_count = f.read(2)
int_reserved_sector_count = int.from_bytes(reserved_sector_count, byteorder='little')
print(f'Reserved Sector Count: 0x{int_reserved_sector_count:x}')
# FAT 테이블 수
number_of_fat_tables = f.read(1)
int_numnumber_of_fat_tables = int.from_bytes(number_of_fat_tables, byteorder='little')
# 루트 디렉토리 엔트리 수 (미사용)
root_directory_entry_count = f.read(2)
# 총 섹터 수, 미디어 타입, FAT 크기 (미사용)
f.read(8)
# 트랙 당 섹터 수
sector_per_track = f.read(2)
int_sector_per_track = int.from_bytes(sector_per_track, byteorder='little')
print(f'Sector per track: 0x{int_sector_per_track:x}')
# 헤드 수, 숨겨진 섹터 수, 총 섹터 수 (미사용)
f.read(10)
# FAT32의 크기
fat32_size = f.read(4)
int_fat32_size = int.from_bytes(fat32_size, byteorder='little')
print(f'FAT32 Size: {int_fat32_size}')
# 확장 플래그, FAT32 볼륨 버전 (미사용)
f.read(4)
# 루트 디렉토리 클러스터 오프셋
root_directory_cluster_offset = f.read(4)
int_root_directory_cluster_offset = int.from_bytes(root_directory_cluster_offset, byteorder='little')
print(f'Root directory cluster offset: {int_root_directory_cluster_offset} cluster\n')
# FSINFO 오프셋
fsinfo_offset = f.read(2)
int_fsinfo_offset = int.from_bytes(fsinfo_offset, byteorder='little')
# FSINFO (파일 시스템 정보) 섹션
print(f'FSINFO')
# FSINFO 섹션 시작 위치로 이동 (섹터 1을 기준으로 함)
f.seek((int_fsinfo_offset+1) * 512)
# RRaA 시그니처 확인
FSINFO_Signature = f.read(4)
if FSINFO_Signature == FSINFO_SIGNATURE:
print(f'Signature: {FSINFO_Signature}')
# rrAa 시그니처 확인
f.seek((int_fsinfo_offset+1) * 512 + 484)
FSINFO_signature = f.read(4)
if FSINFO_signature == fsinfo_signature:
print(f'Signature: {FSINFO_signature}')
# 사용 가능한 클러스터 수
Numver_of_free_Cluster = f.read(4)
int_Numver_of_free_Cluster = int.from_bytes(Numver_of_free_Cluster, byteorder='little')
print(f'Number of free cluster: 0x{int_Numver_of_free_Cluster:x}')
# 다음 사용 가능한 클러스터
Next_free_cluster = f.read(4)
int_Number_of_free_cluster = int.from_bytes(Next_free_cluster, byteorder='little')
print(f'Next free cluster: 0x{int_Number_of_free_cluster}\n')
# FAT 영역 정보 출력
f.seek((int_reserved_sector_count + 1) * 512)
print(f'#FAT Area')
print(f'sector (FAT Area #1): {int_reserved_sector_count + 1}')
print(f'Backup FAT Area (FAT Area #2): {int_reserved_sector_count + 1 + int_fat32_size}')
# 미디어 타입
media_type = f.read(4)
edit_media_type = ' '.join([media_type.hex()[i:i+2] for i in range(0, len(media_type.hex()), 2)])
print(f'Media Type: {edit_media_type}')
# 파티션 상태
partition_status = f.read(4)
edit_partition_status = ' '.join([partition_status.hex()[i:i+2] for i in range(0, len(partition_status.hex()), 2)])
print(f'Partition status: {edit_partition_status}\n')
# 데이터 영역 시작 위치
print(f'# Data Area')
data_area_start_sector = int_starting_LBA_addr + int_reserved_sector_count + (int_numnumber_of_fat_tables * int_fat32_size)
print(f'sector: {data_area_start_sector}\n')
# 파일 정보 (클러스터 위치)
print(f'# File')
# Cluster location ??
# print(f'0. Cluster location: {}\n')
# print(f'1. Cluster location: {}\n')
# print(f'2. Cluster location: {}\n')
else:
print(f'-----MBR Check Failed-----\n')
return False
except FileNotFoundError:
print(f"File {fat32_path} can't find.")
return False
if __name__=='__main__':
# usage
if len(sys.argv) != 2:
print("usage : python ./FAT32_parse.py ./fat32_path")
sys.exit()
# png path
fat32_path = sys.argv[1]
# def Check
FAT(fat32_path)