
ISSTA 2026 논문의 공식 코드: "악성임을 아는 것"으로 충분한가? 정밀한 악성코드 행동 감사를 위한 LLM 평가
기사: “악성 여부를 아는 것만으로 충분한가? 정밀한 악성코드 동작 감사를 위한 LLM 평가”
기사 DOI: 10.1145/3832187
MalEval은 대규모 언어 모델(LLM)이 생성한 Android 악성코드 동작 보고서를 평가하기 위한 프레임워크입니다. 이 저장소의 코드는 두 가지 실행 경로를 구현합니다:
릴리스된 데이터셋은 별도로 MalEval Hugging Face 데이터셋 저장소에 호스팅되어 있습니다.
벤치마크에는 255개의 Android 애플리케이션이 포함되어 있습니다: 보관된 악성코드 샘플 200개, 최신 악성코드 샘플 30개, 그리고 시뮬레이션된 오탐(false positive)으로 사용되는 정상 애플리케이션 25개입니다. 릴리스된 파일, 출처, 권리 및 안전 처리에 관한 내용은 DATA.md를 참조하세요.
info/ Sample metadata for the benign, MalRadar, and new malware splits.
model_registry.yaml Model/provider configuration for LLM-based stages.
DATA.md Dataset composition, provenance, and access instructions.
LICENSE.txt License scope and third-party-material exclusions.
CITATION.cff Machine-readable citation metadata.
src/ Static analysis, summarization, behavior generation, and metrics code.
데이터셋은 저장소가 다음 구조가 되도록 압축을 해제해야 합니다:
MalEval/
|-- info/
|-- src/
`-- artifacts/
|-- apk/
|-- call_chain/
|-- entrypoints/
|-- functions/
|-- meta_info/
|-- reachable_func/
`-- reports/
Python 3.10 이상을 사용하세요. 새로운 가상 환경을 권장합니다:
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install --upgrade pip
python3 -m pip install -r requirements.txt
LLM 기반 단계를 실행하기 전에 model_registry.yaml에서 모델 제공자를 구성하세요. 각 모델 항목은 api_key 및 base_url 같은 리터럴 값이나 api_key_env 및 base_url_env 같은 환경 변수 참조를 저장할 수 있습니다.
예시:
models:
gpt:
provider: openai
model: gpt-5
api_key: <your_openai_key>
base_url: https://api.openai.com/v1
기본 레지스트리에는 gpt, gpt-5, qwen, deepseek, llama, coder, claude, gemini 항목이 포함되어 있습니다. 환경 변수를 선호하는 경우 model_registry.yaml이 참조하는 변수, 예를 들어 OPENAI_API_KEY, DEEPSEEK_API_KEY, QWEN3_API_KEY, HUGGINGFACE_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, GEMINI_PROJECT, GEMINI_LOCATION을 설정하세요.
이 경로는 artifacts/apk/<split>/ 아래의 APK 파일에서 시작하여 정적 분석 아티팩트를 재생성합니다. split은 malradar, new, benign 중 하나여야 합니다.
APK 하나 실행:
sha=<apk_sha256>
python3 src/preparation/run_static_analysis.py \
--folder malradar \
--apk "$sha" \
--output-root results/static_analysis
소규모 샘플 배치 실행:
python3 src/preparation/run_static_analysis.py \
--folder malradar \
--sample-size 5 \
--seed 42 \
--output-root results/static_analysis
생성된 파일은 다음 위치에 기록됩니다:
results/static_analysis/entrypoints/
results/static_analysis/call_chain/
results/static_analysis/functions/
results/static_analysis/reachable_func/
이 경로는 릴리스된 artifacts/ 디렉터리에서 시작합니다. 사전 계산된 functions, call_chain, entrypoints, reachable_func, meta_info 파일을 사용합니다.
model=gpt
split=malradar
sha=<apk_sha256>
python3 src/preparation/get_functionality_summary.py --model "$model" --folder "$split" --apk "$sha"
전체 split을 실행하려면 --apk를 생략하세요.
python3 src/preparation/get_context_summary.py --model "$model" --folder "$split" --apk "$sha"
python3 src/preparation/get_no_context_summary.py --model "$model" --folder "$split" --apk "$sha"
python3 src/generate_behavior/get_behavior.py --model "$model" --folder "$split" --flag context --apk "$sha"
python3 src/generate_behavior/get_behavior.py --model "$model" --folder "$split" --flag no_context --apk "$sha"
python3 src/generate_behavior/get_meta_behavior.py --model "$model" --folder "$split" --apk "$sha"
출력은 results/summary/, results/context_summary/, results/no_context_summary/, results/behavior/, results/no_context_behavior/, results/meta_behavior/ 아래에 기록됩니다.
요약과 동작 보고서가 생성된 후 다음 명령으로 지표를 계산합니다:
python3 src/metrics/run_metrics.py --model "$model" --flag context
python3 src/metrics/run_metrics.py --model "$model" --flag no_context
python3 src/metrics/run_metrics.py --model "$model" --flag meta
판정 모델(judge-model) 호출을 건너뛰려면:
python3 src/metrics/run_metrics.py --model "$model" --flag context --skip-eas
개별 지표 스크립트도 사용할 수 있습니다:
python3 src/metrics/aec_b_f1.py --model "$model" --flag context
python3 src/metrics/fpcr_tpmr_f1c.py --model "$model" --flag context
python3 src/metrics/eas.py --model "$model" --flag context --split malradar --judge-model gpt-5
APK를 다운로드하거나 모델 자격 증명을 구성하지 않고도 소스 트리를 검사할 수 있습니다:
python3 -m compileall -q src
python3 - <<'PY'
import json
from pathlib import Path
expected = {
"archived_sample_info.json": 200,
"latest_sample_info.json": 30,
"benign_sample_info.json": 25,
}
for name, count in expected.items():
actual = len(json.loads((Path("info") / name).read_text()))
assert actual == count, (name, actual, count)
print("metadata check passed: 200 archived malware + 30 recent malware + 25 benign")
PY