난독화란?
- 난독화는 디스어셈블링 했을 때 쉽게 이해할 수 없도록 코드를 변환하는 과정이다.
- 모든 소프트웨어 보호 계획의 필수적인 부분이다.
근데 뱅킹 앱 등 주요 상용 앱들도 난독화가 대부분 안돼있다...
- 앱은 난독화를 거친 후에도 기능은 정상적으로 동작한다. (그냥 우리가 분석하기에만 더럽게 바꿔놓는 것)
- 난독화는 OnOff처럼 쉽게 껐다 켰다 할 수 있는 게 아니다.
- 부분 혹은 전체, 또 난독화 정도가 다르게 할 수도 있다.
난독화 기법이 절대로 리버서가 분석을 못하도록 만드는 기법은 아니다.
항상 명심해야 할 것은 보호기법들은 분석을 늦추기 위해 힘 쓰는 것일 뿐이다.
다만, 여러가지 보호기법들을 다양하게 다 걸어 놓는다면 분석 시작까지 상당한 시간을 지연시킬 수도 있고,
운이 좋다면 공격자가 포기하고 다른 앱을 겨냥하도록 만들 수도 있다. (결국은 공격비용 문제)
난독화의 종류
- Name obfuscation
- Instruction substitution
- Control flow flattening
- Dead code injection
- String encryption
Name Obfuscation
일반적인 컴파일러는 소스코드에 있는 클래스명과 함수명을 기반으로 심볼을 만든다.
따라서 난독화가 적용되지 않는다면 심볼들이 의미있는 형태로 그대로 남아 공격자가 분석하기 쉽게 도와준다.
예시 : 탈옥탐지 함수를 넣었다고 하더라도, "jailbreak"과 같은 쉽게 찾을 수 있는 문자열 형태로 그대로 남음.
DVIA-v2 (Swift)의 앱을 예시로 보자.
Swift는 명명규칙이 특이해서 한번 찾아보는게 이해에 도움이 되지만, 어쨋든 그냥 봐도 Jailbreak와 관련된 문자열이 보이고, 공격자는 이를 보고 분석을 해봐야겠다는 생각이 든다.
반대로 난독화를 거친 후에는 어떤 함수인지 이름만 보고는 파악할 수 없으므로, 분석을 지연시키기 좋다.
[난독화 전] __T07DVIA_v232JailbreakDetectionViewControllerC20jailbreakTest4TappedyypF: stp x22, x21, [sp, #-0x30]! mov rbp, rsp
[난독화 후] __T07DVIA_v232zNNtWKQptikYUBNBgfFVMjSkvRdhhnbyyFySbyypF: stp x22, x21, [sp, #-0x30]! mov rbp, rsp
지금은 이름 난독화만 시킨 상태이므로 어떤 함수를 봐야할 지 식별하는 데에는 지연을 시키겠지만, 공격자는 여전히 디스어셈블 하여 함수 내용을 분석할 순 있다.
(난독화를 거치면 분석을 못한다는 의미는 아니며, 그 난이도와 복잡도에서 차이가 많이 난다는 뜻)
Instruction Substitution (명령어 대체)
명령어를 더 복잡하게 만드는 작업이다.
[난독화 전] x = a + b
[난독화 후] x = -(-a) - (-b)
이런 식으로 결과는 동일하게 나오지만 분석을 어렵게 만들기 위한 변환 작업이다.
하지만 동일한 방식으로 명령어들을 대체하다보면, 난독화 복구 툴을 비교적 금방 만들 수 있다.
따라서 단일 케이스에 여러 대체 기술을 추가하고 무작위 인자를 도입하는 것이 좋습니다.
이 방식은 deobfuscation이 만들어질 수 있다는 취약성이 있지만, 대체 방식의 개수와 복잡도의 깊이에 따라 복호화 툴을 만드는 데에 시간을 많이 쓰도록 강요할 순 있다.
Control Flow Flattening (코드 흐름 복잡화)
원본 코드의 흐름을 더 복잡하게 만드는 방식이다.
변환은 함수의 몸체를 기본블록으로 분해하고, 프로그램 흐름을 제어하는 스위치 문을 가진 단일 무한 루프 안에 모두 넣는다. 이는 코드를 읽기 쉽게 만드는 자연적인 조건부 구조(=코드패턴)를 제거하기 때문에 훨씬 더 흐름을 쫓아가기 어렵게 만든다.

어셈블리가 아닌 소스코드로만 봐도 복잡하다.
결국 내용은 동일한데 굳이 case 2→ case값을 3으로 변환 → case3 → 동작 수행 → case값을 2로 변환 → case 2 → case값을 3으로 변환 → case3 → 동작 수행 → case값을 2로 변환 → ... 이런식으로 처리가 되도록 변환 되었다.
C++ 난독화 글 참조 : Obfuscating C++ programs via control flow flattening
Dead Code Injection (쓰레기 코드 삽입)
진짜 아무 의미 없는 쓰레기 코드를 삽입하는 방법이다.
리버서는 이 코드는 아무 의미가 없다는 것을 알아채기까지 의미없는 함수를 계속 분석하게 될 것이다.
String Encryption (문자열 암호화)
앱은 종종 하드코딩된 keys, licences, tokens, endpoint URLs를 그대로 가진 채 컴파일 되곤 한다.
이는 기본적으로 data section에 평문으로 저장된다.
문자열 난독화 기술은 이러한 평문의 주요 문자열들을 암호화하여 저장하고, 복호화 할 수 있는 stub을 삽입하여
문자열을 사용하기 직전에 복호화를 해서 사용하도록 패치하는 것이다.
추천 툴
- SwiftShield (name obfuscation)
Xcode project에서 class, method, field 이름을 식별하고 컴파일되기 전 랜덤값으로 대체한다.
SwiftShield 도구 사용법- obfuscator-llvm (근데.. 2013년 이후로 업데이트 없음)
소스코드가 아닌 IR(Intermediate Representation)에서 수행한다.
symbol obfuscation, string encryption, control flow flattening 적용 가능.
IR을 기반으로 하기 때문에 SwiftShield에 비해 훨씬 더 많은 어플리케이션 정보를 숨길 수 있다.
평가 및 검증
직접 IPA의 Mach-O와 "Frameworks" 디렉토리(.dynlib 또는 .framework 파일)에 포함된 라이브러리 파일을 디스어셈블하고 정적 분석을 수행해 보자.
최소한 앱의 핵심 기능(즉, 난독화되도록 의도된 기능)은 쉽게 식별되어서는 안 된다.
- 의미있는 식별자(class name, method name, variable name 등)가 제거되었는가?
- 바이너리에 있는 문자열은 암호화가 되었는가?
- 보호된 기능과 관련된 코드 및 데이터는 암호화, 포장 또는 은폐되었는가?
그 외 알아서 추가..;;;