{{위키데이터 속성 추적}}
'''코드 난독화'''는 프로그래밍 언어로 작성된 코드에 대해 읽기 어렵게 만드는 작업이다. 대표적인 사용 예로는 프로그램에서 사용된 아이디어나 알고리즘 등을 숨기는 것 등이 있다. 코드 난독화 과정을 거친 코드를 특정 기준에 의해 심사하는 대회도 있다.

== 개요 ==
코드 난독화는 프로그램 코드의 일부 또는 전체를 변경하는 방법 중 하나로, 코드의 가독성을 낮춰 역공학에 대한 대비책을 제공한다. 난독화를 적용하는 범위에 따라 소스 코드 난독화와 바이너리 난독화로 나눌 수 있다.<ref>마이크로소프트웨어(2007.12월) 서광열의 프로그래밍 언어 이야기, 코드 난독화</ref> 또한, 난독화의 목적에 따라 각각 기술의 무단복제와 불법으로 침입하려는 프로그램을 방지하는 것으로 나뉘기도 한다.<ref>보안공학연구논문지(Journal of Security Engineering), Vol. 5, No. 2, May 2008 이병용, 최용수. Obfuscation 기술의 현황 및 분석과 향후 개발 방향</ref>

== 원리 ==
{{참고|치환 암호}}
* 필요 이상으로 복잡한, 또는 아무것도 하지 않는 코드를 작성한다.
* 관련이 없는 여러 함수들을 뒤섞는다.
* 데이터를 알아보기 힘들게 [[부호화|인코딩]]한다.
=== 만드는 방법 ===
다음과 같은 [[소수 (수론)|소수]]인지를 판별하는 [[액션스크립트|액션스크립트 3]] 소스에 있는 isPrime 함수를 난독화 시켜보자.
<syntaxhighlight lang="actionscript">
//난독화 할 함수.
function isPrime(n:int):Boolean{
	var r:int = 0;
	while(r*r<=n)r++;
	r--;//r은 [n의 제곱근]임.
	if(n==r) return false;//n이 0 또는 1
	if(n<4) return true;
	if(n%2==0 || n%3==0 || n%r==0){
		return false;
	}
	for(var i:int = 6;i<r;i+=6){
		if(n%(i-1)==0) return n==i-1;
		if(n%(i+1)==0) return n==i+1;
	}
	return true;
}

//함수 테스트
var num:int = 0;
for(var i:int=0;i<=100000;i++){
	if(isPrime(i)) num++;
}
trace(num);//9592(π(100000))이 출력된다.
</syntaxhighlight>
==== for를 while로 바꾸고, 특별한 변수를 쓴다. ====
* for 문을 while 문으로 바꾼다.
* 만약 for 문이 두 번 이상 중첩되었을 경우, 아래와 같이 특별한 변수를 쓴다.
<syntaxhighlight lang="c">
int i,j;
for(i=0;i<9;i++)
for(j=0;j<9;j++)
printf("%d*%d=%d\n",i+1,j+1,(i+1)*(j+1));
</syntaxhighlight>
위 [[C (프로그래밍 언어)|C]] 코드를
<syntaxhighlight lang="c">
int k=0;
int i(0),j(0);
while(k<9*9){
	i=k/9;j=k%9;
	printf("%d*%d=%d\n",i+1,j+1,(i+1)*(j+1));
	k++;
}
</syntaxhighlight>
이렇게 바꾼다.

그 결과, 첫 번째의 액션스크립트 코드는 다음과 같이 바뀐다. (함수 부분만)
<syntaxhighlight lang="actionscript">
function isPrime(n:int):Boolean{
	var r:int = 0;
	while(r*r<=n)r++;
	r--;
	if(n==r) return false;
	if(n<4) return true;
	if(n%2==0 || n%3==0 || n%r==0){
		return false;
	}
	var i:int=6;
	while(i<r){
		if(n%(i-1)==0) return n==i-1;
		if(n%(i+1)==0) return n==i+1;
		i+=6;
	}
	return true;
}
</syntaxhighlight>

==== 순환문을 [[재귀]] 함수로 바꾼다. ====
모든 순환문은 재귀 함수로 바꿀 수 있다. 함수의 인자로 함수 내부에 쓰이는 변수를 추가하고, 재귀적으로 호출을 시키는 방식이다.

while문의 조건을 if문으로 바꾸는 식으로 순환문을 다음과 같이 재귀 함수로 바꿀 수 있다.
<syntaxhighlight lang="actionscript">
function isPrime(n:int, r:int=0, i:int=6):Boolean{
	if((r+1)*(r+1)<=n) return isPrime(n, r+1, i);
	else if(n==r) return false;
	else if(n<4) return true;
	else if(n%2==0 || n%3==0 || n%r==0) return false;
	else if(i<r)
		if(n%(i-1)==0) return n==i-1;
		else if(n%(i+1)==0) return n==i+1;
		else return  isPrime(n, r, i+6);
	else return true;
}
</syntaxhighlight>
이 방식에서 생기는 문제는, 수많은 함수 호출로 인해 속도가 매우 느려진다는 것이다.
==== 구조를 난독화하고, 변수 이름을 의미없게 짓는다. ====
<syntaxhighlight lang="c">
if(A) B; else if(C) D; else E;
</syntaxhighlight>
같은 if-else 문을 ?: 조건 연산자를 이용하여
<syntaxhighlight lang="c">
A?B:C?D:E;
</syntaxhighlight>
로 바꿀 수 있다.

