Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
simplify — 안드로이드 가상 머신 및 디난독화 도구 | Kitploit
도구/GitHubGitHub/calebfenton/simplify
Android SecurityDynamic Analysis (Sandboxing)Reverse EngineeringMalware AnalysisBinary Analysis
GitHubcalebfenton/simplify

simplify

안드로이드 가상 머신 및 디난독화 도구

저장소 보기
4.7k45515년 전Kitploit 검토 완료

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

Simplify

Build Status Coverage Status Coverity Scan Build Status

일반 안드로이드 난독화 해제 도구

Simplify는 앱을 가상으로 실행하여 동작을 이해한 후, 동일하게 동작하면서도 사람이 이해하기 쉬운 코드로 최적화를 시도합니다. 각 최적화 유형은 단순하고 일반적이어서 특정 난독화 유형과 관계없이 적용됩니다.

Before and After

왼쪽 코드는 난독화된 앱의 디컴파일 결과이고, 오른쪽 코드는 난독화가 해제된 코드입니다.

수많은 메서드 호출, 명확한 의미 없음 와, 정말 직설적이고 의미가 가득함

개요

이 프로젝트는 smalivm, simplify, 데모 앱의 세 부분으로 구성됩니다.

  1. smalivm: Dalvik 메서드를 실행하기 위한 가상 머신 샌드박스를 제공합니다. 메서드를 실행한 후에는 모든 실행 경로에 대한 가능한 레지스터 및 클래스 값의 그래프를 반환합니다. 파일 및 네트워크 I/O와 같이 일부 값을 알 수 없는 경우에도 작동합니다. 예를 들어, 값을 알 수 없는 if 또는 switch 조건문이 있으면 두 분기를 모두 실행합니다.
  2. simplify: smalivm의 실행 그래프를 분석하여 상수 전파, 죽은 코드 제거, 리플렉션 해제, 일부 피호홀 최적화를 적용합니다. 이러한 최적화는 상당히 단순하지만, 반복적으로 함께 적용하면 문자열을 복호화하고, 리플렉션을 제거하며, 코드를 크게 단순화합니다. 메서드와 클래스의 이름은 변경하지 않습니다.
  3. demoapp: smalivm을 자신의 프로젝트에 사용하기 위한 간단하고 주석이 많이 포함된 예제가 들어 있습니다. Dalvik 코드를 실행해야 하는 무언가를 만드는 중이라면 이곳을 확인하세요.

사용법

root@kitploit:~
usage: java -jar simplify.jar <input> [options]
deobfuscates a dalvik executable
 -et,--exclude-types <pattern>   Exclude classes and methods which include REGEX, eg: "com/android", applied after include-types
 -h,--help                       Display this message
 -ie,--ignore-errors             Ignore errors while executing and optimizing methods. This may lead to unexpected behavior.
    --include-support            Attempt to execute and optimize classes in Android support library packages, default: false
 -it,--include-types <pattern>   Limit execution to classes and methods which include REGEX, eg: ";->targetMethod\("
    --max-address-visits <N>     Give up executing a method after visiting the same address N times, limits loops, default: 10000
    --max-call-depth <N>         Do not call methods after reaching a call depth of N, limits recursion and long method chains, default: 50
    --max-execution-time <N>     Give up executing a method after N seconds, default: 300
    --max-method-visits <N>      Give up executing a method after executing N instructions in that method, default: 1000000
    --max-passes <N>             Do not run optimizers on a method more than N times, default: 100
 -o,--output <file>              Output simplified input to FILE
    --output-api-level <LEVEL>   Set output DEX API compatibility to LEVEL, default: 15
 -q,--quiet                      Be quiet
    --remove-weak                Remove code even if there are weak side effects, default: true
 -v,--verbose <LEVEL>            Set verbosity to LEVEL, default: 0

빌드

빌드하려면 Java Development Kit 8 (JDK)가 설치되어 있어야 합니다.

이 프로젝트는 안드로이드 프레임워크의 서브모듈을 포함하고 있으므로 --recursive 옵션으로 클론하거나:

root@kitploit:~
git clone --recursive https://github.com/CalebFenton/simplify.git

다음 명령어로 언제든지 서브모듈을 업데이트할 수 있습니다:

root@kitploit:~
git submodule update --init --recursive

그런 다음, 모든 의존성을 포함하는 단일 jar 파일을 빌드하려면:

root@kitploit:~
./gradlew fatjar

Simplify jar 파일은 simplify/build/libs/에 위치합니다. 제공된 난독화 예제 앱을 단순화하여 정상 작동을 테스트할 수 있습니다. 실행 방법은 다음과 같습니다 (simplify.jar 경로는 필요에 따라 변경하세요):

root@kitploit:~
java -jar simplify/build/libs/simplify.jar -it "org/cf/obfuscated" -et "MainActivity" simplify/obfuscated-app.apk

