Document verified Windows MCP RAM recovery and per-run limits

This commit is contained in:
kwonta3wook
2026-10-27 15:14:49 +09:00
parent 14a8947c38
commit 6ccc18a5ff
6 changed files with 149 additions and 12 deletions
@@ -2,11 +2,6 @@ name: Windows positive memory validation
on:
workflow_dispatch:
push:
branches: ['test/windows-mcp-positive']
paths:
- 'validation/windows_positive/**'
- '.github/workflows/windows-positive-memory.yml'
permissions:
contents: read
+7 -3
View File
@@ -6,13 +6,17 @@ Windows·Linux 프로세스 메모리에서 MCP/JSON-RPC 메시지 후보를 추
**상태: 초기 구현.** 프레임워크 패키지 버전은 `volatility3==2.28.2`로 고정했습니다.
분석 대상은 Windows x64와 Linux x86-64입니다. 합성 테스트와 함께 공개 Windows 11 x64
빌드 22000 이미지 1개와 Linux 이미지 2개를 시험했습니다.
Windows에서는 선택한 프로세스 4개의 VAD 1,561개를 검사했고 MCP 후보는 0개였습니다.
해당 Windows 11 샘플에서는 선택한 프로세스 4개의 VAD 1,561개를 검사했고 MCP 후보는 0개였습니다.
[Windows 실제 RAM 검증](docs/windows-memory-validation.md)에는 실행 범위와 대형 빈 주소 영역
읽기 개선을 기록했습니다. Linux MCP 활동 샘플의 Python 프로세스
2개에서 후보 41개를 추출하고 원문·해시·VMA 범위를 다시 대조했습니다. 이 샘플은 VMware
메타데이터가 없어 물리 메모리 배치를 추정해 변환한 조건부 결과입니다.
[실제 RAM 검증 기록과 재현 절차](docs/real-memory-validation.md)를 참고하세요.
전체 메시지 복원율·정밀도, Windows의 실제 MCP 메시지 추출, 다른 OS 빌드의 호환성은 아직 검증하지 않았습니다.
추가로 [Windows Server 2022의 실제 MCP 통신·RAM 양성 검증](docs/windows-positive-memory-validation.md)을
수행했습니다. 마지막 실행에서 원문을 별도 보관하지 않은 조건은 논리 메시지 16/21개와 도구 호출
5/8쌍, 원문 보관 대조군은 20/21개와 7/8쌍을 복원했습니다. 내보낸 레코드 120개의 원문·주소·해시도
대조했습니다. 정답 로깅이 있는 작은 stdio 통제 실험이며, 일반적인 복원율·정밀도나 다른
클라이언트·Windows 빌드의 호환성을 보장하지 않습니다.
| 분석할 이미지 | 명령 | 프로세스 메모리 영역 |
| --- | --- | --- |
@@ -236,7 +240,7 @@ Linux의 마운트 네임스페이스·chroot·심볼릭 링크도 해석하지
- `pslist`에서 보이지 않는 프로세스, 해제되어 VAD/VMA 밖에 남은 흔적, 현재 레이어가 읽지 못하는 페이지는 범위 밖입니다.
- `bytes_read`는 읽기에 성공한 바이트 수입니다. 후보 제한으로 중단하면 읽은 버퍼 전체가 처리됐다는 뜻은 아닙니다.
후보 제한은 일반 JSON-RPC에도 적용되므로 잡음이 많으면 관련 메시지에 도달하기 전에 중단할 수 있습니다.
- 검색 결과 없음은 흔적 부재의 증명이 아닙니다. 모든 프로세스에 요약 행을 남기며 탐지율·복원율 수치를 주장하지 않습니다.
- 검색 결과 없음은 흔적 부재의 증명이 아닙니다. 모든 프로세스에 요약 행을 남기며 일반적인 탐지율·복원율 수치를 주장하지 않습니다.
테스트 실행:
+4 -1
View File
@@ -4,7 +4,9 @@
공개 Linux 이미지 2개에 대한 실행 결과는 [실제 RAM 검증 기록](real-memory-validation.md)에
별도로 기록했습니다. MCP 활동 샘플은 누락된 VMware 메타데이터를 대신해 추정한 물리 메모리
배치를 적용했습니다. [Windows 11 실제 이미지 검증](windows-memory-validation.md)도 수행했으나,
그 이미지에서는 MCP 후보가 나오지 않았습니다. 전체 메시지 기준 성능 평가는 아직 수행하지 않았습니다.
그 이미지에서는 MCP 후보가 나오지 않았습니다. 이후
[Windows Server 2022의 실제 MCP 통신·RAM 양성 검증](windows-positive-memory-validation.md)에서
정답이 있는 메시지 복원을 확인했습니다. 일반적인 복원 성능 평가는 아직 수행하지 않았습니다.
## 자동 검증
@@ -25,6 +27,7 @@ CI는 Ubuntu/Windows 분석 호스트와 Python 3.10/3.12 조합을 구성합니
| 어댑터 | 실제 TreeGrid, 프로세스별 제한·요약, 뒤쪽 VAD/VMA 읽기 오류 이후 기존 증거 보존 |
| Linux 태스크 | 실제 PID 필터, 프로세스 간 ID 비연결, 사용자 주소 공간 없음, 레이어 생성 실패, active_mm 대체 사용 금지 |
| 출력 | 실제 Volatility CLI 파일 핸들러, JSONL 원문 왕복·해시, 기존 파일 비덮어쓰기 |
| 검증 하네스 | 논리 메시지/복사본/비전송 대조군 분리, PID/typed ID별 후보 연결 대조, Windows 파일 핸들 정리 |
| 로딩 | 새 CLI 프로세스에서 -p 경로로 Windows/Linux 플러그인 검색 및 도움말 생성 |
`tests/test_plugin.py`의 EPROCESS/VAD, `tests/test_linux_plugin.py`의 task_struct/mm/VMA 열거 객체와
+3 -1
View File
@@ -112,6 +112,8 @@ vol -q --offline --cache-path cache -s symbols -f evidence/Win11Dump.mem -r json
vol -q --offline --cache-path cache -s symbols -p plugins -f evidence/Win11Dump.mem -o output/win11 -r json windows.mcptrace.MCPTrace --pid 3244 6524 6248 2180 --dump > output/win11/findings.json 2> output/win11/stderr.txt
```
후속 검증에는 실제 MCP 호출과 정답 메시지를 기록한 Windows 덤프가 필요합니다.
후속으로 실제 MCP 호출과 정답 메시지를 기록한
[Windows Server 2022 RAM 양성 검증](windows-positive-memory-validation.md)을 수행했습니다.
이는 다른 OS 빌드에서의 별도 실험입니다.
이번 결과만으로 Windows의 MCP 복원 성능, 다른 Windows 빌드 호환성, 정밀도·재현율을
주장하지 않습니다. 원본 덤프·심볼·메모리 내용은 저장소에 커밋하지 않습니다.
+132
View File
@@ -0,0 +1,132 @@
# Windows 실제 MCP 통신의 RAM 복원 검증
검증일: 2026-10-27. GitHub Actions의 Windows Server 2022 x64 빌드 20348 VM에서
공식 Python MCP SDK로 실제 stdio 요청·응답을 실행하고 WinPmem으로 RAM을 수집했습니다.
`windows.mcptrace.MCPTrace`를 실행한 뒤 정답 로그와 비교하고, 모든 추출 원문을 native
Windows 프로세스 레이어에서 다시 읽어 주소·길이·SHA-256·VAD 범위를 대조했습니다.
덤프에 테스트 JSON을 주입하거나 합성 페이지 테이블을 사용하지 않았습니다.
## 실행과 결과
[최종 실행 40459138175](https://github.com/Kowntaewook/MCPTrace/actions/runs/40459138175)은
수집·분석·대조·원본 임시 덤프 삭제를 모두 마치고 성공했습니다.
[첫 실행 40457925570](https://github.com/Kowntaewook/MCPTrace/actions/runs/40457925570)의
분석 관측값도 함께 기록해 실행 사이의 차이를 숨기지 않습니다.
| 실행 | 조건 | 복원 논리 메시지 | 완전한 도구 요청·응답 쌍 | 추출 레코드 / 통신 정답과 일치 | 비전송 대조군 |
| --- | --- | ---: | ---: | ---: | ---: |
| 첫 실행, 정리 단계 실패 | natural | 17/21 (81.0%) | 6/8 | 92 / 92 | 0 |
| 첫 실행, 정리 단계 실패 | retained | 21/21 (100%) | 8/8 | 106 / 105 | 1 |
| 수정 후 전체 성공 | natural | 16/21 (76.2%) | 5/8 | 55 / 55 | 0 |
| 수정 후 전체 성공 | retained | 20/21 (95.2%) | 7/8 | 65 / 64 | 1 |
최종 실행에서 내보낸 **120개 레코드, 33,318 bytes 전부**의 원문·해시·가상 주소·VAD 범위가
재읽기와 일치했습니다. 정답과 대조 가능한 방향성 후보 링크 316개에서 잘못된 연결 0개,
대조 불가능한 링크 0개를 관측했습니다. 이 수에는 복사본 간 연결이 포함되며 316개의 고유
요청·응답 쌍을 의미하지 않습니다. 첫 실행은 198개 레코드·80,401 bytes와 링크 550개를
대조했습니다. 두 실행 모두 각 조건에서 동일 PID 내 완전한 도구 요청·응답 쌍이 존재했습니다.
최종 실행의 동일 PID 내 메시지/쌍은 natural 클라이언트 14개/5쌍, 서버 7개/1쌍,
retained 클라이언트 18개/6쌍, 서버 9개/2쌍입니다. retained의 합집합 7쌍을 한 프로세스에서
7쌍이 모두 복원됐다는 뜻으로 읽으면 안 됩니다.
두 실행의 차이는 관측 결과이며 원인을 분리하는 실험은 수행하지 않았습니다. 특히 프레임을
보관한 조건도 두 번째 실행에서는 1개 메시지를 찾지 못했습니다. 이 결과만으로 누락 원인을
메모리 해제·paging·수집 누락·스캐너 중 하나로 확정하지 않습니다. 전체 실행 성공 조건은
100% 복원이 아니라 원문 검증과 동일 PID의 실제 요청·응답 복원입니다.
최종 코드의 테스트 126개와 Ruff 검사·포맷 검사가 통과했습니다.
[Ubuntu/Windows × Python 3.10/3.12의 네 CI 조합](https://github.com/Kowntaewook/MCPTrace/actions/runs/40459143849)도 통과했습니다.
첫 실행도 메시지 복원과 원문 대조는 통과했지만, 검증기가 파일 핸들을 닫지 않아 마지막
RAM 파일 삭제가 Windows `WinError 32`로 실패했습니다. 첫 실행의 `manifest.json`에는
정리 전에 기록한 `passed`가 남아 있으므로 **첫 실행 전체를 성공으로 해석하면 안 됩니다.**
Volatility 레이어를 의존성 역순으로 닫고, 정리까지 끝난 뒤 성공을 기록하도록 수정했습니다.
검증 예외가 발생할 때도 실제 FileLayer 핸들이 닫히는 회귀 테스트를 추가했습니다.
## 실험 조건과 해석
독립된 클라이언트·서버 쌍 두 개, 총 Python 프로세스 네 개를 동시에 유지했습니다.
각 쌍은 initialize, initialized 알림, tools/list와 echo_marker 도구 호출 8회를 수행합니다.
정답은 조건별 21개 논리 메시지(요청 10개, 응답 10개, 알림 1개)입니다.
도구의 실제 응답에서 입력 문자열·실험 UUID·순번·서버 PID를 확인했습니다.
입력은 ASCII, 한글·이모지, 이스케이프·줄바꿈·중괄호, 2 KiB 문자열, 중복 텍스트 등을 포함합니다.
- `natural`: 전송/수신 경계에서 정답 로그를 기록하지만 직렬화 프레임을 별도 목록으로 보관하지 않습니다.
로깅으로 생성된 복사본이 남을 수 있으므로 계측되지 않은 일반 클라이언트와 같은 조건은 아닙니다.
- `retained`: 실제 통신 프레임 21개를 메모리에 보관하는 유리한 양성 대조군입니다.
전송하지 않은 tools/call JSON 하나도 보관합니다. 이것을 실제 통신 정답에는 포함하지 않습니다.
메시지 복원 수는 두 엔드포인트에서 찾은 결과의 **합집합에서 중복을 제거한 값**입니다.
메모리 복사본은 서로 다른 증거 레코드로 보존하며 복원 메시지 수를 늘리지 않습니다.
요청·응답 쌍도 두 엔드포인트 합집합과 동일 PID 내 발견을 따로 집계합니다.
각 조건의 클라이언트·서버 PID별 수치는 보고서의 `comparison.json`에 있습니다.
정답 대조는 JSON 키 순서와 공백을 정규화한 메시지 객체 기준입니다. 수신 정답은 SDK가 파싱한
객체를 재직렬화한 것으로, 파이프 원본 바이트 캡처가 아닙니다. 원문 바이트 검증은 별도로
덤프의 해당 가상 주소를 `pad=False`로 다시 읽어 수행했습니다. 같은 Volatility의 native
레이어를 사용한 재읽기이며, 다른 포렌식 엔진과의 교차 검증은 아닙니다.
비전송 대조군도 복원됐습니다. 따라서 **MCP 형식의 JSON이 메모리에 존재한다는 사실만으로
실제 전송·공격·도구 실행을 입증할 수 없습니다.** 통신 로그와 일치하는 레코드 비율을
일반적인 탐지 정밀도로 표현하지 않습니다. 후보 연결 오류 0도 이 단일 세션·고유 ID의 작은
통제 집합에서 대조 가능한 연결에 한정됩니다. `ambiguous-id` 표시와 복사본은 유지됩니다.
## 환경·수집·검사 범위
- Windows Server 2022 x64 `10.0.20348`, Python `3.12.10`, `volatility3==2.28.2`.
- 공식 Python SDK `mcp==1.26.0`, stdio, 실제 협상 프로토콜 `2025-11-25`.
- MCPTrace `0.2.0`; 최종 실행 커밋 `14a8947c388f10c559b406f5d3bf783265d29705`.
- [공식 WinPmem 배포 바이너리](https://github.com/Velocidex/WinPmem/releases/download/v4.0.rc1/go-winpmem_amd64_1.0-rc2_signed.exe).
SHA-256: `86691bb4af2c17dd9ec4834c04a99ad51e04f780a07d1b05bc382a5d1892e0c4`.
서명 정책·보안 설정을 변경하지 않고 드라이버 설치·수집·제거를 수행했습니다.
최종 실행의 RAM은 8,584,425,472 bytes이고, 이미지 논리 크기는
11,811,160,064 bytes입니다. 이미지 SHA-256:
`22027df47f06eec202e2d25c9fd40b996a1bc6374f158b035e9245764af3edb6`.
수집 시작/종료는 2026-10-27 06:07:11.326 / 06:08:08.407 UTC로 약 57.08초입니다.
각 조건의 마지막 정답 메시지 기록부터 수집 시작까지 약 0.089초입니다.
첫 실행은 수집 약 40.56초, 마지막 메시지부터 시작까지 약 0.085초였습니다.
| 조건·역할 | PID | VAD 수 | 읽은 bytes | 읽지 못한 bytes | 내보낸 레코드 |
| --- | ---: | ---: | ---: | ---: | ---: |
| natural client | 5752 | 141 | 25,849,856 | 4,441,501,696 | 39 |
| natural server | 3980 | 145 | 20,398,080 | 4,449,112,064 | 16 |
| retained client | 4552 | 141 | 25,763,840 | 4,441,587,712 | 46 |
| retained server | 6784 | 146 | 22,634,496 | 4,463,456,256 | 19 |
총 573개 VAD에서 94,646,272 bytes를 읽었습니다.
모든 대상에서 error/skip이 없고, 바이트·레코드·앵커·후보 제한에 도달하지 않았으며 잘못된 영역은 0입니다.
내부 candidate_records는 126개, MCP 관련성 필터 후 relevant/displayed_records는 120개입니다.
원문 검증과 정답 비교의 분모는 내보낸 120개입니다.
물리 주소 간 빈 구간을 포함한 sparse raw 이미지이므로 파일 논리 크기가 설치 RAM보다 큽니다.
물리 메모리 수집은 시간이 걸리는 live acquisition이며 단일 시점의 원자적 스냅샷이 아닙니다.
호출 직후 수집을 시작하고 수집 동안 추가 도구 호출 없이 프로세스를 유지했습니다.
지연 시간이나 메모리 부하를 달리한 실험이 아니므로 흔적의 보존 기간을 추정하지 않습니다.
`windows.info.Info`에서 심볼을 준비한 뒤 MCPTrace와 원문 재읽기는 offline으로 실행했습니다.
선택한 네 PID의 VAD를 기본 설정으로 검사했고 크기/레코드 제한을 임의로 늘리지 않았습니다.
`unreadable_bytes`에는 예약되어 사용하지 않는 주소 공간도 포함됩니다.
RAM 해시는 분석 전후 같았으며, 전체 덤프는 VM 내부에서 분석 후 삭제했습니다.
## 재현 자료와 남은 범위
[실행 하네스와 명령](../validation/windows_positive/README.md),
[수동 실행 워크플로](../.github/workflows/windows-positive-memory.yml)를 제공합니다.
저장소에는 재현 코드와 집계 결과를 기록합니다. Actions 결과 아티팩트에는 측정 JSON,
정답 메시지, 정답 또는 명시적 비전송 대조군과 일치한 추출 레코드, 수집/분석 로그가 있으며
[최종 아티팩트](https://github.com/Kowntaewook/MCPTrace/actions/runs/40459138175/artifacts/12713857072)의
보관 만료는 2026-11-03입니다. ZIP SHA-256은
`abfdbbea869bc47c8dfac01bfaa515882d8204d5914a62abf70ce68851689a5e`입니다. RAM 이미지나 미분류 후보 원문은 업로드하지 않습니다.
RAM에서 추출한 원문을 포함하는 결과 ZIP은 저장소에 추가하지 않았습니다.
덤프 원본을 보존하지 않았으므로 동일 이미지의 제3자 재분석은 불가능하며, 하네스로 새로운
캡처를 만들어 반복 검증할 수 있습니다. 각 실행의 이미지 해시는 실행 결과의 식별자입니다.
이 결과는 **Windows Server 2022의 특정 Python SDK·stdio 조건에서 실제 MCP 메시지를
추출할 수 있다는 양성 검증**입니다. Windows 11에서의 MCP 양성 검증, Claude Desktop 등
실제 클라이언트, HTTP/SSE 전송, 장시간 지연·추가 부하, 다른 SDK, 다중 세션의 ID 재사용,
부분 메시지·인자 복원율은 아직 평가하지 않았습니다. 공격 탐지율을 측정한 실험도 아닙니다.
기존 [Windows 11 공개 덤프 검사](windows-memory-validation.md)는 MCP 후보가 없었던 별도
호환성·읽기 검증입니다. 그 결과와 이번 Server 2022 양성 검증을 구분합니다.
+3 -2
View File
@@ -40,7 +40,7 @@ WinPmem은 제작자가 제공한 서명된 실행 파일을 사용하고 SHA-25
수행합니다. 실패를 성공/건너뛰기로 처리하지 않습니다.
GitHub Actions의 `Windows positive memory validation` 워크플로도 같은 하네스를 실행합니다.
초기 검증 브랜치의 push로 실행하고, 기본 브랜치에 반영한 뒤에는 workflow_dispatch로 실행할 수 있습니다.
기본 브랜치에 반영한 뒤 Actions 화면에서 workflow_dispatch로 수동 실행할 수 있습니다.
실제 덤프는 일회용 VM 안에서만 분석하고 종료 시 삭제합니다. 전체 RAM이나 미분류 후보 원문은
업로드하지 않으며 정답 메시지·대조군과 일치한 아티팩트, 측정값, 수집/분석 로그만 7일 보관합니다.
@@ -55,4 +55,5 @@ GitHub Actions의 `Windows positive memory validation` 워크플로도 같은
성공 조건은 실제 통신한 도구 요청·응답 한 쌍 이상이 동일 PID에서 복구되고, 내보낸 원문이
재읽기 대조를 통과하며, 정답과 대조할 수 있는 연결에 오류가 없는 것입니다. `retained`만 성공해도
전체 실험은 실행 가능성을 확인한 것으로 기록되므로 **반드시 natural/retained 수치를 나눠 읽어야 합니다.**
현재 문서는 실행 절차이며, 실제 실행 결과는 실행한 Actions 기록과 결과 보고서로 확인합니다.
실제로 수행한 Windows Server 2022 캡처와 조건별 수치는
[양성 검증 보고서](../../docs/windows-positive-memory-validation.md)에 기록했습니다.