[IDA] Obfuscated String --> De-Obfuscation (IDAPython으로 문자열 난독화 해제)
Published by Jack2 on January 14th, 2018
0) 개요 및 목표
- 악성코드 분석가로서, IDA Pro를 사용
- 복합적인 문자열 난독화를 스크립트를 이용해서 분석
- 난독화 알고리즘 확인
- 목표 : 난독화 된 문자열이 특정 함수가 호출 된 후 난독화 해제가 되는 경우 IDAPython을 이용하여 동적 실행없이 복호화
1) 배경지식
- 0. 난독화 된 문자열 부분 확인(MD5: e53428a55b212e61507746b649b648d8 / SHA2: b4e43fec37a026e4452ebfa6e480ecaa96e109899e6282852af451c4d8ad5a40)
- 1. 문자열을 복호화하는 역할로 추정되는 함수 확인
- 2. Xrefs to 를 이용한 함수 확인
- Xrefs 확인 결과, 20개로 해당 함수가 호출되면 각각의 경우
- 3. 해당 함수를 호출하는 경우
- 런타임 상에서 해당 함수를 이용하여 문자열을 복호화 하는 것을 확신
- 이러한 상태에 직면하게 되는 경우 선택 가능한 부분
- 1) 난독화 된 문자열을 수동으로 복호화 및 복호화 된 이름으로 변경
- 2) 동적으로 실행 후 복호화 및 복호화 된 이름으로 변경
- funcap (IDA Plugin) - https://github.com/deresz/funcap
- 3) 복호화 및 복호화 된 이름으로 변경하는 스크립트 작성
- 이러한 경우가 많지 않은 경우에는 1), 2) 로 커버가능하지만 몇 백개가 되는 경우에는 한계가 있으므로 스크립트를 이용한 해결 방법 필요
2) IDAPython 을 이용한 스크립트
- 2-1) XrefsTo() - 0x10003b00
for addr in XrefsTo(0x10003b00, flags=0):
print hex(addr.frm)
——————————————————— 실행 화면 ————————————————————
Python>for addr in XrefsTo(0x10003b00, flags=0):
Python> print hex(addr.frm)
Python>
0x100034feL
0x100036afL
0x10003908L
0x1000391fL
0x10003936L
0x1000394cL
0x10003963L
0x1000397aL
0x10003990L
0x100039b0L
0x100039d0L
0x100039efL
0x10003a0fL
0x10003a2fL
0x10003a4fL
0x10003a6fL
0x10003a8fL
0x10003aafL
0x10003acfL
0x10003ae6L
- 2-2) supplied argument (문자열 인자) 가져오기
.text:100038F0 push ebp
.text:100038F1 mov ebp, esp
.text:100038F3 push ecx
.text:100038F4 mov [ebp+var_4], ecx
.text:100038F7 mov eax, [ebp+var_4]
.text:100038FA add eax, 318h ; Add
.text:100038FF push eax
.text:10003900 push offset aCxwweckrxwTeey ; "Cxwweckrxw: teey-aurme"
.text:10003905 mov ecx, [ebp+var_4]
.text:10003908 call sub_10003B00 ; Call Procedure
.text:1000390D mov ecx, [ebp+var_4]
.text:10003910 add ecx, 418h ; Add
.text:10003916 push ecx
.text:10003917 push offset aCxwkewkUewgkh ; "Cxwkewk-Uewgkh: "
.text:1000391C mov ecx, [ebp+var_4]
.text:1000391F call sub_10003B00 ; Call Procedure
.text:10003924 mov edx, [ebp+var_4]
.text:10003927 add edx, 44Ah ; Add
.text:1000392D push edx
.text:1000392E push offset aCacheCxwkixuVa ; "Cache-Cxwkixu: vao-age=0"
.text:10003933 mov ecx, [ebp+var_4]
.text:10003936 call sub_10003B00 ; Call Procedure
.text:1000393B mov eax, [ebp+var_4]
.text:1000393E add eax, 47Ch ; Add
.text:10003943 push eax
.text:10003944 push offset aAcceyk ; "Acceyk: */*"
.text:10003949 mov ecx, [ebp+var_4]
.text:1000394C call sub_10003B00 ; Call Procedure
.text:10003951 mov ecx, [ebp+var_4]
.text:10003954 add ecx, 0D80h ; Add
.text:1000395A push ecx
.text:1000395B push offset aCxwkewkKpyeVlu ; "Cxwkewk-Kpye: vlukryaik/fxiv-daka; bxlw"...
.text:10003960 mov ecx, [ebp+var_4]
.text:10003963 call sub_10003B00 ; Call Procedure
.text:10003968 mov edx, [ebp+var_4]
.text:1000396B add edx, 0E84h ; Add
.text:10003971 push edx
.text:10003972 push offset aAcceykEwcxdrwg ; "Acceyk-Ewcxdrwg: gzry,defuake,jdch"
.text:10003977 mov ecx, [ebp+var_4]
.text:1000397A call sub_10003B00 ; Call Procedure
- 관련 내용 스크립트
- 문자열이 위치한 오프셋 주소 획득 => 0x1002471c
.text:10003900 push offset aCxwweckrxwTeey ; "Cxwweckrxw: teey-aurme"
.text:10003905 mov ecx, [ebp+var_4]
.text:10003908 call sub_10003B00 ; Call Procedure
…
.rdata:1002471C aCxwweckrxwTeey db 'Cxwweckrxw: teey-aurme',0
def find_function_arg(addr):
while True:
addr = idc.PrevHead(addr)
if GetMnem(addr) == "push":
print 'We found it at 0x%x' % GetOperandValue(addr, 0)
break
Python>def find_function_arg(addr):
Python> while True:
Python> addr = idc.PrevHead(addr)
Python> if GetMnem(addr) == "push":
Python> print 'We found it at 0x%x' % GetOperandValue(addr, 0)
Python> break
Python>
Python>find_function_arg(0x10003908)
We found it at 0x1002471c
- 2-3) 오프셋 주소에서 문자열 추출
.rdata:1002471C aCxwweckrxwTeey db 'Cxwweckrxw: teey-aurme',0
def get_string(addr):
out = ""
while True:
if Byte(addr) != 0:
out += chr(Byte(addr))
else:
break
addr += 1
return out
Python>def get_string(addr):
Python> out = “"
Python> while True:
Python> if Byte(addr) != 0:
Python> out += chr(Byte(addr))
Python> else:
Python> break
Python> addr += 1
Python> return out
Python>
Python>get_string(0x1002471c)
Cxwweckrxw: teey-aurme
- 2-4) 복호화 함수 (0x10003B00) 분석
- Hex-Ray를 이용하여 복호화 함수를 파악 후 스크립트로 구현
def de_obf_str(obf_str):
deobf = list(obf_str)
deobf_str = ""
num = 0
for i in deobf:
each_str = ord(i)
if each_str < ord("i") or each_str > ord("p"):
if each_str < ord("r") or each_str > ord("y"):
if each_str < ord("I") or each_str > ord("P"):
if each_str >= ord("R") and each_str <= ord("Y"):
each_str -= 9
deobf_str += chr(each_str)
else : deobf_str += chr(each_str)
else:
each_str += 9
deobf_str += chr(each_str)
else:
each_str -= 9
deobf_str += chr(each_str)
else:
each_str += 9
deobf_str += chr(each_str)
return deobf_str
- 2-5) 출력 및 자동 주석 기능 추가
print "[*] Attempting to de-obfuscate strings in malware"
for x in XrefsTo(0x10003b00, flags=0):
ref = find_function_arg(x.frm)
string = get_string(ref)
deobf_string = de_obf_str(string)
print '[STRING]:%s\n[Deobfuscated]:%s' % (string,deobf_string)
MakeComm(x.frm, deobf_string)
MakeComm(ref, deobf_string)
def find_function_arg(addr):
while True:
addr = idc.PrevHead(addr)
if GetMnem(addr) == "push":
return GetOperandValue(addr, 0)
return ""
def get_string(addr):
out = ""
while True:
if Byte(addr) != 0:
out += chr(Byte(addr))
else:
break
addr += 1
return out
def de_obf_str(obf_str):
deobf = list(obf_str)
deobf_str = ""
num = 0
for i in deobf:
each_str = ord(i)
if each_str < ord("i") or each_str > ord("p"):
if each_str < ord("r") or each_str > ord("y"):
if each_str < ord("I") or each_str > ord("P"):
if each_str >= ord("R") and each_str <= ord("Y"):
each_str -= 9
deobf_str += chr(each_str)
else : deobf_str += chr(each_str)
else:
each_str += 9
deobf_str += chr(each_str)
else:
each_str -= 9
deobf_str += chr(each_str)
else:
each_str += 9
deobf_str += chr(each_str)
return deobf_str
print "[*] Attempting to de-obfuscate strings in malware"
for x in XrefsTo(0x10003b00, flags=0):
ref = find_function_arg(x.frm)
string = get_string(ref)
deobf_string = de_obf_str(string)
print '[STRING]:%s\n[Deobfuscated]:%s' % (string,deobf_string)
MakeComm(x.frm, deobf_string)
MakeComm(ref, deobf_string)
- 2-7) 실행화면
- 2-7-1) 스크립트 파일 선택
- 2-7-2) 문자열 출력 => print '[STRING]:%s\n[Deobfuscated]:%s' % (string,deobf_string)
- 2-7-3) 자동주석
[References]
- IDAPython home page: http://code.google.com/p/idapython/
- IDAPython docs: http://www.hex-rays.com/idapro/idapython_docs/
- Requirements: IDA 5.x and Python 2.5 (some versions use 2.6). Works with IDA Demo and Wine :)
- Optional IPython support (does't work for me, I get a black window): https://www.openrce.org/blog/view/1509/Interactive_IPython_Shell_for_IDA_Python
[Future works]
- Solving Ad-hoc Problems with Hex-Rays API, https://www.fireeye.com/blog/threat-research/2018/04/solving-ad-hoc-problems-with-hex-rays-api.html
Copyright 2018. (JAEKI KIM) all rights reserved.
Copyright 2018. (JAEKI KIM) All pictures cannot be copied without permission. |