무엇이 난독화 해제되는지 이해하려면 Obfuscated App의 README를 확인하세요.

문제 해결

Simplify가 실패하면 다음 권장 사항을 순서대로 시도해보세요:

  1. -it 옵션을 사용하여 몇 개의 메서드나 클래스만 대상으로 지정하세요.
  2. 최대 방문 횟수 초과로 인한 실패라면 --max-address-visits, --max-call-depth, --max-method-visits 값을 높여보세요.
  3. -v 또는 -v 2 옵션으로 실행하고 로그와 DEX 또는 APK의 해시를 함께 문제를 보고하세요.
  4. 다시 시도하되, 눈을 마주치지 마세요. Simplify는 공포를 감지할 수 있습니다.

Windows에서 빌드할 때 다음과 유사한 오류로 빌드가 실패하는 경우:

Could not find tools.jar. Please check that C:\Program Files\Java\jre1.8.0_151 contains a valid JDK installation.

이는 Gradle이 올바른 JDK 경로를 찾지 못함을 의미합니다. JDK가 설치되어 있는지 확인하고, JAVA_HOME 환경 변수를 JDK 경로로 설정한 후, 빌드에 사용하는 명령 프롬프트를 닫고 다시 열어주세요.

기여

망설이지 마세요. 저는 가상 실행과 난독화 해제가 매우 흥미로운 문제라고 생각합니다. 관심 있는 사람은 자동으로 멋진 사람이며, 오타 수정만 해도 기여는 환영입니다. 이슈에서 질문하고 풀 리퀘스트를 제출해 주세요.

이슈 보고

APK나 DEX 링크와 사용 중인 전체 명령어를 포함해 주세요. 그래야 문제를 재현하고 수정하기가 훨씬 쉽습니다.

샘플을 공유할 수 없는 경우, 파일 해시(SHA1, SHA256 등)를 꼭 포함해 주세요.

최적화 전략

상수 전파

명령어가 문자열, 숫자, 부울 등 상수로 변환 가능한 유형의 값을 배치하는 경우, 이 최적화는 해당 명령어를 상수로 대체합니다. 예를 들어:

root@kitploit:~
const-string v0, "VGVsbCBtZSBvZiB5b3VyIGhvbWV3b3JsZCwgVXN1bC4="
invoke-static {v0}, Lmy/string/Decryptor;->decrypt(Ljava/lang/String;)Ljava/lang/String;
# Decrypts to: "Tell me of your homeworld, Usul."
move-result v0

이 예제에서 암호화된 문자열이 복호화되어 v0에 배치됩니다. 문자열은 "상수화 가능"하므로 move-result v0를 const-string으로 대체할 수 있습니다:

root@kitploit:~
const-string v0, "VGVsbCBtZSBvZiB5b3VyIGhvbWV3b3JsZCwgVXN1bC4="
invoke-static {v0}, Lmy/string/Decryptor;->decrypt(Ljava/lang/String;)Ljava/lang/String;
const-string v0, "Tell me of your homeworld, Usul."

죽은 코드 제거

