
V8 직렬화 바이트코드(JSC 파일)를 고수준의 읽기 가능한 JavaScript 유사 코드로 디컴파일하며, 여러 V8 버전 지원, 트리 출력, 맬웨어 분석을 위한 결정적 함수 명명 기능을 제공합니다.
View8은 직렬화된 V8 바이트코드 객체(JSC 파일)를 고수준의 읽기 가능한 코드로 디컴파일하도록 설계된 정적 분석 도구입니다. 이러한 직렬화된 객체를 파싱하고 디스어셈블하기 위해 View8은 패치된 컴파일 V8 바이너리를 활용합니다. 그 결과 View8은 JavaScript와 유사한 텍스트 출력을 생성합니다.
9.4.146.24 (Node V16.x에서 사용)10.2.154.26 (Node V18.x에서 사용)11.3.244.8 (Node V20.x에서 사용)컴파일된 버전은 릴리스 페이지를 방문하세요.
--inp, -i: 입력 파일 이름.--out, -o: 출력 경로. 선택한 옵션에 따라 출력은 단일 파일 또는 디렉터리 트리가 될 수 있습니다.--input_format, -f: 입력 형식을 지정합니다. 옵션은 다음과 같습니다:
raw: 입력이 원시 JSC 파일입니다.disassembled: 입력 파일이 이미 디스어셈블된 상태입니다.serialized: 입력이 이미 디컴파일되어 직렬화된 형식으로 저장된 상태입니다. 현재 직렬화 형식은 Python pickle입니다. 신뢰할 수 있는 입력만 사용하세요.--export_format, -e: 내보내기 형식을 지정합니다. 옵션은 v8_opcode, translated, decompiled, serialized입니다. 여러 옵션을 결합할 수 있습니다. 기본값: decompiled.--path, -p: 디스어셈블러 바이너리 경로. 입력이 raw 형식이고 View8이 일치하는 디스어셈블러를 자동으로 찾을 수 없는 경우 필요합니다.--scope: 스코프 인자를 전파합니다. 기본값: 1.--normalize: 주소에서 파생된 함수 식별자를 파싱 순서에 기반한 결정적 이름으로 대체합니다.--normalize-map [CSV]: --normalize를 사용하는 동안 모든 원래 함수 이름을 정규화된 이름에 매핑하는 CSV를 작성합니다. 경로가 생략되면 View8은 --out에서 <output>.name_map.csv를 파생하거나, 출력 경로가 설정되지 않은 경우 --inp에서 파생합니다.--tree, -t: 모든 함수를 하나의 파일에 저장하는 대신 출력을 트리 구조로 분할합니다. 트리 루트로 사용할 함수를 지정합니다. 기본 main 함수에서 시작하려면 start를 사용하세요.--split_mode: 트리 분할 모드. 옵션은 declarers, calls, references입니다. 기본값: declarers.--inline_depth, -d: calls 및 references 모드에서 선택한 트리 루트에서 깊이 N까지 도달 가능한 함수를 기본 트리 파일에 포함합니다. 깊이 0은 선택한 루트만 의미하고, 깊이 1은 직접 호출/참조 대상을 포함하며, 깊이 2는 해당 하위 항목을 포함합니다. declarers에서는 사용되지 않습니다.--inline_branch_limit, -l: 트리 모드에서 --inline_depth에 의해 하위 분기가 포함될 때 최대 N개의 함수를 가진 완전한 하위 분기를 기본 트리 파일에 인라인합니다. 더 큰 분기는 별도로 저장됩니다.--split_depth: calls 및 references 모드에서 내보낸 사용 분기가 탐색되는 깊이를 제한합니다. 기본값: 4.--include, -n: 출력에 포함할 함수가 포함된 파일.--exclude, -x: 출력에서 제외할 함수가 포함된 파일.--func: 선택한 함수를 표시합니다.--show_all: 함수 표시 모드에서 숨김으로 표시된 줄도 표시합니다.--verbosity, -v: 상세 수준. 허용 범위: 0 ~ 3.V8 바이트코드 파일을 디컴파일하고 디컴파일된 코드를 내보내려면:
python view8.py -i input_file -o output_file기본적으로 View8은 VersionDetector.exe를 사용하여 입력 파일의 V8 바이트코드 버전을 감지하고 Bin 폴더에서 호환되는 디스어셈블러 바이너리를 자동으로 검색합니다. 이는 --path 또는 -p 옵션으로 다른 디스어셈블러 바이너리를 지정하여 변경할 수 있습니다:
python view8.py -i input_file -o output_file --path /path/to/disassembler디스어셈블 과정을 건너뛰고 이미 디스어셈블된 파일을 입력으로 제공하려면 --input_format disassembled 또는 -f disassembled 옵션을 사용하세요:
python view8.py -i input_file -o output_file -f disassembled--normalize를 사용하여 주소에서 파생된 함수 이름을 결정적 식별자로 대체합니다. 원래 이름과 정규화된 이름 간의 관계를 유지하려면 --normalize-map을 추가하세요:
python view8.py \
--input_format disassembled \
--inp sample.jsc.disasm.txt \
--normalize \
--normalize-map \
--out decompiled/sample.dec.txt \
--export_format decompiled serialized이 명령은 다음 열이 포함된 decompiled/sample.dec.name_map.csv를 작성합니다:
original_name,normalized_name
func_start_0x268514e9dcd9,func_start_0x100000000
func_rne_0x268514eb0779,func_rne_0x100000001명시적 CSV 경로도 제공할 수 있습니다:
python view8.py \
--input_format disassembled \
--inp sample.jsc.disasm.txt \
--normalize \
--normalize-map mappings/sample.names.csv \
--out decompiled/sample.dec.txt때로는 파싱된 객체와 구조를 보존하는 직렬화된 형식으로 파일을 디컴파일하는 것이 유용합니다. 이러한 유형의 출력은 예를 들어 추가 난독화 해제 중에 텍스트 형식보다 후처리하기 더 쉬울 수 있습니다. 직렬화된 출력을 만들려면 serialized 내보내기 형식을 사용하세요:
python view8.py -i input_file -o output_file -e serialized보안 경고: 현재 직렬화 형식은 Python pickle 파일(.pkl)입니다. 신뢰할 수 없는 소스의 데이터를 unpickle하면 임의 코드가 실행될 수 있습니다. 직접 생성한 직렬화된 파일만 로드하세요.
직렬화된 출력을 다시 로드하고 다른 형식으로 내보내려면 --input_format serialized 또는 -f serialized를 사용하세요:
python view8.py -i input_file -o output_file -f serialized--export_format 또는 -e 옵션을 사용하여 내보내기 형식을 지정합니다. 여러 형식을 결합할 수 있습니다:
v8_opcodetranslateddecompiledserialized예를 들어 V8 opcode와 디컴파일된 코드를 나란히 내보내려면:
python view8.py -i input_file -o output_file -e v8_opcode decompiled기본적으로 사용되는 형식은 decompiled입니다.
대규모 번들 페이로드의 경우 모든 디컴파일된 함수를 단일 파일에 작성하는 것은 분석하기 어려울 수 있습니다. 트리 출력은 선택한 루트와 관련 함수를 디렉터리 구조로 분할합니다.
--tree를 사용하여 트리 루트를 선택하세요:
python view8.py \
--inp input.pkl \
--input_format serialized \
--out ./tree_out/ \
--tree start특수 값 start는 View8이 복구한 기본 main 함수를 의미합니다.
트리는 다음 세 가지 모드 중 하나로 분할할 수 있습니다:
declarers: 어휘적 선언 관계를 따릅니다. 즉, 어떤 함수가 다른 함수 내부 또는 하위에 선언되었는지를 의미합니다. 이는 번들 또는 모듈 유사 구조를 이해하는 데 유용하지만 실행 흐름을 나타내지는 않습니다.calls: func_x(...)와 같은 직접 함수 호출을 따릅니다. 이는 선택한 루트에서 실행 골격을 복구하는 데 유용합니다.references: 직접 호출뿐만 아니라 모든 표시 가능한 함수 참조를 따릅니다. 여기에는 콜백, 내보낸 핸들러, 라우트 핸들러, 객체 속성 및 기타 할당된 함수가 포함됩니다. 이 모드는 기능 표면을 발견하는 데 유용하지만 calls보다 훨씬 큰 트리를 생성할 수 있습니다.예시:
python view8.py \
--inp input.pkl \
--input_format serialized \
--out ./tree_calls/ \
--tree start \
--split_mode calls기본 트리 파일에는 항상 선택한 루트 함수가 포함됩니다.
calls 및 references 모드에서 --inline_depth는 기본 파일에 포함되는 그래프 수준 수를 제어합니다:
--inline_depth 0 -> 루트만
--inline_depth 1 -> 루트 + 직접 호출/참조 대상
--inline_depth 2 -> 루트 + 직접 호출/참조 대상 + 해당 하위 항목예를 들어 다음 명령은 루트와 직접 호출 대상을 포함하는 간결한 실행 개요를 생성합니다:
python view8.py \
--inp input.pkl \
--input_format serialized \
--out ./tree_calls/ \
--tree start \
--split_mode calls \
--inline_depth 1호출 레이어를 하나 더 포함하려면:
python view8.py \
--inp input.pkl \
--input_format serialized \
--out ./tree_calls/ \
--tree start \
--split_mode calls \
--inline_depth 2--inline_depth는 calls 및 references 모드에서만 지원됩니다. declarers에서는 사용되지 않습니다.
큰 하위 분기는 별도의 파일로 저장됩니다. calls 및 references 모드에서 --split_depth는 내보낸 사용 분기가 탐색되는 깊이를 제어합니다:
python view8.py \
--inp input.pkl \
--input_format serialized \
--out ./tree_calls/ \
--tree start \
--split_mode calls \
--inline_depth 1 \
--split_depth 5--inline_branch_limit 옵션은 작은 완전한 하위 분기도 기본 파일에 포함할지 여부를 제어합니다:
--inline_branch_limit 3이는 최대 3개의 함수를 포함하는 완전한 하위 분기가 기본 파일에 인라인될 수 있음을 의미합니다. 더 큰 분기는 별도로 저장됩니다.
calls 및 references 모드에서 하위 분기는 선택한 --inline_depth가 이미 하위 함수를 포함하는 경우에만 인라인됩니다. 예를 들어 --inline_depth 0은 루트만 의미하므로 하위 분기가 작더라도 인라인되지 않습니다.
간결한 실행 개요의 경우:
python view8.py \
--inp input.pkl \
--input_format serialized \
--out ./tree_calls/ \
--tree start \
--split_mode calls \
--inline_depth 1 \
--split_depth 5더 넓은 아키텍처 개요의 경우:
python view8.py \
--inp input.pkl \
--input_format serialized \
--out ./tree_calls/ \
--tree start \
--split_mode calls \
--inline_depth 2 \
--split_depth 5내보낸 콜백, 핸들러, 라우트 및 기능 표면의 경우:
python view8.py \
--inp input.pkl \
--input_format serialized \
--out ./tree_refs/ \
--tree start \
--split_mode references \
--inline_depth 1 \
--split_depth 3어휘적 또는 모듈 유사 구조의 경우:
python view8.py \
--inp input.pkl \
--input_format serialized \
--out ./tree_declarers/ \
--tree start \
--split_mode declarers \
--split_depth 3선택한 함수를 표시하려면 --func를 사용하세요:
python view8.py \
--inp input.pkl \
--input_format serialized \
--func func_name숨김으로 표시된 줄도 표시하려면:
python view8.py \
--inp input.pkl \
--input_format serialized \
--func func_name \
--show_allV8 바이트코드 버전은 파일 시작 부분에 해시로 저장됩니다. VersionDetector.exe에 사용 가능한 옵션은 다음과 같습니다:
-h: 버전을 가져와 해당 해시를 반환합니다.-d: 리틀엔디언 형식의 해시를 가져와 무차별 대입으로 해당 버전을 반환합니다.-f: 파일을 가져와 해당 버전을 반환합니다.