본문으로 건너뛰기

Memory — 메모리 확인 (선택) ​

R3-PROC에서 인젝션 분기 기준을 충족했을 때만 진입한다. 메모리 덤프로 리플렉티브 인젝션·할로잉·파일리스 페이로드의 흔적을 확인한다. 메모리만으로는 Confirmed를 내리지 않으며, 디스크 축과의 교차가 필수다.

왜 중요한가 ​

일부 치트는 디스크에 파일을 남기지 않는다. 리플렉티브 DLL 로딩(T1620)이나 프로세스 할로잉(T1055.012)은 메모리에만 존재할 수 있고, 이런 경우 PF·USN·BAM에 본체 흔적이 없거나 약하다. 디스크 축이 "깨끗"한데 기능이 동작 중이라면, 남은 관찰 지점은 메모리뿐이다.

반대로 이 축은 Ring3 카드 중 오탐률이 가장 높다. 게임과 안티치트가 RWX 메모리 영역, JIT 코드, 자체 보호 훅을 대량으로 만든다. malfind 출력을 곧이곧대로 읽으면 거의 모든 게임이 감염처럼 보인다. 그래서 진입 자체가 조건부이고, 결과 해석은 항상 "정상 설명이 성립하는가"에서 시작한다.

무엇인가 ​

항목설명
대상풀 RAM 덤프 또는 개별 프로세스 덤프
수집DumpIt, winpmem, 작업 관리자 "메모리 덤프 파일 만들기" (동의·정책 허용 시에만)
분석Volatility 3
정책 제약동의·정책에 따라 덤프 자체가 불가할 수 있다. 불가 시 이유를 기록하고 건너뛴다
MITRE 참조T1055 계열, T1620

풀 RAM 덤프는 수집에 몇 분이 걸리고 수 GB가 나온다. 단일 프로세스만 보면 되는 상황이면 작업 관리자 또는 덤프 도구의 프로세스 대상 수집이 빠르다. 어떤 쪽이든 수집 직후 도구·버전·파일 해시를 기록한다. 해시가 없는 덤프는 재검증이 불가능해 증거 가치가 떨어진다.

플러그인 세트 ​

Volatility 3 기준 최소 세트와, 의심이 잡힐 때 추가하는 플러그인이다. 플러그인 이름은 vol.py -f 덤프 파일명 뒤에 붙는 형태다.

플러그인하는 일
windows.info덤프의 OS·빌드·심볼 확인. 다른 모든 해석의 전제다
windows.pslist연결 리스트를 따라가는 프로세스 목록
windows.psscan풀 스캔으로 종료됐거나 리스트에서 끊긴 프로세스까지 찾는다
windows.pstree부모-자식 관계 트리. 할로잉은 비정상 부모를 동반하는 경우가 많다
windows.psxview여러 열거 방식을 교차해 한 방식에만 숨은 프로세스를 찾는다
windows.cmdline프로세스 명령행. 인젝터·로더의 인자가 남아 있을 수 있다
windows.ldrmodulesPEB의 세 모듈 목록(InLoadOrder·InMemoryOrder·InInitOrder)과 VAD를 교차한다. 수동 매핑·언링크된 DLL을 잡는다
windows.malfind실행 가능한 Private 영역 중 MZ·PE 구조나 쉘코드 형태를 보고한다
windows.malware.hollowprocesses이미지 교체(할로잉) 지표를 보고한다
windows.vadinfoVAD 단위의 보호 속성·매핑 유형 상세. malfind 히트의 정확한 속성 확인용
windows.memmap특정 영역을 파일로 덤프해 헤더·문자열을 직접 확인한다 (--dump)
windows.threads스레드 목록과 시작 주소. 모듈 밖 시작 주소 탐지용
windows.handles열린 핸들. 다른 프로세스·파일과의 관계 확인용
windows.yarascan시그니처로 메모리 전체를 스캔한다. 알려진 치트 문자열·패턴이 있을 때

이름 주의 ​

hollowprocesses의 현재 이름은 windows.malware.hollowprocesses다. 이전 이름 windows.hollowprocesses는 deprecated이고, Volatility 2의 hollowfind는 다른 플러그인이다. Vol2 시절 출력 예시나 튜토리얼 명령을 Vol3에 그대로 가져오면 안 된다. 플러그인 목록은 vol.py -h로 확인한다.

라이브 문자열 검사와의 관계 ​

