Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

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

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

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

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
zyrox — Zyrox: LLVM 기반의 컴파일 타임 난독화 플러그인. | Kitploit
도구/GitHubGitHub/peterhackz/zyrox
Static AnalysisCode AnalysisReverse EngineeringBinary AnalysisPapers & ResearchLearning & EducationLearning Paths & Courses
GitHubpeterhackz/zyrox

zyrox

Zyrox: LLVM 기반의 컴파일 타임 난독화 플러그인.

저장소 보기
9411167개월 전Kitploit 검토 완료

인기

모두 보기 →

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

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
웹사이트
공유

Zyrox LLVM 난독화 도구

네이티브 코드를 난독화하는 llvm 컴파일 및 링크 타임 플러그인

왜

why not ¯\_(ツ)_/¯

제 가장 큰 프로젝트 중 하나로, LLVM 내부, 바이너리 포맷, 어셈블리, 난독화 기법에 대해 많이 배운 프로젝트입니다.

무언가를 만들면서 배우는 것이 가장 좋은 학습 방법이라고 믿기 때문에, 이 프로젝트를 통해 이 주제들을 더 깊게 배우고자 만들었습니다.

연구

저는 Zyrox의 개념을 설명하는 블로그 4개를 작성했습니다:

  • Part I: Zyrox 빌드하기: 커스텀 LLVM 난독화 도구
  • Part II: 제어 흐름 평탄화
  • Part III: 암호화된 점프 테이블
  • Part IV: 피날레

이 글들은 이 README보다 더 깊이 다루며, 주제에 관심이 있다면 꼭 읽어볼 가치가 있습니다.

빌드

템플릿 사용 (빠른 시작, 권장)

Zyrox를 _빠르게 테스트_하거나 CMake 프로젝트에 통합하는 방법을 배우려는 사람을 위한 것입니다.

Zyrox Template 저장소의 단계를 따르세요.

소스에서 빌드

llvm 설치:

sudo apt update
sudo apt install llvm-18 llvm-18-dev clang-18

zyrox 클론 및 컴파일:

git clone --recurse-submodules https://github.com/PeterHackz/zyrox.git
cd zyrox
cmake -S . -B build -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++
cmake --build build --parallel 4

Python (컴파일 후) 플러그인 설정

python3와 pip가 설치되어 있는지 확인하세요.

환경 설정 (권장)

# Create a virtual environment
python3 -m venv .venv

# Activate the env
source .venv/bin/activate

pip install -r requirements.txt

전역 설치

pip install -r requirements.txt

사용법

빠른 사용법

clang -O0 -flto=full -c main.c -o out/main.o
clang -flto=full -fuse-ld=lld -Wl,--load-pass-plugin=./build/libzyrox.so out/main.o -o out/main

난독화 후 PyPlugin.py를 실행하여 점프 테이블을 암호화하세요:

# if you installed dependencies in a virtual environment, activate it first:
source .venv/bin/activate
#  then run with:
python PyPlugin.py --in=<input_file> [--out=<output_file>] [--tables=<zyrox_tables_file>] [--android]

CMake와 함께 사용하기

CMake 통합 예제는 Zyrox Template 저장소를 확인하세요.

연락처

이 주제가 복잡하다는 점을 알고 있습니다. 이 프로젝트는 주로 교육 목적으로 만들어졌으며, BSD Brawl을 지원하기 위해서도 만들어졌습니다.

질문이 있거나 그냥 대화하고 싶다면 언제든지 연락하세요:

  • Discord: @s.b
  • Email: [email protected] 또는 [email protected]
  • Discord 서버

풀 리퀘스트나 이슈를 통한 모든 도움에 감사드립니다!

동작 방식

ZyroxPlugin.cpp는 패스를 등록한 다음 siphash를 링크하고(자세한 내용은 나중에) StringEncryption을 호출하여 문자열을 암호화합니다.

문자열을 초기에 암호화하는 이유는 나중에 복호화 로직도 함께 난독화되도록 하기 위해서입니다.

그런 다음 ModuleUtils::ExpandCustomAnnotations와 QuickConfig::RegisterPasses를 호출하여 모든 __attribute__((annotate("..."))) 표현식을 파싱하고 QuickJs 구성을 실행합니다 (ZyroxConfig.js에 위치).

모든 함수는 ZyroxCore.cpp에 있는 Zyrox::RunOnFunction을 호출하여 난독화됩니다. 이에 대한 자세한 문서는 추후 제공될 예정입니다.

추가 유틸

스위치는 점프 테이블을 만들고 PHI 노드는 다루기 까다롭기 때문에 FunctionUtils와 BasicBlockUtils를 사용하여 각각 (if 문으로) 평탄화하고 강등합니다.

패스

아이고, 어디서부터 시작해야 할지

  • 기본 블록 분할기
  • 제어 흐름 평탄화
  • 간접 분기
  • 단순 간접 분기
  • 혼합 부울 산술

모든 js 플러그인 인자는 index.d.ts에 있으므로 이 문서에서는 다루지 않습니다.

어노테이션 문서는 여기를 클릭하세요.

기본 블록 분할기

이 패스는 기본 블록을 더 작은 블록들로 분할하고 섞습니다. 다음과 같은 코드가 있다고 가정해 봅시다:

