대부분의 컴퓨팅 역사에서, "웹의 바이너리"는 JavaScript였습니다 — devtools에서 열 수 있고 이해할 수 있는 인간 읽을 수 있는 텍스트입니다. WebAssembly가 그것을 바꿨습니다. Wasm은 브라우저에서 거의 네이티브 속도로 실행되는 컴팩트한 바이너리 지침 형식이며, 점점 더 엣지, 플러그인, 서버리스 런타임, wasm 샌드박스를 임베드하는 애플리케이션에서 실행됩니다. 성능과 이식성이 성공을 만들었지만, 보안 작업을 하는 모든 사람에게 새로운 현실을 창출했습니다: 사용자에게 배송되는 로직의 점점 증가하는 부분이 이제 읽을 수 있는 소스 대신 불투명한 바이너리 블롭으로 도착합니다. 그 블롭이 웹페이지에 밀반입된 암호화폐 채굴기, 난독화된 라이선싱 체크, 또는 JavaScript 중심 탐지를 피하기 위해 wasm을 사용하는 악성코드라면, 누군가는 그것을 역공학해야 합니다. 2026년에 그 "누군가"는 점점 더 자주 보안 분석가이며, 도구가 필요성을 충족할 정도로 성숙했습니다.
이 가이드는 WebAssembly 역공학에 대한 실용적인 소개입니다. wasm을 네이티브 바이너리와 다르게 하는 것을 설명하고, 표준이 된 오픈소스 도구 체인 — WebAssembly Binary Toolkit (WABT), diswasm 디컴파일러, Binaryen, wasm-tools — 을 걷고, 미지의 .wasm 파일에서 그것이 무엇을 하는지에 대한 이해로 가는 워크플로우를 제시합니다. 목표는 보이기에는 위협적이지만 중요한 방식으로 더 분석 가능한 형식을 신비화하지 않는 것입니다.
wasm을 다르게 만드는 것
wasm을 효과적으로 역공학하려면 x86이나 ARM 바이너리 대부분의 RE 도구가 어떻게 구축되었는지와 어떻게 다른지 이해해야 합니다. 차이는 양쪽으로 잘라집니다 — 일부는 wasm을 더 쉽게 분석하고, 다른 것은 더 어렵게 합니다.
첫 번째 결정적인 특성은 wasm이 스택 머신이지 레지스터 머신이 아니라는 것입니다. 네이티브 코드는 고정된 CPU 레지스터 집합을 조작합니다. wasm 명령어는 피연산자 스택에 값을 푸시하고 팝합니다. 처음에는 낯설지만, 구조적이고 예측 가능하며, 레지스터 할당에 대해 생각할 필요가 없다는 뜻입니다. 두 번째, 더 도움이 되는 특성은 wasm이 구조화된 제어 흐름을 가진다는 것입니다. 네이티브 코드는 디컴파일러가 고통스럽게 루프와 조건부로 재구성해야 하는 임의의 점프를 사용합니다. wasm은 형식에 빌트인 명시적 block, loop, if 구성을 가집니다. 제어 흐름 그래프는 어떤 의미에서 이미 복구되었습니다 — 네이티브 디컴파일의 가장 어려운 부분 중 하나는 크게 당신에게 주어집니다. 세 번째 특성은 깨끗한 모듈 구조입니다: wasm 모듈은 잘 정의된 섹션 (타입, 임포트, 함수, 코드, 데이터, 내보내기)으로 조직되어, 함수가 어디에 있는지, 모듈이 호스트에서 임포트하는 것, 그것이 노출하는 것을 항상 알고 있습니다.
그 임포트/내보내기 구조는 분석가에게 가장 가치 있는 단일 항목입니다. wasm 모듈은 자신으로 외부 세계에 대해 아무것도 할 수 없습니다 — syscall이 없습니다. 그것이 중요한 외부 세계에 하는 모든 것 (네트워크 접근, DOM 조작, 파일 I/O)은 임포트된 호스트 함수를 호출함으로써 발생하고, 그 임포트는 모듈에 명시적으로 나열됩니다. 임포트 섹션을 읽는 것은 단일 지침을 분석하기 전에 모듈의 기능을 알려줍니다: 네트워크에 도달할 수 있는 것을 임포트하지 않으면, 그것은 데이터를 유출할 수 없습니다. 페칭이나 암호 함수를 임포트하면, 그것이 보기 시작할 곳입니다. 이것은 네이티브 바이너리가 당신에게 거의 주지 않는 수준의 미리 기능 통찰력입니다. 이 비대칭이 준비된 defender에 유리합니다.
더 어려운 쪽: wasm은 기본적으로 심볼 이름을 제거합니다 (함수는 func[42]가 됨), 타입은 소수의 숫자 원시로 제한되어 더 높은 수준의 구조가 손실되고, 도구 체인과 난독화기는 조밀하고 머신에서 생성된 코드를 생성할 수 있습니다. 하지만 구조화된 제어 흐름과 명시적 모듈 레이아웃이 훨씬 보상하므로, 그 이유가 wasm 디컴파일이 일반적으로 네이티브 디컴파일보다 더 관리 가능한 것으로 여겨집니다.
도구 체인
오픈소스 wasm RE 도구 체인은 작고, 초점이 맞춰지고, 보완적입니다 — 단일 도구가 모든 것을 하지 않으며, 표준 워크플로우는 여러 개를 함께 사용합니다. 각각이 무엇을 위한 것인지 아는 데 도움이 됩니다.
WABT, WebAssembly Binary Toolkit은 기초입니다. wasm2wat로 바이너리 .wasm 형식과 인간이 읽을 수 있는 .wat (WebAssembly 텍스트) 형식 사이에 변환하고, wasm-objdump로 섹션을 덤프하고 코드를 분석하고, 모듈을 검증하고 — RE에 중요하게 — wasm-decompile로 C 같은 디컴파일을 생성합니다. WABT는 당신이 처음 손을 뻗는 것입니다: 바이너리를 읽을 수 있는 것으로 바꾸고 모듈의 구조를 보여줍니다. 그 --generate-names 옵션은 이름 없는 함수에 대한 이름을 합성하므로 출력을 따르기 훨씬 더 쉽게 만듭니다.
diswasm는 읽을 수 있음을 향해 한 발 더 나아갑니다. wasm2wat이 생성하는 충실하지만 저수준인 WAT보다는 더 높은 수준의 의사코드로 wasm 바이트코드를 디컴파일합니다. WABT가 모듈이 정확히 말하는 것을 보여줄 때, diswasm은 그것이 의미하는 것을 보여주려고 시도하고, 정상적인 프로그램처럼 읽히는 구조화된 코드를 재구성합니다. 분류 중에 빠르게 로직을 이해하기 위해, 이 더 높은 수준의 뷰는 가치 있습니다.
Binaryen은 컴파일러 급 도구 체인으로서 RE에 대한 관련성이 약간 간접적이지만 실제입니다. 그 wasm-opt 도구는 모듈에 대해 최적화 및 변환 passes를 실행하고, 그 passes의 여러 개 — 상수 폴딩, 데드 코드 제거, 로컬 단순화 — 우연히 컴파일러와 난독화기가 남기는 노이즈를 정리합니다. 실용적인 트릭은 혼란스러운 모듈을 단순화 passes를 통해 실행한 후 더 정사한 결과를 디컴파일하는 것입니다. Binaryen의 wasm-dis 또한 분석하고, wasm-reduce는 관심 있는 동작을 나타내는 최소 피스로 모듈을 축소할 수 있습니다.
wasm-tools, Rust 저수준 도구 키트가 마무리합니다. 검증, 파싱, 변경, 더 최신 wasm 제안 (구성 요소, GC, 스레드) 지원. 프로그래매틱하게 모듈을 검사하거나 변경해야 할 때 — 또는 바이너리가 기존 도구가 거부하는 기능을 사용할 때 — wasm-tools는 현대적이고 활발하게 유지되는 옵션입니다. 함께 이들 4개는 RE 라이프사이클을 다룹니다: WABT와 diswasm이 읽고, Binaryen이 단순화하고, wasm-tools가 검증하고 변경합니다.
실용적인 분석 워크플로우
미지의 .wasm 파일에 직면했을 때 — 의심스러운 웹페이지에서 끌어낸 것이라고 말하십시오 — 반복 가능한 워크플로우는 이해로 빠르게 당신을 얻습니다. 아래 시퀀스는 경험 많은 분석가들이 수렴하는 것입니다.
코드가 아닌 기능으로 시작하세요. 단일 지침을 읽기 전에 임포트와 내보내기를 덤프하세요: wasm-objdump -x module.wasm (또는 임포트/내보내기 섹션 구체적으로). 임포트는 모듈이 할 수 있는 것을 알려줍니다 — 호출할 수 있는 호스트 함수 — 그리고 내보내기는 진입점을 알려줍니다, 주변 JavaScript가 실제로 호출하는 함수들. 이것은 모든 것을 프레임합니다: 수학 함수만을 임포트하는 모듈은 fetch와 암호 원시를 임포트하는 것과는 아주 다른 위협입니다. 많은 분석이 효과적으로 여기서 끝납니다, 기능 목록이 이미 질문에 답하기 때문입니다 ("네트워크에 도달할 수 없으므로 데이터를 유출할 수 없습니다").
다음, 이름과 함께 분석하세요: wasm2wat --generate-names module.wasm. 이것은 합성된 이름과 함께 충실한 구조를 제공하고, 섹션 레이아웃, 데이터 섹션 (종종 문자열, URL, 또는 grep할 가치 있는 임베드된 상수를 포함), 그리고 전체 모양을 볼 수 있게 해줍니다. 데이터 섹션과 WAT에서 알려진 문자열을 grep하세요 — 도메인, API 경로, 암호 상수, 오류 메시지 — 이는 자주 심화 코드 읽기 없이 의도를 드러냅니다.
그 다음, 특정 로직을 이해해야 한다면, 읽을 수 있음을 위해 디컴파일하세요: wasm-decompile (WABT) 또는 diswasm을 실행하여 의사코드를 얻고, 출력이 조밀하거나 난독화되었다면, 먼저 단순화하세요 Binaryen으로 (wasm-opt --precompute --simplify-locals --vacuum) 정사한 모듈을 디컴파일하기 전에. 내보낸 함수와 흥미로운 임포트를 호출하는 것에 읽기를 집중하세요 — 전체 모듈을 읽을 필요가 거의 없습니다. 마지막으로, 진정 완고한 샘플의 경우, wasm-reduce는 동작을 재현하는 최소 모듈을 격리할 수 있고, 이해해야 할 표면을 축소합니다.
이 기능 우선, 그 다음 구조, 그 다음 로직의 진행은 좋은 네이티브 RE 실행을 미러링합니다만 wasm의 이점을 활용합니다: 명시적 임포트는 기능 단계를 비상하게 정보 전달하고, 구조화된 제어 흐름은 디컴파일 단계를 비상하게 깨끗하게 합니다.
Wasm 악성코드 및 회피
분석가들이 점점 더 이들 기술을 필요로 하는 왜를 이해할 가치가 있습니다, 왜냐하면 그것이 무엇을 찾을 것인지 형성합니다. 공격자들이 wasm을 채택한 구체적인 이유가 있습니다. 가장 확립된 것은 암호화폐 채굴입니다: wasm의 거의 네이티브 속도는 피해자의 브라우저에서 암호화폐 채굴에 이상적이므로, 드라이브 바이 채광기가 years 동안 wasm으로 해싱 루프를 배송했습니다. 더 광범위하게, wasm은 정도의 회피를 제공합니다: JavaScript 분석 및 탐지하는 데 10년을 보낸 보안 생태계는 wasm을 검사하는 데 덜 성숙하므로, 로직을 wasm 모듈로 이동하면 도구와 인간 리뷰어를 통과할 수 있습니다. 난독화된 로직 — 라이선싱 체크, 항분석 루틴, 키 유도 — 은 또한 wasm 바이너리에서 읽기 가능한 JS에서 빼내기 더 어렵고, 일부 공급업체와 일부 악성코드는 역공학에 저항하기 위해 특히 wasm을 사용합니다.
방어 의미는 "우리가 JavaScript를 검토했습니다"는 더 이상 웹 전달 코드에 대한 충분한 보증이 아니라는 것입니다. 페이지가 wasm 모듈을 배송하면, 그 모듈은 공격 표면의 일부이고 위의 기능 우선 분석을 받을 만합니다. 좋은 소식은, 재정, wasm의 명시적 임포트 구조는 모듈이 뭔가 위험한 할 수 있는지 질문에 대답하는 것을 최소한 빠르게 만듭니다 — 난독화된 네이티브 바이너리보다 훨씬 더 빠르게 결정할 수 있습니다. 그 비대칭이 기꺼이 도구 체인을 배우는 defender를 선호합니다.
wasm을 전통적인 RE 도구로 연결
경험 많은 역공학자에게 빠르게 나오는 질문은 기존 도구 — Ghidra, IDA, Binary Ninja — 를 wasm 대신 사용하는 도구를 사용할 수 있는지입니다, 전체 별도의 도구 체인을 배우는 것보다. 2026년의 답변은 자격이 있는 예, 그리고 절충을 이해할 가치가 있습니다. 커뮤니티 플러그인은 주요 RE 플랫폼에 wasm 지원을 가져옵니다: Ghidra와 다른 사람들을 위한 WebAssembly 프로세서/로더 모듈이 있어, .wasm를 로드하고 친숙한 그래프 뷰, 교차 참조, 디컴파일러 워크플로우를 사용할 수 있게 해줍니다. 하나의 이 환경에서 이미 깊이 유창한 분석가에게, 그 친숙함은 네이티브 코드를 위해 설계된 모델을 스택 머신에 적응시키고, 가장자리에서 손실되거나 어색할 수 있는 일반 RE 플랫폼의 이점을 이길 수 있습니다. 실용적인 접근 많은 분석가들이 정착하는 것은 둘 다를 사용하는 것입니다: 여기에서 설명된 빠른 기능 우선 분류를 위해 경량 wasm CLI 도구 (덤프 임포트, 분석, grep 문자열, 빠른 의사코드 얻기), 그리고 그 후, 샘플이 깊은 수동 분석을 보장한다면, 모든 네비게이션과 주석 기능이 있는 자신의 플랫폼 선택에 로드합니다.
이것은 또한 RE 기초가 옮기는 곳입니다. Wasm을 역공학하는 것은 완전히 별도의 규율이 아닙니다 — 분석 분해, 제어 및 데이터 흐름 다음, 그 호출자와 호출자로부터 흥미로운 함수를 식별, 바이너리가 무엇을 하는지에 대한 추론의 핵심 기술은 직접 옮깁니다. 변경되는 것은 표면 세부사항입니다: 레지스터 대신 스택 머신, 원본 점프 대신 구조화된 제어 흐름, syscall 대신 호스트 임포트. 경험 많은 역공학자는 정확히 때문에 wasm을 빠르게 집어올 수 있습니다 사드-승리된 직관이 여전히 적용됩니다; wasm 특정 도구가 단지 마찰을 제거합니다. 그 이동성은 wasm에 투자하기를 꺼리는 누구에게나 안심입니다 — 당신은 처음부터 시작하지 않고 있습니다, 기존 기술을 연장합니다.
최종 요점
WebAssembly는 현대 웹의 1순위 바이너리 형식이 되었습니다, 그것을 읽는 것은 이제 호기심보다는 보안 기술입니다. Wasm은 진정으로 네이티브 코드와 다릅니다 — 구조화된 제어 흐름을 가진 스택 머신, 깨끗한 모듈 섹션, 그리고 가장 유용하게, 코드를 읽기 전에 모듈의 기능을 드러내는 명시적 호스트 임포트. 오픈소스 도구 체인이 필요와 일치합니다: WABT 분석 및 디컴파일, diswasm로 더 높은 수준의 의사코드, Binaryen로 난독화를 단순화, wasm-tools로 검증 및 변경. 기능 우선으로 작업하세요 — 명령어 전 임포트 및 내보내기 — 그 다음 이름과 함께 분석하고, 그 다음 중요한 부분을 디컴파일하고, 필요할 때 단순화합니다. 그것을 하면, 웹의 새로운 바이너리는 불투명한 블롭을 중지하고 읽을 수 있는 것이 됩니다.
참고 및 자료
도구
배경 및 분석
- WebAssembly 역공학 — PNF Software
- WebAssembly 바이너리 분석 — Forcepoint X-Labs
- WebAssembly 바이너리 디컴파일 기술 종합 연구
관련 1337skills 치트시트