본문 바로가기
.NET/MAUI

MAUI 디컴파일 회피 검토

by leo21c 2026. 1. 12.

AI의 도움으로 아래와 같은 정보를 확인했다.

나는 아래 방법 중에 안드로이드용 so 파일을 제작해서 사용하는 방법을 이용하려고 한다.

기존에 C#으로 개발한 프로그램도 인증이나 Key 처리는 DLL을 제작해서 사용을 했기 때문이다.


NET MAUI(Multi-platform App UI)로 개발된 안드로이드 앱(APK/AAB)도 C# 윈도우 프로그램과 마찬가지로 디컴파일이 가능하며, 소스 코드를 복원하는 것이 비교적 쉽습니다.

특히 전력 제어 장치(Recloser 등)와 같은 중요 인프라를 다루는 소프트웨어에서 **하드코딩된 암호화 키(Key)**가 노출되는 것은 보안상 매우 치명적입니다. 제공해주신 문서 내용과 귀하의 개발 환경(C++, C#, MAUI)을 고려하여, 디컴파일 위험성과 암호화 키 보호 방안을 정리해 드립니다.

 

1. MAUI APK 디컴파일 가능 여부

결론: 가능합니다.

  • 원리: MAUI로 빌드된 APK 파일은 내부적으로 압축 파일과 같습니다. 이 압축을 풀면 assemblies 폴더 내에 .dll 파일들이 들어 있습니다. 이 DLL들은 C# 코드가 컴파일된 MSIL(Intermediate Language) 형태이므로, dotPeek, ILSpy, dnSpy 같은 도구를 사용하면 원본 소스와 거의 유사한 수준으로 복원이 가능합니다.
  • 위험성: 소스 코드 내에 string SecretKey = "1234...";와 같이 키를 문자열로 선언해 두었다면, 디컴파일 툴의 '문자열 검색' 기능만으로도 몇 초 안에 키를 찾아낼 수 있습니다.

2. 암호화 키 보호 및 소스 코드 보안 전략

완벽한 방어는 불가능하지만, 해커가 키를 찾아내는 데 드는 비용과 시간을 비약적으로 높이는 '심층 방어(Defense in Depth)' 전략을 사용해야 합니다.

A. 코드 난독화 (Obfuscation) [필수]

가장 기본적이고 필수적인 조치입니다. 난독화 도구는 클래스, 메서드, 변수 이름을 a(), b() 처럼 의미 없는 문자로 바꾸고, 제어 흐름을 꼬아서 코드를 읽기 어렵게 만듭니다.

  • 도구:
    • Dotfuscator: Visual Studio에 기본 포함(Community 버전)되어 있거나 상용 버전을 사용할 수 있습니다.
    • ConfuserEx: 오픈 소스 난독화 도구로 강력한 기능을 제공합니다.
  • 효과: 키 변수명이 숨겨지고 코드가 꼬이지만, 문자열(String) 자체가 평문으로 남아있으면 여전히 위험합니다. 따라서 '문자열 암호화(String Encryption)' 옵션을 반드시 켜야 합니다.

B. NDK(Native Development Kit) 활용 (C++ 라이브러리) [추천]

귀하께서 C++ 개발 경험이 있으시므로 이 방법이 매우 효과적입니다.

  • 방법: 중요한 암호화 키 생성 로직이나 통신 프로토콜의 핵심 부분을 **C++(.so 라이브러리)**로 작성하고, MAUI(C#)에서 JNI(Java Native Interface) 또는 P/Invoke를 통해 호출합니다.
  • 장점: C++로 컴파일된 .so 파일은 기계어(Assembly)로 되어 있어, C# DLL(IL 코드)보다 리버스 엔지니어링 난이도가 훨씬 높습니다. (IDA Pro 같은 전문 툴을 써야 분석 가능)
  • 적용 예시:
    • 제공된 자료에서 언급된 AES-CMACAES-CTR 로직과 키 관리 부분을 C++ 라이브러리로 구현하여 APK에 포함시킵니다.

C. Android Keystore 시스템 사용 (Secure Storage) [가장 안전]

키를 소스 코드에 두지 않고, OS가 제공하는 보안 영역에 저장하는 방식입니다.

  • 방법: MAUI의 Microsoft.Maui.Storage.SecureStorage 또는 안드로이드 네이티브 API인 Android Keystore System을 사용합니다.
  • 원리: 앱이 설치된 후, 암호화 키를 TEE(Trusted Execution Environment) 또는 **SE(Secure Element)**라는 하드웨어 보안 영역에 저장합니다. 이 영역은 루팅된 폰에서도 추출이 매우 어렵습니다.
  • 시나리오:
    1. 앱 최초 실행 시 서버로부터 키를 받거나, 난수를 통해 생성합니다.
    2. 생성된 키를 SecureStorage에 저장합니다.
    3. 이후 통신 시 저장소에서 키를 꺼내 사용합니다.

D. 키 파생 및 동적 생성 (Key Derivation)

소스 코드에 '완성된 키'를 두지 않고, 런타임에 계산해서 만듭니다.

  • 방법: 키를 여러 조각으로 나누어 코드 곳곳에 숨기거나, 특정 알고리즘(XOR 연산 등)을 통해 런타임에 조립하여 메모리 상에서만 잠시 존재하게 합니다.
  • 참고: 제공된 자료의 IEEE 1686 보안 표준 을 준수하기 위해, 고정된 마스터 키보다는 Diffie-Hellman (ECDH) 알고리즘을 사용하여 통신 세션마다 새로운 세션 키를 생성하는 방식이 가장 안전합니다. 블루투스 연결 시 이 과정을 수행하면 고정 키 탈취 위험을 원천 차단할 수 있습니다.

3. 요약 및 제안

귀하의 프로젝트(CMR 안드로이드 앱) 에 적합한 단계별 보안 조치는 다음과 같습니다.

  1. 난독화 적용 (기본): 배포 전 반드시 Dotfuscator 등을 통해 난독화를 수행하십시오.
  2. C++ 네이티브 이전 (중급): 이미 C++에 익숙하시므로, AES-CMAC, AES-CTR 관련 키 처리 로직을 C++(.so)로 옮기십시오. 이것만으로도 일반적인 디컴파일 시도는 대부분 막을 수 있습니다.
  3. Android Keystore 활용 (고급): 키를 소스 코드에 하드코딩하지 말고, 앱 실행 시 안전한 저장소(Keystore)에서 불러오도록 설계하십시오.
LIST