본문 바로가기

File Structure

ZIP File Structure Analysis

이번에 분석해볼 파일구조는 ZIP 파일입니다.

 

ZIP 파일이란?

Archive File Format 중 하나로 무손실 데이터 압축 방식을 지원합니다.

여러 알고리즘을 사용하고 있었지만 현재에는 Deflate 알고리즘을 대부분 가장 많이 사용하고 지원되는 압축 알고리즘 입니다.

 

먼저 파일의 구조 레이아웃을 보기 전에 ZIP 파일의 간략한 구조를 한번 확인하고, 구동 원리를 확인한 후에 세부적인 구조를 알아 보겠습니다.

 

ZIP파일의 간략한 구조는 아래와 같습니다.

ZIP File Simple Structure Layout

위의 구조는 ZIP 파일내에 3개의 파일이 압축 되어 있을때 확인 할 수있는 구조 입니다.

 

아래의 구조는 ZIP File의 동작 원리를 알수 있는 구조입니다.

ZIP File Structure Principle of Motion

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파일로 압축을 진행했습니다.

Create Example ZIP File
data.zip File Full Hex data

1. Local File Header

Local File Header Layout

위 파일 구조는 Local File Header의 구조로 고정적인 데이터는 0x00 ~ 0x1D 까지 입니다.

실제 파일의 Hex값을 확인해 보면 아래와 같습니다.

Example File Local File Header Hex data

이제 위의 구조에 맞춰서 해당 값이 어떤 값을 가지는 지 알아 보겠습니다.

 

1.1 Local File Header - Local Header Signatrue

Local File Header - Local Header Signature

0x00 ~ 0x03은 Local Header Signature이 있는 필드 입니다.

고정적인 값으로 0x04034B50( \x50\x4B\x03\x04 )이 들어갑니다.

 

1.2 Local File Header - Version Required When Decompressing

Local File Header - Version Required When Decompressing

0x04~0x05은 압축해제시에 필요한 버전이 값으로 들어가게 됩니다.

 

1.3 Local File Header - Flags

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

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

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

Local File Header - CRC-32 CheckSum

0x0E~0x11은 CRC-32 알고리즘을 이용해서 file data의 CRC-32값을 가집니다.

 

1.7 Local File Header - Compressed Size/Uncompressed Size

Local File Header - Compressed Size/Unc ompressed Size

0x12~0x15 / 0x16~0x19 은 압축 크기와 원본 크기가 들어가는 필드 입니다.

 

1.8 Local File Header - File Name Length/Extra Field Length

Local File Header - File Name Length/Extra Field Length

0x1A~0x1B / 0x1C~0x1D은 파일 이름의 길이와 추가 필드 길이가 들어가는 필드 입니다.

 

1.9 Local File Header - File Name

Local File Header - File Name

0x1E~(0x1E+파일의길이) 는 파일 명이 들어가는 필드 입니다.

 

1.10 Local File Header - Extra Field

Local File Header - Extra Field

파일 명이 끝난뒤 부터는 추가 필드가 나오게 되며 추가 필드 길이만큼 데이터가 쓰입니다.
(Extra Field Length가 존재한다면 파일명 뒤에 위와 같이 Extra Field가 존재하지만 위의 데이터는 Extra Field가 아닌 실제 데이터입니다. 강의 하다가 포스팅 글의 잘못된 부분을 인지하게 되어서 Notion으로 해당 글을 옮길때 수정하겠습니다.)

 

1.11 Local File Header - Data Descriptor

번외로 Flags 의 값이 0x03 일때 Data descriptor 라는 게 생성이 되는데 구조는 아래와 같습니다.

Local File Header - Data Descriptor

CRC-32, 압축 크기, 원본 크기의 데이터가 추가 됩니다.

 

2. Central Directory File Header

Central Directory File Header Layout

위 파일 구조는 Central Directory File Header의 구조로 고정적인 데이터는 0x00 ~ 0x2D 까지 입니다.

 

실제 파일의 Hex값을 확인해 보면 아래와 같습니다.

Example File Central Directory File Header Hex data

이제 위의 구조에 맞춰서 해당 값이 어떤 값을 가지는 지 알아 보겠습니다.

 

