개요
안녕하세요. 앞으로 몇 차례에 걸쳐 Java 난독화 기술을 심층적으로 다룰 예정입니다. 소프트웨어 난독화는 피땀 흘려 개발한 제품과 지적 재산을 보호하기 위한 필수 보안 전략입니다.
실제로 리버싱 엔지니어으로 인한 소스코드 도용 사례들을 주변에서 손쉽게 찾아 볼 수 있습니다.
2012년 시만텍(Symantec) 보안 소프트웨어 소스 코드가 유출되어 공격자들이 방어 우회를 위한 악성코드를 만들거나 시스템 취약점을 발견하기 쉬워졌습니다. 이로 인해 Symantec에서 대대적인 코스 코드 리뷰 작업과 개선 작업이 진행되었고 추가 개발 비용 또한 상당히 투입될 수밖에 없었습니다. 제품에 대한 신뢰도 저하 및 평판 훼손도 피할 수 없었습니다.
그리고 피그마(Figma) 소프트웨어의 소스 코드 도용으로 인한 소송 사건도 대표적인 도용 사례로 언급됩니다. Figma 어플리케이션을 역컴파일 하는 등 리버스 엔지니어링으로 코드를 분석하여 구조와 UI 동작 방식을 그대로 모방한 소프트웨어를 개발한 클론 제품이 출시되어 Figma에서는 이에 대해 저작권 침해 및 계약 위반으로 소송을 제기했습니다.
개발한 앱이 손쉽게 리버스 엔지니어링되어 무단 복제ㆍ변조가 이루어진다면 복제 앱이 시장을 잠식하거나 크랙 버전이 유포되어 기업에 큰 타격을 입힐 수 있습니다.
앞으로 세 차례에 걸쳐 대표적인 Java 난독화 기법을 다룰 예정이며, 오늘은 첫 번째인 Control Flow 난독화를 집중적으로 살펴봅니다.
1. Control Flow 난독화란?
Control Flow(CF) 난독화는 프로그램의 제어 흐름(Control Flow Graph)을 의도적으로 변형해 로직 분석과 역공학을 어렵게 만드는 기법입니다. 핵심 알고리즘을 숨기고 해킹·변조를 방지하기 위해 사용됩니다.
2. Control Flow 난독화의 원리와 주요 기법
분류 | 설명 |
---|---|
Flattening(평탄화) | 모든 분기를 하나의 거대한 루프와 switch로 평탄화해 CFG를 난해하게 만듦 |
Opaque Predicate(불투명 조건식) | 항상 참/거짓으로 평가되지만 분석자가 쉽게 알 수 없는 조건 삽입 |
Dead Code 삽입 | 실행되지 않는 코드를 넣어 분석 시간 증가 |
조건문·반복문 재배치 | 코드 블록 순서를 바꿔 실제 흐름 추적을 어렵게 함 |
Switch‑case 확장 | 단순 if 를 복잡한 switch 로 변환, 가짓수 폭발 유도 |
Irreducible CFG 생성 | 자연스러운 루프 구조를 깨 변환 도구가 이해하기 힘든 그래프 구성 |
중첩 try–catch | 불필요한 예외 흐름 추가로 스택 트레이스를 흐림 |
3. Control Flow 난독화의 예제 코드
3.1 조건문과 반복문 재배치
난독화 전의 코드 예시
for (int i = 0; i < 10; i++) {
if (i % 2 != 0) {
System.out.println("Odd Number: " + index);
} else {
System.out.println("Even Number: : " + index);
}
}
난독화 후의 코드 예시
int index = 0;
int limit = 10;
boolean continueLoop = true;
while (continueLoop) {
if (index >= limit) {
continueLoop = false;
continue;
}
// Opaque predicate: XOR 후 하위 1비트 확인 → 가독성 저하 목적
if (((index ^ 0x5) & 1) == 0) {
System.out.println("Even Number: " + index);
} else {
System.out.println("Odd Number: " + index);
}
int dummy = (index * 17) % 3; // dead calculation
if (index > 1000) { // never taken
System.out.println("Dummy branch");
}
index++;
}
3.2 Dead Code & Opaque Predicate 삽입
난독화 전의 코드 예시
int sum(int a, int b) {
return a + b;
}
난독화 후의 코드 예시
public static int sum(int a, int b) {
int result = a + b;
// **Opaque predicate** – 논리적으로 불가능하지만 분석 시점엔 불명확
if (a != b && (a - b) > Integer.MAX_VALUE) {
result = 42; // unreachable
}
// 실행되지 않는 루프
for (int i = 0; i < 0; i++) {
result += i;
}
try {
if (false) {
throw new Exception("Dummy");
}
} catch (Exception e) {
result *= 2;
}
return result;
}
3.3 스위치(switch) 구문 활용
난독화 전의 코드 예시
int increment(int x) {
if (x < 0) {
return;
}
return x + 1;
}
난독화 후의 코드 예시
public static int increment(int x) {
if (x < 0) {
return;
}
// 계산 과정에서 불필요한 산술 연산을 추가
int temp = (x * 13 + 7) % 7;
switch (temp) {
case 0:
case 1:
// 중첩 switch 구문으로 단순 동작을 감춤
switch (x % 2) {
case 0:
case 1:
return x + 1;
default:
return x + 1;
}
case 2:
case 3:
if (x < 0) { // 절대 참이 되지 않거나 결과에 영향 없는 분기
return x;
} else {
return x + 1;
}
case 4:
return x + 1;
case 5:
case 6:
return x + 1;
default:
return x;
}
}
3.4 복잡한 예외 처리(try-catch)
난독화 전의 코드 예시
int divide(int a, int b) {
return a / b;
}
난독화 후의 코드 예시
public static int divide(int a, int b) {
int res = 0;
try {
// 실제 나눗셈 연산
res = a / b;
// 첫 번째 중첩 try 블록으로 불필요한 예외 흐름 도입
try {
if (b == 1) {
throw new Exception("Forced exception for b==1");
}
// 산술 연산과 무관한 불필요한 체크
int bogus = (a * b) % 3;
if (bogus == 0 && a != 0) {
throw new Exception("Dummy unreachable");
}
} catch (Exception e) {
// 예외 발생 시 아무런 처리 없이 원래 값을 유지
res = res;
}
// 두 번째 중첩 try 블록으로 불필요한 반복 처리
try {
for (int i = 0; i < 1; i++) {
int temp = res * 1; // 산술 연산에 영향을 주지 않는 연산
}
} catch (Exception ex) {
// 예외 발생 시 아무런 조치도 취하지 않음
}
} catch (ArithmeticException e) {
// 실제 0으로 나누었을 때의 예외 처리
res = 0;
}
// 추가적인 불필요한 조건문
if (res == 0 && a != 0) {
res = 0;
}
return res;
}
4. Control Flow 난독화의 장점과 단점
장점
- 핵심 알고리즘 보호, 역공학 난이도 급증
- 자동화 툴(디컴파일러) 출력 난독화 → 분석 지연
단점
- 가독성 및 유지보수 악화, 디버깅 어려움
- JIT 최적화 저하·메서드 수 증가로 성능 하락 가능
- 과도한 CF 변형은 Play Integrity 등 변조 탐지에 걸릴 위험
6. Control Flow 난독화를 지원하는 대표적인 도구 소개
- dexguard
- 자바 및 안드로이드 애플리케이션 보호를 위해 널리 사용됩니다. 특히 코드 난독화, 최적화, 클래스 및 메서드 이름 변경 등의 기능을 지원합니다.
- Allatori
- 자바 코드 보호를 위한 상용 솔루션으로, 제어 흐름 난독화를 강력히 지원하며 문자열 암호화와 같은 다양한 기능을 제공합니다.
- DashO
- 성능 손실을 최소화하면서 제어 흐름 난독화를 수행하는 도구로, 다양한 플랫폼 지원과 함께 추가적인 보안 기능을 제공합니다.
7. NHN AppGuard Control Flow 난독화
글로벌 IT 기업 NHN이 직접 개발한 보안 솔루션인 NHN AppGuard는 모바일 앱에 특화된 상용 보안 도구로, 복잡한 설정 없이도 손쉽게 Java 난독화를 적용할 수 있습니다. 이 솔루션은 제어 흐름 난독화뿐만 아니라 문자열 암호화와 함수 호출 숨김 등 고급 난독화 기능을 탑재하고 있습니다.
NHN AppGuard에서 제공하는 대표적인 Control Flow 난독화는 Inline Method 난독화입니다.
Inline Method 난독화란 다수의 메서드를 하나의 메서드로 합쳐서 난독화(Obfuscation)하는 기법입니다. 결과적으로 클래스 내부에 임시로 새로 만들어진 메서드 안에 여러 다른 메서드들이 합쳐진 뒤, 원래 메서드는 그 내부에서 만들어진 스위치(또는 분기) 로직을 통해 호출되도록 수정됩니다.
사례로 살펴보면 아래와 같습니다.
난독화 전 | 난독화 후 |
---|---|
![]() |
![]() |
이와 같이 NHN AppGuard는 앱 운영자가 보안 문제에 대한 걱정 없이 안정적으로 서비스를 제공할 수 있도록 지원하며,
강력한 Java 보안 솔루션을 통해 소스 코드 분석과 역공학 공격으로부터 보호할 수 있습니다.
다음 시간에는 문자열(String) 난독화 기법에 대해 알아보겠습니다. 앞으로 이어질 난독화 시리즈에 많은 관심 부탁드립니다!
'BLOG > 인사이드' 카테고리의 다른 글
iOS 앱 개발자가 알아야 할 iOS탈옥의 위험성 (0) | 2025.03.20 |
---|---|
모바일 앱 난독화란? (0) | 2025.03.11 |
GPS 조작 어뷰징 탐지/차단 (0) | 2024.07.03 |
2024년 상반기 결산 및 로드맵 (0) | 2024.06.26 |
[칼럼] 모바일 생태계를 위협하는 변조앱(MOD)과 대응 방법 (0) | 2023.11.09 |