ICO 파일 구조 분석|ICONDIR·이미지 엔트리·PNG·DIB 구조
ICO 파일은 Windows 운영체제에서 아이콘 이미지를 저장하기 위해 사용하는 대표적인 파일 형식이다.
일반적으로 .ico 확장자를 사용하며 프로그램 아이콘, 바탕화면 바로가기, 웹사이트 파비콘 등 다양한 환경에서 활용된다.
ICO 파일은 단일 이미지 한 장만 저장하는 단순한 구조가 아니다. 하나의 파일에 서로 다른 크기와 비트 깊이를 가진 여러 아이콘 이미지를 포함할 수 있으며, 각 이미지의 위치와 크기는 디렉터리 항목을 통해 관리된다.
특히 ICO 파일 내부의 이미지 데이터는 전통적인 DIB 기반 비트맵일 수도 있고 PNG 형식일 수도 있다.
따라서 ICO 파일 구조 분석에서는 ICONDIR 헤더, ICONDIRENTRY 배열, 이미지 데이터 오프셋, PNG 시그니처, DIB 헤더와 실제 파일 경계를 함께 확인해야 한다.
이번 글에서는 ICO 파일의 전체 구조와 이미지 저장 방식, 크기 필드, 색상 깊이, PNG·DIB 판별, 파일 손상 검증 원리를 알아본다.
또한 Windows PowerShell 5.1을 기준으로 작성한 읽기 전용 코드로 ICO 헤더와 디렉터리 항목, 이미지 데이터의 기본 범위를 확인하고 SHA-256 해시값을 계산하는 방법을 설명한다.
1. ICO 파일 구조 분석이 필요한 이유
ICO 파일은 Windows와 웹 환경에서 널리 사용되지만, 파일 확장자만으로 내부 이미지가 정상인지 판단할 수는 없다.
다음과 같은 상황에서 구조 분석이 도움이 된다.
- 아이콘이 정상적으로 표시되지 않는 경우
- 작은 아이콘은 보이지만 큰 아이콘은 표시되지 않는 경우
- 파비콘을 등록했는데 일부 환경에서만 표시되는 경우
- ICO 파일 안에 몇 개의 이미지가 들어 있는지 확인하려는 경우
- 이미지 크기와 비트 깊이를 확인하려는 경우
- PNG와 DIB 기반 아이콘을 구분하려는 경우
- 이미지 데이터 오프셋이 잘못되었는지 점검하려는 경우
- 파일 복사나 전송 과정에서 데이터가 변경되었는지 확인하려는 경우
ICO 구조 분석의 핵심은 파일 헤더가 가리키는 이미지 항목과 실제 저장된 데이터 범위가 일치하는지 확인하는 것이다.
단, 기본 구조가 정상이라고 해서 모든 아이콘 이미지가 올바르게 디코딩되거나 안전하다는 뜻은 아니다.
2. ICO 파일의 기본 개념과 특징
ICO는 여러 크기의 아이콘 이미지를 하나의 파일에 묶어 저장할 수 있는 컨테이너형 이미지 파일이다.
대표적인 특징은 다음과 같다.
- 하나의 파일에 여러 이미지 포함 가능
- 이미지별 너비와 높이 정보 저장
- 이미지별 색상 관련 정보 기록
- 이미지 데이터의 크기와 시작 오프셋 기록
- 전통적인 DIB 기반 아이콘 지원
- PNG 기반 아이콘 지원
- Windows 프로그램 아이콘과 웹 파비콘에 활용
- 이미지 항목마다 다른 크기와 형식 사용 가능
ICO 파일 자체는 JPEG나 PNG처럼 단일 이미지의 픽셀 구조만 정의하는 형식과 구분된다.
ICO는 먼저 이미지 목록을 정의하고, 각 목록 항목이 실제 이미지 데이터를 가리키는 방식으로 구성된다.
3. ICO 파일의 전체 구조
일반적인 ICO 파일은 다음과 같이 구성된다.
ICO File
│
├── ICONDIR (6 bytes)
│ ├── idReserved
│ ├── idType
│ └── idCount
│
├── ICONDIRENTRY Array
│ ├── Entry 1 (16 bytes)
│ ├── Entry 2 (16 bytes)
│ └── ...
│
└── Image Data
├── Image 1 (DIB or PNG)
├── Image 2 (DIB or PNG)
└── ...
ICONDIR는 파일 전체의 기본 정보를 제공한다.
ICONDIRENTRY는 개별 이미지의 크기, 색상 관련 값, 데이터 길이와 오프셋을 기록한다.
이미지 데이터는 디렉터리 항목에서 지정한 위치에 저장된다.
따라서 파일을 순서대로 읽는 것만으로 이미지 위치를 추정하지 말고, 각 항목의 오프셋을 확인해야 한다.
4. ICO 파일 시그니처와 시작 바이트
ICO 파일은 일반적으로 다음 6바이트로 시작한다.
00 00 01 00 NN NN
여기서 마지막 2바이트는 이미지 개수를 나타내는 리틀엔디언 정수다.
예를 들어 이미지가 3개라면 다음과 같다.
00 00 01 00 03 00
각 필드의 의미는 다음과 같다.
| 오프셋 | 크기 | 필드 | 일반적인 ICO 값 |
|---|---|---|---|
| 0 | 2바이트 | idReserved | 0 |
| 2 | 2바이트 | idType | 1 |
| 4 | 2바이트 | idCount | 이미지 개수 |
ICO는 PNG처럼 고정된 긴 시그니처를 사용하는 방식이 아니다.
파일 시작의 예약 필드, 형식 값, 이미지 개수를 함께 해석해야 한다.
참고로 커서 파일인 CUR은 비슷한 디렉터리 구조를 사용하지만 idType 값이 2다.
이번 글의 실습 대상은 idType이 1인 ICO 파일이다.
5. ICONDIR 헤더 구조
ICONDIR는 6바이트로 구성된다.
idReserved
일반적인 ICO 파일에서는 0으로 설정된다.
idType
파일의 유형을 나타낸다.
1 = ICO
2 = CUR
idCount
파일에 포함된 이미지 항목의 개수다.
예를 들어 idCount가 5라면 ICONDIRENTRY 항목이 5개 존재해야 한다.
각 항목은 16바이트이므로 디렉터리 전체 크기는 다음과 같다.
DirectoryBytes = 6 + (16 × idCount)
이미지가 5개라면 다음과 같다.
6 + (16 × 5) = 86 bytes
따라서 최소한 86바이트의 디렉터리 영역이 필요하다.
6. ICONDIRENTRY 구조
각 이미지의 메타데이터는 16바이트 ICONDIRENTRY에 기록된다.
| 상대 오프셋 | 크기 | 필드 |
|---|---|---|
| 0 | 1바이트 | bWidth |
| 1 | 1바이트 | bHeight |
| 2 | 1바이트 | bColorCount |
| 3 | 1바이트 | bReserved |
| 4 | 2바이트 | wPlanes |
| 6 | 2바이트 | wBitCount |
| 8 | 4바이트 | dwBytesInRes |
| 12 | 4바이트 | dwImageOffset |
이 필드들은 이미지의 기본 정보와 파일 내부 위치를 나타낸다.
단, 일부 값은 실제 이미지 데이터에 기록된 정보와 비교해야 한다.
특히 PNG 기반 아이콘에서는 이미지 내부의 PNG 헤더가 실제 크기와 색상 형식을 정의한다.
7. 아이콘 크기 필드와 256픽셀 규칙
ICONDIRENTRY의 bWidth와 bHeight는 각각 1바이트다.
따라서 표현할 수 있는 숫자 범위는 0~255다.
하지만 ICO에서는 값 0을 특별하게 해석한다.
bWidth = 0 → 256 pixels
bHeight = 0 → 256 pixels
예를 들어 다음과 같은 항목이 있다고 가정하자.
bWidth = 0
bHeight = 0
이 항목은 일반적으로 256×256 아이콘을 나타낸다.
| 저장된 값 | 해석한 크기 |
|---|---|
| 16 | 16픽셀 |
| 32 | 32픽셀 |
| 48 | 48픽셀 |
| 0 | 256픽셀 |
이 규칙을 무시하면 256픽셀 아이콘을 너비와 높이가 0인 이미지로 잘못 해석할 수 있다.
8. 색상 수와 비트 깊이
ICONDIRENTRY에는 색상 관련 정보가 포함된다.
bColorCount
색상 테이블의 색상 수를 나타내는 필드다.
0은 일반적으로 256색 이상이거나 색상 수를 별도로 지정하지 않는 경우에 사용된다.
wPlanes
전통적인 비트맵 관련 색상 평면 정보다.
wBitCount
픽셀당 비트 수를 나타낸다.
예를 들어 다음과 같은 값이 사용될 수 있다.
1-bit
4-bit
8-bit
24-bit
32-bit
그러나 디렉터리 항목에 기록된 값만으로 이미지의 실제 픽셀 형식을 완전히 판단해서는 안 된다.
PNG 기반 이미지라면 PNG 내부의 IHDR 청크 정보를 확인해야 한다.
DIB 기반 이미지라면 DIB 헤더와 비트 마스크 등의 정보를 함께 해석해야 한다.
9. 이미지 데이터 크기와 오프셋
ICO 파일의 각 ICONDIRENTRY에는 두 가지 중요한 값이 있다.
dwBytesInRes
해당 이미지 데이터의 바이트 크기다.
dwImageOffset
파일 시작을 기준으로 해당 이미지 데이터가 저장된 위치다.
예를 들어 다음 값이 기록되어 있다고 가정하자.
dwImageOffset = 100
dwBytesInRes = 500
이미지 데이터의 범위는 다음과 같다.
Start = 100
End = 100 + 500 = 600
End는 마지막 데이터 바이트 다음 위치를 뜻한다.
파일 길이가 550바이트라면 해당 이미지 데이터가 파일 범위를 초과한다.
이처럼 이미지 오프셋과 크기를 확인하면 일부 잘림이나 구조 오류를 탐지할 수 있다.
10. ICO 파일 안의 PNG 이미지
현대적인 ICO 파일에는 PNG 형식의 이미지 데이터가 포함될 수 있다.
PNG 데이터는 일반적으로 다음 8바이트 시그니처로 시작한다.
89 50 4E 47 0D 0A 1A 0A
이 시그니처가 이미지 데이터 시작 위치에서 발견되면 PNG 기반 이미지일 가능성이 높다.
PNG 기반 아이콘은 PNG 파일의 구조를 따른다.
대표적으로 다음 요소를 포함한다.
- PNG Signature
- IHDR Chunk
- IDAT Chunk
- IEND Chunk
다만 PNG 시그니처가 있다고 해서 전체 PNG 데이터가 정상이라는 의미는 아니다.
실제 검증에는 청크 길이, 청크 타입, CRC, 압축 데이터와 종료 구조 확인이 필요하다.
11. ICO 파일 안의 DIB 이미지
전통적인 ICO 이미지 데이터는 DIB 기반 비트맵으로 저장될 수 있다.
이 경우 이미지 데이터가 반드시 BM 시그니처로 시작하는 것은 아니다.
일반적인 BMP 파일과 달리 ICO 내부에는 BITMAPFILEHEADER 없이 DIB 헤더부터 저장되는 경우가 많다.
따라서 ICO 이미지 데이터에서 BM을 찾지 못했다고 해서 손상된 파일로 판단하면 안 된다.
DIB 기반 아이콘에는 다음과 같은 구조가 포함될 수 있다.
DIB Header
Color Information / Masks
XOR Bitmap
AND Mask
XOR 비트맵은 이미지의 색상 데이터를 나타내고, AND 마스크는 전통적인 투명도 처리에 사용된다.
다만 현대적인 32비트 아이콘에서는 알파 채널이 투명도 처리에 중요한 역할을 한다.
12. DIB 기반 아이콘의 높이 필드
ICO 내부의 전통적인 DIB 이미지에서는 높이 필드를 주의해서 해석해야 한다.
일반적인 경우 DIB 헤더의 높이는 XOR 비트맵과 AND 마스크를 포함한 높이로 기록된다.
예를 들어 실제 아이콘 높이가 32픽셀이라면 DIB 헤더에는 다음과 같이 기록될 수 있다.
biHeight = 64
이는 다음 두 영역을 포함하기 때문이다.
XOR Bitmap Height = 32
AND Mask Height = 32
DIB Height = 64
따라서 DIB 헤더의 높이를 그대로 아이콘의 실제 표시 높이로 해석하면 잘못된 결과가 나올 수 있다.
단, 모든 ICO 이미지가 동일한 DIB 배치를 사용하는 것은 아니다.
PNG 기반 이미지에는 이 규칙을 적용하지 않는다.
13. XOR 비트맵과 AND 마스크
전통적인 DIB 기반 아이콘은 XOR 비트맵과 AND 마스크를 함께 사용할 수 있다.
XOR Bitmap
아이콘의 색상 데이터를 저장한다.
AND Mask
1비트 마스크를 이용해 픽셀의 투명도 관련 정보를 표현한다.
일반적인 마스크에서는 각 행이 4바이트 경계에 맞춰 정렬된다.
예를 들어 32픽셀 너비의 1비트 마스크 한 행은 다음과 같다.
32 bits = 4 bytes
따라서 32×32 마스크의 기본 데이터 크기는 다음과 같다.
4 bytes × 32 rows = 128 bytes
하지만 실제 투명도 처리는 알파 채널, 이미지 비트 깊이와 Windows의 렌더링 방식에 따라 달라질 수 있다.
14. ICO 파일의 여러 이미지 선택 원리
하나의 ICO 파일에는 다음과 같은 이미지가 함께 저장될 수 있다.
| 이미지 번호 | 크기 | 비트 깊이 | 내부 형식 |
|---|---|---|---|
| 1 | 16×16 | 32비트 | DIB |
| 2 | 32×32 | 32비트 | DIB |
| 3 | 48×48 | 32비트 | DIB |
| 4 | 256×256 | PNG 기반 | PNG |
위 표는 설명을 위한 예시다.
운영체제나 애플리케이션은 표시 환경에 적합한 크기와 형식의 이미지를 선택할 수 있다.
다만 어떤 항목을 선택하는지는 운영체제 버전, 화면 배율, 애플리케이션 구현 등에 따라 달라질 수 있다.
15. ICO 파일과 BMP·PNG의 차이
| 비교 항목 | ICO | BMP | PNG |
|---|---|---|---|
| 주요 용도 | 아이콘 컨테이너 | 비트맵 이미지 | 범용 래스터 이미지 |
| 여러 이미지 포함 | 가능 | 일반적으로 단일 이미지 | 일반적인 PNG는 단일 이미지 |
| 대표 구조 | ICONDIR·ICONDIRENTRY | 파일 헤더·DIB | 시그니처·청크 |
| 이미지 오프셋 목록 | 있음 | 일반적으로 없음 | 일반적으로 없음 |
| 압축 방식 | 내부 이미지에 따라 다름 | DIB 설정에 따라 다름 | DEFLATE 기반 |
| 투명도 | 알파·AND 마스크 등 | 형식에 따라 다름 | 알파 채널 등 |
ICO 파일은 여러 이미지를 관리하는 디렉터리 구조가 있다는 점에서 BMP 및 일반적인 PNG 파일과 구분된다.
16. ICO 파일의 기본 구조 검증 순서
ICO 파일을 분석할 때는 다음 순서로 확인하는 것이 좋다.
① 파일 길이 확인
최소 6바이트 ICONDIR 헤더가 존재하는지 확인한다.
② ICONDIR 확인
예약 필드, 파일 유형, 이미지 개수를 확인한다.
③ 디렉터리 크기 계산
이미지 개수에 16바이트를 곱해 ICONDIRENTRY 영역이 파일 안에 있는지 확인한다.
④ 이미지 크기 필드 해석
너비와 높이 값 0을 256픽셀로 해석한다.
⑤ 이미지 데이터 범위 계산
각 항목의 dwImageOffset과 dwBytesInRes를 이용해 파일 경계를 확인한다.
⑥ PNG·DIB 구분
이미지 데이터 시작 위치의 PNG 시그니처를 확인한다.
⑦ 내부 이미지 구조 분석
PNG라면 PNG 청크를, DIB라면 DIB 헤더와 비트맵·마스크 구조를 추가 분석한다.
⑧ 무결성 확인
신뢰할 수 있는 원본 해시값과 SHA-256을 비교한다.
17. PowerShell 5.1로 ICONDIR 헤더 분석하기
첫 번째 실습에서는 ICO 파일의 시작 6바이트를 읽어 기본 헤더를 확인한다.
① 실습 파일
C:\FileTest\sample.ico
실행할 때 실제 ICO 파일 경로로 변경한다.
② PowerShell 코드
$path = "C:\FileTest\sample.ico"
$stream = [System.IO.File]::OpenRead($path)
try {
$reader = New-Object System.IO.BinaryReader($stream)
if ($stream.Length -lt 6) {
throw "ICO header is incomplete."
}
$reserved = $reader.ReadUInt16()
$type = $reader.ReadUInt16()
$count = $reader.ReadUInt16()
if ($reserved -ne 0 -or $type -ne 1) {
throw "Not a standard ICO file."
}
if ($count -eq 0) {
throw "ICO contains no image entries."
}
$directoryEnd = [uint64]6 + ([uint64]16 * $count)
[PSCustomObject]@{
Reserved = $reserved
Type = $type
ImageCount = $count
DirectoryEnd = $directoryEnd
ActualFileSize = $stream.Length
DirectoryWithinFile = (
$directoryEnd -le [uint64]$stream.Length
)
}
}
finally {
$stream.Dispose()
}
③ 출력 예시
Reserved : 0
Type : 1
ImageCount : 3
DirectoryEnd : 54
ActualFileSize : 2054
DirectoryWithinFile : True
위 값은 구조 설명을 위한 예시다.
④ 코드 해석
ICONDIR의 예약 필드와 파일 유형을 확인하고 이미지 항목 개수로 디렉터리 끝 위치를 계산한다.
⑤ 코드의 한계
이 코드는 ICONDIR의 기본 필드와 디렉터리 영역만 확인한다.
개별 이미지 데이터의 정상 여부는 검증하지 않는다.
18. PowerShell 5.1로 ICONDIRENTRY 목록 확인하기
두 번째 실습에서는 ICO 파일의 이미지 목록을 읽어 크기, 비트 깊이, 이미지 오프셋을 확인한다.
① PowerShell 코드
$path = "C:\FileTest\sample.ico"
$stream = [System.IO.File]::OpenRead($path)
try {
$reader = New-Object System.IO.BinaryReader($stream)
if ($stream.Length -lt 6) {
throw "ICO header is incomplete."
}
$reserved = $reader.ReadUInt16()
$type = $reader.ReadUInt16()
$count = $reader.ReadUInt16()
if ($reserved -ne 0 -or $type -ne 1 -or $count -eq 0) {
throw "Invalid ICO directory header."
}
$directoryEnd = [uint64]6 + ([uint64]16 * $count)
if ($directoryEnd -gt [uint64]$stream.Length) {
throw "ICO directory exceeds file length."
}
$results = @()
for ($i = 0; $i -lt $count; $i++) {
$widthRaw = $reader.ReadByte()
$heightRaw = $reader.ReadByte()
$colorCount = $reader.ReadByte()
$entryReserved = $reader.ReadByte()
$planes = $reader.ReadUInt16()
$bitCount = $reader.ReadUInt16()
$bytesInRes = $reader.ReadUInt32()
$imageOffset = $reader.ReadUInt32()
$width = if ($widthRaw -eq 0) { 256 } else { $widthRaw }
$height = if ($heightRaw -eq 0) { 256 } else { $heightRaw }
$imageEnd = [uint64]$imageOffset + [uint64]$bytesInRes
$results += [PSCustomObject]@{
Entry = $i + 1
Width = $width
Height = $height
ColorCount = $colorCount
Planes = $planes
BitCount = $bitCount
BytesInResource = $bytesInRes
ImageOffset = $imageOffset
ImageWithinFile = (
$bytesInRes -gt 0 -and
[uint64]$imageOffset -ge $directoryEnd -and
$imageEnd -le [uint64]$stream.Length
)
}
}
$results | Format-Table -AutoSize
}
finally {
$stream.Dispose()
}
② 출력 예시
Entry Width Height ColorCount Planes BitCount BytesInResource ImageOffset ImageWithinFile
----- ----- ------ ---------- ------ -------- --------------- ----------- ---------------
1 16 16 0 1 32 400 54 True
2 32 32 0 1 32 600 454 True
3 256 256 0 1 32 1000 1054 True
위 값은 설명을 위한 예시다.
③ 코드 해석
각 ICONDIRENTRY의 크기와 오프셋을 읽고 이미지 데이터가 파일 안에 있는지 확인한다.
④ 코드의 한계
이 코드는 개별 이미지 데이터의 바이트 범위만 점검한다.
이미지 내부의 PNG 청크, DIB 픽셀 배열, 마스크 또는 실제 렌더링 가능 여부는 확인하지 않는다.
19. PowerShell 5.1로 PNG·DIB 이미지 구분하기
세 번째 실습에서는 각 ICO 이미지 데이터의 시작 바이트를 읽어 PNG 시그니처 여부를 확인한다.
PNG 시그니처가 발견되지 않는 경우에는 DIB 가능성을 추가로 점검한다.
① PowerShell 코드
$path = "C:\FileTest\sample.ico"
$stream = [System.IO.File]::OpenRead($path)
try {
$reader = New-Object System.IO.BinaryReader($stream)
if ($stream.Length -lt 6) {
throw "ICO header is incomplete."
}
$reserved = $reader.ReadUInt16()
$type = $reader.ReadUInt16()
$count = $reader.ReadUInt16()
if ($reserved -ne 0 -or $type -ne 1 -or $count -eq 0) {
throw "Invalid ICO directory header."
}
$directoryEnd = [uint64]6 + ([uint64]16 * $count)
if ($directoryEnd -gt [uint64]$stream.Length) {
throw "ICO directory exceeds file length."
}
$entries = @()
for ($i = 0; $i -lt $count; $i++) {
$widthRaw = $reader.ReadByte()
$heightRaw = $reader.ReadByte()
$colorCount = $reader.ReadByte()
$entryReserved = $reader.ReadByte()
$planes = $reader.ReadUInt16()
$bitCount = $reader.ReadUInt16()
$bytesInRes = $reader.ReadUInt32()
$imageOffset = $reader.ReadUInt32()
$entries += [PSCustomObject]@{
Entry = $i + 1
Offset = $imageOffset
Size = $bytesInRes
}
}
foreach ($entry in $entries) {
$imageEnd = [uint64]$entry.Offset + [uint64]$entry.Size
if ($entry.Size -lt 4 -or
[uint64]$entry.Offset -lt $directoryEnd -or
$imageEnd -gt [uint64]$stream.Length) {
[PSCustomObject]@{
Entry = $entry.Entry
Format = "Invalid range"
}
continue
}
$stream.Position = [long]$entry.Offset
$readLength = [int][Math]::Min(8, $entry.Size)
$signature = $reader.ReadBytes($readLength)
$pngBytes = [byte[]]@(137, 80, 78, 71, 13, 10, 26, 10)
$isPng = $false
if ($signature.Length -ge 8) {
$isPng = $true
for ($j = 0; $j -lt 8; $j++) {
if ($signature[$j] -ne $pngBytes[$j]) {
$isPng = $false
break
}
}
}
if ($isPng) {
$format = "PNG signature"
}
else {
$stream.Position = [long]$entry.Offset
$dibSize = $reader.ReadUInt32()
if ($dibSize -in @(12, 40, 52, 56, 108, 124) -and
[uint64]$dibSize -le [uint64]$entry.Size) {
$format = "Possible DIB"
}
else {
$format = "Unknown"
}
}
[PSCustomObject]@{
Entry = $entry.Entry
Format = $format
}
}
}
finally {
$stream.Dispose()
}
② 출력 예시
Entry Format
----- ----------------
1 Possible DIB
2 Possible DIB
3 PNG signature
위 출력은 설명을 위한 예시다.
③ 코드 해석
PNG의 8바이트 시그니처를 먼저 확인하고, 일치하지 않으면 DIB 헤더 크기 후보를 확인한다.
④ 코드의 한계
이 코드는 PNG와 DIB의 시작 구조를 구분하는 기본적인 판별 도구다.
PNG 청크 CRC, DIB 이미지 데이터, 색상 마스크와 투명도 정보를 검증하지 않는다.
20. ICO 파일 손상 시 확인할 항목
ICO 파일이 정상적으로 표시되지 않으면 다음 항목을 점검할 수 있다.
| 점검 항목 | 확인 목적 |
|---|---|
| idReserved | 예약 필드 확인 |
| idType | ICO·CUR 구분 |
| idCount | 이미지 항목 수 |
| Directory Length | 디렉터리 경계 |
| bWidth·bHeight | 이미지 크기 |
| bColorCount | 색상 관련 정보 |
| wPlanes | 색상 평면 |
| wBitCount | 비트 깊이 |
| dwBytesInRes | 이미지 데이터 크기 |
| dwImageOffset | 이미지 시작 위치 |
| PNG Signature | PNG 기반 이미지 식별 |
| DIB Header | DIB 기반 이미지 식별 |
| XOR Bitmap | 색상 데이터 |
| AND Mask | 투명도 관련 데이터 |
| SHA-256 | 원본 동일성 |
대표적인 손상 상황
① ICONDIR 오류
예약 필드나 파일 유형이 잘못되면 파일을 정상적인 ICO로 해석하기 어렵다.
② 이미지 항목 수 오류
idCount가 실제 디렉터리 영역보다 크면 파일이 잘렸거나 헤더가 잘못되었을 수 있다.
③ 이미지 데이터 오프셋 오류
dwImageOffset이 파일 범위를 벗어나면 해당 이미지 데이터를 읽을 수 없다.
④ 이미지 데이터 길이 오류
dwBytesInRes가 실제 데이터보다 크면 이미지 데이터가 누락되었을 가능성이 있다.
⑤ 내부 이미지 구조 오류
PNG 또는 DIB 데이터의 헤더가 손상되면 디렉터리 정보가 정상이어도 이미지가 표시되지 않을 수 있다.
21. ICO 구조 검증과 SHA-256 무결성 검증
ICO 구조 분석과 SHA-256 해시 검증은 목적이 다르다.
구조 분석
ICONDIR, ICONDIRENTRY, 이미지 오프셋과 데이터 범위를 확인한다.
이미지 내부 검증
PNG 청크 또는 DIB 헤더, 픽셀 데이터와 투명도 정보를 분석한다.
SHA-256 검증
신뢰할 수 있는 원본 해시값과 현재 파일의 해시값을 비교한다.
PowerShell 5.1 코드
$path = "C:\FileTest\sample.ico"
Get-FileHash -LiteralPath $path -Algorithm SHA256 |
Format-List Algorithm, Hash, Path
검증 방식 비교
| 구분 | ICO 구조 분석 | 내부 이미지 분석 | SHA-256 |
|---|---|---|---|
| 확인 대상 | 디렉터리·오프셋 | PNG·DIB 데이터 | 파일 전체 |
| 범위 오류 확인 | 일부 가능 | 일부 가능 | 직접 판별 불가 |
| 이미지 디코딩 | 수행하지 않음 | 별도 구현 필요 | 수행하지 않음 |
| 원본 동일성 | 확인 불가 | 확인 불가 | 기준값과 비교 가능 |
| 파일 안전성 | 보장 불가 | 보장 불가 | 보장 불가 |
SHA-256 값이 신뢰할 수 있는 기준값과 일치한다면 두 파일의 바이트 내용이 동일하다고 매우 높은 신뢰도로 판단할 수 있다.
하지만 해시값만으로 ICO 내부 이미지가 정상적으로 표시되는지 또는 안전한 파일인지를 판단할 수는 없다.
22. 자주 묻는 질문
Q1. ICO 파일은 무엇인가요?
Windows 아이콘 이미지를 저장하는 파일 형식으로, 하나의 파일에 여러 크기의 이미지를 포함할 수 있다.
Q2. ICO 파일의 대표적인 시작 바이트는 무엇인가요?
일반적으로 00 00 01 00으로 시작하고, 다음 2바이트에 이미지 개수가 기록된다.
Q3. ICONDIR는 무엇인가요?
ICO 파일의 예약 필드, 파일 유형, 이미지 개수를 저장하는 6바이트 헤더다.
Q4. ICONDIRENTRY는 무엇인가요?
각 이미지의 크기, 색상 관련 정보, 데이터 길이와 오프셋을 저장하는 16바이트 항목이다.
Q5. ICO의 너비와 높이가 0이면 오류인가요?
아니다. ICONDIRENTRY에서 0은 일반적으로 256픽셀을 의미한다.
Q6. ICO 파일에 PNG 이미지가 들어갈 수 있나요?
가능하다. PNG 시그니처로 시작하는 이미지 데이터가 포함될 수 있다.
Q7. ICO 내부의 DIB 이미지도 BM 시그니처로 시작하나요?
일반적으로 그렇지 않다. ICO 내부의 DIB 데이터에는 BMP 파일 헤더가 없는 경우가 많다.
Q8. ICO의 DIB 높이가 실제 아이콘 높이보다 두 배인 이유는 무엇인가요?
전통적인 DIB 기반 아이콘에서는 XOR 비트맵과 AND 마스크를 함께 저장하기 때문이다.
Q9. ICO 파일의 모든 이미지를 PowerShell 코드로 검증할 수 있나요?
이번 코드로는 디렉터리와 이미지 데이터 범위, 시작 구조를 일부 확인할 수 있다. 모든 이미지의 완전한 검증에는 PNG·DIB 디코딩이 추가로 필요하다.
마무리
ICO는 ICONDIR와 ICONDIRENTRY를 이용해 여러 아이콘 이미지의 크기와 위치를 관리하는 파일 형식이다.
ICO 파일 구조 분석에서는 파일 유형, 이미지 항목 개수, 디렉터리 길이, 이미지 오프셋, 데이터 크기와 PNG·DIB 구분을 순서대로 확인하는 것이 중요하다.
특히 이미지 크기 필드의 0을 256픽셀로 해석하는 규칙과 DIB 기반 아이콘의 XOR·AND 마스크 구조를 이해하면 아이콘 파일의 저장 방식을 보다 정확하게 파악할 수 있다.
그러나 디렉터리와 이미지 데이터 범위가 정상이라고 해서 모든 이미지가 정상적으로 디코딩되거나 파일의 안전성이 보장되는 것은 아니다.
따라서 ICO 구조 분석, 내부 PNG·DIB 검증과 SHA-256 무결성 검증을 목적에 맞게 구분해 사용해야 한다.
관련 글 함께 읽기
ICO 내부 이미지 구조를 더 자세히 이해하려면 PNG 파일 구조 분석, BMP 파일 구조 분석 글을 함께 참고할 수 있다.
핵심 내용 3줄 요약
- ICO는 ICONDIR와 ICONDIRENTRY를 통해 여러 크기의 아이콘 이미지를 하나의 파일에서 관리한다.
- 각 이미지의 오프셋과 길이를 확인하고 PNG·DIB 시작 구조를 구분하면 기본적인 구조 오류를 탐지할 수 있다.
- 파일 경계 검증과 SHA-256 비교는 이미지의 완전한 디코딩 또는 안전성 검증과 구분해야 한다.
공식 및 기술 참고자료
- Microsoft Learn — ICONDIR 구조 관련 Windows 아이콘 자료
https://learn.microsoft.com/windows/win32/menurc/icon-resource - Microsoft Learn — BITMAPINFOHEADER Structure
https://learn.microsoft.com/windows/win32/api/wingdi/ns-wingdi-bitmapinfoheader - Microsoft Learn — Bitmap Storage
https://learn.microsoft.com/windows/win32/gdi/bitmap-storage - W3C — PNG Specification (Third Edition)
https://www.w3.org/TR/png-3/ - Microsoft Learn — BinaryReader Class
https://learn.microsoft.com/dotnet/api/system.io.binaryreader - Microsoft Learn — File.OpenRead Method
https://learn.microsoft.com/dotnet/api/system.io.file.openread - Microsoft Learn — Get-FileHash (PowerShell 5.1)
https://learn.microsoft.com/powershell/module/microsoft.powershell.utility/get-filehash?view=powershell-5.1
※ 본문의 PowerShell 코드는 ICO의 기본 디렉터리 구조와 이미지 데이터 경계를 읽기 전용으로 분석하는 학습용 예시다. 모든 ICO 변형이나 PNG·DIB 내부 데이터를 완전히 검증하는 디코더가 아니며, Windows PowerShell 5.1 실제 실행 테스트는 별도로 필요하다.
디지털 파일 검증 연구소
댓글 0
첫 댓글을 남겨보세요.