덤프 없이 서비스·셸 프로세스의 메모리 문자열을 System Informer로 읽는 검사는 Process / Module 카드에 있다. 두 검사는 같은 메모리를 다른 방식으로 읽는다. 라이브 검사는 실행 중인 프로세스를 하나씩 골라 문자열을 바로 보고 필터로 좁히며, 남는 것은 그 순간의 화면과 저장한 텍스트뿐이다. windows.yarascan은 수집해 둔 덤프를 규칙으로 훑으므로 같은 덤프에 나중에 다시 돌려 재현할 수 있다. 라이브 검사에서 이름이나 경로가 잡히면 그 문자열을 yarascan 규칙으로 옮겨 덤프 안 어느 프로세스에 있는지 확인한다. 덤프를 뜨지 않는 세션에서는 라이브 검사가 유일한 메모리 문자열 관찰이다. 문자열을 지우는 로더 앞에서는 둘 다 같은 한계를 가지므로, 어느 쪽에서든 문자열 부재를 부정 증거로 쓰지 않는다(아래 "문자열 제거 로딩").

SS에서 어떻게 쓰나 ​

진입 기준은 표준 절차의 T+30 단계와 같다. 다음 중 하나 이상 + 디스크 교차 계획이다.

  • 경로 불일치·할로잉 의심 프로세스
  • 게임 프로세스 내 사용자 경로 미서명 모듈 + 실행 아티팩트
  • 조직 정책상 강제 덤프

기준을 충족하면:

  1. T+30에 덤프 수집 동의를 확인하고 도구·버전을 고정한다.
  2. 덤프를 뜨고 즉시 해시를 기록한다.
  3. windows.info → pslist/psscan/pstree/psxview로 프로세스 상을 파악한다.
  4. ldrmodules로 목록 불일치, malfind로 unbacked(파일에 매핑되지 않은, 용어집) 실행 영역을 훑는다. 할로잉 의심이 있으면 hollowprocesses를 추가한다.
  5. 히트가 나오면 vadinfo로 보호 속성을 확인하고 memmap --dump로 해당 영역을 뽑아 MZ 헤더·문자열을 본다.
  6. 모든 메모리 소견을 디스크 타임라인(PF·USN·BAM)과 교차한다.

진입 기준을 충족하지 않으면 이 카드를 건너뛰고, 건너뛴 이유를 기록한다. T+30은 선택 슬롯이다.

탐지 지표와 남는 흔적 ​

지표보는 법해석
RWX + Private 영역vadinfo/malfind에서 EXECUTE_READWRITE + Private 커밋JIT·게임 스크립트 엔진이 만드는 정상 패턴이기도 하다. 단독 의미 약함. MZ 헤더나 실행 증거가 있어야 가중치가 붙는다
Unbacked 실행 PEPrivate 실행 영역 안에 MZ 시그니처 + PE 헤더 구조파일이 아닌 메모리에서 올라온 코드. 수동 매핑·리플렉티브 로딩의 전형. 디스크 축에서 대응하는 DLL이 없는지 확인한다
ldrmodules 불일치세 목록 중 일부에만 있거나, VAD에는 있는데 목록에는 없는 모듈목록에서 끊긴(unlinked) DLL 또는 목록을 거치지 않은 매핑. 세 목록 중 어디가 False인지의 조합이 기법을 가린다
할로잉 지표hollowprocesses 보고: PEB 이미지 경로와 VAD의 실제 코드 불일치정상 exe로 위장한 대체 페이로드. 부모-자식·생성 시각·디스크 부재와 같이 읽는다
스레드 시작 주소 이탈threads에서 시작 주소가 로드된 모듈 범위 밖인젝션·하이재킹 리드(재검증 전 단서, 용어집). R3-PROC 라이브 소견과 맞춘다
파일리스 어셈블리스크립트 호스트(powershell·wscript)나 정상 프로세스 안의 .NET 어셈블리·CLR 구조. yarascan·memmap --dump로 확인디스크에 페이로드가 없어도 메모리에는 있다. Assembly.Load 계열의 리플렉션 실행이 올린 어셈블리와 문자열이 호스트 프로세스 안에 남는다. 호스트 자체는 powershell.exe의 PF·BAM·ScriptBlock 로그로 교차한다
문자열 제거 로딩yarascan의 알려진 치트 문자열 미검출과 malfind·ldrmodules의 구조 지표를 함께 본다일부 로더는 리플렉티브 로드 뒤 덤프에 잡히는 문자열을 지운다. "문자열이 없다"는 부정 증거가 아니다. 지워지는 것은 문자열이고, unbacked 실행 영역·인젝션 아티팩트·모듈 목록 불일치는 문자열과 무관하게 남는다
복제 프로세스 실행pstree에서 대상과 같은 이미지 이름의 자식 프로세스, 그 프로세스의 malfind·vadinfo대상을 복제(fork)해 복제본에서 코드를 실행하는 주입(Dirty Vanity)은 대상의 주소 공간을 복사한 자식 프로세스를 만든다. 페이로드가 복제본에서 실행되므로 대상 프로세스만 보면 실행 위치를 놓친다
이미지 교체 변종hollowprocesses·malfind의 이미지 불일치·unbacked PEhasherezade PoC 계열(process ghosting·transacted hollowing·process overwriting·process doppelganging·module overloading)은 프로세스 이름은 정상으로 두고 실제 이미지를 바꾼다. 일부 변종이 남기는 잔여 임시 파일은 R3-USN과 교차된다
파일 은닉과의 비대칭ADS·이어붙인 파일 등 디스크 목록에서 안 보이는 실행체디스크에서 안 보여도 실행 중 메모리에는 올라가 있다. 파일 축이 깨끗할 때 메모리가 남는 관찰 지점이다

