FAT32(USB) File Parser

g0ni·2025년 3월 16일

FAT32 File

목록 보기
2/2
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)
profile
Let it rip!

0개의 댓글