1. 개요
자바스크립트 난독화 중 jjencode라는 생소한 형태의 난독화가 있다. 이 난독화는 일본 연구가 하세가와 요스케(Yosuke HASEGAWA - 블로그)에 의해 만들어 졌고, 처음 공개된 것은 일본에서 열린 2009 JUI(JavaScript User Interface) 세미나이다. 자세한 공개 내용은 블로그에 공개된 발표자료를 통해 볼 수 있으며(다운로드) 생성 도구는 이곳에서 사용할 수 있다.
2. 목적
jjencode의 목적은 자바스크립트 기호로만 사용하여 자바스크립트와 (거의) 동등하게 동작하는 난독화 코드를 만드는 것이다.
3. 난독화 규칙
jjencode의 기본 규칙은 다음과 같다.
- 기호만 사용
- 알파벳 금지
- 숫자 금지
- US-ASCII 이외의 문자 금지
- 사용 가능한 문자 !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~) 32종류
4. 실사례 코드
실제 악성 소프트웨어 유포지를 분석하는 과정에서 발견되었던 코드로 동일한 알고리즘을 가진 것으로 보았을 때 jjencode 도구를 이용하여 생성한 것으로 추측한다.
5. 분석
분석에 사용할 난독화 코드는 하세가와 요스케가 만든 도구를 이용하여 생성했다. 이 자바스크립트가 정상적으로 실행하면 alert 창에 a를 출력한다.
$=~[];$={___:++$,$$$$:(![]+"")[$],__$:++$,$_$_:(![]+"")[$],_$_:++$,$_$$:({}+"")[$],$$_$:($[$]+"")[$],_$$:++$,$$$_:(!""+"")[$],$__:++$,$_$:++$,$$__:({}+"")[$],$$_:++$,$$$:++$,$___:++$,$__$:++$};$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$$=($.$+"")[$.__$])+((!$)+"")[$._$$]+($.__=$.$_[$.$$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;$.$$=$.$+(!""+"")[$._$$]+$.__+$._+$.$+$.$$;$.$=($.___)[$.$_][$.$_];$.$($.$($.$$+"\""+$.$_$_+(![]+"")[$._$_]+$.$$$_+"\\"+$.__$+$.$$_+$._$_+$.__+"(\\\""+$.$_$_+"\\\");"+"\"")())();
좀 더 가독성 있게 코드를 변환 하면 다음과 같다.
$=~[];
$={
___:++$,
$$$$:(![]+"")[$],
__$:++$,
$_$_:(![]+"")[$],
_$_:++$,
$_$$:({}+"")[$],
$$_$:($[$]+"")[$],
_$$:++$,
$$$_:(!""+"")[$],
$__:++$,
$_$:++$,
$$__:({}+"")[$],
$$_:++$,
$$$:++$,
$___:++$,
$__$:++$
};
$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$$=($.$+"")[$.__$])+((!$)+"")[$._$$]+($.__=$.$_[$.$$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;
$.$$=$.$+(!""+"")[$._$$]+$.__+$._+$.$+$.$$;
$.$=($.___)[$.$_][$.$_];
$.$($.$($.$$+"\""+$.$_$_+(![]+"")[$._$_]+$.$$$_+"\\"+$.__$+$.$$_+$._$_+$.__+"(\\\""+$.$_$_+"\\\");"+"\"")())();
5.1. Line 1
$=~[];
자바스크립트의 독특한 형태중 하나가 $, _를 변수로 사용할 수 있는 것이다. 변수이름 맨 앞에서 사용해도 되고, 단독으로도 사용이 가능하다. $ 변수에 ~[]를 저장하는데 []는 배열 오브젝트로 단독으로 사용할 경우 ""와 같은 역할을 한다.
$ 변수를 []로 초기화하면 $ 변수는 배열을 가지게 된다. 하지만 독특하게 배열 앞에 연산자를 사용하면 숫자(number)가 저장된다. 생성자 난독화(Object Obfuscation) 형태에서 사용하는 방법 중 하나로 null 값을 가진 배열에 값을 의미하는 연산이 붙으면 0000 0000으로 초기화 되면서 값이 저장되는 것으로 추측하고 있다. 몇 가지 실험을 해본 결과 []에 덧셈을 하면 문자열(string) 형태로 저장되고 뺄셈 연산을 하면 숫자(number) 형태로 저장된다. 위 첫번째 라인은 틸드(~) [] 로 연산을 하면 0000 0000 이 ffff ffff로 연산되어 $변수에는 -1이 저장된다.
5.2. Line 2~19
$={
___:++$,
$$$$:(![]+"")[$],
__$:++$,
$_$_:(![]+"")[$],
_$_:++$,
$_$$:({}+"")[$],
$$_$:($[$]+"")[$],
_$$:++$,
$$$_:(!""+"")[$],
$__:++$,
$_$:++$,
$$__:({}+"")[$],
$$_:++$,
$$$:++$,
$___:++$,
$__$:++$
};
jjencode의 제 1 엔진 역할을 하는 부분이다. 이 구문은 JSON(JavaScript Object Notation) 표현방식으로 객체 표기 방식 중 한 가지이다. 배열을 한번에 설정하는데 객체를 쉼표(,)로 구분하고 키와 값 사이는 콜론(:)으로 구분하여 사용한다.
- Line 3 의 ___ 키(key)에는 ++$를 저장한다. $는 -1의 값을 가지고 있기 때문에 0 값을 할당 받는다.
- Line 4 의 $$$$ 키(key)에는 (![]+"")[0] 값을 할당 받는다. (![]+"")[0] 값은 "false"[0]으로 "f" 을 할당 받는다.
- Line 5 의 __$ 키(key)에는 ++$를 통해 1 값을 할당 받는다.
- Line 6 의 $_$_ 키(key)에는 "false"[1]의 값인 "a" 값을 할당 받는다.
- Line 7 의 _$_ 키(key)에는 ++$를 통해 2 값을 할당 받는다.
- Line 8 의 $_$$ 키(key)에는 ({}+"")[2] 값을 할당 받는다. ({}+"")[2] 값은 "[object Object]"[2]로 "b" 값을 할당 받는다.
- Line 9 의 $$_$ 키(key)에는 ($[$]+"")[2] 값을 할당 받는다. ($[$]+"")[2] 값은 "undefined"[2]로 "d" 값을 할당 받는다.
- Line 10 의 _$$ 키(key)에는 ++$를 통해 3 값을 할당 받는다.
- Line 11 의 $$$_ 키(key)에는 (!""+"")[3] 값을 할당 받는다. (!""+"")[3] 값은 "true"[3]로 "e" 값을 할당 받는다.
- Line 12 의 $__ 키(key)에는 ++$를 통해 4 값을 할당 받는다.
- Line 13 의 $_$ 키(key)에는 ++$를 통해 5 값을 할당 받는다.
- Line 14 의 $$__ 키(key)에는 ({}+"")[5] 값을 할당 받는다. ({}+"")[5] 값은 "[object Object]"[5]로 "c" 값을 할당 받는다.
- Line 15 의 $$_ 키(key)에는 ++$를 통해 6 값을 할당 받는다.
- Line 16 의 $$$ 키(key)에는 ++$를 통해 7 값을 할당 받는다.
- Line 17 의 $___ 키(key)에는 ++$를 통해 8 값을 할당 받는다.
- Line 18 의 $$_$ 키(key)에는 ++$를 통해 9 값을 할당 받는다.
분석한 내용대로 각각의 키에는 0~f까지 16진수의 값이 저장된다. 저장되는 값이 숫자타입(number)이든 문자타입(strings)이든 상관없다.
두번째로 눈여겨 봐야할 것은 내장 문자열 기법(Builtin Strings Technique)이다. 자바스크립트 내장 문자열은 잘못된 연산이나 연산 결과가 문자 형태로 출력되는 것을 말한다. 만약 자바스크립트에서 3/0과 같은 연산을 할 경우 NaN을 출력한다. 이 때 NaN이 내장 문자열이 되는 것이다.
출력된 내장 문자열을 +"" 연산을 통해 강제로 문자열(Strings) 타입으로 치환하여 변수에 저장 할 수 있다. 저장된 문자열에서 원하는 문자를 추출하여 사용하는 형태로 몽타주 문자와 비슷한 형태를 가지게 된다. 이러한 자바스크립트의 특징을 이용한 난독화를 생성자 난독화(Object Obfuscation)라고 불린다.
몽타주 문자 : 필체를 은닉하기 위해 사용하는 방법으로 신문지나 잡지와 같은데서 사용하고자 하는 문자를 오려내어 문장을 만드는 방법
다시 5.2를 정리하면 다음과 같다.
키(key) |
값(value) |
___ |
0 |
__$ |
1 |
_$_ |
2 |
_$$ |
3 |
$__ |
4 |
$_$ |
5 |
$$_ |
6 |
$$$ |
7 |
$___ |
8 |
$__$ |
9 |
$_$_ |
a |
$_$$ |
b |
$$__ |
c |
$$_$ |
d |
$$$_ |
e |
$$$$ |
f |
5.3. Line 20
$.$_=
($.$_=$+"")[$.$_$]
+($._$=$.$_[$.__$])
+($.$$=($.$+"")[$.__$])
+((!$)+"")[$._$$]
+($.__=$.$_[$.$$_])
+($.$=(!""+"")[$.__$])
+($._=(!""+"")[$._$_])
+$.$_[$.$_$]
+$.__
+$._$
+$.$;
5.2 에서 설명한 키에 따른 값을 생성하는 방법들로 내장 문자열 기법(Builtin Strings Technique)과 강제 문제열 치환 (+"")을 이용한 생성자 난독화(Object Obfuscation)을 이용하여 라인 20을 분석하면 다음과 같이 나온다.
키 (key) |
값 (value) |
($.$_=$+"")[$.$_$] |
c |
($._$=$.$_[$.__$]) |
o |
($.$$=($.$+"")[$.__$]) |
n |
((!$)+"")[$._$$] |
s |
($.__=$.$_[$.$$_]) |
t |
($.$=(!""+"")[$.__$]) |
r |
($._=(!""+"")[$._$_]) |
u |
$.$_[$.$_$] |
c |
$.__ |
t |
$._$ |
o |
$.$ |
r |
$.$_ |
constructor |
$.$_에 constructor가 저장된다. 자바스크립트에서 constructor는 객체를 만드는 기능함수를 반환하거나 설정하는 메소드이다. 객체를 만드는 기능 함수를 반환하기 때문에 자바스크립트의 모든 요소를 다 가지고 있다.
5.4. Line 21~22
$.$$=$.$+(!""+"")[$._$$]+$.__+$._+$.$+$.$$;
$.$=($.___)[$.$_][$.$_];
키 (key) |
값 (value) |
$.$+(!""+"")[$._$$]+$.__+$._+$.$+$.$$ |
"return" |
($.___)[$.$_][$.$_] |
(0)['constructor']['constructor'] |
라인 22는 $.$$에 return 값을 저장하고 $.$에는 (0)['constructor']['constructor'] 를 저장하여 사용한다. 라인 20부터 22까지 이 난독화의 제 2 엔진이 된다.
(0)을 사용한 이유는 constructor를 사용하기 위해서는 객체(Object)를 선언해야만 가능하다. 문자든, 숫자든 객체를 선언하고 constructor를 사용하는 형태이다. 뒤의 constructor를 두번 사용했는데 이는 함수로 만들어 사용하기 위함이다. 뒤에 분석된 결과를 보면 알겠지만 return 으로 최종 명령을 실행하게 된다.
5.5. Line 23
$.$($.$($.$$+"\""+$.$_$_+(![]+"")[$._$_]+$.$$$_+"\\"+$.__$+$.$$_+$._$_+$.__+"(\\\""+$.$_$_+"\\\");"+"\"")())();
라인 23을 분석하면 $.$($.$(return"ale\162t(\"a\");")())();과 같다. 여기서 중요 포인트는 \162이다. 간단한 문자의 경우 내장 함수에서 추출해서 사용할 수 있는데, 매우 복잡하게 만들어야 하거나 구할 수 없는 알파벳의 경우 \162와 같이 사용한다. 이 경우 r을 8진수를 이용하여 만든 정확한 이유는 모르겠으나, 앞서 Line 2~19 에서 정의한 16진수를 이용하여 아스키코표의 모든 문자들을 사용할 수 있다.
최종적으로 constructor에 의해 $.$(alert("a");)(); 와 같이 변형되고 다시 constructor에 의해 alert이 실행되어 a를 출력한다.
6. 결론
$.$($.$$+"\""+$.$_$_+(![]+"")[$._$_]+$.$$$_+"\\"+$.__$+$.$$_+$._$_+$.__+"(\\\""+$.$_$_+"\\\");"+"\"")())
위 코드는 jjencode 예제로 사용자 코드를 난독화 한 부분이다. 그 외의 잘라낸 부분은 어떤 코드를 jjencode 하더라도 하세가와 요스케가 만든 도구를 사용했다면 동일하다.
(0)['constructor']['constructor']로 만들어진 함수는 함수명을 선언하지 않았기 때문에 anonymous 형태의 함수가 생성된다. 그리고 함수를 반환하는 값이 사용자 코드가 된다.
function anonymous() {
function anonymous() {
return"ale\162t(\"a\");"
}
}
function anonymous() {
alert("a");
}
anonymous 함수의 return으로 8진수 코드는 아스키코드표에 의거에하여 변환되어 나오고, 다시 anonymous 함수를 통해 alert이 실행되게 된다.
이런 난독화는 일반적인 도구로 분석이 불가능하다. 우선 자바스크립트 엔진(JavaScript Engine)에 사용하는 내장 문자열은 엔진마다 다르고, 또한 일반적으로 도구에서 사용하는 자바스크립트 엔진은 내장 문자열을 정의하지 않는다.
또한 소스코드 변형을 통한 난독화를 해제 하려고 할 때 document.write와 같은 실행부 자바스크립트 함수를 alert으로 치환해야하는데 그 위치도 찾기 힘들다. 이러한 난독화는 어떻게 해결해야 할까? 어쩔수 없이 상세한 난독화 알고리즘을 파악한 후 최종 실행부를 찾는 수 밖에 없다. 이 난독화의 최종 실행은 마지막 라인의 $.$ 이다. 해당 부분을 alert으로 치환하면 난독화 해제한 결과를 볼 수 있다.
$=~[];
$={
___:++$,
$$$$:(![]+"")[$],
__$:++$,
$_$_:(![]+"")[$],
_$_:++$,
$_$$:({}+"")[$],
$$_$:($[$]+"")[$],
_$$:++$,
$$$_:(!""+"")[$],
$__:++$,
$_$:++$,
$$__:({}+"")[$],
$$_:++$,
$$$:++$,
$___:++$,
$__$:++$
};
$.$_=($.$_=$+"")[$.$_$]+($._$=$.$_[$.__$])+($.$$=($.$+"")[$.__$])+((!$)+"")[$._$$]+($.__=$.$_[$.$$_])+($.$=(!""+"")[$.__$])+($._=(!""+"")[$._$_])+$.$_[$.$_$]+$.__+$._$+$.$;
$.$$=$.$+(!""+"")[$._$$]+$.__+$._+$.$+$.$$;
$.$=($.___)[$.$_][$.$_];
alert($.$($.$$+"\""+$.$_$_+(![]+"")[$._$_]+$.$$$_+"\\"+$.__$+$.$$_+$._$_+$.__+"(\\\""+$.$_$_+"\\\");"+"\"")())();
7. 참조
- 하세가와 요스케 연구 페이지 - http://utf-8.jp/
- jjencode 발표 자료 - http://utf-8.jp/public/20090710/jjencode.pps
- jjencode 생성 도구 - http://utf-8.jp/public/jjencode.html
'Information Security > Malware' 카테고리의 다른 글
공다팩(Gondad EK) 분석 #02 (0) | 2014.07.04 |
---|---|
공다팩(Gondad EK) 분석 #01 (0) | 2014.06.27 |
Sothink SWF Decompiler 3.7 (4) | 2014.01.06 |
알고리즘을 이용한 16진수 변형 + 메소드 치환 난독화 / DOM을 이용한 Script 실행 (0) | 2014.01.02 |
Base64를 이용한 JavaScript 난독화 (0) | 2013.09.24 |