이번에 분석해볼 파일구조는 ZIP 파일입니다.
ZIP 파일이란?
Archive File Format 중 하나로 무손실 데이터 압축 방식을 지원합니다.
여러 알고리즘을 사용하고 있었지만 현재에는 Deflate 알고리즘을 대부분 가장 많이 사용하고 지원되는 압축 알고리즘 입니다.
먼저 파일의 구조 레이아웃을 보기 전에 ZIP 파일의 간략한 구조를 한번 확인하고, 구동 원리를 확인한 후에 세부적인 구조를 알아 보겠습니다.
ZIP파일의 간략한 구조는 아래와 같습니다.
위의 구조는 ZIP 파일내에 3개의 파일이 압축 되어 있을때 확인 할 수있는 구조 입니다.
아래의 구조는 ZIP File의 동작 원리를 알수 있는 구조입니다.
1. ZIP파일을 실행 하면 먼저 End of Central Directory 로 들어가게 됩니다.
2. 그리고 1번 화살 표를 따라서 End of Central Directory 에 존재 하는 값인 Central Header Offset 에 존재 하는 Offset으로 이동하게 됩니다.
3. Central Header Offset에 들어있는 값을 따라 이동을 해보면 Central Directory 시작 Offset으로 가게 됩니다.
4. Central Directory의 맨위 부터 아래로 내려오면서 내부에 존재하는 Central Header의 개수를 구별하면서 Central Directory에 존재하는 Local Header Offset에 들어있는 값을 확인합니다.
5. 확인한 Local Header Offset의 값을 바탕으로 2번 화살표를 통해서 Local Header 시작 Offset으로 가게 됩니다.
6. Local Header Offset 으로 간뒤 3번 화살 표를 통해서 해당 File Data로 이동함으로서 zip파일 사용자가 zip파일 내부 압축 데이터를 확인 할수 있게 됩니다.
위와 같은 방식으로 ZIP파일이 실행될때 데이터를 읽어 오게 됩니다.
이제 ZIP File Detail Structure 을 확인해 보겠습니다.
data.txt 라는 파일안에 "data is important" 라는 데이터를 작성한뒤에 zip파일로 압축을 진행했습니다.
1. Local File Header
위 파일 구조는 Local File Header의 구조로 고정적인 데이터는 0x00 ~ 0x1D 까지 입니다.
실제 파일의 Hex값을 확인해 보면 아래와 같습니다.
이제 위의 구조에 맞춰서 해당 값이 어떤 값을 가지는 지 알아 보겠습니다.
1.1 Local File Header - Local Header Signatrue
0x00 ~ 0x03은 Local Header Signature이 있는 필드 입니다.
고정적인 값으로 0x04034B50( \x50\x4B\x03\x04 )이 들어갑니다.
1.2 Local File Header - Version Required When Decompressing
0x04~0x05은 압축해제시에 필요한 버전이 값으로 들어가게 됩니다.
1.3 Local File Header - Flags
0x06~0x07은 FLAG 값이 들어 있습니다.
FLAG에는 어떠한 값이 들어가는지 알아 보겠습니다.
└ 0x00 : encrypted file
└ 0x01 : compression option
└ 0x02 : compression option
└ 0x03 : data descriptor
└ 0x04 : enhanced deflation
└ 0x05 : compressed patched data
└ 0x06 : strong encryption
└ 0x07-0x10 : unused
└ 0x11 : language encoding
└ 0x12 : reserved
└ 0x13 : mask header values
└ 0x14-0x15 : reserved
1.4 Local File Header - Compression Method
0x08~0x09은 압축 방법이 들어 있습니다.
압축 방법으로 어떤 값이 들어 있는지 알아 보겠습니다.
└ 0x00 : no compression
└ 0x01 : shrunk
└ 0x02 : reduced with compression factor 1
└ 0x03 : reduced with compression factor 2
└ 0x04 : reduced with compression factor 3
└ 0x05 : reduced with compression factor 4
└ 0x06 : imploded
└ 0x07 : reserved
└ 0x08 : deflated
└ 0x09 : enhanced deflated
└ 0x0A : PKWare DCL imploded
└ 0x0B : reserved
└ 0x0C : compressed using BZIP2
└ 0x0D : reserved
└ 0x0E : LZMA
└ 0x0F-0x11 : reserved
└ 0x12 : compressed using IBM TERSE
└ 0x13 : IBM LZ77 z
└ 0x62 : PPMd version I, Rev 1
1.5 Local File Header - File Modification Time/Date
0x0A~0x0B은 파일 수정 시간을 의미하고 0x0C~0x0D는 파일 수정 날짜를 의미합니다.
먼저 시간 변환을 해보겠습니다.
0x0623 를 2진수로 변환을 해보면 아래와 같습니다.
0x0623 = 0000 0110 0010 0011 입니다.
5비트(hhhhh) / 6비트(mmmmmm) / 5비트(sssss)로 나눠 보면 아래와 같이 나눌 수 있습니다.
00000 / 110001 / 00011 로 변환이 가능합니다.
0시 49분 3초 로 해석이 가능합니다.
하지만 초부분은 *2 연산을 해야하기 때문에 6초 입니다.
정확한 시간은 0시 49분 6초 입니다.
이번에는 날짜를 변환해 보겠습니다.
0x504C 을 2진수로 바꾸면 아래와 같습니다.
0x504C = 0101 0000 0100 1100 입니다.
날짜는 시간과 달리 7비트(yyyyyyy) / 4비트(mmmm) / 5비트(ddddd)로 나눠야 합니다.
0101000 / 0010 / 01100 로변환이 가능합니다.
40 / 2 / 12 으로 나오는데 년도 부분이 조금 이상하다는 것을 알 수 있습니다.
그 이유는 년도에서 -1980 한 값이 들어있기 때문입니다.
그렇기 때문에 재대로 계산을 해보면 2020 / 2 / 12 로 해석이 가능하다는 것을 알 수 있습니다.
1.6 Local File Header - CRC-32 CheckSum
0x0E~0x11은 CRC-32 알고리즘을 이용해서 file data의 CRC-32값을 가집니다.
1.7 Local File Header - Compressed Size/Uncompressed Size
0x12~0x15 / 0x16~0x19 은 압축 크기와 원본 크기가 들어가는 필드 입니다.
1.8 Local File Header - File Name Length/Extra Field Length
0x1A~0x1B / 0x1C~0x1D은 파일 이름의 길이와 추가 필드 길이가 들어가는 필드 입니다.
1.9 Local File Header - File Name
0x1E~(0x1E+파일의길이) 는 파일 명이 들어가는 필드 입니다.
1.10 Local File Header - Extra Field
파일 명이 끝난뒤 부터는 추가 필드가 나오게 되며 추가 필드 길이만큼 데이터가 쓰입니다.
(Extra Field Length가 존재한다면 파일명 뒤에 위와 같이 Extra Field가 존재하지만 위의 데이터는 Extra Field가 아닌 실제 데이터입니다. 강의 하다가 포스팅 글의 잘못된 부분을 인지하게 되어서 Notion으로 해당 글을 옮길때 수정하겠습니다.)
1.11 Local File Header - Data Descriptor
번외로 Flags 의 값이 0x03 일때 Data descriptor 라는 게 생성이 되는데 구조는 아래와 같습니다.
CRC-32, 압축 크기, 원본 크기의 데이터가 추가 됩니다.
2. Central Directory File Header
위 파일 구조는 Central Directory File Header의 구조로 고정적인 데이터는 0x00 ~ 0x2D 까지 입니다.
실제 파일의 Hex값을 확인해 보면 아래와 같습니다.
이제 위의 구조에 맞춰서 해당 값이 어떤 값을 가지는 지 알아 보겠습니다.
2.1 Central Directory File Header - Central Directory Header Signatrue
0x00 ~ 0x03은 Central Directory Header Signature이 있는 필드 입니다.
고정적인 값으로 0x02014B50( \x50\x4B\x01\x02 )이 들어갑니다.
2.2 Central Directory File Header - Version Required When Creating
0x04~0x05는 Version은 압축시에 사용한 압축버전 필드 입니다.
해당 필드에 들어가는 값은 아래와 같습니다.
Upper Byte :
└ 0x00 - MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)
└ 0x01 - Amiga
└ 0x02 - OpenVMS
└ 0x03 - UNIX
└ 0x04 - VM/CMS
└ 0x05 - Atari ST
└ 0x06 - OS/2 H.P.F.S.
└ 0x07 - Macintosh
└ 0x08 - Z-System
└ 0x09 - CP/M
└ 0x0A - Windows NTFS
└ 0x0B - MVS (OS/390 - Z/OS)
└ 0x0C - VSE
└ 0x0D - Acorn Risc
└ 0x0E - VFAT
└ 0x0F - alternate MVS
└ 0x10 - BeOS
└ 0x11 - Tandem
└ 0x12 - OS/400
└ 0x13 - OS/X (Darwin)
└ 0x24 - 0xFF : unused
Lower Byte :
└zip specification version
여기서는 0x003F 이기 때문에 Upper Byte는 0x00 / Lower Byte 는 0x3F 입니다.
MS-DOS 6.3 버전입니다.
2.3 Central Directory File Header - Version Required When Decompressing
0x06~0x07은 압축해제시에 필요한 버전이 값으로 들어가게 됩니다.
2.4 Central Directory File Header - Flags
0x08~0x09은 FLAG 값이 들어 있습니다.
FLAG에는 어떠한 값이 들어가는지 알아 보겠습니다.
└ 0x00 : encrypted file
└ 0x01 : compression option
└ 0x02 : compression option
└ 0x03 : data descriptor
└ 0x04 : enhanced deflation
└ 0x05 : compressed patched data
└ 0x06 : strong encryption
└ 0x07-0x0A : unused
└ 0x0B : language encoding
└ 0x0C : reserved
└ 0x0D : mask header values
└ 0x0E-0x0F : reserved
2.5 Central Directory File Header - Compression Method
0x0A~0x0B은 압축 방법이 들어 있습니다.
압축 방법으로 어떤 값이 들어 있는지 알아 보겠습니다.
└ 0x00 : no compression
└ 0x01 : shrunk
└ 0x02 : reduced with compression factor 1
└ 0x03 : reduced with compression factor 2
└ 0x04 : reduced with compression factor 3
└ 0x05 : reduced with compression factor 4
└ 0x06 : imploded
└ 0x07 : reserved
└ 0x08 : deflated
└ 0x09 : enhanced deflated
└ 0x0A : PKWare DCL imploded
└ 0x0B : reserved
└ 0x0C : compressed using BZIP2
└ 0x0D : reserved
└ 0x0E : LZMA
└ 0x0F-0x11 : reserved
└ 0x12 : compressed using IBM TERSE
└ 0x13 : IBM LZ77 z
└ 0x62 : PPMd version I, Rev 1
2.6 Central Directory File Header - File Modification Time/Date
0x0A~0x0B은 파일 수정 시간을 의미하고 0x0C~0x0D는 파일 수정 날짜를 의미합니다.
먼저 시간 변환을 해보겠습니다.
0x0623 를 2진수로 변환을 해보면 아래와 같습니다.
0x0623 = 0000 0110 0010 0011 입니다.
5비트(hhhhh) / 6비트(mmmmmm) / 5비트(sssss)로 나눠 보면 아래와 같이 나눌 수 있습니다.
00000 / 110001 / 00011 로 변환이 가능합니다.
0시 49분 3초 로 해석이 가능합니다.
하지만 초부분은 *2 연산을 해야하기 때문에 6초 입니다.
정확한 시간은 0시 49분 6초 입니다.
이번에는 날짜를 변환해 보겠습니다.
0x504C 을 2진수로 바꾸면 아래와 같습니다.
0x504C = 0101 0000 0100 1100 입니다.
날짜는 시간과 달리 7비트(yyyyyyy) / 4비트(mmmm) / 5비트(ddddd)로 나눠야 합니다.
0101000 / 0010 / 01100 로변환이 가능합니다.
40 / 2 / 12 으로 나오는데 년도 부분이 조금 이상하다는 것을 알 수 있습니다.
그 이유는 년도에서 -1980 한 값이 들어있기 때문입니다.
그렇기 때문에 재대로 계산을 해보면 2020 / 2 / 12 로 해석이 가능하다는 것을 알 수 있습니다.
2.7 Central Directory File Header - CRC-32 CheckSum
0x0E~0x11은 CRC-32 알고리즘을 이용해서 file data의 CRC-32값을 가집니다.
2.8 Central Directory File Header - Compressed Size/Uncompressed Size
0x12~0x15 / 0x16~0x19 은 압축 크기와 원본 크기가 들어가는 필드 입니다.
2.9 Central Directory File Header - File Name Length/Extra Field Length
0x1A~0x1B / 0x1C~0x1D은 파일 이름의 길이와 추가 필드 길이가 들어가는 필드 입니다.
2.10 Central Directory File Header - File Comment Length
0x20~0x21 은 파일의 주석 길이를 의미합니다.
2.11 Central Directory File Header - Disk Start Number
0x22~0x23은 파일이 존재 하는 디스크의 번호를 의미합니다.
2.12 Central Directory File Header - Internal Attribute
0x24~0x25 는 파일의 내부 속성 값을 의미 합니다.
해당 필드에 들어가는 값은 아래의 의미를 가집니다.
Internal File Attribute :
└ 0x00 : Apparent ASCII/text file
└ 0x01 : Reserved
└ 0x02 : Control Field Records Precede Logical Records
└ 0x03~0x10 : Unused
2.13 Central Directory File Header - External Attribute
0x26~0x29 는 파일의 외부 속성 값을 의미합니다.
호스트 시스템이 의존 하는 속성 값이 들어갑니다.
2.14 Central Directory File Header - Local Header Offset
0x2A~0x2D 는 Local Header의 시작 Offset 값이 들어가게 됩니다.
2.15 Central Directory File Header - File Name
0x2E~(0x2E+파일의길이) 는 파일 명이 들어가는 필드 입니다.
2.16 Central Directory File Header - Extra Field
파일 명이 끝난뒤 부터는 추가 필드가 나오게 되며 추가 필드 길이만큼 데이터가 쓰입니다.
2.17 Central Directory File Header - File Comment
예시 파일에는 파일 주석의 길이가 0이기 때문에 나와 있지 않지만 추가필드 이후에 나오게 되며 길이는 파일주석의 길이가 적힌 0x20~0x21에 다릅니다.
3. End of Central Directory Record
위 파일 구조는 End of Central Directory Record의 구조로 고정적인 데이터는 0x00 ~ 0x15 까지 입니다.
실제 파일의 Hex값을 확인해 보면 아래와 같습니다.
이제 위의 구조에 맞춰서 해당 값이 어떤 값을 가지는 지 알아 보겠습니다.
3.1 End of Central Directory Record - End of Central Directory Record Signatrue
0x00 ~ 0x03은 End of Central Directory Record Signature이 있는 필드 입니다.
고정적인 값으로 0x06054B50( \x50\x4B\x05\x06 )이 들어갑니다.
3.2 End of Central Directory Record - Disk Start Number
0x04~0x05은 파일이 존재 하는 디스크의 번호를 의미합니다.
3.3 End of Central Directory Record - Disk # w/cd
0x06~0x07은 중앙 디렉토리가 시작되는 디스크 수를 의미합니다.
3.4 End of Central Directory Record - Disk Entry
0x08~0x09는 해당 디스크의 Central Directory의 개수를 의미합니다.
3.5 End of Central Directory Record - Total Entry
0x0A~0x0B는 Central Directory의 개수를 의미합니다.
3.6 End of Central Directory Record - Size of Central Directory
0x0C~0x0F는 Central Directory의 크기를 의미합니다.
3.7 End of Central Directory Record - Central Header Offset
0x10~0x13은 Central Directory의 시작위치를 의미합니다.
3.8 End of Central Directory Record - Comment Length
0x14~0x15는 뒤에올 ZIP File Comment의 길이를 의미합니다.
3.9 End of Central Directory Record - ZIP File Comment
해당 예제 파일에서는 Comment Length의 길이가 0이기 때문에 없습니다.
마지막으로 위의 구조들을 보기 쉽게 한번에 나열하면 아래와 같습니다.
'File Structure' 카테고리의 다른 글
BEncode Structure Analysis (0) | 2021.03.23 |
---|---|
Windows Storage Pool Disk File Structure Analysis (0) | 2020.03.30 |
PDF(Portable Document Format) File Structure Analysis (0) | 2020.03.02 |