xmin. guest@xmin ~ $
~/ $
[보안 리서치] 2026년 6월 14일

IrfanView Legacy JPM.dll 분석 회고: Type Confusion 기반 Pointer Dereference

현재 IrfanView 기본 설정 영향 항목이 아닌, 비활성화된 legacy JPM.dll 플러그인 대상 퍼징 분석 회고입니다. 조작된 JPM 박스 구조가 서로 다른 노드 타입을 같은 구조체처럼 처리하며 pointer dereference 크래시로 이어진 흐름을 정리한 기록입니다.

irfanviewjpm.dlljpeg2000legacy-plugintype-confusionpointer-dereferencefuzzingcrash-analysisvendor-not-accepted

공개 범위 메모 : 이 글은 현재 IrfanView 기본 설정에서 악용 가능한 취약점 공개가 아닙니다. 개발자 답변에 따르면 JPM.dll 플러그인은 약 2년 전부터 기본 비활성화된 legacy plugin이며, 사용자가 수동으로 활성화하고 IrfanView의 보안 경고를 무시해야만 도달 가능한 코드입니다. 따라서 본문은 현재 제품 advisory가 아니라 WinAFL 기반 파일 포맷 파서 퍼징과 크래시 분석 과정을 정리한 연구 회고로 봐야 합니다.

개발자 답변과 현재 영향 범위

제보 후 IrfanView 개발자는 해당 JPM 플러그인이 현재 IrfanView에서 기본 활성화되어 있지 않으며, 이 문제를 현재 IrfanView의 보안 취약점으로 보지 않는다고 답변했습니다. 이 내용을 반영해 본 글에서는 해당 케이스를 비활성화된 legacy 플러그인 분석 기록 으로 정리합니다.

개요

이번 케이스는 JPM 박스 트리를 재귀적으로 파싱하는 과정에서 구조체 타입이 섞이며 발생한 untrusted pointer dereference다. 보고서 기준으로는 type confusion 패턴에 가깝다.

크래시 지점에서는 구조체의 offset 0x1c 필드가 배열 포인터처럼 사용되는데, PoC에서는 이 값이 유효한 heap 주소가 아니라 파일에서 온 정수값 0x00000001 로 들어간다.

크래시 샘플: fuzzer10id00006600EXCEPTIONACCESSVIOLATION.jpm Size: 319 bytes

샘플 특징

크래시 샘플은 JPM 시그니처와 기본 박스들을 갖고 있지만, ftyp 주변의 값과 하위 박스 흐름이 일반적인 JPM 파일과 다르다.

00000000: 00 00 00 0c 6a 50 20 20 0d 0a 87 0a 00 00 00 14 00000010: 66 74 79 70 6a 70 6d 20 00 00 40 00 6a 70 6d 20 00000020: 00 00 00 1d 6d 68 64 72 00 00 00 01 01 01 00 00

크래시

Exception: Access violation (0xc0000005) Address: 0x61d32985 Module: JPM.dll Base: 0x61cf0000

Crash instruction: mov eax, dword ptr [eax+ecx4]

Dereferenced address: 0x00000001

near-NULL에 가까운 주소를 배열 포인터처럼 역참조하면서 크래시가 발생했다.

호출 흐름

fuzzReadJPMW!fuzzme JPM!ReadJPMW+0x198 sub100347A6 sub1003A5C0 sub1003A7A0 sub10042B40 sub10042940

크래시 함수는 sub10042940 , IDA 기준 0x10042940 이며, 크래시 지점은 0x10042985 다.

원인 분석

정상 경로에서는 구조체의 특정 필드가 heap allocation 내부 오프셋을 가리켜야 한다. 보고서 기준 sub10042BD0 에서는 a1[7] = v11 + v14 형태로 배열 포인터에 해당하는 값이 설정된다.

하지만 크래시 샘플 입력에서는 다른 노드 타입의 구조체가 같은 offset 패턴으로 처리되는 것으로 보인다.

field0x18 = count field0x1c = arrayptr

index < field0x18 형태의 bounds check는 통과하지만, 정작 field0x1c 가 유효한 heap pointer인지 확인하지 않는다. 그 결과 파일에서 유래한 0x00000001 이 포인터처럼 사용된다.

또 다른 함수인 sub1003D680 은 같은 구조체의 다른 필드쌍인 offset 0x4c , 0x44 를 사용한다. 즉 여러 노드 타입이 같은 포인터로 전달되고, 호출 위치에 따라 서로 다른 구조체 레이아웃을 가정하는 흐름이 존재한다.