변수 이름을 무작위로 (예: int rabbitNum = 0;을 int m = 0;으로 바꿈) 지어서 코드를 더욱 난독화 시킬 수 있다.
<syntaxhighlight lang="actionscript">
function isPrime(a:int, b:int=0, c:int=6):Boolean{
	return (b+1)*(b+1)<=a?isPrime(a, b+1, c):
	a==b?false:
	a<4?true:
	a%2==0 || a%3==0 || a%b==0?false:
	c<b?a%(c-1)==0?a==c-1:a%(c+1)==0?a==c+1:isPrime(a, b, c+6):true;
}
</syntaxhighlight>
==== 내부 변수를 없앤다. ====
만약 내부 변수가 쓰인다면, 그것을 다른 것으로 치환한다.

예 : 다음 C 코드를 다음과 같이 바꾼다.
<syntaxhighlight lang="c">
double divide(int a, int b){
double c = a/(double)b;
return c;
}
</syntaxhighlight>
c를 a/(double)b로 치환한다.
<syntaxhighlight lang="c">
double divide(int a, int b){
return a/(double)b;
}
</syntaxhighlight>
==== 이름을 다시 한번 난독화한다. ====
함수 이름과 변수 이름을 바꾼다. 여기에서는 변수 이름을 _, __, ___으로 바꾸고, 함수 이름을 ____으로 바꿨다.
<syntaxhighlight lang="actionscript">
function ____(_:int, __:int=0, ___:int=6):Boolean{
	return (__+1)*(__+1)<=_?____(_, __+1, ___):
	_==__?false:
	_<4?true:
	_%2==0 || _%3==0 || _%__==0?false:
	___<__?_%(___-1)==0?_==___-1:_%(___+1)==0?_==___+1:____(_, __, ___+6):true;
}
</syntaxhighlight>
==== [[리터럴]]을 없앤다. ====
[[:en:Obfuscated_code#Remove_literals|리터럴을 함수 인자로 넘겨주는 방법]]을 쓸 수도 있고, 살짝 위험하기는 하지만, 1을 a/a와 같이 다른 변수로 치환시키는 방법을 쓸 수도 있다.

비록 권장하는 방법은 아니지만, 여기에서는 후자의 방법을 쓰겠다.
<syntaxhighlight lang="actionscript">
function ____(_:int, __:int=0, ___:int=6):Boolean{
	return (__+___/___)*(__+___/___)<=_?____(_, __+___/___, ___):
	_==__?_-_:
	_<___-(__+_+__-_)/__?_/_:
	_%(__/__+_/_)==_-_ || _%(__*___/(__+__))==__-__ || _%__==___-___?___/___-_/_:
	___<__?_%(___-_/_)==__/__-___/___?_==___-__/__:_%(___+___/___)==__+_-__-_?
	_==___+___/___:____(_, __, ___+(__*___*(_+_+_)+__*_*___+(__+__)*___*_)/_/__/___):_;
}
</syntaxhighlight>
==== 스페이스, 탭 등을 없앤다. ====
여기에서는 한 줄로 적으면 너무 길어지므로, 적당히 줄바꿈을 하였다.
<syntaxhighlight lang="actionscript">
function ____(_:int,__:int=0,___:int=6):Boolean{return(__+___/___)*(__+___/___)<=_?____(_,__+___/___,___):_==__?_-_:
_<___-(__+_+__-_)/__?_/_:_%(__/__+_/_)==_-_||_%(__*___/(__+__))==__-__||_%__==___-___?___/___-_/_:___<__?
_%(___-_/_)==__/__-___/___?_==___-__/__:_%(___+___/___)==__+_-__-_?_==___+___/___:
____(_,__,___+(__*___*(_+_+_)+__*_*___+(__+__)*___*_)/_/__/___):_}
</syntaxhighlight>
==== 최종 결과 ====
<syntaxhighlight lang="actionscript">
function ____(_:int,__:int=0,___:int=6):Boolean{return(__+___/___)*(__+___/___)<=_?____(_,__+___/___,___):_==__?_-_:
_<___-(__+_+__-_)/__?_/_:_%(__/__+_/_)==_-_||_%(__*___/(__+__))==__-__||_%__==___-___?___/___-_/_:___<__?
_%(___-_/_)==__/__-___/___?_==___-__/__:_%(___+___/___)==__+_-__-_?_==___+___/___:
____(_,__,___+(__*___*(_+_+_)+__*_*___+(__+__)*___*_)/_/__/___):_}

//함수 테스트
var num:int = 0;
for(var i:int=0;i<=100000;i++){
	if(____(i))num++;
}
trace(num);//9592
</syntaxhighlight>

== 사용 예 ==
* [[자바스크립트]] 코드의 용량을 줄이는 데 쓰는 Packer는, 또한 자바스크립트를 읽기 어렵게 하는 데 쓰인다.

== 같이 보기 ==
* [[스파게티 코드]]
* [[난해한 프로그래밍 언어]]
* [[콰인 (전산학)]]
* [[다형성 코드]]
* [[소스 대 소스 컴파일러]]
* [[디지털 권리 관리]]
== 각주 ==
{{각주}}

== 외부 링크 ==
* {{언어링크|en}} [https://web.archive.org/web/20140528122619/http://www.ioccc.org/ International Obfuscated C Code Contest]

{{정보 보안}}

[[분류:난독화| ]]
[[분류:보안]]
[[분류:컴퓨터 프로그래밍]]
[[분류:프로그램 변환]]
[[분류:안티패턴]]