C#은 왜 디컴파일에 취약할까?
#C-FamilyC#의 컴파일 과정과 실행 과정 그리고 그 취약점에 대해서
C#의 활용력은 정말로 넓다. 윈도우 앱, 웹 개발, 클라우드, 모바일, IOT 그리고 게임까지 정말 만능인 거 같다.
또한 이식성이 매우 뛰어나다. 윈도우 환경에서 개발한 C# 소프트웨어를 .NET
이 구축된 리눅스와 맥에서 실행할 수 있다(물론 제약 사항은 존재한다). 이 이식성을 위해서 설계한 부분이
C#의 취약점을 낳았다.
컴파일 과정
우선 C#의 컴파일과 실행 과정을 살펴 보아야 한다.
우리가 작성한 C# 코드는 C# 컴파일러에 의해 중간 언어(Intermediate Language, IL)
가 만들어진다.
우리가 C# 프로그램을 실행하면 CLR(Common Language Runtime)
이 IL 언어를 JIT(Just-in-Time)
컴파일러로 컴파일하여 실행 가능한 네이티브 코드
를 만들어서 실행한다.
이렇게 컴파일을 두 번이나 하는 이유는 이식성
때문이다. IL 파일만 가지고 있으면 CLR이 구축된 어느 환경에서도 실행이 가능하다.
마치 자바의 JVM(자바 가상 머신)
과 느낌이 비슷하다. 이 과정에서 자바와 C#은 피할 수 없는 취약점을 안고 다닐 수 밖에 없다.
디컴파일에 취약
바로 디컴파일이 매우 쉽다는 것이다. C#의 실행파일(exe, dll 등)은 IL(중간 언어)를 가지고 있다. 이 중간 언어에는 아주 풍부한 메타데이터가 들어있고 이것을 해석하면 원본 소스 코드와 거의 유사하게 코드가 복원이 된다. 흔히 dotpeek이라는 소프트웨어를 이용해서 디컴파일한다. 역시 자바도 마찬가지이다. 자바도 jd-gui를 이용하면 쉽게 디컴파일이 된다.
취약점 극복
취약점 극복의 방법으로 다음과 같은 방법이 있다.
- 코드 난독화
Dotfuscator
같은 난독화 소프트웨어를 이용해서 코드를 난독화 시키는 것이다. 설령 디컴파일이 된다고 해도 코드 해석에 어려움을 주는 것이다.
- C++ DLL 활용
내부 중요한 로직은 C++ DLL로 만들어서 C#에서는 호출만 한다면 디컴파일을 어렵게 할 수 있다. 물론 C++도 리버싱의 위험에서 자유롭지 못하지만 C언어나 C#에 비하면 비교적 리버싱이 어려운 편이다.