41 레지스트리 하이브 파일(REGF)
MSIX 패키지 속 Registry.dat 와 User.dat 의 파일 형식이다. Microsoft 는 이것을 공개하지 않는다. 여기의 모든 사실은 [observed] 다: 고른 키/값 집합으로 Windows 의 오프라인 레지스트리 라이브러리(offreg.dll, 10.0.26100, Windows 패키징 도구가 쓰는 작성기 - 그 표시가 기본 블록에 있다)가 쓴 하이브, 그리고 같은 집합으로 rubrapack 이 쓴 하이브를 Windows 에서 OROpenHive 와 RegLoadAppKey 로 읽어 Windows 가 자기 하이브에서 늘어놓는 것과 정확히 같은 키와 값이 나오는 것을 확인했다. 새로 쓴 하이브에 필요한 것만 적는다: 트랜잭션 로그, 휘발성 키, 빈 칸 재사용은 없다.
41.1 배치#
- 4096바이트 기본 블록, 그다음 하이브 bin 들. 칸 속의 오프셋("칸 오프셋")은 기본 블록 끝에서부터 센다 (파일 오프셋 - 4096). "없음"은 0xFFFFFFFF 다.
- bin:
hbin, u32 자신의 칸 오프셋, u32 크기(4096 이나 그 배수), 0 인 8바이트, u64 시각(0), u32 여분(0); 모두 32바이트. 그 뒤에 칸이 온다. 지금 bin 에 들어가지 않는 칸은 그것을 담을 크기의 새 bin 을 시작하고, bin 의 나머지는 빈 칸 하나다. - 칸: i32 크기(쓰는 중이면 음수, 8의 배수, 크기 필드 포함), 그다음 내용. 칸은 제 bin 의 끝을 넘지 않는다.
41.2 기본 블록#
| 오프셋 | 필드 | 값 |
|---|---|---|
| 0 | 서명 | regf |
| 4, 8 | 순서 번호 | 1, 1 (다르면 = 깨끗이 닫히지 않음; 판독기는 거부하거나 로그를 다시 적용) |
| 12 | u64 시각 | 0 도 받는다 |
| 20, 24 | 판 | 1, 5 |
| 28, 32 | 종류, 형식 | 0, 1 |
| 36 | 루트 키의 칸 오프셋 | |
| 40 | 모든 bin 의 크기 | |
| 44 | 클러스터링 | 1 |
| 0xB0 | offreg 의 표시 | OfRg, 그다음 u32 1 |
| 508 | 체크섬 | 앞의 dword 127개의 XOR; 0 은 1 로, 0xFFFFFFFF 는 0xFFFFFFFE 로 쓴다 |
나머지는 모두 0 이다.
41.3 키(nk)#
nk, u16 플래그, u64 시각, u32 접근 비트(0), u32 부모(루트면 없음), u32 하위 키 수, u32 휘발성 하위 키 수(0), u32 하위 키 목록, u32 휘발성 목록(없음), u32 값 수, u32 값 목록, u32 보안 칸, u32 클래스(없음), u32 가장 긴 하위 키 이름, u32 가장 긴 클래스(0), u32 가장 긴 값 이름, u32 가장 큰 값 데이터, u32 작업 변수(0), u16 이름 길이, u16 클래스 길이(0), 그다음 이름.
- 플래그: 이름을 Latin-1 로 저장하면("압축": 모든 UTF-16 단위가 256 미만) 0x20, 아니면 이름은 UTF-16LE 다. offreg 하이브의 루트 키 이름은
ROOT이고 플래그는 0x20 뿐이다. - 가장 긴 이름들은 저장 형태와 상관없이 UTF-16 바이트로 센다.
- 이름은 대소문자 없이 비교한다: UTF-16 단위마다 유니코드 단순 대문자로 바꾼다.
41.4 하위 키 목록(lh, ri)#
lh, u16 수, 그다음 하위 키마다: u32 키 칸, u32 해시. 대문자로 바꾼 이름순 정렬.- 해시: h = 0; 이름의 UTF-16 단위마다 h = h * 37 + upper(unit)(32비트에서 넘침).
- 하위 키가 507개보다 많으면: 507개까지 담는
lh목록들의ri(u16 수,lh목록마다 u32).
41.5 값(vk)과 값 목록#
- 값 목록은 u32 값 칸 오프셋을 값을 정한 순서대로 담은 보통 칸이다.
vk, u16 이름 길이, u32 데이터 크기, u32 데이터 오프셋, u32 형식, u16 플래그, u16 여분, 그다음 이름. 플래그 1 = Latin-1 이름. 이름 없는 기본값은 이름이 비고 플래그가 0 이다.- 4바이트 이하의 데이터(빈 값 포함)는 데이터 오프셋 필드에 두고 크기의 최상위 비트를 켠다.
- 16344바이트까지: 데이터 칸 하나. 16345바이트부터:
db칸(db, u16 조각 수, u32 조각 목록), u32 조각 칸들의 목록 칸, 저마다 16344바이트인 조각들 - 마지막 것까지 모든 조각 칸을 온 크기로 잡는다: 마지막 조각 칸이 더 짧으면 Windows 는 그 값을 읽다 멈춘다.
41.6 보안 칸(sk)#
모든 키가 나눠 쓰는 sk 칸 하나: sk, u16 0, u32 다음과 u32 이전(둘 다 자기 자신), u32 참조 수(키의 수), u32 서술자 길이, 그다음 자기 상대(self-relative) 보안 서술자. offreg 의 것: 소유자와 그룹은 Administrators; SYSTEM 과 Administrators 모든 권한, Everyone 과 RESTRICTED 읽기, 모두 컨테이너 상속.
41.7 재현 가능한 하이브#
시각 필드를 모두 0 으로 두고 칸을 깊이 우선으로 놓으면(키; 루트 키 다음에는 보안 칸; 키의 하위 키 목록, 값 목록, 값마다 그 뒤에 데이터; 그다음 하위 키들을 정렬 순서로) 같은 키와 값은 어느 호스트에서나 같은 바이트가 된다. Windows 는 그런 하이브를 아무 불평 없이 읽는다.