2.1 Central Directory File Header - Central Directory Header Signatrue

Central Directory File Header - Central Directory Header Signature

0x00 ~ 0x03은 Central Directory Header Signature이 있는 필드 입니다.

고정적인 값으로 0x02014B50( \x50\x4B\x01\x02 )이 들어갑니다.

 

2.2 Central Directory File Header - Version Required When Creating

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

Central Directory File Header - Version Required When Decompressing

0x06~0x07은 압축해제시에 필요한 버전이 값으로 들어가게 됩니다.

 

2.4 Central Directory File Header - Flags

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

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

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

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

Central Directory File Header - Compressed Size/Uncompressed Size

0x12~0x15 / 0x16~0x19 은 압축 크기와 원본 크기가 들어가는 필드 입니다.

 

2.9 Central Directory File Header - File Name Length/Extra Field Length

Central Directory File Header - File Name Length/Extra Field Length

0x1A~0x1B / 0x1C~0x1D은 파일 이름의 길이와 추가 필드 길이가 들어가는 필드 입니다.

 

2.10 Central Directory File Header - File Comment Length

Central Directory File Header - File Comment Length

0x20~0x21 은 파일의 주석 길이를 의미합니다.

 

2.11 Central Directory File Header - Disk Start Number

Central Directory File Header - Disk Start Number

0x22~0x23은 파일이 존재 하는 디스크의 번호를 의미합니다.

 

2.12 Central Directory File Header - Internal Attribute

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

Central Directory File Header - External Attribute

0x26~0x29 는 파일의 외부 속성 값을 의미합니다.

호스트 시스템이 의존 하는 속성 값이 들어갑니다.

 

2.14 Central Directory File Header - Local Header Offset

Central Directory File Header - Local Header Offset

0x2A~0x2D 는 Local Header의 시작 Offset 값이 들어가게 됩니다.

 

2.15 Central Directory File Header - File Name

Central Directory File Header - File Name

0x2E~(0x2E+파일의길이) 는 파일 명이 들어가는 필드 입니다.

 

2.16 Central Directory File Header - Extra Field

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 Layout

위 파일 구조는 End of Central Directory Record의 구조로 고정적인 데이터는 0x00 ~ 0x15 까지 입니다.

 

실제 파일의 Hex값을 확인해 보면 아래와 같습니다.

Example File End of Central Directory Record Hex data

이제 위의 구조에 맞춰서 해당 값이 어떤 값을 가지는 지 알아 보겠습니다.

 

3.1 End of Central Directory Record - End of Central Directory Record Signatrue

End of Central Directory Record -  End of Central Directory Record   Signature

0x00 ~ 0x03은 End of Central Directory Record Signature이 있는 필드 입니다.

고정적인 값으로 0x06054B50( \x50\x4B\x05\x06 )이 들어갑니다.

 

3.2 End of Central Directory Record - Disk Start Number

End of Central Directory Record - Disk Start Number

0x04~0x05은 파일이 존재 하는 디스크의 번호를 의미합니다.

 

3.3 End of Central Directory Record - Disk # w/cd

End of Central Directory Record - Disk # w/cd

0x06~0x07은 중앙 디렉토리가 시작되는 디스크 수를 의미합니다.

 

3.4 End of Central Directory Record - Disk Entry

End of Central Directory Record - Disk Entry

0x08~0x09는 해당 디스크의 Central Directory의 개수를 의미합니다.

 

3.5 End of Central Directory Record - Total Entry

End of Central Directory Record - Total

0x0A~0x0B는 Central Directory의 개수를 의미합니다.

 

3.6 End of Central Directory Record - Size of Central Directory

End of Central Directory Record - Size of Central Directory

0x0C~0x0F는 Central Directory의 크기를 의미합니다.

 

3.7 End of Central Directory Record - Central Header Offset

End of Central Directory Record - Central Header Offset

0x10~0x13은 Central Directory의 시작위치를 의미합니다.

 

3.8 End of Central Directory Record - Comment Length

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이기 때문에 없습니다.

마지막으로 위의 구조들을 보기 쉽게 한번에 나열하면 아래와 같습니다.

ZIP File Structure Full Layout