이 지표들의 공통점: 전부 "형태"를 보는 것이지 "치트"를 보는 게 아니다. 같은 형태를 만드는 정상 소프트웨어가 존재한다. 디스크 타임라인에서 이 형태를 만든 실행(로더·인젝터·설치)이 보여야 소견이 증거로 승격된다.

정상 vs 이상 ​

구분정상이상
RWX 영역JIT, 오버레이, AV 훅, 게임 엔진unbacked 영역 + PE 구조 + 대응하는 실행 증거
프로세스표준 PEB, 알려진 부모할로잉 지표 + 디스크 부재 + 비정상 부모
모듈벤더 서명, PEB 목록과 VAD 일치unbacked + 무서명 + ldrmodules 불일치 + 디스크 타임라인 일치
프로세스 목록pslist = psscan = pstree한 방식에서만 사라진 프로세스

오탐 ​

  • JIT·게임 엔진: .NET·Lua·JS 같은 JIT 구성 요소는 실행 가능한 Private 영역을 만든다. 대부분의 현대 게임이 해당한다.
  • 오버레이·안티치트 자체 보호: malfind가 잡는 상당수가 이들이다.
  • 정상 RWX 관행: 일부 정상 소프트웨어가 RWX를 쓴다. 보호 속성만으로 판단하지 않는다.
  • 단일 malfind 히트: 디스크 교차가 없으면 Suspicious 또는 Insufficient가 상한이다.

교차 검증 ​

교차 카드확인 내용
R3-PF/USN/BAM이 메모리 소견을 만든 실행의 디스크 타임라인. 교차 없는 메모리 소견은 승격되지 않는다
R3-PROC덤프 진입의 원래 분기 기준이 라이브에서도 확인됐는지
R3-SIG메모리에서 찾은 경로의 서명 상태
R3-AF디스크 축 공백이 "없음"인지 "지워짐"인지. 파일리스 가설과 와이프 가설을 구분한다

기본 정책은 라이브 SS에서 메모리 소견만으로 Confirmed를 내리지 않는 것이다. 조직 정책이 달리 명시하는 경우에만 예외를 둔다. 메모리는 "지금"의 스냅샷이고, 덤프 자체가 어떻게 수집됐는지(도구·권한·시점)가 해석의 일부다.

증거 캡처 ​

12-memory/ 폴더에 둔다.

  1. 덤프 파일 해시 + 도구·버전 + 수집 시각
  2. 실행한 플러그인 목록과 출력 원문(txt)
  3. memmap --dump로 뽑은 의심 영역 + 그 안의 MZ·문자열 소견
  4. 메모리 소견과 디스크 경로·시각의 매핑 메모(어느 PF·USN 레코드와 맞물리는지)

흔한 실수 ​

  • 메모리 히트 하나로 Confirmed를 내린다.
  • R3-PROC 분기 기준 없이 메모리 카드에 진입한다.
  • 동의·정책 확인 없이 덤프를 수집한다.
  • Volatility 2 튜토리얼의 hollowfind 출력 예시를 Vol3 hollowprocesses와 같은 것으로 취급한다.
  • malfind의 RWX 보고를 곧장 "주입됨"으로 읽는다. 게임이 만드는 정상 RWX와 구분이 안 된다.

Community 커뮤니티에서 "디스크를 안 건드리는 로더"로 소문난 제품도 결국 로더 exe의 실행 기록(PF·BAM)은 남기는 경우가 반복 보고된다. 메모리 소견의 가치는 디스크에 없는 본체를 보여 주는 것이고, 그것을 띄운 실행은 대부분 디스크에 있다.

"RAM 덤프를 우회한다"는 주장도 반복 등장한다. 실제로 우회되는 것은 문자열 스캔뿐이다. 메모리 영역 구조(unbacked 실행 영역·이미지 불일치)와 인젝션 아티팩트는 문자열과 무관하게 남으므로, "메모리에 안 남는다"가 아니라 "문자열 검색에 안 걸린다"로 읽는 것이 정확하다.

Sources ​

Next ​