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)