计划是写一个android中so文件反混淆的系列文章,目前只写了这一篇。
样本libbaiduprotect_dump.so来自看雪上的帖子:百度加固免费版分析及VMP修复
原文把整个流程已经分析很清楚了,这里就不分析了,只说怎么处理libbaiduprotect_dump.so里面的混淆。
很多函数里面都插了垃圾代码,比如JNI_OnLoad:

两个相邻的数相乘肯定是偶数,while条件永远false,if条件永远true。这里我的方法就是直接把ADRP X8, #dword_C0144@PAGE(ADRP X8, 0xC0000)这样的指令改成ADRP X8, 0xA0000,因为0xC0124在bss段没有初始化,0xA0124在eh_frame段已经初始化,所以这样改了以后IDA F5的时候就会把这些垃圾代码自动优化掉。
注意:需要自己去装一个keystone,因为脚本用到了kstool.exe生成机器码。
处理以后:

加密后的字符串基本都长这个样子:

每个字符串的解密函数虽然都不一样,但是逻辑都差不多。处理字符串加密可以用的工具有很多,我习惯用frida。
第一步是通过交叉引用拿到加密后的字符串和它对应的解密函数的表:
结果:

第二步是把这个表丢给frida,让frida去调一遍,拿到解密后的字符串。为了代码简洁这个表就没有列完,只有两项:
结果:

第三步就是把加密后的字符串直接patch成加密前的字符串,因为如果用set_cmt(也就是IDA7.4以前的MakeComm)把加密前的字符串当成注释加上的话F5的窗口是没有的,这样直接patch看起来更清晰直观。加密后的字符串总是比加密前的字符串长,多出来的就patch成0。同样为了代码简洁加密前的字符串没有列完,只有两项:
还是前面的sub_12274,来看处理完以后的效果:

sub_B3B4动态获取libc中的函数并保存,我们这里做一下符号重命名即可。
首先把F5中的sub_B3B4保存下来,然后写个脚本把qword_BE238命名为_exit_libc,qword_BE240命名为exit_libc,qword_BE248命名为pthread_create_libc,依次类推即可。
结果:

用这些函数的地方也看的比较清楚。

