# Android 메모리에서 마스터 키 복구 및 DB 복호화 2026-09-29, LDPlayer 14 / Android 14 / 게임 1.2.0, PID 4380에서 수행했다. ## 결과 - 게임의 마스터 관리 객체에서 파일별 경로와 키 **379개**를 복구했다. - 원본 암호화 파일 **379개, 61,485,056바이트**를 PC로 복사했다. - **15,011개 페이지 전부**의 HMAC-SHA512를 검증하고 AES-256-CBC 복호화에 성공했다. - 복호화된 **379개 DB 전부**를 독립적인 Python 표준 SQLite로 읽기 전용으로 열었다. 모든 `PRAGMA integrity_check` 결과가 `ok`였으며, 모든 테이블을 끝까지 읽어 **233,312행**을 확인했다. - Card는 189행, Music은 211행, LangMusic_Kor의 Lang 테이블은 2,167행이다. 행 내부에는 BLOB이 포함되므로 계산기용 필드/JSON 변환을 완료했다는 뜻은 아니다. - 게임 프로세스/파일의 수정, 후킹, 재시작, 서버 요청, 계정 인증 정보 사용은 하지 않았다. - 계산기 서비스 데이터에는 반영하지 않았다. ## 확보 방법 1. root ADB에서 `/proc/4380/maps`를 읽고 `/proc/4380/mem`의 필요한 영역을 덤프했다. LDPlayer `su` 경유 바이너리 출력의 줄바꿈 변환을 피하기 위해 기기 쪽에서 base64로 감싼 뒤 PC에서 디코딩했다. 2. 이전에 분석한 현재 앱의 IL2CPP 타입 정보로 `MasterManager.<>c → declaringType → MasterManagerBase → static_fields → _instance`를 따라갔다. 3. `_downloadedMasterFileInfos`의 사전과 `DownloadMasterFileInfo` 객체들을 읽어 마스터 이름, 저장 경로, 키 byte 배열, 원본 크기를 확보했다. 관련 메모리는 64KiB 단위의 제한된 청크로 저장했으며 전체 프로세스 덤프는 필요하지 않았다. 4. 키 배열은 67바이트의 SQLCipher `x'<64 hex characters>'` 형태다. 가운데 64자리 hex는 원시 256비트 키다. 실제 키 값은 이 문서나 Git 추적 파일에 포함하지 않는다. 5. 원본 파일을 ADB pull로 복사하고, 파일별 복구 키로 각 페이지의 HMAC를 확인한 뒤 복호화했다. ## 검증된 파일 형식 - 페이지 크기: 4,096바이트 - 암호화: AES-256-CBC, 원시 키 32바이트 - 파일 첫 16바이트: salt - 페이지 끝 reserved 영역: 80바이트 (IV 16 + HMAC 64) - HMAC: SHA512, 암호문과 IV 뒤에 little-endian 페이지 번호를 포함 - HMAC 키: 원시 DB 키를 입력으로, `salt XOR 0x3A`와 PBKDF2-HMAC-SHA512 2회를 사용해 32바이트 파생 - 첫 페이지의 평문 SQLite 헤더를 복원하고 reserved 영역은 0으로 채운 복사본을 생성했다. 페이지 헤더의 reserved 크기는 유지한다. 설정은 추정으로만 채택한 것이 아니라 전체 페이지 HMAC 일치 및 독립 SQLite 무결성 검사로 검증했다. 암호화와 평문 파일의 SHA-256을 파일별로 남겼다. ## 로컬 산출물 (Git 제외) 모두 `data/inspection/android-master-2026-09-29/` 아래에 있다. - `master-keys.private.json`: 파일별 키, 경로, 마스터 버전 및 객체 주소. **비공개로 유지할 자료**. - `memory/`: 키 복구에 사용한 선택적 메모리 덤프. 계정 관련 값이 섞일 수 있으므로 비공개로 유지한다. - `encrypted-master/`: 암호화된 원본 복사본 379개. - `decrypted-master/`: 이름을 붙인 평문 SQLite DB 379개 (`Card.sqlite`, `Music.sqlite` 등). - `decrypt-manifest.json`: 암호 검증 페이지 수, 파일 크기 및 양쪽 SHA-256. - `sqlite-verification.json`: DB별 무결성 검사, 테이블 스키마와 행 수. - `memory.py`, `master_instance.py`, `dump_master_keys.py`: 메모리 읽기 및 키 복구 스크립트. - `decrypt-master.mjs`, `verify_decrypted.py`: 로컬 복사본 복호화와 독립 SQLite 검증 도구. 메모리 주소와 타입 레이아웃은 현재 앱 빌드/프로세스 기준이다. 앱을 재시작하거나 업데이트하면 재확인해야 한다. 확보한 키와 같은 버전의 암호화 파일 복사본은 앱 실행 없이도 로컬에서 다시 검증할 수 있다. ## 수집 기준 확인 작업 전 `npm run data:sync`를 실행하고 `latest.json`, `latest.md`, `changes.patch`를 모두 확인했다. 영문/한국어/일본어 공식 원격은 기존 9월 26일 기준 커밋과 같고, 모든 콘텐츠 분류에서 변경이 없었다. 이번 로컬 게임 스냅샷의 확보가 HolodoriDB 수집 기준을 갱신하지는 않는다. 참고: [SQLCipher 키 API](https://www.zetetic.net/sqlcipher/sqlcipher-api/), [SQLCipher 설계](https://www.zetetic.net/sqlcipher/design/).