Process / Module — 프로세스·모듈 확인
게임 프로세스에 로드된 모듈과 스레드·핸들·메모리 영역을 검사해 인젝션·할로잉 흔적을 찾는다. 프로세스 상태는 라이브 SS에서만 유효하며, 프로세스 종료나 재부팅으로 증발한다.
왜 중요한가
디스크 아티팩트(PF, USN, BAM)는 과거를 보여 준다. 프로세스·모듈 확인은 지금 메모리에 무엇이 올라가 있는지 보여 준다. 두 축을 맞춰야 "파일이 있었고, 실행됐고, 지금도 동작 중이다"까지 도달할 수 있다.
유저모드 치트는 어떤 형태로든 다른 프로세스의 주소 공간을 건드린다. LoadLibrary 경유의 고전 DLL 인젝션부터 수동 매핑·할로잉·리플렉티브 로딩까지, 기법이 정교해질수록 모듈 목록에 안 잡히도록 설계된다. 그래서 이 카드의 핵심 질문은 "모듈 목록에 뭐가 있나"가 아니라 "기법이 쓰였다면 잔류물이 어디에 남는가"다.
동시에 이 축은 오탐이 잦다. 게임·안티치트·오버레이·GPU 스택·백신이 정상적으로도 수십 개의 DLL과 훅을 만든다. pe-sieve 계열 히트는 단서이지 판정이 아니다.
무엇인가
| 항목 | 설명 |
|---|---|
| 대상 | 라이브 프로세스 트리 + 로드된 모듈 + 스레드 + 핸들 + 메모리 영역 |
| 도구 | System Informer(프로세스 트리·모듈·스레드·메모리 탭), Process Explorer, tasklist /m, listdlls |
| 보조 | pe-sieve 계열(단서 생성기로만), Sysmon 이벤트(배포된 경우에만) |
| 메모리 문자열 | DPS·PcaSvc·DcomLaunch를 호스팅하는 svchost, csrss.exe, explorer.exe 같은 프로세스의 메모리 문자열. 전용 파서는 DPS-Analyzer·pcasvc-executed·process-parser·JARParser. 아래 절 |
| MITRE 참조 | T1055 Process Injection 계열, T1620 Reflective Code Loading |
| 한계 | 라이브 SS 전용. 프로세스 종료 후에는 디스크 축만 남는다 |
System Informer에서 실제로 여는 뷰는 다섯 개다. 프로세스 트리는 부모-자식 관계를 보여 주고, 모듈 탭(프로세스 더블클릭 → Modules)은 그 프로세스가 로드한 DLL 전체다. 스레드 탭은 각 스레드의 시작 주소와 상태를 보여 주는데, 시작 주소가 로드된 어떤 모듈에도 속하지 않으면 인젝션 리드(판정 전 재검증이 필요한 단서, 용어집)다. 메모리 탭은 커밋된 영역의 보호 속성(EXECUTE_READWRITE 등)과 매핑 유형(Private/Mapped/Image)을 보여 준다. 핸들 탭은 무관한 프로세스가 게임 프로세스를 연 흔적을 잡는다.
tasklist /m은 "이 DLL을 로드한 프로세스 전부"를 뒤집어 보는 용도로 빠르고, listdlls는 특정 프로세스의 로드 모듈을 텍스트로 뽑을 때 쓴다. 둘 다 스크린샷보다 복붙 가능한 텍스트가 남아 증거 패키지에 넣기 좋다.
pe-sieve 계열 도구는 프로세스 메모리를 스캔해 임플란트·패치된 코드·교체된 이미지를 보고한다. 결과물은 반드시 리드 목록으로만 취급한다. 이 도구들은 "이 영역이 의심스러운 형태다"까지만 말해 주고, "치트다"라고는 말해 주지 않는다. JIT 컴파일러, AV 훅, 안티치트 자체 보호 루틴이 모두 같은 모양으로 보고된다.
Sysmon이 배포돼 있으면 이벤트 8(CreateRemoteThread)·10(ProcessAccess)·7(ImageLoaded)이 인젝션의 직접 신호다. 레지스트리 경유 설정 변경은 12–14가 받친다. 대부분의 개인 PC에는 Sysmon이 없으므로 부재를 증거로 읽지 않는다.
SS에서 어떻게 쓰나
- T+28에 System Informer 프로세스 트리를 열어 게임·안티치트·오버레이 기준선을 먼저 식별한다.
- 게임 프로세스의 모듈 목록에서 비벤더·무서명 DLL을 확인한다. 특히 Temp·AppData·Downloads 같은 사용자 쓰기 가능 경로에서 로드된 모듈에 주목한다.
- 스레드 탭에서 시작 주소가 로드된 모듈 밖에 있는 스레드를 찾는다.
- 메모리 탭에서 Private이면서 실행 가능한 영역을 본다. 파일 미매핑 + 실행 가능 조합이 수동 매핑·리플렉티브 계열의 모양이다.
- PEB·이미지 경로 불일치(경로는 정상 exe인데 내용이 다르다)가 보이면 R3-MEM 분기 기준 충족으로 기록한다.
- pe-sieve를 돌렸다면 히트 하나하나에 "정상 설명이 성립하는가"를 먼저 적용하고, 남은 것만 디스크 축과 교차한다.
- 서비스·셸 프로세스의 메모리 문자열을 읽고, 그 프로세스의 시작 시각을 부팅 시각과 비교한다. 방법은 다음 절에 있다.
서비스와 프로세스의 메모리 문자열
실행 중인 시스템 서비스와 셸 프로세스는 자기 메모리에 최근 다룬 실행 파일의 경로와 날짜 같은 문자열을 쌓아 둔다. 이 문자열을 읽어 Prefetch·BAM·USN 같은 디스크 축과 이름·경로·시각을 맞춰 보는 것이 이 검사다. 디스크의 기록을 지워도 다른 프로세스 메모리에 남은 경로는 따로 지워야 하므로, 디스크 축과 다른 관찰 지점이 된다. 대신 프로세스가 끝나면 함께 사라지는 기록이라 라이브 SS에서만 쓸 수 있다.
대상별로 남는 문자열
| 대상 | 본래 역할 | 메모리에 남는 것 | 읽는 도구 |
|---|---|---|---|
DPS (Diagnostic Policy Service, dps.dll을 싣는 svchost) | Windows 구성 요소의 문제 감지·해결을 맡는 진단 서비스 | \Device\HarddiskVolumeN\…\*.exe 형태의 장치 경로, !!파일명.exe!날짜!… 형태의 구조화된 항목 | DPS-Analyzer, System Informer |
| PcaSvc (Program Compatibility Assistant Service) | 사용자가 설치·실행한 프로그램을 지켜보며 알려진 호환성 문제를 감지한다 | 드라이브 문자로 시작하는 파일 경로 | pcasvc-executed, System Informer |
| explorer.exe | Windows 셸(바탕 화면·작업 표시줄·파일 탐색기) | TRACE,로 시작하는 PCA 클라이언트 기록 블록. 그 밖의 판독 관행은 아래 Community | System Informer, pcasvc-executed |
| DcomLaunch (DCOM Server Process Launcher) | 개체 활성화 요청에 따라 COM·DCOM 서버를 띄운다 | -jar가 들어간 명령줄 문자열 | JARParser, System Informer |
| csrss.exe | Win32 하위 시스템의 사용자 모드 부분. 콘솔 창과 스레드 생성·삭제를 맡는다 | 무엇을 찾는지, 두 인스턴스 중 어느 쪽을 여는지는 아래 Community | System Informer |
| DiagTrack (Connected User Experiences and Telemetry) | 진단·사용 데이터 수집 | \Device\HarddiskVolumeN\… 형태의 파일 경로 | process-parser |
| AppInfo (Application Information) | 추가 관리자 권한이 필요한 앱 실행을 돕는다(UAC 승격) | 드라이브 문자로 시작하는 .exe 경로 | process-parser |
| Dnscache (DNS Client) | 조회한 DNS 이름을 캐시한다 | 최근 조회한 도메인 이름 | ipconfig /displaydns |
형식마다 읽는 법이 다르다. DPS의 장치 경로는 드라이브 문자 대신 볼륨 장치 이름으로 적혀 있어, DPS-Analyzer는 이를 C:\ 같은 경로로 바꾼 뒤 서명 상태와 현재 존재 여부를 붙여 출력한다. 지금 디스크에 없는 경로는 dps-full-notfound-executables.txt로 따로 나온다. !!로 시작하는 항목은 파일명과 날짜 필드를 담고, DPS-Analyzer는 같은 파일명에 서로 다른 날짜가 붙은 항목(dps-suspicious-results.txt)과 exe가 들어가지 않은 장치 경로(dps-modified-extension.txt)를 따로 모은다. Echo 핸드북은 이 DPS 기록을 "실행된 실행 파일과 그 컴파일 시각"으로 보여 주고, explorer의 PCA 클라이언트 기록을 "explorer를 마지막으로 재시작한 뒤 실행된 파일"로 보여 준다. pcasvc-executed는 TRACE, 블록을 모든 프로세스 메모리에서 찾고, PcaSvc 호스트에서는 드라이브 경로 문자열을 뽑는다. JARParser가 DcomLaunch에서 뽑는 -jar 문자열은 java -jar 형태로 JAR를 실행한 명령줄이다.
csrss.exe는 Win32 하위 시스템이 항상 떠 있어야 하는 핵심 프로세스라 재시작으로 메모리를 비울 수 없다. DNS 캐시는 메모리 문자열을 뒤지기보다 ipconfig /displaydns로 직접 읽는다. 캐시는 최근 조회 결과를 담는 것이라 휘발성이 높고, ipconfig /flushdns로 비울 수 있다.
어느 문자열이든 그 경로가 해당 프로세스의 메모리를 거쳤다는 기록이다. 누가 언제 실행했는지는 디스크 축과 맞춰 봐야 정해진다.
읽는 법
- 대상 PID를 찾는다. 서비스는
tasklist /svc /fi "services eq DPS"처럼 서비스 이름으로 호스팅 svchost의 PID를 찾는다. PcaSvc·DcomLaunch·DiagTrack·AppInfo도 같은 방식이다. System Informer에서 svchost의 속성을 열면 Services 탭에 그 프로세스가 호스팅하는 서비스가 나온다. - System Informer를 관리자 권한으로 실행하고 대상 프로세스의 속성(Properties)을 연다. 권한 때문에 메모리가 열리지 않는 시스템 프로세스가 있다. 열리지 않으면 그 사실을 기록한다.
- Memory 탭에서 Strings를 연다. 빌드에 따라 탭의 버튼으로 있거나 Options 메뉴 안의
Strings...로 있다. 최소 길이(Minimum length), 검색할 영역(Private·Image·Mapped), 유니코드 옵션(대화 상자의 Detect Unicode·Extended Unicode, 새 창에서는 Options 메뉴의 Unicode·Extended character set)을 정한다. 최소 길이가 짧을수록 잡음이 늘고, 영역을 줄이면 놓치는 문자열이 생긴다. - Filter로 좁힌다. Contains로 제보된 이름과 확장자(
.exe·.dll·.jar)를 찾고, Regex로^[A-Z]:\\.+\.exe$같은 드라이브 경로 형태를 거른다. 둘 다 대소문자를 무시하는 옵션이 있다. - 결과를 텍스트로 저장해
05-process/에 둔다. 파일 이름에 프로세스 이름·PID·검사 시각을 넣고, 최소 길이·영역·필터 설정을 함께 적는다. DPS-Analyzer·pcasvc-executed·process-parser·JARParser의 출력 파일도 같은 폴더에 둔다.
서비스 시작 시각과 부팅 시각
문자열은 그 프로세스가 시작된 뒤에 쌓인 것만 담는다. 호스트 프로세스가 다시 뜨면 이전 메모리의 문자열은 남지 않으므로, 문자열이 비었거나 얇으면 그 프로세스가 언제 시작됐는지부터 본다.
- 부팅 시각:
(Get-CimInstance Win32_OperatingSystem).LastBootUpTime - 서비스 호스트의 PID:
Get-CimInstance Win32_Service -Filter "Name='DPS'" | Select-Object Name,ProcessId - 그 프로세스의 시작 시각:
Get-CimInstance Win32_Process -Filter "ProcessId=<PID>" | Select-Object Name,CreationDate. System Informer 속성의 General 탭 Started 칸도 시작 시각을 보여 준다.
서비스 호스트의 시작 시각이 부팅 시각보다 한참 늦다면 재시작 흔적으로 보고 리드에 적는다. System 로그에서 그 서비스의 7036(서비스 상태 변경)을 필터링하면 정지·실행 시각이 나온다. explorer.exe는 로그온 때 뜨므로 로그온 시각과 비교한다.
Windows 10 1703부터 RAM이 3.5GB를 넘는 PC에서는 서비스가 대부분 각자의 svchost에서 돈다. 이 구성에서는 서비스를 재시작하면 호스트 프로세스도 새로 떠 시작 시각이 바뀐다. RAM이 3.5GB 이하이거나 분리하지 않는 서비스처럼 여러 서비스가 한 호스트를 나눠 쓰면, 서비스만 재시작돼도 호스트 시작 시각은 그대로다. 이때는 7036 기록으로 판단한다.
늦은 시작에는 정상 사유도 있다. 수동·트리거 시작 서비스는 필요할 때 뜨고, 업데이트·설치 프로그램과 서비스 복구 설정도 서비스를 다시 띄운다. 시작 유형(sc qc)과 7036 전후 맥락을 같이 적는다.
한계
- 휘발성: 재부팅이나 재시작이면 문자열이 사라진다. 사후 수집 세션에는 이 관찰 지점이 없다.
- 문자열만으로 실행이 증명되지 않는다: 형식마다 뜻이 다르고, 경로가 메모리에 남은 것과 사용자가 그 파일을 실행한 것은 다른 진술이다. 디스크 축의 실행 기록과 이름·경로·시각이 맞을 때만 무게를 둔다.
- 대부분은 정상 사용 흔적이다: 게임·런처·설치 프로그램·업데이트 경로가 대다수다. 제보 이름, 사용자 쓰기 경로, 무서명, 디스크 부재에 해당하는 것만 추린다.
- 검사 도구도 문자열을 남긴다: System Informer·DPS-Analyzer·스캐너를 실행하면 그 경로가 DPS·PCA 문자열에 새로 들어간다. 도구마다 실행 시각을 적어 두고 결과에서 가려낸다.
- 꺼진 서비스는 대상이 없다: 서비스가 비활성이면 그 프로세스 자체가 없다. 서비스 상태를 먼저 기록한다.
문자열 검사를 피하는 방법과 남는 흔적
| 기법 | 공격자가 하는 일 | 남는 흔적 |
|---|---|---|
| 서비스 재시작으로 비우기 | DPS·PcaSvc 같은 서비스나 explorer.exe를 재시작해 메모리를 새로 띄운다 | 호스트 프로세스 시작 시각이 부팅(explorer는 로그온) 시각보다 한참 늦다. System 7036의 정지→실행 기록, 재시작에 쓴 명령(sc·net)의 PF·BAM |
| 서비스 스레드 정지 | 호스트는 그대로 두고 기록 스레드만 Suspend해 새 문자열이 쌓이지 않게 한다 | 시작 시각은 정상인데 디스크 축에 있는 최근 실행이 문자열에 없다. 스레드 상태 판독은 Prefetch·Anti-forensics 카드의 "서비스 스레드 정지" 행에 있다 |
| 문자열 제거 로더 | 로드한 뒤 자기 메모리에서 탐지용 문자열을 지운다 | 로더가 지우는 것은 자기 쪽 문자열이다. DPS·PcaSvc 같은 다른 프로세스에 남은 로더 실행 경로는 별개이고, 구조 지표는 Memory 카드의 "문자열 제거 로딩" 행이 본다 |
| 편집 도구로 덮어쓰기 | System Informer 같은 도구의 메모리 편집 창으로 대상 프로세스의 문자열을 직접 지운다 | 편집 도구의 실행 기록(PF·BAM·DPS 문자열). System Informer의 메모리 편집 창 제목은 이름.exe (PID) (0x시작 - 0x끝) 형식이다 |
인젝션 기법과 남는 흔적
기법이 정교할수록 "모듈 목록에 나타난다"는 가정이 깨진다. 각 기법이 어디에 잔류물을 남기는지를 알아야 "없다"와 "안 보인다"를 구분할 수 있다. 모듈 목록의 "이름"도 같은 함정이다. 시스템·드라이버 DLL 이름을 베낀 모듈은 목록에서 정상으로 보이지만, 실제 위치·서명 상태·백킹 파일(모듈이 매핑된 디스크 파일)에서 위장이 드러난다.
| 기법 | 공격자가 하는 일 | 남는 흔적 |
|---|---|---|
| 고전 DLL 인젝션 | OpenProcess → VirtualAllocEx → WriteProcessMemory → CreateRemoteThread로 대상에 DLL 경로를 쓰고 LoadLibrary를 원격 호출한다 (T1055.001) | 모듈 목록에 실제로 나타나는 계열이다. 비벤더·무서명 DLL + 사용자 경로가 1차 리드. 인젝터 exe의 PF·BAM, DLL 파일의 USN CREATE, Sysmon 8·10·7이 보조다 |
| 수동 매핑 | LoadLibrary를 거치지 않고 PE를 직접 메모리에 매핑·재배치·import 해결한다. OS 로더의 모듈 목록(PEB LDR)에 올라가지 않는다 | 모듈 탭에는 없는데 메모리 탭에 파일 미매핑 실행 영역 + MZ·PE 구조가 있다. ldrmodules 불일치는 R3-MEM에서 확인한다. 매퍼 자체는 exe라 PF·BAM에 남는다 |
| 프로세스 할로잉 | 정상 exe를 suspended 상태로 만든 뒤 이미지를 통째로 교체하고 재개한다 (T1055.012) | 프로세스 경로는 notepad.exe·svchost.exe인데 메모리 안의 코드는 다른 바이너리고, 스레드 시작 주소도 그 바이너리를 가리킨다. 비정상 부모-자식 관계, PEB 이미지 경로와 실제 코드 영역 불일치가 잡힌다. Volatility hollowprocesses·pe-sieve가 겨냥하는 대표 패턴 |
| APC 인젝션 | 대상 스레드의 APC 큐에 코드 실행을 등록한다 (T1055.004). 새 스레드를 만들지 않아 스레드 카운트로는 안 잡힌다 | 기존 스레드의 호출 스택에 모듈 밖 프레임이 낀다. 큐잉 직전의 프로세스 접근(Sysmon 10)과 메모리 쓰기 흔적이 보조다. 라이브 스냅샷에서 잡기 어려워 메모리 축 의존도가 높다 |
| 스레드 하이재킹 | 실행 중인 스레드를 Suspend하고 컨텍스트를 바꿔 RIP를 악성 코드로 돌린 뒤 Resume한다 (T1055.003) | 스레드 시작 주소는 정상 모듈인데 현재 실행 위치·스택 프레임이 로드된 모듈 밖이다. SI 스레드 탭에서 파일 미매핑 주소를 가리키는 프레임이 리드다 |
| 리플렉티브 DLL | DLL이 자기 자신을 로드하는 로더를 내장해 디스크 경유 없이 메모리에서 올라간다 (T1620) | unbacked(파일에 매핑되지 않은, 용어집) 실행 영역 + MZ 헤더(malfind류 패턴). 디스크에 DLL이 없는데 기능은 동작 중이라면 "로더 실행 기록(PF·BAM) + 현재 기능" 두 축이 필요하다 |
| IAT 훅 | 로드된 모듈의 import 주소 테이블 엔트리를 자기 코드 주소로 덮어쓴다 | 파일은 정상인데 메모리 상의 IAT가 디스크 이미지와 다르다. 모듈 무결성 비교(메모리 vs 디스크)로만 잡힌다. 오버레이·AV가 정상적으로도 같은 행위를 해서 FP가 매우 높다 |
| 인라인 훅 | ntdll·게임 함수의 프롤로그를 jmp/call로 패치한다 | 함수 선두 바이트가 디스크 이미지와 불일치한다. pe-sieve가 "hooked"로 보고한다. 안티치트·AV·오버레이가 같은 패턴이라 단독 의미가 약하다 |
| DLL 사이드로딩·하이잭 | 정상 exe가 로드할 DLL을 같은 이름의 비정상 DLL로 교체하거나, exe 옆 검색 우선 폴더에 둔다. 서명된 정상 exe가 악성 DLL을 대신 로드한다 (T1574.001·T1574.002) | 모듈 이름은 정상인데 로드 경로가 기대 위치(System32·설치 폴더)가 아니다. 서명 없는 동명 DLL, 교체된 DLL의 USN rename·write 체인. hijacklibs 같은 공개 목록이 하이잭 가능한 DLL 이름을 가린다 |
| LdrLoadDll 스텁 | 대상 프로세스에 심은 코드가 OS 내부 로더 함수(LdrLoadDll)를 호출해 모듈을 올린다. ExtremeInjector 같은 다기법 인젝터가 제공하는 방식이다 | 모듈 목록에는 나타나지만 stub이 실행된 파일 미매핑 영역·원격 스레드 생성 흔적(Sysmon 8·10)이 남는다. 인젝터 exe는 PF·BAM에 남는다 |
| 이미지 교체 변종 | hasherezade의 PE 인젝션 PoC 계열(process ghosting·transacted hollowing·process overwriting·process doppelganging·module overloading)이 정상 프로세스를 띄우고 내용을 페이로드로 바꾼다 | 프로세스 이름·경로는 정상인데 실제 이미지와 불일치한다. unbacked 실행 영역, PEB·VAD 불일치, 일부 변종이 남기는 잔여 임시 파일. pe-sieve·hollows_hunter가 겨냥하는 패턴이다 |
| 드라이버 모듈명 위장 | 치트 DLL을 GPU 드라이버 모듈명(atig6pxx.dll·aticfx64.dll)으로 바꿔 javaw 같은 게임 프로세스의 모듈 목록에서 드라이버처럼 보이게 한다 | 이름은 정상이어도 위치·서명·환경이 아니다. 정품은 System32·드라이버 설치 경로에서 유효 서명과 함께 로드되고, NVIDIA·Intel GPU 환경의 AMD 드라이버 DLL은 환경과 모순된다 |
| rundll 없는 DLL 실행 | 전용 로더가 rundll32·regsvr32를 거치지 않고 DLL을 직접 호출한다 | rundll32의 PF·BAM 부재는 부정 증거가 아니다. 대상 프로세스의 모듈 목록과 로더 자체의 실행 기록(PF·BAM)이 남는다 |
공통 원칙: 기법이 디스크를 건드리지 않아도 로더·인젝터는 exe로 먼저 실행됐어야 한다. "인젝터의 PF·BAM + 프로세스 내 잔류물" 조합이 이 카드의 표준 증거 모양이다.
정상 vs 이상
| 구분 | 정상 | 이상 |
|---|---|---|
| 모듈 | MS·벤더 서명, 게임·설치 폴더, 알려진 오버레이 | 무서명 + 사용자 경로 + 치트 네이밍, 또는 모듈 목록에 없는데 실행 영역 존재 |
| 스레드 | 시작 주소가 로드된 모듈 내부 | 시작 주소·스택 프레임이 파일 미매핑 영역 |
| 프로세스 구조 | 표준 부모-자식 | PEB·경로 불일치(할로잉 의심), 게임이 무관한 exe의 부모 |
| 핸들·접근 | 게임이 자체 리소스 접근 | 무관 프로세스가 게임에 높은 권한으로 접근 |
| 무결성 | 메모리 모듈 = 디스크 이미지 | IAT·프롤로그 불일치(단, 오버레이·AV와 구분 필요) |
| 모듈 이름 | 모듈명과 경로·서명·환경이 정합 | 시스템·드라이버 이름인데 경로·서명 불일치, GPU 환경과 모순되는 드라이버 모듈명 |
| 서비스 문자열 | 게임·런처·설치 프로그램·업데이트 경로, 서명된 실행 파일 | 제보 이름, 사용자 쓰기 경로의 무서명 exe, 지금 디스크에 없는 exe, 같은 파일명에 날짜가 다른 DPS 항목 |
| 호스트 시작 시각 | 부팅 직후(explorer.exe는 로그온 직후) | 부팅보다 한참 늦은 시작과 7036 정지·실행 기록, 그와 함께 비어 있는 문자열 |
오탐
- 오버레이 인젝션: Discord·Steam·NVIDIA 오버레이는 게임 프로세스에 정상 주입된다. 벤더 서명과 설치 여부로 가린다.
- 그래픽·입력 스택: GPU 드라이버, 입력 장치 DLL, MSI Afterburner/RTSS 계열의 훅.
- 백신·EDR: 사용자모드 훅과 모니터링 DLL을 거의 모든 프로세스에 넣는다.
- 안티치트 자체: 자체 보호 루틴이 인젝션 탐지 패턴을 만든다. 안티치트를 치트로 판정하지 않는다.
- 개발 PC의 디버거: Visual Studio·x64dbg가 연결된 상태는 같은 신호를 낸다.
- pe-sieve 히트: JIT·AV·안티치트 훅이 같은 보고를 만든다. 히트는 리드이며, FP 베이스라인과 디스크 교차 없이 무게를 두지 않는다.
- 검사 도구가 만든 문자열: System Informer·DPS-Analyzer·스캐너를 실행하면 그 경로가 서비스 문자열에 새로 들어간다. 도구 실행 시각을 기록해 결과에서 가려낸다.
- 정상적인 늦은 시작: 수동·트리거 시작 서비스, 업데이트나 서비스 복구로 다시 뜬 호스트, 충돌 뒤 다시 뜬 explorer.exe. 시작 유형과 7036 맥락으로 가린다.
교차 검증
| 교차 카드 | 확인 내용 |
|---|---|
| R3-SIG | 의심 모듈 경로의 서명 상태와 경로 위생 |
| R3-PF/BAM | 로더·인젝터 exe의 실행 기록, 제보 시간대와의 정렬 |
| R3-USN | 드롭된 DLL의 CREATE·DELETE, 인젝터 파일의 존재 이력 |
| R3-MEM | PEB·경로 불일치, unbacked 실행 영역이 보이면 분기 |
| R3-PF/BAM·PCA | 메모리 문자열의 이름·경로·시각이 PF·BAM 실행 기록, PCA 파일 기록(BAM / Registry·Windows 흔적)과 맞는지 |
| R3-AF | 서비스 재시작·스레드 정지 정황. 호스트 시작 시각, 7036, 스레드 상태 |
| MITRE T1055 | 기법 프레이밍. Confirmed 단독 근거가 아니다 |
프로세스·모듈 소견만으로는 Confirmed를 내리지 않는다. 라이브 관찰(모듈·스레드·메모리)이 한 축이고, 디스크 타임라인(인젝터 실행·DLL 생성)이 다른 축이다. 둘이 같은 스토리로 수렴해야 한다. 서비스 메모리 문자열도 라이브 관찰 축에 속한다. 문자열 여러 개가 같은 경로를 가리켜도 디스크 축 없이는 한 축이다.
증거 캡처
05-process/ 폴더에 둔다.
- 프로세스 트리 전체 스크린샷(부모-자식이 보이게)
- 비Microsoft·비벤더 필터를 건 모듈 목록 + 의심 모듈의 경로·서명 상태
- 이상 스레드의 시작 주소·스택, 파일 미매핑 실행 영역의 메모리 탭 화면
- pe-sieve를 썼다면 출력 원문 + 각 히트의 정상 설명 검토 메모
- Sysmon 배포 시 관련 이벤트(8·10·7) export
- 서비스·프로세스 문자열 검사 결과(txt): 프로세스 이름·PID·시작 시각, 최소 길이·영역·필터 설정, 검사 시각. 전용 파서를 썼다면 출력 파일 원본
- 부팅 시각과 대상 호스트 시작 시각 메모. 재시작이 의심되면 7036 필터 화면을 함께 두고
06-af/에도 적는다
흔한 실수
- pe-sieve 히트 하나로 Confirmed를 내린다. 이 도구는 단서 생성기다.
- 무서명 DLL 하나로 판정한다. 정당한 무서명 소프트웨어가 너무 많다.
- 안티치트 자체 보호·오버레이를 치트로 판정한다.
- 모듈 목록만 보고 "없다"고 끝낸다. 수동 매핑·리플렉티브 계열은 모듈 목록에 나타나지 않는다. 메모리·스레드 탭을 봐야 한다.
- 라이브 SS 없이 프로세스 증거를 주장한다. 프로세스가 꺼지면 이 축의 증거도 사라진다.
- 메모리 문자열 하나로 실행을 확정한다. 형식마다 뜻이 다르고, 디스크 축과 맞아야 한다.
- 문자열이 비어 있는데 호스트 시작 시각을 보지 않는다. 방금 다시 뜬 프로세스는 원래 비어 있다.
Community SS 커뮤니티에서 "injector stub"·"manual map loader"·"steam hideloader" 같은 이름의 로더가 반복 언급된다. 공통 패턴은 로더 exe는 디스크에 남고(=PF·BAM에 잡히고) 페이로드만 메모리에 간다는 것이다. 모듈 목록이 깨끗해도 로더의 실행 기록과 파일 미매핑 실행 영역이 같이 있으면 같은 가설을 지지하는 두 축이다.
다기법 인젝터(ExtremeInjector 등)가 "표준·manual map·thread hijacking·LdrLoadDll stub" 4종 세트로 유통된다는 보고도 반복된다. 각각이 남기는 모듈 목록·메모리 시그니처는 위 표의 개별 기법과 같다. "정규식·prefetch 파서를 전부 우회한다"고 스스로 밝힌 클라이언트 사례(slinky)는 저널 없는 파일 시스템 + 유니코드 폴더명 + 정상 모듈명 rename의 조합이었다. 회피용으로 만든 이름·경로 패턴 자체가 정상 베이스라인에 없는 모양이라, 조합의 각 조각은 해당 축의 카드가 잡는다.
서비스·프로세스 메모리 문자열 검사는 Minecraft·FiveM SS 가이드가 공통으로 다루는 기본 점검이다. 가이드들의 판독 관행은 이렇다. csrss.exe는 보통 두 개가 떠 있는데, 개인 바이트(private bytes)가 적은 쪽에서
.exe전체 경로를, 많은 쪽에서.dll경로와 확장자를 바꾼 실행 파일 경로를 찾는다. explorer.exe에서는pcaclient로 최근 실행 경로를 찾고,file:///로 셸에서 열어 본 경로를 보되 이쪽은 실행 증거로 쓰지 않는다. DPS에서는!!로 시작하면서.exe로 끝나지 않는 항목과exe가 없는 장치 경로를 걸러 확장자를 바꿔 실행한 파일을 찾는다. PcaSvc에서는 점 없이jar로 검색해 확장자를 바꾼 JAR 실행까지 잡는다. 최소 길이는 가이드마다 4에서 6 사이로 다르다.같은 이름의 도구가 DPS에 서로 다른 컴파일 시각으로 두 번 이상 보이면, 정상 도구 이름을 빌린 다른 파일을 의심하는 강한 신호로 다룬다. explorer.exe의 PCA 클라이언트 기록이 비어 있는데 explorer가 방금 시작됐다면 흔적을 지우려고 재시작한 것으로 본다. System Informer의 메모리 편집 창으로 문자열을 지우면 그 창 제목(
이름.exe (PID) (0x… - 0x…))이 dwm.exe·explorer.exe·taskhostw.exe 메모리에 남는다고 보고) (0x로 검색한다. 게임 프로세스(javaw.exe)의 문자열에서 치트 모듈 이름과 키 바인딩 패턴을 찾는 전용 도구도 쓰이고, SearchIndexer.exe·ctfmon.exe를 보조 대상으로 드는 가이드도 있다.
Sources
- MITRE: T1055 · T1055.001 DLL Injection · T1055.003 Thread Hijacking · T1055.004 APC · T1055.012 Process Hollowing · T1574.001 DLL Search Order Hijacking · T1574.002 DLL Side-Loading · T1620 Reflective Code Loading
- MS Learn API 문서: LoadLibrary · VirtualAllocEx · WriteProcessMemory · CreateRemoteThread · DLL 검색 순서
- 도구: System Informer · Process Explorer · listdlls · Sysmon (이벤트 7·8·10·12–14)
- 스캐너: pe-sieve · hollows_hunter
- MS Learn 서비스·프로세스: 시스템 서비스 안내(DPS·PcaSvc·DcomLaunch·DiagTrack·Appinfo·Dnscache 설명) · Service Host 분리(Windows 10 1703, RAM 3.5GB 기준) · MS05-018(CSRSS 설명) · tasklist · ipconfig
- MS Learn WMI 클래스: Win32_Process(CreationDate) · Win32_OperatingSystem(LastBootUpTime) · Win32_Service(ProcessId)
- 문자열 파서·뷰어: DPS-Analyzer · pcasvc-executed · process-parser · JARParser · System Informer 소스(Strings 창·메모리 편집 창) · Echo 핸드북: How to Use Echo
- 현장 가이드: RedLotus Guide: 프로세스별 검색 대상 · Lafferrr ScreensharingGuide
Next
- 메모리 심층 → Memory
- 삭제 흔적 판독 → Anti-forensics
- 실행 기록과의 교차 → Prefetch