百度加固免费版libbaiduprotect.so里面基本上就是这些花样,还是比较好搞定的。
from idautils import *
from idaapi import *
from idc import *
import subprocess
for segea in Segments():
for funcea in Functions(segea, get_segm_end(segea)):
for (startea, endea) in Chunks(funcea):
for line in Heads(startea, endea):
if idc.GetDisasm(line) in ["ADRP X8, #dword_C0144@PAGE", \
"ADRP X8, #dword_C0140@PAGE", \
"ADRP X8, #dword_C013C@PAGE", \
"ADRP X8, #dword_C0138@PAGE", \
"ADRP X8, #dword_C0134@PAGE", \
"ADRP X8, #dword_C0130@PAGE", \
"ADRP X8, #dword_C012C@PAGE", \
"ADRP X8, #dword_C0128@PAGE", \
"ADRP X8, #dword_C0124@PAGE", \
"ADRP X8, #dword_C0120@PAGE", \
"ADRP X8, #dword_C011C@PAGE", \
"ADRP X8, #dword_C0118@PAGE"]:
pi = subprocess.Popen(['D:\\keystone-0.9.2-win64\\kstool.exe', 'arm64', 'ADRP X8, 0xA0000', hex(line)], shell=True, stdout=subprocess.PIPE)
output = pi.stdout.read()
asmcode = str(output[20:33])[:-1]
asmcode = asmcode.split(" ")
asmcode = "0x" + asmcode[4] + asmcode[3] + asmcode[2] + asmcode[1]
print(asmcode)
patch_dword(line, int(asmcode, 16))
elif idc.GetDisasm(line) in ["ADRP X9, #dword_C0140@PAGE", \
"ADRP X9, #dword_C013C@PAGE", \
"ADRP X9, #dword_C0138@PAGE", \
"ADRP X9, #dword_C0134@PAGE", \
"ADRP X9, #dword_C0130@PAGE", \
"ADRP X9, #dword_C012C@PAGE", \
"ADRP X9, #dword_C0128@PAGE", \
"ADRP X9, #dword_C0124@PAGE", \
"ADRP X9, #dword_C0120@PAGE", \
"ADRP X9, #dword_C011C@PAGE", \
"ADRP X9, #dword_C0118@PAGE"]:
pi = subprocess.Popen(['D:\\keystone-0.9.2-win64\\kstool.exe', 'arm64', 'ADRP X9, 0xA0000', hex(line)], shell=True, stdout=subprocess.PIPE)
output = pi.stdout.read()
asmcode = str(output[20:33])[:-1]
asmcode = asmcode.split(" ")
asmcode = "0x" + asmcode[4] + asmcode[3] + asmcode[2] + asmcode[1]
print(asmcode)
patch_dword(line, int(asmcode, 16))
elif idc.GetDisasm(line) in ["ADRP X10, #dword_C0140@PAGE", \
"ADRP X10, #dword_C013C@PAGE", \
"ADRP X10, #dword_C0138@PAGE", \
"ADRP X10, #dword_C0134@PAGE", \
"ADRP X10, #dword_C0130@PAGE", \
"ADRP X10, #dword_C012C@PAGE", \
"ADRP X10, #dword_C0128@PAGE", \
"ADRP X10, #dword_C0124@PAGE", \
"ADRP X10, #dword_C0120@PAGE", \
"ADRP X10, #dword_C011C@PAGE", \
"ADRP X10, #dword_C0118@PAGE"]:
pi = subprocess.Popen(['D:\\keystone-0.9.2-win64\\kstool.exe', 'arm64', 'ADRP X10, 0xA0000', hex(line)], shell=True, stdout=subprocess.PIPE)
output = pi.stdout.read()
asmcode = str(output[20:33])[:-1]
asmcode = asmcode.split(" ")
asmcode = "0x" + asmcode[4] + asmcode[3] + asmcode[2] + asmcode[1]
print(asmcode)
patch_dword(line, int(asmcode, 16))
from idautils import *
from idaapi import *
from idc import *
import subprocess
for segea in Segments():
for funcea in Functions(segea, get_segm_end(segea)):
for (startea, endea) in Chunks(funcea):
for line in Heads(startea, endea):
if idc.GetDisasm(line) in ["ADRP X8, #dword_C0144@PAGE", \
"ADRP X8, #dword_C0140@PAGE", \
"ADRP X8, #dword_C013C@PAGE", \
"ADRP X8, #dword_C0138@PAGE", \
"ADRP X8, #dword_C0134@PAGE", \
"ADRP X8, #dword_C0130@PAGE", \
"ADRP X8, #dword_C012C@PAGE", \
"ADRP X8, #dword_C0128@PAGE", \
"ADRP X8, #dword_C0124@PAGE", \
"ADRP X8, #dword_C0120@PAGE", \
"ADRP X8, #dword_C011C@PAGE", \
"ADRP X8, #dword_C0118@PAGE"]:
pi = subprocess.Popen(['D:\\keystone-0.9.2-win64\\kstool.exe', 'arm64', 'ADRP X8, 0xA0000', hex(line)], shell=True, stdout=subprocess.PIPE)
output = pi.stdout.read()
asmcode = str(output[20:33])[:-1]
asmcode = asmcode.split(" ")
asmcode = "0x" + asmcode[4] + asmcode[3] + asmcode[2] + asmcode[1]
print(asmcode)
patch_dword(line, int(asmcode, 16))
elif idc.GetDisasm(line) in ["ADRP X9, #dword_C0140@PAGE", \
"ADRP X9, #dword_C013C@PAGE", \
"ADRP X9, #dword_C0138@PAGE", \
"ADRP X9, #dword_C0134@PAGE", \
"ADRP X9, #dword_C0130@PAGE", \
"ADRP X9, #dword_C012C@PAGE", \
"ADRP X9, #dword_C0128@PAGE", \
"ADRP X9, #dword_C0124@PAGE", \
"ADRP X9, #dword_C0120@PAGE", \
"ADRP X9, #dword_C011C@PAGE", \
"ADRP X9, #dword_C0118@PAGE"]:
pi = subprocess.Popen(['D:\\keystone-0.9.2-win64\\kstool.exe', 'arm64', 'ADRP X9, 0xA0000', hex(line)], shell=True, stdout=subprocess.PIPE)
output = pi.stdout.read()
asmcode = str(output[20:33])[:-1]
asmcode = asmcode.split(" ")
asmcode = "0x" + asmcode[4] + asmcode[3] + asmcode[2] + asmcode[1]
print(asmcode)
patch_dword(line, int(asmcode, 16))
elif idc.GetDisasm(line) in ["ADRP X10, #dword_C0140@PAGE", \
"ADRP X10, #dword_C013C@PAGE", \
"ADRP X10, #dword_C0138@PAGE", \
"ADRP X10, #dword_C0134@PAGE", \
"ADRP X10, #dword_C0130@PAGE", \
"ADRP X10, #dword_C012C@PAGE", \
"ADRP X10, #dword_C0128@PAGE", \
"ADRP X10, #dword_C0124@PAGE", \
"ADRP X10, #dword_C0120@PAGE", \
"ADRP X10, #dword_C011C@PAGE", \
"ADRP X10, #dword_C0118@PAGE"]:
pi = subprocess.Popen(['D:\\keystone-0.9.2-win64\\kstool.exe', 'arm64', 'ADRP X10, 0xA0000', hex(line)], shell=True, stdout=subprocess.PIPE)
output = pi.stdout.read()
asmcode = str(output[20:33])[:-1]
asmcode = asmcode.split(" ")
asmcode = "0x" + asmcode[4] + asmcode[3] + asmcode[2] + asmcode[1]
print(asmcode)
patch_dword(line, int(asmcode, 16))
from idautils import *
from idaapi import *
from idc import *
import string
rodata_start = 0x959B0
rodata_end = 0x9AF68
def get_string(addr):
out = ""
while True:
if get_byte(addr) != 0:
out += chr(get_byte(addr))
else:
break
addr += 1
return out
addr = rodata_start
index = 0
while addr < rodata_end:
str = get_string(addr)
str_len = len(str) + 1
if all(c in string.hexdigits for c in str) and str_len > 8:
xrefaddrs = XrefsTo(addr, flags=0)
for xrefaddr in xrefaddrs:
call_addr = xrefaddr.frm
while print_insn_mnem(call_addr) != "BL":
call_addr = next_head(call_addr)
decode_func_addr = print_operand(call_addr, 0)
print("\"" + decode_func_addr + '***' + str + "\"" + ",")
addr += str_len
from idautils import *
from idaapi import *
from idc import *
import string
rodata_start = 0x959B0
rodata_end = 0x9AF68
def get_string(addr):
out = ""
while True:
if get_byte(addr) != 0:
out += chr(get_byte(addr))
else:
break
addr += 1
return out
addr = rodata_start
index = 0
while addr < rodata_end:
str = get_string(addr)
str_len = len(str) + 1
if all(c in string.hexdigits for c in str) and str_len > 8:
xrefaddrs = XrefsTo(addr, flags=0)
for xrefaddr in xrefaddrs:
call_addr = xrefaddr.frm
while print_insn_mnem(call_addr) != "BL":
call_addr = next_head(call_addr)
decode_func_addr = print_operand(call_addr, 0)
print("\"" + decode_func_addr + '***' + str + "\"" + ",")
addr += str_len
[培训]传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!