40 MSIX 패키지
Windows 가 MSIX 패키지를 읽고, 설치하고, 실행하게 하려면 프로그램이 무엇을 써야 하는가. 출처 표시는 구현하는 사람을 위한 패키지 형식와 같다: [spec] 은 Microsoft Learn(패키지 매니페스트와 블록 맵 스키마)과 ECMA-376 Part 2(Open Packaging Conventions), [observed] 는 Windows 자신의 패키징 API(Windows 의 일부인 AppxPackaging.dll 의 IAppxFactory/IAppxPackageWriter)가 쓴 패키지, 그리고 IAppxPackageReader 로 다시 읽고 Windows 11 에서 Add-AppxPackage 로 설치한 rubrapack 의 패키지다. rubrapack 은 여기 적은 것을 쓴다.
40.1 ZIP 압축 파일#
- 페이로드 파일이 먼저, 그다음
AppxManifest.xml,AppxBlockMap.xml,[Content_Types].xml이 그 순서로 온다. [observed] - 모든 항목은 크기와 상관없이 ZIP64 다: 로컬 머리는 필요 판 4.5, 플래그 0x0008(데이터 서술자), CRC 와 크기 0, extra 필드 없음. 데이터 뒤에는 ZIP64 데이터 서술자(
PK\7\8, CRC-32, 압축 크기와 원 크기 각 8바이트)가 온다. 중앙 디렉터리 항목은 만든 판과 필요 판이 4.5(MS-DOS), 크기와 오프셋이 0xFFFFFFFF 이고 ZIP64 extra 필드(0x0001, 24바이트: 원 크기, 압축 크기, 로컬 머리 오프셋)를 가진다. 압축 파일은 ZIP64 끝 레코드(크기 44), 그 로케이터, 그리고 개수와 오프셋이 모두 0xFFFF / 0xFFFFFFFF 인 끝 레코드로 끝난다. [observed] - 방식: 저장(0)과 deflate(8).
AppxManifest.xml,AppxBlockMap.xml,[Content_Types].xml은 페이로드가 저장이어도 deflate 한다. [observed] - 항목 이름은 OPC 부분 이름이다: 폴더 사이는
/,A-Z a-z 0-9 - . _ ~밖의 모든 바이트는 UTF-8 바이트까지 퍼센트 인코딩한다 -data\<U+C790> %#(1).txt(한글 음절, 공백,%,#, 괄호)는data/%EC%9E%90%20%25%23%281%29.txt로 저장한다 - 그리고 UTF-8 이름 플래그는 켜지 않는다.[Content_Types].xml은 대괄호를 그대로 둔다. [observed] - 머리의 날짜는 읽지 않는다. Windows 는 쓰는 시각을, rubrapack 은 1980-01-01 00:00 을 써서 빌드마다 패키지가 바뀌지 않게 한다. [observed]
40.2 블록 맵(AppxBlockMap.xml)#
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<BlockMap xmlns="http://schemas.microsoft.com/appx/2010/blockmap"
xmlns:b4="http://schemas.microsoft.com/appx/2021/blockmap" IgnorableNamespaces="b4"
HashMethod="http://www.w3.org/2001/04/xmlenc#sha256">
<File Name="data\text.txt" Size="218890" LfhSize="43">
<Block Hash="(원 바이트 65536개의 base64 SHA-256)" Size="(이 블록의 압축 바이트 수)"/>
...
<b4:FileHash Hash="(파일 전체의 base64 SHA-256)"/>
</File>
...
</BlockMap>
- 페이로드 파일마다
File하나,AppxManifest.xml에도 하나. 블록 맵과[Content_Types].xml은 싣지 않는다.Name은 적은 그대로의 경로로\를 쓰고 퍼센트 인코딩하지 않는다.Size는 원 크기,LfhSize는 로컬 머리의 크기(30 + ZIP 이름 길이)다. 빈 파일에는Block이 없다. [spec] [observed] - 원 데이터 65536바이트마다
Block하나.Hash는 그 원 블록의 base64 SHA-256 이다. [spec] - deflate 한 파일은 블록마다 독립된 원시 deflate 조각 하나다: 조각마다 새 디코더로 풀리고(앞 블록을 되돌아 가리키는 것이 없다) 빈 저장 블록(
00 00 FF FF)으로 끝나며, 마지막 조각 뒤에는 빈 마지막 블록(03 00)이 온다. 블록의Size는 그 조각의 바이트 수라서, 파일의 압축 크기는Size합 더하기 2 다(빈 파일은 2바이트, 블록 없음). 저장 파일의 블록에는Size가 없다. 압축되지 않는 데이터도 (저장 블록으로) deflate 한다. [observed] b4:FileHash는 블록이 둘 이상인 파일에만 나온다. [observed]- Windows 의 판독기는 파일을 읽으면서 블록마다 해시를 확인하고, 파일이 블록 맵과 다른 패키지는 읽을 때도 설치할 때도 거부한다. [observed]
40.3 [Content_Types].xml#
한 줄: 처음 쓰인 순서대로의 파일 확장자(소문자)마다 Default 하나, xml 은 application/vnd.ms-appx.manifest+xml, 그리고 application/vnd.ms-appx.blockmap+xml 인 Override PartName="/AppxBlockMap.xml". rubrapack 은 확장자 없는 파일마다 Override 를, 그리고 페이로드의 .xml 파일이 xml 기본을 차지했으면 /AppxManifest.xml 에 Override 를 더한다. [observed]
40.4 매니페스트(AppxManifest.xml)#
Windows 가 설치하고 시작하는 가장 작은 데스크톱 앱(네임스페이스 foundation/windows10, uap/windows10, restrictedcapabilities): [spec] [observed]
Identity:Name(A-Z a-z 0-9 . -로 3~50자),Publisher(서명 인증서의 주체),Version(네 부분, 각 65535 이하),ProcessorArchitecture(x64,arm64,x86).Properties:DisplayName,PublisherDisplayName,Logo(패키지 속 PNG).MinVersion과MaxVersionTested를 가진Dependencies/TargetDeviceFamily Name="Windows.Desktop".Resources/Resource Language.uap:VisualElements(DisplayName,Description,BackgroundColor,Square150x150Logo,Square44x44Logo)를 가진Application Id Executable EntryPoint="Windows.FullTrustApplication", 그리고 제한된 기능runFullTrust.- 매니페스트 속 경로는
\를 쓰고 패키지의 파일을 가리킨다.
40.5 가상 레지스트리(Registry.dat, User.dat)#
패키지 뿌리의 레지스트리 하이브(REGF 형식: 레지스트리 하이브 파일(REGF)). Windows 11(26100)에서 패키지된 앱으로 잰 것: [observed]
Registry.dat: 그REGISTRY\MACHINE\SOFTWARE키가HKLM\Software를 나타낸다(하이브의 뿌리 자체는 아니다).REGISTRY\MACHINE\SOFTWARE\WOW6432Node\...는 앱이 32비트 보기에서 보는 것이다. Microsoft 의 설명("registry.dat serves as the logical equivalent of HKLM\Software")은 앱이 보는 것에 대한 말이지 하이브의 배치에 대한 말이 아니다.User.dat: 그 뿌리가HKCU를 나타낸다(그 아래Software\...가HKCU\Software\...).- 앱은 패키지의 키를 실제 레지스트리와 합쳐 읽는다. 컴퓨터의 레지스트리에는 아무것도 쓰지 않고, 제거한 뒤에는 아무것도 남지 않는다.
- Windows 의 패키징 도구는 이 하이브를 오프라인 레지스트리 라이브러리로 쓴다(그 표시 "OfRg" 가 기본 블록에 있다).
40.6 가상 파일 시스템(VFS\...)#
VFS\<폴더> 아래의 파일은 앱에게 실제 자리에 있는 것으로 보이고, 실제 폴더는 바뀌지 않는다. 잰 것: ProgramFilesX64(%ProgramFiles%), SystemX64(System32), Common AppData(%ProgramData%) - 그리고 Microsoft Learn 이 말하는 대로 AppData 나 Local AppData 에는 없다. rubrapack 이 쓰는 다른 이름(ProgramFilesX86, ProgramFilesCommonX64/X86, SystemX86, Windows)은 Microsoft Learn 이 늘어놓은 것이다. [spec] [observed]
40.7 자원 색인(resources.pri) [observed]#
매니페스트의 ms-resource:Name 과, Assets\Logo.scale-200.png 로만 있는 로고 Assets\Logo.png 는 resources.pri 에서 찾는다. 공개된 명세는 없다. 여기 적은 것은 Windows SDK 의 makepri.exe 가 쓰는 배치 중 패키지에 필요한 만큼이고, makepri 자신의 덤프와 Windows 가 rubrapack 의 파일에서 그대로 읽어 낸 것이다. 숫자는 모두 리틀엔디언, 한정자·이름 표의 문자열은 따로 적지 않으면 UTF-16 이다.
- 파일:
mrm_pri2, u16 0, u16 1, u32 파일 크기, u32 32(차례), u32 첫 절의 위치, u16 절 수, u16 0xFFFF, u32 0. 이어 절마다 32바이트 항목(16바이트 이름, u32 0, u32 0, 첫 절부터의 u32 위치, u32 길이), 절들,DE FA FF DE, u32 파일 크기,mrm_pri2. - 절: 16바이트 이름, u32 0, u32 0, u32 길이, u32 0, 자료(8바이트로 채움),
DE FA F5 DE, u32 길이. [mrm_decn_info]- 조건: 개수(구별 한정자, 한정자, 한정자 집합, 결정, 색인 항목, 값 글자), 결정과 한정자 집합은 (첫 색인 항목, 개수), 한정자는 (구별 한정자, 우선순위, 기본값으로서의 점수 x 1000, 0), 구별 한정자는 (2, 형식, 0, 10, u32 값 위치)이고 형식은 Language 0, Scale 2. 집합(한정자 번호)과 결정(집합 번호)이 함께 쓰는 u16 색인 표, 그리고 값들. 저마다 0번은 비어 있다. 우선순위: Language 700, Scale 200. 점수: 기본 언어 1.0, 다른 언어 0, 배율 100 1.0, 125 0.937, 150 0.875, 200 0.75, 400 0.437. 결정은 집합을 점수가 낮은 것부터 적는다.[mrm_pridescex]- 스키마, 결정, 자원 지도, 자료 항목이 어느 절에 있는지.[mrm_hschemaex]- 이름:ms-appx://<Identity Name>/과 이름, 이어 범위와 항목의 나무 (Resources/AppDisplayName,Files/Assets/Logo.png)를 12바이트 항목(부모 항목, 전체 경로 길이, 대문자로 바꾼 첫 글자, 이름 길이, 0x10 범위 | 0x20 ASCII 이름, 이름 위치, 범위나 항목 번호)으로 - 범위마다 자식들을 모아 이름 순으로. 범위(항목, 자식 수, 첫 자식), 항목(항목), ASCII 이름들. 이름들에 대한 32비트 검사값이 들어 있지만 검사되는 것은 보지 못했다.[mrm_res_map2_]- 항목마다 결정과 첫 후보, 후보마다 값 형식(UTF-16 문자열 0, 경로 1, ASCII 문자열 3, ASCII 경로 5)과 자료 항목(절, 번호).[mrm_dataitem]- 한정자 집합마다 절 하나: (위치, 길이) 쌍과 끝 문자까지 담은 문자열들.
40.8 확장#
rubrapack 이 앱의 <Extensions>(uap:VisualElements 뒤)에 쓰는 것, 그리고 이것뿐이다: 여기 행이 없는 원본 기능은 오류이고, 필요한 Windows 빌드가 패키지의 MinVersion 보다 높은 것은 min-version 을 올리라고 요구한다. [spec] Microsoft Learn, "Integrate your desktop app with Windows using packaging extensions" 와 요소 문서들. 마지막 열은 Windows 11(26100)에 패키지를 설치해 확인한 것이다. [observed]
| 원본 | 요소(범주) | 네임스페이스 | 최소 빌드 | 기능 | Windows 11 에서 확인한 것 |
|---|---|---|---|---|---|
[assoc] | uap:Extension windows.fileTypeAssociation > uap3:FileTypeAssociation(Name, Parameters) > uap:DisplayName, uap:SupportedFileTypes > uap:FileType | uap, uap3 | 14393 | runFullTrust | .rpx/.rpy 파일을 열면 프로그램이 그 파일과 함께 시작된다 |
[protocol] | uap3:Extension windows.protocol > uap3:Protocol(Name, Parameters) | uap3 | 14393 | runFullTrust | scheme: URI 를 시작하면 프로그램이 그것과 함께 시작된다 |
[msix-extension] 별칭 | uap3:Extension windows.appExecutionAlias(Executable, EntryPoint) > uap3:AppExecutionAlias > desktop:ExecutionAlias(Alias) | uap3, desktop | 14393 | runFullTrust | 별칭이 %LOCALAPPDATA%\Microsoft\WindowsApps 에 생기고 프로그램을 시작한다 |
[msix-extension] 시작 작업 | desktop:Extension windows.startupTask(Executable, EntryPoint) > desktop:StartupTask(TaskId, Enabled, DisplayName) | desktop | 14393 | runFullTrust | 첫 시작 뒤에 등록된다 |
[shortcut] Desktop | desktop7:Extension windows.shortcut > desktop7:Shortcut(File $(Desktop)\<이름>.lnk, Icon, Arguments, Description) | desktop7 | 19645 | runFullTrust | 사용자의 바탕화면에 바로가기가 생기고 프로그램을 시작한다 |
[shortcut] Programs, StartMenu | 없음: 앱 자신의 시작 메뉴 항목 | - | - | - | 시작 메뉴에 앱이 있다 |
[font] | uap4:Extension windows.sharedFonts > uap4:SharedFonts > uap4:Font(File Fonts\<이름>), 첫 앱에 | uap4 | 15063 | - | 패키지가 설치되어 있는 동안 다른 프로그램이 글꼴을 보고, 제거하면 보지 못한다 |
- 네임스페이스는 쓸 때만
Package에 선언하고 무시 가능(ignorable)으로 둔다. 그래서 확장 없는 패키지는 위의 매니페스트를 그대로 지킨다. Parameters,Arguments: 리터럴 글(MSI 의[...]는 거부). Windows 는%1자리에 파일이나 URI 를 넣는다.FileTypeAssociation의Name: prog-id 를 소문자로. prog-id 를 같이 쓰는[assoc]표들은FileType이 여럿인 연결 하나가 된다.- 모든 것은 원본이 대상으로 적은 실행 파일을 가진 앱에 들어간다. 앱의 실행 파일이 아닌 대상은 오류다.
40.9 묶음(.msixbundle)#
Windows 의 묶음 작성기(IAppxBundleWriter)가 만드는 대로, 패키지처럼 놓인 ZIP 압축 파일(데이터 서술자를 가진 ZIP64 항목): [observed]
- 패키지들이 먼저, 저장(방식 0)으로, 그 파일 이름으로, 더한 순서대로. 그다음
AppxMetadata/AppxBundleManifest.xml,AppxBlockMap.xml,[Content_Types].xml을 deflate 로. - 블록 맵은 묶음 매니페스트(
AppxMetadata\AppxBundleManifest.xml)만 싣는다. 패키지들은 제 블록 맵을 가진다. [Content_Types].xml:Defaultmsix=application/vnd.ms-appx,Defaultxml=application/vnd.ms-appx.bundlemanifest+xml, 그리고/AppxBlockMap.xml의Override.- 묶음 매니페스트, 줄 끝은 CRLF, 들여쓰기는 탭, 마지막 꼬리표 뒤에는 줄 끝이 없다:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Bundle xmlns="http://schemas.microsoft.com/appx/2013/bundle" SchemaVersion="5.0" xmlns:b4="http://schemas.microsoft.com/appx/2018/bundle" xmlns:b5="http://schemas.microsoft.com/appx/2019/bundle" IgnorableNamespaces="b4 b5">
<Identity Name="Example.App" Publisher="CN=Example" Version="1.0.0.0"/>
<Packages>
<Package Type="application" Version="1.0.0.0" Architecture="x64" FileName="Example.App_1.0.0.0_x64.msix" Offset="66" Size="61340">
<Resources>
<Resource Language="en-US"/>
</Resources>
<b4:Dependencies>
<b4:TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.26100.0"/>
</b4:Dependencies>
</Package>
</Packages>
</Bundle>
Offset은 묶음에서 패키지의 바이트가 시작하는 곳(로컬 머리 다음),Size는 그 길이다.Resources와Dependencies는 패키지 매니페스트의Resource와TargetDeviceFamily요소를 되풀이한다.- 묶음의
Version은 작성기의 인수(부분마다 16비트인 64비트 수)다. rubrapack 은 패키지들의 판을 준다. 모든 패키지는 묶음의Name과Publisher, 한 가지 판, 그리고 저마다 다른 아키텍처를 가져야 한다. - 같은 패키지들로 만든 rubrapack 의 묶음은 같은 항목을 같은 오프셋에 가지고, 매니페스트·블록 맵·콘텐츠 형식이 바이트까지 같다. ZIP 날짜만 다르다(rubrapack 은 1980). Windows 는 그 가운데 자기 아키텍처의 패키지를 설치한다: x64 컴퓨터는 x86 과 arm64 가 있어도 x64 를, x86 만 든 묶음에서는 x86 을. [observed]
40.10 서명(AppxSignature.p7x)#
Windows 의 서명기(APPX_SIP_CLIENT_DATA 를 준 mssign32!SignerSignEx2; PowerShell 명령은 패키지에 서명하지 못한다)와 대조해 알아내고, rubrapack 이 서명한 패키지를 설치해 확인했다. [observed]
- 매니페스트의
Publisher는 Windows 가 보여 주는 방식으로 쓴 서명 인증서의 주체와 같아야 한다: RDN 을 마지막부터 처음으로,A=value를,로 이어서 -/CN=Example/O=Example Ltd로 만든 인증서는O=Example Ltd, CN=Example이 필요하다. 그렇지 않으면 서명이 0x8007000B 로 실패한다. - 서명은 서명기가 하는 대로 압축 파일을 다시 쓴다: 페이로드의 로컬 레코드, 매니페스트, 블록 맵은 그대로 두고,
[Content_Types].xml에<Override PartName="/AppxSignature.p7x" ContentType="application/vnd.ms-appx.signature"/>를 더하고, 서명을 맨 끝에 deflate 로, 크기를 로컬 머리에 담아(필요 판 2.0, 데이터 서술자 없음)더한다. 중앙 디렉터리는 크기와 오프셋이 허락하는 한 ZIP32 방식(ZIP64 extra 필드 없음)으로 쓰고, 끝 레코드의 디스크 번호는 0 이다. AppxSignature.p7x는PKCX뒤에 Authenticode 서명와 같은 CMS SignedData 가 오되, 다음이 다르다:data는SEQUENCE { SpcSipInfo (1.3.6.1.4.1.311.2.1.30), SEQUENCE { INTEGER 0x01010000, OCTET STRING <SIP GUID>, INTEGER 0, INTEGER 0, INTEGER 0, INTEGER 0, INTEGER 0 } }이고 패키지 SIP GUID 바이트는4B DF C5 0A 07 CE E2 4D B7 6E 23 C8 39 A0 9F D1, 묶음 SIP GUID 바이트는B3 58 5F 0F DE AA 9A 4B A4 34 95 74 2D 92 EC EB다. 서명 속성은contentType과messageDigest뿐이다.- DigestInfo 의 다이제스트는 해시 하나가 아니라
APPX뒤에 4바이트 꼬리표와 SHA-256 의 기록들이 오는 것이다:AXPC: 압축 파일 처음부터 서명 항목의 로컬 머리까지;AXCD: 서명 항목을 뺀 중앙 디렉터리, 그다음 ZIP64 끝 레코드, 그 로케이터, 끝 레코드 - 모두 서명 항목이 없는 것처럼(중앙 디렉터리가 서명의 로컬 머리 자리에서 시작하는 것처럼). Windows 는 서명 항목의 자리를 그 ZIP32 필드에서 읽는다: ZIP64 방식으로 기술한 서명 항목(거기 0xFFFFFFFF)은HashMismatch이고, 서명한 뒤 중앙 디렉터리를 그렇게 다시 쓴 패키지도 그렇다;AXCT:[Content_Types].xml(원 바이트);AXBM:AppxBlockMap.xml;AXCI:AppxMetadata/CodeIntegrity.cat, 패키지에 그것이 있을 때만.
- 프로그램 파일이 있는 패키지는 Windows 의 서명기가 하듯
AppxMetadata/CodeIntegrity.cat- 같은 키로 서명한 그 파일들의 카탈로그 - 와 그 해시AXCI도 받는다. 그것은[Content_Types].xml(여기에 그것을 위한 Overrideapplication/vnd.ms-pkiseccat이 붙는다) 뒤, 서명 앞에 들어가고, 블록 맵에는 적히지 않는다. 카탈로그 [observed]:- 서명된 속성이 contentType 과 messageDigest 뿐인 SignedData 이고, 내용(형식
1.3.6.1.4.1.311.10.1, 인증서 신뢰 목록)은: 용도1.3.6.1.4.1.311.12.1.1(카탈로그 목록), 16바이트 목록 식별자, 시각, 구성원 알고리즘1.3.6.1.4.1.311.12.1.3, 구성원들, 그리고 이름-값 둘(1.3.6.1.4.1.311.12.2.1:PackageFullName과OSAttr=2:6.2, 저마다 BMPString 이름, 플래그0x10010001, UTF-16 값). - PE 파일마다 구성원 둘: 구성원 정보
1.3.6.1.4.1.311.12.2.3을 단 SHA-1, 그리고 그것과 PE 이미지용 SpcIndirectData 를 단 SHA-256. - 파일의 해시는 Authenticode 다이제스트이되, 서명이 없는 파일은 0 으로 8바이트 배수까지 채운 것 위에서 잰다 - 서명을 붙이기 전의 모습 그대로. 길이가 8의 배수인 파일은 둘이 같다.
- 패키지 전체 이름은
<Name>_<Version>_<Architecture>_<ResourceId>_<PublisherId>이고, 게시자 ID 는 매니페스트Publisher의 UTF-16LE 에 대한 SHA-256 앞 8바이트를 Crockford base32(0-9 a-z에서i l o u를 뺀 것) 13글자로 적은 것이다.
- 서명된 속성이 contentType 과 messageDigest 뿐인 SignedData 이고, 내용(형식
- 묶음: 안의 모든 패키지를 먼저 서명하고(저마다 제
AppxSignature.p7x), 그 둘레에 묶음을 쓰고, 묶음 SIP GUID 로AXCI없이 서명한다. -AllowUnsigned와 publisher OID(아래)가 필요한 서명 없는 패키지는 서명하지 않는다: 서명은 그 OID 를 가진 publisher 를 거부한다.
40.11 서명 없는 패키지 설치하기#
Publisher가OID.2.25.311729368913984317654407730594956997722=1로 끝나야 한다. 그러면Add-AppxPackage -AllowUnsigned가 Windows 11 에 설치한다. [spec]- 실행 파일이 든 패키지는 관리자 권한 프로세스가 필요하다(아니면 0x80073D2B: 서명 없는 패키지는 실행 파일 활성화를 가질 수 없다). 개발자 모드는 필요 없다. [observed]
- 네트워크 로그온(SSH 세션)에서
Add-AppxPackage는 "PLM initialization" 에서 0x80070005 로 실패하고, 대화형 세션에서는 된다. [observed] - 파일 형식이 든 패키지를 제거하면
HKCU\Software\Classes\.<ext>아래에 빈OpenWithProgids키가 남는다 - 패키지가 아니라 Windows 가 하는 일이다. [observed]
40.12 실제 예: 튜토리얼의 hello.msix#
튜토리얼 17장의 MSIX(--unsigned-test, x64)는 11119 바이트다. 첫 파일 hello.exe 의 로컬 머리로 시작한다:
| 오프셋 | 바이트 | 필드 | 값 |
|---|---|---|---|
0x00 | 50 4b 03 04 | 서명 | PK\3\4 |
0x04 | 2d 00 | 필요한 판 | 45 (4.5, ZIP64) |
0x06 | 08 00 | 플래그 | 0x0008: 크기는 데이터 뒤에 |
0x08 | 08 00 | 방법 | 8 (deflate) |
0x0A | 00 00 21 00 | 시각, 날짜 | 1980-01-01 00:00 |
0x0E | 00 00 00 00 00 00 00 00 00 00 00 00 | CRC, 크기 | 0 (데이터 기술자에) |
0x1A | 09 00 00 00 | 이름, 추가 필드 길이 | 9, 0 |
0x1E | 68 65 6c 6c 6f 2e 65 78 65 | 이름 | hello.exe |
hello.exe 의 deflate 된 6706 바이트가 뒤따르고, 이어서 데이터 기술자가 온다: 50 4b 07 08 ac a3 c6 2e 32 1a 00 00 00 00 00 00 00 46 00 00 00 00 00 00 - PK\7\8, CRC-32 2EC6A3AC, 그리고 압축된 크기와 원래 크기를 8 바이트씩(6706, 17920).
AppxBlockMap.xml 에 있는 그 항목:
<File Name="hello.exe" Size="17920" LfhSize="39">
<Block Hash="K7HbHzXLkhbwTo3dcUr0vs35DlYX27qMOexDOTR8e2k=" Size="6704"/>
파일이 64 KiB 보다 작아 블록은 하나다. Hash 는 원래 17920 바이트의 SHA-256 을 base64 로 쓴 것(여기서 계산한 값 K7HbHzXLkhbwTo3dcUr0vs35DlYX27qMOexDOTR8e2k=), Size 는 그 deflate 부분의 6704 바이트 - 압축된 크기 6706 에서 2 바이트 마지막 블록을 뺀 것 - 이고, LfhSize 는 로컬 머리의 39 바이트(30 + 이름 9 바이트)다.