코드를 제거해도 앱의 동작을 절대 변경할 수 없다면 그 코드는 죽은 코드입니다. 가장 명확한 경우는 코드에 도달할 수 없는 경우입니다(예: if (false) { // dead }). 코드에 도달할 수 있더라도 메서드 외부의 상태에 영향을 미치지 않는다면(즉, 부작용이 없다면) 죽은 코드로 간주될 수 있습니다. 예를 들어, 코드가 메서드의 반환값에 영향을 주지 않거나, 클래스 변수를 변경하지 않거나, I/O를 수행하지 않는 경우입니다. 정적 분석에서는 이를 판단하기 어렵습니다. 다행히 smalivm은 영리할 필요가 없습니다. 그냥 할 수 있는 모든 것을 무식하게 실행하고, 확실하지 않으면 부작용이 있다고 가정합니다. 상수 전파의 예제를 고려해보세요:

root@kitploit:~
const-string v0, "VGVsbCBtZSBvZiB5b3VyIGhvbWV3b3JsZCwgVXN1bC4="
invoke-static {v0}, Lmy/string/Decryptor;->decrypt(Ljava/lang/String;)Ljava/lang/String;
const-string v0, "Tell me of your homeworld, Usul."

이 코드에서 invoke-static은 더 이상 메서드의 반환값에 영향을 주지 않으며, 파일 시스템에 바이트를 쓰거나 네트워크 소켓에 쓰는 등의 이상한 동작을 하지 않는다고 가정합니다. 따라서 부작용이 없으므로 간단히 제거할 수 있습니다.

root@kitploit:~
const-string v0, "VGVsbCBtZSBvZiB5b3VyIGhvbWV3b3JsZCwgVXN1bC4="
const-string v0, "Tell me of your homeworld, Usul."

마지막으로 첫 번째 const-string은 레지스터에 값을 할당하지만, 그 값은 사용되지 않습니다. 즉, 할당이 죽은 것입니다. 이것도 제거할 수 있습니다.

root@kitploit:~
const-string v0, "Tell me of your homeworld, Usul."

만세!

리플렉션 해제

자바의 정적 분석에서 가장 큰 도전 과제 중 하나는 리플렉션입니다. 신중한 데이터 흐름 분석 없이는 리플렉션 메서드의 인수를 알 수 없습니다. 이를 해결하는 똑똑하고 영리한 방법이 있지만, smalivm은 코드를 실행하여 해결합니다. 리플렉션 메서드 호출(예: 아래와 같은)을 발견하면:

root@kitploit:~
invoke-virtual {v0, v1, v2}, Ljava/lang/reflect/Method;->invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;

v0, v1, v2의 값을 알 수 있습니다. 값이 확실하다면 Method.invoke() 호출을 실제 리플렉션이 아닌 메서드 호출로 대체할 수 있습니다. 이는 리플렉션 필드 및 클래스 조회에도 동일하게 적용됩니다.

피호홀

특정 범주에 깔끔하게 들어맞지 않는 모든 것에는 피호홀 최적화가 적용됩니다. 여기에는 불필요한 check-cast 명령어 제거, Ljava/lang/String;-><init> 호출을 const-string으로 대체하는 작업 등이 포함됩니다.

난독화 해제 예제

최적화 전

root@kitploit:~
.method public static test1()I
    .locals 2

    new-instance v0, Ljava/lang/Integer;
    const/4 v1, 0x1
    invoke-direct {v0, v1}, Ljava/lang/Integer;-><init>(I)V

    invoke-virtual {v0}, Ljava/lang/Integer;->intValue()I
    move-result v0

    return v0
.end method

이것이 하는 일은 v0 = 1뿐입니다.

상수 전파 후

root@kitploit:~
.method public static test1()I
    .locals 2

    new-instance v0, Ljava/lang/Integer;
    const/4 v1, 0x1
    invoke-direct {v0, v1}, Ljava/lang/Integer;-><init>(I)V

    invoke-virtual {v0}, Ljava/lang/Integer;->intValue()I
    const/4 v0, 0x1

    return v0
.end method

move-result v0가 const/4 v0, 0x1로 대체되었습니다. 이는 intValue()I의 반환값이 하나뿐이고 반환 유형을 상수로 만들 수 있기 때문입니다. 인수 v0와 v1은 명확하며 변경되지 않습니다. 즉, intValue()I의 가능한 모든 실행 경로에 대해 값의 합의가 있습니다. 상수로 변환할 수 있는 다른 유형의 값:

  • 숫자 - const/4, const/16 등
  • 문자열 - const-string
  • 클래스 - const-class

죽은 코드 제거 후

root@kitploit:~
.method public static test1()I
    .locals 2

    const/4 v0, 0x1

    return v0
.end method

const/4 v0, 0x1 위의 코드는 메서드 외부 상태에 영향을 미치지 않으므로(부작용 없음) 동작을 변경하지 않고 제거할 수 있습니다. 파일 시스템이나 네트워크에 무언가를 쓰는 메서드 호출이 있었다면 메서드 외부 상태에 영향을 미치므로 제거할 수 없습니다. 또는 test()I가 LinkedList와 같은 변경 가능한 인수를 받았다면, 해당 인수에 접근하는 명령어는 죽은 것으로 간주할 수 없습니다.

죽은 코드의 다른 예:

  • 참조되지 않은 할당 - 레지스터 할당 후 사용하지 않음
  • 도달할 수 없는 명령어 - if (false) { dead_code(); }

라이선스

이 도구는 이중 라이선스로 제공됩니다: 폐쇄 소스 프로젝트에 적합한 상업용 라이선스와 오픈 소스 소프트웨어에서 사용할 수 있는 GPL 라이선스입니다.

필요에 따라 하나를 선택하고 해당 정책을 따라야 합니다. 각 라이선스 유형의 정책과 계약에 대한 자세한 내용은 LICENSE.COMMERCIAL 및 LICENSE.GPL 파일에서 확인할 수 있습니다.

추가 자료

  • Dalvik Virtual Execution with SmaliVM
  • Guillot, Yoann, and Alexandre Gazet. "Automatic Binary Deobfuscation." Journal in Computer Virology 6.3 (2010): 261-76
  • Unicorn - The ultimate CPU emulator
  • Babak Yadegari, Saumya Debray. "Symbolic Execution of Obfuscated Code"
  • 성공 사례:
    • Android Dynamic Class Loading with "AES/CFB/NoPadding" encryption. Take a peek before & after. Tool used: #simplify. #Android #obfuscation #classencryption #dex
    • Decrypting Malware String Encryption
도구 다운로드