NTFS File Parser

g0ni·2024년 11월 23일

NTFS File

목록 보기
2/2
import sys

# GPT 헤더 서명
gpt_header_signature = b'EFI PART'

def NTFS(ntfs_path):
    global gpt_header_signature
    
    try:
        with open(ntfs_path, 'rb') as f:
            
            # MBR (마스터 부트 레코드)
            f.seek(0)  
            f.read(446)  
            
            print(f'\n# GPT (MBR)\n')
            print(f"@ GPT(MBR) - Partition table entry")
            
            # 부트 인디케이터
            boot_indicator = f.read(1)
            int_boot_indicator = int.from_bytes(boot_indicator, byteorder='little')
            print(f"Boot Indicator: {int_boot_indicator}")
            
            # 시작 CHS 주소
            f.read(3)
            
            # 파티션 유형
            f.read(1)
            
            # 끝 CHS 주소
            f.read(3)
            
            # LBA 시작 주소
            lba_start_address = f.read(4)
            int_lba_start_address = int.from_bytes(lba_start_address, byteorder='little')
            print(f"LBA Start Address: {int_lba_start_address} sector")
            
            # 총 섹터 수
            total_sectors = f.read(4)
            int_total_sectors = int.from_bytes(total_sectors, byteorder='little')
            print(f"Total Sector: 0x{int_total_sectors:x}")
            
            
            # GPT 헤더 정보 출력
            print(f"\n@ GPT (MBR) - GPT Header")

            f.seek(512) 

            # 서명 확인
            signature = f.read(8)
            if signature == gpt_header_signature:
                print(f"Signature: {signature}")
                
            # 리비전 (사용 안 함)
            f.read(4)

            # 헤더 크기 (사용 안 함)
            f.read(4)

            # CRC32 (사용 안 함)
            f.read(4)

            # 예약 필드 (사용 안 함)
            f.read(4)
            
            # 현재 LBA (사용 안 함)
            f.read(8)
            
            # 백업 LBA 주소
            backup_lba = f.read(8)
            int_backup_lba = int.from_bytes(backup_lba, byteorder='little')
            print(f"Backup LBA: {int_backup_lba}")
            
            # 첫 사용 가능 LBA
            first_usable_lba = f.read(8)
            int_first_usable_lba = int.from_bytes(first_usable_lba, byteorder='little')
            print(f"Starting LBA for partition: {int_first_usable_lba} sector")
            
            # 마지막 사용 가능 LBA
            last_usable_lba = f.read(8)
            int_last_usable_lba = int.from_bytes(last_usable_lba, byteorder='little')
            print(f"Ending LBA for partition: {int_last_usable_lba} sector")
            
            # 디스크 GUID (사용 안 함)
            f.read(8)
            
            # 파티션 엔트리 LBA 위치
            partition_entry_lba = f.read(8)

            # 파티션 엔트리 개수
            num_partition_entries = f.read(4)
            int_num_partition_entries = int.from_bytes(num_partition_entries, byteorder='little')
            print(f"Number of partition entries: {int_num_partition_entries}")
            
            # 파티션 엔트리 크기
            partition_entry_size = f.read(4)
            int_partition_entry_size = int.from_bytes(partition_entry_size, byteorder='little')
            print(f"Size of each entry: {int_partition_entry_size}")
            
            # 파티션 배열 CRC32 (사용 안 함)
            f.read(4)

            # GPT 파티션 엔트리 출력
            print(f"\n@ GPT (MBR) - GPT Partition Entry")
            f.seek(int(int.from_bytes(partition_entry_lba, byteorder='little')) * 512) 
            partitions = []
            
            for i in range(int_num_partition_entries):
                # 파티션 유형 GUID
                part_type_guid = f.read(16)
                
                # 고유 파티션 GUID
                unique_guid = f.read(16)
                
                # 첫 LBA
                first_lba = int.from_bytes(f.read(8), byteorder='little')
                
                # 마지막 LBA
                last_lba = int.from_bytes(f.read(8), byteorder='little')
                
                # 속성 정보
                attributes = f.read(8)
                
                # 파티션 이름
                name = f.read(72).decode('utf-16').strip('\x00')
                
                # 빈 파티션은 건너뜀
                if first_lba == 0 and last_lba == 0:
                    continue
                
                # 파티션 크기(MB)
                partition_size_mb = (last_lba - first_lba + 1) * 512 // (1024 * 1024)
                
                # 파티션 정보를 리스트에 추가
                partitions.append({
                    "Partition Index": i + 1,
                    "First LBA": first_lba,
                    "Last LBA": last_lba,
                    "Partition Size": partition_size_mb,
                    "Attributes": " ".join(f"{x:02x}" for x in attributes),
                    "Partition Name": name
                })

            # 총 파티션 개수 출력
            print(f"총 파티션 개수: {len(partitions)}")
            for part in partitions:
                print(f"\n- Partition {part['Partition Index']}")
                print(f"Partition start offset: {part['First LBA']} sector")
                print(f"Partition end offset: {part['Last LBA']} sector")
                print(f"Partition Size: {part['Partition Size']} MB")
                print(f"Partition attribute(flag): {part['Attributes']}")
                print(f"Partition Name: {part['Partition Name']}")

            print("\n----------------------------------------------------------")

            # "기본 데이터 파티션"에 대한 VBR 및 MFT 세부 정보 별도 출력
            for part in partitions:
                if "Basic data partition" in part['Partition Name']:
                    print(f"\n- Partition {part['Partition Index']}")

                    # VBR 위치로 이동
                    f.seek(part['First LBA'] * 512)
                    
                    print(f"\n# VBR (Only Basic data partition)")
                    
                    # 점프 부트 코드
                    jump_boot_code = f.read(3)
                    print(f"Jump Boot Code: {' '.join(f'{x:02x}' for x in jump_boot_code)}")
                    
                    # OEM ID
                    oem_id = f.read(8)
                    print(f"OEM ID (str/hex): {oem_id.decode('ascii').strip()} / {' '.join(f'{x:02x}' for x in oem_id)}")
                    
                    # 섹터당 바이트 수
                    bytes_per_sector = int.from_bytes(f.read(2), byteorder='little')
                    print(f"Bytes Per Sector: {bytes_per_sector}")
                    
                    # 클러스터당 섹터 수
                    sectors_per_cluster = int.from_bytes(f.read(1), byteorder='little')
                    print(f"Sectors Per Cluster: {sectors_per_cluster}")
                    
                    # $MFT와 $MFTMirr의 시작 클러스터 위치
                    f.seek(part['First LBA'] * 512 + 48)
                    start_cluster_mft = int.from_bytes(f.read(8), byteorder='little')
                    print(f"Start Cluster for $MFT: {start_cluster_mft}")
                    
                    start_cluster_mftmirr = int.from_bytes(f.read(8), byteorder='little')
                    print(f"Start Cluster for $MFTMirr: {start_cluster_mftmirr}")
                    
                    # MFT 시작 오프셋
                    mft_start_offset = part['First LBA'] + (start_cluster_mft * sectors_per_cluster)
                    print(f"\n# MFT (Master File Table)")
                    print(f"MFT Start offset: {mft_start_offset} sector")

    except FileNotFoundError:
        print(f"File {ntfs_path} not found.")
        return False

if __name__ == '__main__':

    if len(sys.argv) != 2:
        print("Usage: python NTFS_parser.py ./ntfs_path")
        sys.exit(1)

    ntfs_path = sys.argv[1]
    
    NTFS(ntfs_path)
profile
Let it rip!

0개의 댓글