0x0 样本信息 样本:17年BD加固
NativeHook:基于Substrate的Nativehook
Android系统: 6.0.1 0x1 IDAPython脚本辅助应对花指令上一个样本中,分析壳的initarray时候,就发现有花指令和大循环,那时候没有处理,而是直接找了别的办法去脱出dex,这个样本,又一次遇到了带大量简单花指令的initarray,在老大的要求下,决定对抗一波。
简单的脚本界面
脱壳成长之路(3)-初识VMP
log_saver:主要是保存动态调试保存so的日志
init_array:快速定位到so的initarray起始,提高一下每次调试的效率
最后一个就是辅助调试花指令了
花指令详情:
脱壳成长之路(3)-初识VMP
汇编代码中有大量的形似与上面的指令,都是无效指令,分析的时候十分费时间,由于这个花指令特征非常明显,所以可以写脚本去辅助分析。
我的思路:
遍历整个代码匹配花指令的头,然后在花指令后面2句最终BEQ或者B的地址继续循环,直到不是花指令为止,下断点。这里面有可能会遇到真正有用的代码在花指令中,这种情况,可以try一下,catch的时候在头部地址下段即可
核心代码: [pre]# 脚本一定要在线程中执行,否则会卡住主线程,导致界面卡死
def loop_flower_code(self, cur_addr):
dsm = idaapi.generate_disasm_line(cur_addr)
dsm = str(dsm)
if '0x3F0C' in dsm and 'LDR' in dsm:
try:
print 'flower code start'
self.flower_start = True
addrbe = cur_addr + 0x18
addrB = cur_addr + 0x1A
dsmBe = idaapi.generate_disasm_line(addrbe)
dsmB = idaapi.generate_disasm_line(addrB)
f_addr = dsmBe.split('loc_')[1]
s_addr = dsmB.split('loc_')[1]
f_addr = int(f_addr, 16)
s_addr = int(s_addr, 16)
# 继续循环后面跳转的地址
self.loop_flower_code(f_addr)
self.loop_flower_code(s_addr)
except BaseException:
# 这里检测到不是标准的花指令,说明中间有有用的代码,所以在头部下断点
idc.add_bpt(cur_addr, 1)
elif self.flower_start:
# 检测到已经不是花指令了,下断点
print 'bpt:' + str(hex(cur_addr))
self.flower_start = False
idc.add_bpt(cur_addr, 1)[/pre]
后面继续分析initarray,发现有so抹头,初始化反调试、和解密so的操作,篇幅原因就不截图了,印象笔记有完整的分析笔记,有需要的可以私我一哈。 0x2 dexdump,并修复大偏移标准操作,dexdump,并且修复大偏移,这个操作就不再重复写了,有需求可以看我之前的文章。
贴一个dump出的dex
脱壳成长之路(3)-初识VMP
会发现,apk中的所有activity的onCreate函数被抽取了,然后调用了native的函数,现在仔细分析一下native函数
hook register_natvie 拿到动态注册函数的地址,然后进行分析
最终发现so中频繁调用JNI接口,于是简单的hook了一波
find cls android/app/Activity|onCreate
find cls com/nfbazi/xuankong/activity_register | setContentView
find cls android/widget/EditText
find cls com/nfbazi/xuankong/a/a
setText
setFocusable
setFocusableInTouchMode
find cls android/widget/Button
find cls com/nfbazi/xuankong/cr
find cls com/nfbazi/xuankong/cq
find cls android/widget/TextView
发现,之前java实现的功能,都用JNI实现了。于是开始了漫长的分析(过程十分漫长,我反复看了很多遍so)最终在老大的提示下,定位到下图结构体
脱壳成长之路(3)-初识VMP
脱壳成长之路(3)-初识VMP
codeitem相关:
脱壳成长之路(3)-初识VMP
置换:
正常
206F 001A 0054 invoke-super {v4, v5},
处理后
2086 001A 0054 invoke-super {v4, v5},
所以这里面0x86 对应 smali opcode 6F 0x3 修复nativeMethodhook点:
脱壳成长之路(3)-初识VMP
dump code_item脚本[pre]void *(*old_func)(void *baidu, int index);
void *new_func(void *baidu, int index) {
//这里会Crash。不过不要紧,我们紧紧要他的code
int startAddress = (int) baidu;
BDList *list = (BDList *) startAddress;
log("%x", list->onCreateCodeStart[0xA]);
CreateCode *code = (CreateCode *) list->onCreateCodeStart[0xA];
log("%x", code->index);
int codeSize = code->codeSize;
log("code size is %d", codeSize);
FILE *codeFile = fopen("/data/data/com.nfbazi.xuankong/cache/code.dex", "w+");
char *CodeItem = (char *) code->codeItem;
fwrite(CodeItem + 2, 1, codeSize * 2, codeFile);
fclose(codeFile);
exit(0);
return old_func(baidu, index);
}
/**
* register函数启始地址
* @param address
*/
void dumpCodeItem(void *address) {
int addr = (int) address;
int offest = 0x1785C;
void *p_addr = (void *) (addr + offest);
log("%p", p_addr);
if (old_func == 0) {
elf_hook_Direct(p_addr, (void *) &new_func, (void **) &old_func);
}
}
本地修复dex
#include <iostream>
#include <cstdio>
#define BYTE unsigned char
/**
* 每个opcode长度
*/
static unsigned char OpLen[256] =
{
0x02, 0x02, 0x04, 0xFF, 0xFF, 0x04, 0xFF, 0x02, 0x04, 0xFF, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x04, 0x06, 0x04, 0x04, 0x06, 0x0A, 0x04, 0x04, 0xFF, 0x04, 0x02, 0x02, 0x04,
0x04, 0x02, 0x04, 0x04, 0x06, 0x06, 0x06, 0x02, 0x02, 0x04, 0xFF, 0x06, 0x06, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x06, 0x06,
0x06, 0x06, 0x06, 0xFF, 0x06, 0x06, 0x06, 0x06, 0x06, 0xFF, 0xFF, 0x02, 0xFF, 0x02, 0xFF, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x06, 0xFF,
0x06, 0xFF, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x06, 0x06, 0x06, 0x06, 0xFF, 0xFF, 0xFF, 0xFF
};
//置换表
int Res_OpBaidu[256] =
{
//0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, 0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // 0
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00, // 1
0x0F,0x0E,0x11,0x10,0x18,0x19,0x1A,0x1B, 0x1C,0x12,0x13,0x14,0x15,0x16,0x17,0x01, // 2
0x02,0x03,0x08,0x09,0x04,0x05,0x06,0x07, 0x0A,0x0B,0x0C,0x0D,0x1D,0x1E,0x1F,0x23, // 3
0x24,0x20,0x21,0x22,0x25,0xFF,0x27,0x28, 0x29,0x2A,0x34,0x35,0x36,0x37,0xFF,0x49, // 4
0x4E,0x51,0x52,0x53,0x54,0x55,0xFF,0x2D, 0x31,0x32,0x33,0x38,0x39,0x3A,0x2E,0x2F, // 5
0x30,0x3B,0x3C,0x3D,0x44,0x45,0x46,0x4A, 0x4B,0x4C,0x4D,0x47,0x48,0x4F,0x50,0x56, // 6
0x5C,0x5D,0x5E,0x57,0x58,0x59,0x5A,0x5B, 0x62,0x63,0x64,0x65,0x5F,0x60,0x61,0x66, // 7
0x67,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,0x68, 0x69,0x70,0x71,0x72,0x82,0x83,0x84,0x85, // 8
0x86,0x74,0x78,0x7B,0x7C,0x7D,0x7E,0x7F, 0x75,0x76,0x77,0x80,0x81,0x87,0x88,0x89, // 9
0x8A,0x8B,0x93,0x94,0x95,0xA7,0xA8,0xA9, 0xAA,0xAB,0xAC,0x96,0x97,0x98,0x99,0x9A, // A
0x9B,0x9C,0x9D,0xB4,0xB5,0xB6,0xC6,0xC7, 0xC8,0xC9,0x9E,0x9F,0xA0,0xA1,0xA2,0x8C, // B
0x8D,0x8E,0x8F,0x90,0x91,0x92,0xA3,0xA4, 0xA5,0xA6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC, // C
0xBD,0xBE,0xBF,0xAD,0xAE,0xAF,0xB0,0xB1, 0xB2,0xB3,0xCA,0xCB,0xCC,0xD5,0xD6,0xD7, // D
0xD8,0xD9,0xDA,0xC0,0xC1,0xC2,0xC3,0xC4, 0xC5,0xDD,0xDE,0xDF,0xE0,0xE1,0xE2,0xFF, // E
0xFF,0xFF,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2, 0xD3,0xD4,0xDB,0xDC,0xFF,0xFF,0xFF,0xFF // F
};
int main() {
using namespace std;
int i = Res_OpBaidu[0x86];
cout << hex << i << endl;
int length = OpLen;
cout << hex << length << endl;
FILE *codeFile = fopen("/Users/roy/CLionProjects/FixCodeItem/code.dex", "r");
void *saveCode = malloc(214);
fread(saveCode, 1, 214, codeFile);
fclose(codeFile);
FILE *fixFile = fopen("/Users/roy/CLionProjects/FixCodeItem/code_fix.dex", "w+");
BYTE *codeChar = (BYTE *) saveCode;
int len = 0;
for (int j = 0; j < 214; ++j) {
BYTE code = codeChar[j];
int realopcode = Res_OpBaidu[pre];
if (j == len) {
printf("real opcode is %x\n", code);
codeChar[j] = realopcode;
len = len + OpLen[realopcode];
}
printf("%x\n", code);
}
fwrite(codeChar, 1, 214, fixFile);
fclose(fixFile);
// fread()
return 0;
}[/pre]
0x4 完成
脱壳成长之路(3)-初识VMP
感谢我的老大!
感谢大家观看
|