int __test_fn(int x)
{
    if (x == 2) {
        printf("x is 2\n");
    } else {
        printf("x is not 2!, x is: %d\n", x);
    }
    return x + 4 * x - 2 / 4;
}

다음과 같이 컴파일됩니다:

define internal i32 @__test_fn(i32 noundef %0) #0 !zyrox !8 !obfuscated !11 {
  %2 = alloca i32, align 4
  store i32 %0, ptr %2, align 4
  %3 = load i32, ptr %2, align 4
  %4 = icmp eq i32 %3, 2
  br i1 %4, label %5, label %7

5:                                                ; preds = %1
  %6 = call i32 (ptr, ...) @printf(ptr noundef @.str.1)
  br label %10

7:                                                ; preds = %1
  %8 = load i32, ptr %2, align 4
  %9 = call i32 (ptr, ...) @printf(ptr noundef @.str.2, i32 noundef %8)
  br label %10

10:                                               ; preds = %7, %5
  %11 = load i32, ptr %2, align 4
  %12 = load i32, ptr %2, align 4
  %13 = mul nsw i32 4, %12
  %14 = add nsw i32 %11, %13
  %15 = sub nsw i32 %14, 0
  ret i32 %15
}

Basic Block Splitter를 다음 구성으로 사용하면:

z.RegisterPass(ObfuscationType.BasicBlockSplitter, {
    PassIterations: 1,
    "BasicBlockSplitter.SplitBlockChance": 100,
    "BasicBlockSplitter.SplitBlockMinSize": 2,
    "BasicBlockSplitter.SplitBlockMaxSize": 5,
});

다음과 같이 변합니다:

define internal i32 @__test_fn(i32 noundef %0) #0 !zyrox !8 !obfuscated !11 {
  %2 = alloca i32, align 4
  store i32 %0, ptr %2, align 4
  %3 = load i32, ptr %2, align 4
  %4 = icmp eq i32 %3, 2
  br i1 %4, label %5, label %14

5:                                                ; preds = %1
  %6 = call i32 (ptr, ...) @printf(ptr noundef @.str.1)
  br label %7

7:                                                ; preds = %14, %5
  %8 = load i32, ptr %2, align 4
  %9 = load i32, ptr %2, align 4
  %10 = mul nsw i32 4, %9
  %11 = add nsw i32 %8, %10
  br label %12

12:                                               ; preds = %7
  %13 = sub nsw i32 %11, 0
  ret i32 %13

14:                                               ; preds = %1
  %15 = load i32, ptr %2, align 4
  %16 = call i32 (ptr, ...) @printf(ptr noundef @.str.2, i32 noundef %15)
  br label %7
}

이런 작은 함수의 경우 크게 달라 보이지 않지만, 기본 블록을 분할하는 것을 볼 수 있습니다. 이는 제어 흐름 평탄화 같은 다른 패스와 결합할 때 유용합니다.

제어 흐름 평탄화

아이고, 이 패스는 모든 패스 중 기능이 제일 많습니다 ㅋㅋ.

먼저 동작 방식을 설명한 다음 구성을 설명하겠습니다. 다음과 같은 코드가 있다고 가정해 봅시다:

LABEL_A: bool b = x == 2;
         IF EQ: goto LABEL_B
         goto LABEL_C
LABEL_B  do_stuff()
LABEL_C  do_other_stuff()
         goto LABEL_A

각 기본 블록(A, B, C)에는 고유한 디스패처 상태가 할당됩니다. 예: (단순화됨)

states = {
    1: LABEL_A,
    2: LABEL_B,
    3: LABEL_C,
};

그런 다음 모든 것을 제어하는 디스패처 블록을 주입하여 코드가 다음과 같이 됩니다:

         int state = 0;
LABEL_D  goto LABEL_CA // dispatcher label jumps to first condition block, label condition A
LABEL_CA if state == 1: goto LABEL_A
         // if not 1, go to check if it is label B (fallback)
LABEL_CB if state == 2: goto LABEL_B
LABEL_CC if state == 3: goto LABEL_CC
         // unreachable
         goto LABEL_D
LABEL_A: bool b = x == 2;
         // IF EQ: goto LABEL_B
         // goto LABEL_C
         state = 2 if b else 3 // update state for the block we want and back to dispatcher
         goto LABEL_D
LABEL_B  do_stuff()
LABEL_C  do_other_stuff()
         state = 1
         goto LABEL_D

이 방식에는 난독화 도구가 해결하는 몇 가지 결함이 있습니다. 보다시피 디스패처 변수가 하나뿐이므로 블록이 상태를 설정한 후 어디로 가는지 알 수 있어 쉽게 비난독화할 수 있습니다. 고치기 쉽습니다!

z.RegisterPass(ObfuscationType.ControlFlowFlattening, {
    PassIterations: 1,
    "ControlFlowFlattening.UseFunctionResolverChance": 60,
    "ControlFlowFlattening.UseGlobalStateVariablesChance": 60,
    "ControlFlowFlattening.UseOpaqueTransformationChance": 40,
    "ControlFlowFlattening.UseGlobalVariableOpaquesChance": 80,
    "ControlFlowFlattening.UseSipHashedStateChance": 40,
    "ControlFlowFlattening.CloneSipHashChance": 80,
});

옵션을 하나씩 살펴보겠습니다:

도구 다운로드