$MFT, $UsnJrnl, $LogFile¶
한 줄 요약
마스터 파일 테이블(MFT)은 볼륨의 모든 파일 목록입니다(타임스톰핑을 잡아낼 수 있는 두 세트의 타임스탬프 포함). USN 변경 저널은 최근 며칠~몇 주 동안의 모든 파일 작업 기록(생성, 이름 변경, 삭제, 수정)이고, $LogFile은 짧지만 아주 자세한 트랜잭션 로그입니다. 셋을 합치면 오래전에 삭제된 파일까지 포함해 파일에 무슨 일이 있었는지 재구성할 수 있습니다.
알려 주는 것¶
| 아티팩트 | 답하는 질문 | 보존 기간 |
|---|---|---|
$MFT |
어떤 파일이 존재(했)는지, 위치, 크기, 8개 타임스탬프 전부, 작은 파일의 상주 데이터, ADS (Zone.Identifier!), 상위 폴더, 아직 재사용되지 않은 삭제 항목 | 항목이 재사용될 때까지 |
$UsnJrnl:$J |
파일이 언제 생성 / 이름 변경 / 삭제 / 쓰기 / 속성 변경됐는지, 파일 이름과 상위 MFT 참조와 함께 순서대로 | 바쁜 워크스테이션에서 보통 1–4주 (기본 최대 32 MB, 커질 수 있음) |
$LogFile |
저수준 NTFS 트랜잭션 (MFT 레코드 갱신, 인덱스 변경) — 이전 MFT 레코드 전체 내용을 복구할 수 있음 | 몇 시간 ~ 이틀 정도 (기본 64 MB, 순환) |
$I30 인덱스 속성 (폴더) |
삭제된 파일의 이름과 타임스탬프가 남은 슬랙 항목 | 슬랙이 덮어써질 때까지 |
위치¶
모두 각 볼륨 루트에 있는 NTFS 메타파일이며 일반 목록에는 보이지 않습니다:
| 파일 | MFT 레코드 번호 | 메모 |
|---|---|---|
C:\$MFT |
0 | $MFTMirr (레코드 1)도 있음 – 처음 4개 레코드 |
C:\$LogFile |
2 | |
C:\$Extend\$UsnJrnl |
$Extend (11) 안 |
스트림 두 개: $Max (설정)와 $J (실제 저널, sparse — 끝부분에만 데이터가 있음) |
C:\$Extend\$RmMetadata\$TxfLog\... |
트랜잭션 NTFS — 거의 필요 없음 |
원시 읽기 도구(KAPE, FTK Imager, RawCopy, Sleuth Kit의 icat, Velociraptor)가 필요합니다 — 일반 API로는 열 수 없습니다.
$MFT 레코드 핵심¶
모든 레코드는 1024바이트입니다(시그니처 FILE). 중요한 속성:
| 속성 | 타입 | 내용 |
|---|---|---|
$STANDARD_INFORMATION ($SI) |
0x10 | 생성, 수정, MFT 변경, 접근 (MACE), 플래그 (숨김, 시스템, …), 소유자/보안 ID, USN. 탐색기 / dir이 보여 주는 값 — 타임스톰핑 도구가 바꾸는 값 |
$FILE_NAME ($FN) |
0x30 | 이름 (긴 이름 + 8.3 이름이 별도 속성), 상위 폴더 참조, 자체 MACE 세트, 크기. 생성/이름 변경/이동 시 커널만 갱신 — 사용자 모드 도구는 직접 설정할 수 없음 |
$DATA |
0x80 | 파일 내용: 상주 (≤ ~700바이트, 레코드 안) 또는 비상주 (데이터 런). 이름 있는 $DATA 스트림 = 대체 데이터 스트림 (file.exe:Zone.Identifier) |
$ATTRIBUTE_LIST |
0x20 | 속성이 확장 레코드로 넘칠 때 존재 |
$INDEX_ROOT / $INDEX_ALLOCATION |
0x90 / 0xA0 | 폴더 내용 ($I30) |
$OBJECT_ID |
0x40 | 링크 추적용 GUID (LNK ObjectID와 일치) |
| 헤더 필드 | 시퀀스 번호 (재사용 시 증가), 하드 링크 수, 사용 중 / 폴더 플래그, 기본 레코드 참조, $LogFile 시퀀스 번호 (LSN) |
MFT 참조 = 48비트 엔트리 번호 + 16비트 시퀀스 번호. 삭제된 항목은 재사용될 때까지 내용을 유지합니다(플래그 = 사용 안 함). 시퀀스가 올라갔다면 LNK나 Jump List의 참조가 이전 파일을 가리킨다는 뜻입니다.
타임스탬프 규칙 (타임스톰핑을 잡는 것들)¶
| 관찰 | 의미 |
|---|---|
$SI 생성 시각이 $FN 생성 시각보다 이른 |
거의 항상 타임스톰핑 (파일이 자기 디렉터리 항목보다 먼저 존재할 수는 없음). 예외: 일부 설치 프로그램 / 원래 시각을 보존하는 robocopy /COPY:DAT |
$SI 타임스탬프의 나노초가 0 (.0000000) |
초 단위를 받는 API로 설정됨 (많은 스톰핑 도구, touch 류. 단 PowerShell [IO.File]::SetCreationTime은 전체 정밀도로 설정) |
$SI 수정 시각이 $SI MFT 변경 시각보다 한참 오래됐고, $FN이 MFT 변경 시각과 일치 |
파일이 스톰핑됨; MFT 변경 시각이 스톰핑이 일어난 시점 |
$FN 시각이 $SI보다 최신 |
스톰핑 후 이동/이름 변경됐거나 복사됨 (복사 → 새 $FN 생성) |
| 막 떨어진 실행 파일의 생성 ≠ 수정 | 다른 곳에서 복사됨 (수정 시각은 파일과 함께 이동하고, 생성 시각은 이 볼륨에 쓸 때 설정됨) |
$FN도 정상적으로 갱신될 수 있습니다
같은 볼륨 안에서 이름을 바꾸거나 이동하면 Windows는 현재 $SI 값을 새 $FN에 복사합니다 — 그래서 스톰핑된 파일의 이름을 바꾸면 $FN 시각도 스톰핑된 것처럼 보입니다. 진실은 USN 저널과 비교해서 확인하세요.
Zone.Identifier — 어디서 왔나?¶
다운로드한 파일의 Zone.Identifier ADS에는 ZoneId=3(인터넷)과, 최신 Windows에서는 ReferrerUrl과 HostUrl — 실제 다운로드 URL — 이 들어 있습니다. 라이브에서는 Get-Content file.exe -Stream Zone.Identifier로, 오프라인에서는 MFTECmd의 ZoneIdContents 열로 확인하세요. zip에서 풀린 파일은 이를 물려받고, copy/xcopy로 복사한 파일은 유지하며, 공격자의 Unblock-File이나 MOTW(Mark-of-the-Web) 제거는 이를 지웁니다.
USN 저널($J) 핵심¶
각 레코드: USN (오프셋), 타임스탬프, 파일 참조 (MFT 번호 + 시퀀스), 상위 참조, 이유 플래그, 파일 이름. 이유는 USN_REASON_CLOSE까지 하나의 "세션" 동안 누적됩니다:
| 이유 플래그 | 의미 |
|---|---|
FILE_CREATE |
새 파일/폴더 |
FILE_DELETE |
삭제됨 |
RENAME_OLD_NAME / RENAME_NEW_NAME |
이름 변경 또는 이동 (레코드 두 개; 새 레코드에 목적지 상위 폴더가 보임) |
DATA_EXTEND / DATA_OVERWRITE / DATA_TRUNCATION |
내용이 써짐 / 교체됨 / 줄어듦 |
BASIC_INFO_CHANGE |
타임스탬프나 속성 변경 — 타임스톰핑이 이것을 남김 |
SECURITY_CHANGE |
ACL 변경 |
NAMED_DATA_* |
대체 데이터 스트림 쓰기 (Zone.Identifier 추가, 또는 STREAM_CHANGE로 제거) |
HARD_LINK_CHANGE, REPARSE_POINT_CHANGE, OBJECT_ID_CHANGE, INDEXABLE_CHANGE, CLOSE |
이름 그대로 |
저널에는 전체 경로가 없습니다 — 상위 MFT 참조만 있습니다. 파서는 $MFT와 결합해서 경로를 다시 만드는데, 상위 폴더 자체가 삭제되고 재사용됐다면 경로가 일부만 나올 수 있습니다 — 그래서 MFTECmd는 두 파일을 같이 원합니다.
수집 방법¶
Windows.NTFS.MFT (매우 큼), Windows.Forensics.Usn, Windows.NTFS.Recover (MFT id로 삭제된 파일 데이터 복구).
파싱 방법¶
# $MFT → CSV (one row per file, both $SI and $FN timestamps side by side)
MFTECmd.exe -f C:\Case\$MFT --csv C:\Case\out --csvf mft.csv
# $MFT → bodyfile for a super-timeline (mactime / Timeline Explorer)
MFTECmd.exe -f C:\Case\$MFT --body C:\Case\out --bodyf mft.body --bdl C
# $J with $MFT for full paths
MFTECmd.exe -f C:\Case\$J -m C:\Case\$MFT --csv C:\Case\out --csvf usn.csv
# Dump one record (by entry number or path) in full detail
MFTECmd.exe -f C:\Case\$MFT --de 0x2A3F
MFTECmd.exe -f C:\Case\$MFT --dd C:\Case\resident --do 0x2A3F # carve resident data
# $LogFile (limited support) / $Boot / $I30
MFTECmd.exe -f C:\Case\$Boot --csv C:\Case\out
MFTECmd.exe -f C:\Case\$I30 --csv C:\Case\out
$MFT CSV에서 볼 열: InUse, ParentPath, FileName, Extension, FileSize, Created0x10 vs Created0x30, LastModified0x10 vs 0x30, SI<FN (true = 수상함), uSecZeros, Copied, ZoneIdContents, HasAds, IsAds, Timestomped.
분석 팁¶
30초 워크플로
MFTECmd $J→ 사고 시간대에서UpdateReasons에FileCreate가 있고Extension이.exe .dll .ps1 .bat .vbs .zip .7z .rar인 것을 필터링. 이것이 떨어뜨린 도구 목록입니다.- 각 결과마다
$MFT행을 열어SI<FN,ZoneIdContents(다운로드 URL!),ParentPath확인. - 같은 이름으로
$J에서FileDelete필터 → 공격자가 정리한 시점.RenameNewName필터 → 도구 이름을 무엇으로 바꿨는지. - 도구에 대한
$JBasicInfoChange→ 타임스톰핑 순간.
- 삭제 ≠ 사라짐:
InUse = False인$MFT레코드도 이름, 타임스탬프, 크기, 그리고 (상주라면) 작은 파일의 내용 전체를 갖고 있습니다 — 배치 스크립트, 설정,.lnk, 작은 텍스트 전리품 목록. - 대량 활동 = 랜섬웨어 / 와이퍼 / 유출 준비: 몇 초 안에 새 확장자로
RenameNewName수천 건, 또는DataOverwrite수천 건 —$J는 정확한 시작/종료 시각과 공격받은 폴더 순서를 알려 주어 암호화 도구의 순회 경로와 첫 감염 경로를 보여 줍니다. - 유출용 zip 준비:
Users\Public,ProgramData,Temp의.zip/.7z/.rar에FileCreate+ 빠른DataExtend, 그리고 곧이어FileDelete= 전형적인 수집 후 유출 패턴; (레코드가 살아 있다면)$MFT의 크기로 얼마나 나갔는지 알 수 있습니다. - 볼륨 섀도 복사본에는 더 오래된
$MFT와$J가 있습니다 — 각 VSC에 같은 파싱을 돌려 저널 범위를 몇 주 더 과거로 늘리세요 (vssadmin list shadows, KAPE--vss). - 시퀀스 번호로 LNK/Jump List/Prefetch가 가리키는 항목이 같은 파일인지, 나중에 그 자리를 재사용한 파일인지 알 수 있습니다.
- 최근 몇 시간은
$LogFile: MFT 레코드의 변경 전과 후 이미지를 저장합니다 — 스톰핑 전 타임스탬프, 이름 변경 전 이름. 범위는 짧지만 걸리면 금맥입니다. - 안티포렌식:
fsutil usn deletejournal /D C:(아주 뚜렷한 공백 +$Max초기화와 이벤트를 남김), SDelete (AAAAAAAA.AAA… 로 이름 변경을 잔뜩 만듦), 타임스톰핑 도구 (SI<FN, 나노초 0),cipher /w.
타임라인 / 상관분석¶
| 질문 | 교차 확인 |
|---|---|
| 떨어뜨린 파일이 실행됐나? | Prefetch, Amcache, Shimcache, 4688, Sysmon 1 |
| 어떤 사용자 / 프로세스가 썼나? | Sysmon 11 (프로세스가 포함된 FileCreate), 4663 객체 접근 (SACL이 있다면), $SI 소유자 SID (→ SAM/ProfileList) |
| 어디서 왔나? | Zone.Identifier HostUrl, 브라우저 기록, 4624 type 3 + 5145 (SMB로), LNK의 USB 볼륨 시리얼 |
| 공격자가 열었나? | LNK / Jump Lists, ShellBags, RecentDocs |
| 로그 공백? | $J 타임라인 vs. Security 로그 — $J는 바쁜데 Security 이벤트가 0개인 구간 = 로그 삭제 (1102 확인) |