对某梆企业加固壳分析

.init_proc

1
2
3
4
5
6
7
void __fastcall init_proc()
{
_BYTE *buf; // x0

buf = init_buf((__int64)&elf_hash_bucket[730] + (_QWORD)&off_128078, (__int64)&qword_2CEF0);
sub_12868C((uint64_t)&elf_hash_bucket[730] + (_QWORD)&off_128078, (uint64_t)&qword_2CEF0, (uint64_t)buf);
}

init_buf

通过mmap申请一块rwx内存,将压缩后的数据从data复制到申请的内存区域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
_BYTE *__fastcall init_buf(__int64 option, __int64 data)
{
int v3; // w20
_BYTE *v4; // x19
__int64 j; // x1
int i; // [xsp+3Ch] [xbp+3Ch]

for ( i = 273; i != 70; i = 70 )
;
v3 = *(_DWORD *)(option + 0x28); // 378034
v4 = bangbang_mmap_12818C(0, (v3 + 0xFFF) & 0xFFFFF000, 7, 34);// PROT_READ | PROT_WRITE | PROT_EXEC
// MAP_PRIVATE | MAP_ANONYMOUS
for ( j = 0; j != v3; ++j )
v4[j] = *(_BYTE *)(data + j);
bangbang_clean_data_128274((__int64)v4, (unsigned __int64)&v4[j]);
return v4;
}

do_deflate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
__int64 sub_12868C(uint64_t option, uint64_t data, uint64_t buf)
{
char *v3; // x30
int v7; // w24
int v8; // w22
int v9; // w1
elf64_hdr *module_base; // x19
unsigned __int8 *dst; // x20
int xor_key; // w25
unsigned int len; // w24
unsigned __int8 *v14; // x2
int v15; // w1
__int64 j; // x0
__int64 v17; // x1
unsigned __int64 v18; // x22
int v19; // w20
char *v20; // x26
int i; // [xsp+6Ch] [xbp+6Ch]

for ( i = 273; i != 70; i = 70 )
;
v7 = bangbang_strncmp_1281e8(v3, "__b_a_n_g_", 10);
v8 = bangbang_strncmp_1281e8(v3 + 10, "c_l_e__che", 10);
v9 = bangbang_strncmp_1281e8(v3 + 20, "ck1234567_", 10);
if ( (v7 == 0) <= (unsigned int)(v8 != 0) || v9 )
sub_128380(v3);
if ( (unsigned int)bangbang_strncmp_1281e8(unk_128D10, "__p_k_g_n_a_m_e__", 17) )
check_pkg_name();
module_base = (elf64_hdr *)(data - *(unsigned int *)(option + 0xC));
dst = &module_base->e_ident[*(unsigned int *)(option + 0x24)];
xor_key = *(_DWORD *)(option + 0x20); // always == 0
len = *(_DWORD *)(option + 0x28);
bangbang_mprotect_1281a0(
module_base,
((unsigned __int64)&dst[*(unsigned int *)(option + 0x1C) + 0xFFF + xor_key] & 0xFFFFFFFFFFFFF000LL)
- (_QWORD)module_base,
7);
sub_128A90((__int64)dst, buf, *(unsigned int *)(option + 0x1C), *(_DWORD *)(option + 0x28));
if ( xor_key )
{
for ( j = 0; xor_key > (int)j; j += 4 )
{
v17 = j + *(unsigned int *)(option + 0x1C);
*(_DWORD *)&dst[v17] ^= xor_key;
}
}
bangbang_clean_data_128274((__int64)dst, (unsigned __int64)&dst[*(unsigned int *)(option + 28)]);
v14 = &module_base->e_ident[module_base->e_phoff];// pht offset
v15 = *(_DWORD *)v14 == 1;
do
{
v14 += module_base->e_phentsize; // pht_size
if ( *(_DWORD *)v14 == 1 )
++v15;
}
while ( v15 != 2 );
v18 = (unsigned __int64)&module_base->e_ident[*((_QWORD *)v14 + 2)];
v19 = v18 + *((_QWORD *)v14 + 5);
v20 = (char *)(v18 & 0xFFFFFFFFFFFFF000LL);
LODWORD(v18) = (v18 + *((_QWORD *)v14 + 4) + 4095) & 0xFFFFF000;
bangbang_mprotect_1281a0(v20, (int)v18 - (int)v20, 3);
bangbang_mprotect_1281a0(&v20[(int)v18 - (int)v20], (int)(((v19 + 4095) & 0xFFFFF000) - v18), 3);
sub_12852C(
(__int64)&module_base->e_ident[*(unsigned int *)(option + 0x18)],
(__int64)&module_base->e_ident[*(unsigned int *)(option + 0x10)],
*(_DWORD *)(option + 0x14),
(int)module_base); // entry type
bangbang_munmap_128180((void *)buf, len);
return 0;
}

解压算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
__int64 __fastcall sub_128AB4(__int64 buf, unsigned int len, __int64 dst, unsigned int *a4)
{
unsigned int v4; // w7
unsigned int v5; // w5
unsigned int v6; // w9
unsigned __int64 v7; // x4
int v8; // w6
int v9; // w4
char v10; // w6
int i; // w6
int v12; // w8
int v13; // w6
unsigned __int64 v14; // x4
int v15; // w4
int v16; // w6
int v17; // w8
int v18; // w4
int v19; // w8
int v20; // w6
int v21; // w4
unsigned int v22; // w8
int v23; // w6
__int64 v24; // x6
unsigned int v25; // w5
int v26; // w8
int v27; // w6
int v28; // w4
int v29; // w6
int v30; // w6
int v31; // w8
int v32; // w6
int v33; // w4
int v34; // w8
int v35; // w4
_BYTE *v36; // x13
unsigned int v37; // w7
__int64 v38; // x8
char v39; // w12
__int64 v40; // x10
__int64 result; // x0

v4 = 0;
v5 = 1;
v6 = 0;
LODWORD(v7) = 0;
while ( 1 )
{
while ( 1 )
{
v8 = v7 & 0x7F;
LODWORD(v7) = 2 * v7;
if ( !v8 )
{
v9 = *(unsigned __int8 *)(buf + v6++);
LODWORD(v7) = 2 * v9 + 1;
}
if ( (v7 & 0x100) == 0 )
break;
v10 = *(_BYTE *)(buf + v6++);
*(_BYTE *)(dst + v4++) = v10;
}
for ( i = 1; ; i = ((v7 >> 8) & 1) + v20 )
{
v12 = v7 & 0x7F;
v13 = 2 * i;
v14 = (unsigned int)(2 * v7);
if ( !v12 )
{
v15 = *(unsigned __int8 *)(buf + v6++);
v14 = (unsigned int)(2 * v15 + 1);
}
v16 = ((v14 >> 8) & 1) + v13;
v17 = v14 & 0x7F;
LODWORD(v14) = 2 * v14;
if ( !v17 )
{
v18 = *(unsigned __int8 *)(buf + v6++);
LODWORD(v14) = 2 * v18 + 1;
}
if ( (v14 & 0x100) != 0 )
break;
v19 = v14 & 0x7F;
v20 = 2 * (v16 + 0x7FFFFFFF);
v7 = (unsigned int)(2 * v14);
if ( !v19 )
{
v21 = *(unsigned __int8 *)(buf + v6++);
v7 = (unsigned int)(2 * v21 + 1);
}
}
v22 = v6;
if ( v16 != 2 )
break;
v23 = v14 & 0x7F;
v14 = (unsigned int)(2 * v14);
if ( !v23 )
{
++v6;
v14 = 2 * (unsigned int)*(unsigned __int8 *)(buf + v22) + 1;
}
v24 = (v14 >> 8) & 1;
LABEL_21:
v26 = v14 & 0x7F;
v27 = 2 * v24;
v7 = (unsigned int)(2 * v14);
if ( !v26 )
{
v28 = *(unsigned __int8 *)(buf + v6++);
v7 = (unsigned int)(2 * v28 + 1);
}
v29 = ((v7 >> 8) & 1) + v27;
if ( !v29 )
{
v30 = 1;
do
{
v31 = v7 & 0x7F;
v32 = 2 * v30;
v7 = (unsigned int)(2 * v7);
if ( !v31 )
{
v33 = *(unsigned __int8 *)(buf + v6++);
v7 = (unsigned int)(2 * v33 + 1);
}
v30 = ((v7 >> 8) & 1) + v32;
v34 = v7 & 0x7F;
LODWORD(v7) = 2 * v7;
if ( !v34 )
{
v35 = *(unsigned __int8 *)(buf + v6++);
LODWORD(v7) = 2 * v35 + 1;
}
}
while ( (v7 & 0x100) == 0 );
v29 = v30 + 2;
}
v36 = (_BYTE *)(dst + v4 - (unsigned __int64)v5);
if ( v5 > 0x500 )
++v29;
*(_BYTE *)(dst + v4) = *v36;
v37 = v4 + 1;
v38 = 0;
do
{
v39 = v36[v38 + 1];
v40 = v37 + (unsigned int)v38++;
*(_BYTE *)(dst + v40) = v39;
}
while ( v29 != (_DWORD)v38 );
v4 = v37 + v29;
}
++v6;
v25 = *(unsigned __int8 *)(buf + v22) + (v16 << 8) - 768;
if ( v25 != -1 )
{
LODWORD(v24) = !(*(_BYTE *)(buf + v22) & 1);
v5 = (v25 >> 1) + 1;
goto LABEL_21;
}
*a4 = v4;
result = 0;
if ( v6 != len )
{
if ( v6 >= len )
return 4294967095LL;
else
return 4294967091LL;
}
return result;
}

一键脱壳脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
from elftools.elf.elffile import ELFFile
from unicorn.arm64_const import *
from unicorn import *
from capstone.arm64_const import *
from capstone import *
import lief

SP_START = 0x80000000
SP_SIZE = 0x1000 * 0x1000 * 6

so_name = "xxxxxxxxxxx.so"

def load_elf(filename):
global img_size
global out_data
segs = []
with open(filename, 'rb') as f:
out_data = f.read()
elf_file = ELFFile(f)
for seg in elf_file.iter_segments():
if seg['p_type'] != 'PT_LOAD':
continue
print('file_off:%s, va: %s, size: %s' %(hex(seg['p_offset']), hex(seg['p_vaddr']), hex(seg['p_filesz'])))
segs.append((seg['p_offset'],seg['p_vaddr'], seg['p_filesz'], seg.data()))

img_size = segs[-1][1] + segs[-1][2]
byte_arr = bytearray([0] * img_size)
for seg in segs:
vaddr = seg[1]
size = seg[2]
data = seg[3]
byte_arr[vaddr: vaddr + size] = bytearray(data)

return byte_arr


def hook_code(uc : Uc, address, size, user_data):
bytes = uc.mem_read(address, size)
ins = list(cs.disasm(bytes, address))
if len(ins) == 0:
return
ins = ins[0]

print("%x : %s %s" % (address, ins.mnemonic, ins.op_str))

def set_sp():
uc.reg_write(UC_ARM64_REG_SP, SP_START + SP_SIZE)

def skip_ins(n = 1):
uc.reg_write(UC_ARM64_REG_PC, uc.reg_read(UC_ARM64_REG_PC) + 4 * n)

# def hook_mem_access_invalid(uc : Uc, access_type, address, size, value, user_data):
# print("%x" % address)
# return True

def init_unicorn(file_name):
global bin_data
global uc

bin_data = bytes(load_elf(file_name))

uc = Uc(UC_ARCH_ARM64, UC_MODE_ARM)

uc.mem_map(SP_START, SP_SIZE)
uc.mem_map(0, 8 * 0x1000 * 0x1000)
uc.mem_map(0x13370000, 0x100000)

uc.mem_write(0, bin_data)

set_sp()

# uc.hook_add(UC_HOOK_CODE, hook_code)
uc.hook_add(UC_HOOK_MEM_WRITE, hook_mem_write)

def init_capstone():
global cs

cs = Cs(CS_ARCH_ARM64, CS_MODE_ARM)
cs.detail = True


sp_start = 0
sp_end = 0
chunk_start = 0
chunk_end = 0

def hook_mem_write(uc : Uc, access_type, address, size, value, user_data):
# print("0x%x: %s" % (address, hex(value)))

global sp_start, sp_end, chunk_start, chunk_end

if address <= 0x13470000 and address >= 0x13370000:
chunk_start = min(chunk_start, address)
chunk_end = max(chunk_end, address + size)


init_unicorn(so_name)
init_capstone()

init_proc_pattern = bytes.fromhex("FF 03 04 D1 E0 7B 00 A9 E0 07 01 A9 E2 0F 02 A9 E4 17 03 A9 E6 1F 04 A9 E8 27 05 A9 EA 2F 06 A9 EC 37 07 A9 EE 3F 08 A9 F0 47 09 A9 F2 4F 0A A9 F4 57 0B A9 F6 5F 0C A9 F8 67 0D A9 FA 6F 0E A9 FC 77 0F A9")
init_proc_offset = bin_data.find(init_proc_pattern)
print("init proc: %x" % (init_proc_offset))

init_block_offset = init_proc_offset + 0x44

uc.emu_start(init_block_offset, init_block_offset + 0x20, 0, 0)
option = uc.reg_read(UC_ARM64_REG_X0)
data = uc.reg_read(UC_ARM64_REG_X1)

print("option", hex(option))
print("data", hex(data))

# option + 0x1C dwrod
offset = int.from_bytes(uc.mem_read(option + 0x1C, 4), "little")
print("offset", hex(offset))

# option + 0x24 dword
dst = int.from_bytes(uc.mem_read(option + 0x24, 4), "little")
print("dst", hex(dst))

# option + 0x20 dword
xor_key = int.from_bytes(uc.mem_read(option + 0x20, 4), "little", signed=True)
print("xor_key", hex(xor_key))

if xor_key != 0:
print("not supported")
exit()

# option + 0x28 dword
length = int.from_bytes(uc.mem_read(option + 0x28, 4), "little", signed=True)
print("length", hex(length))

# 开始解密
# 128A90(dst, buf, offset, len)
deflate_pattern = bytes.fromhex("FD 7B BE A9 E2 03 00 AA E0 03 01 AA FD 03 00 91 E1 03 03 2A A3 73 00 91")
deflate_offset = bin_data.find(deflate_pattern)
print("deflate offset: %x" % (deflate_offset))

chunk_start = 0x13470000
chunk_end = 0

uc.reg_write(UC_ARM64_REG_X0, 0x13370000)
uc.reg_write(UC_ARM64_REG_X1, data)
uc.reg_write(UC_ARM64_REG_X2, offset)
uc.reg_write(UC_ARM64_REG_X3, length)
uc.reg_write(UC_ARM64_REG_LR, 0)
uc.emu_start(deflate_offset, 0, 0, 0)


if uc.reg_read(UC_ARM64_REG_X0) != 0:
print("解密失败")
exit(0)

new_length = chunk_end - chunk_start
dst_data = uc.mem_read(chunk_start, new_length)

binary = lief.parse(so_name)

target_segment = None
for segment in binary.segments:
start = segment.virtual_address
end = start + segment.virtual_size
if dst >= start and dst < end:
target_segment = segment
print(target_segment)
break

if target_segment is None:
raise RuntimeError("没找到包含目标地址的段")

offset_in_segment = dst - target_segment.virtual_address
segment_data = bytearray(target_segment.content)
segment_data[offset_in_segment:offset_in_segment + len(dst_data)] = dst_data
target_segment.content = list(segment_data)

if target_segment.sections:
for section in target_segment.sections:
section.name = ".text"

binary.write(so_name+"_fix.so")
print("解密完成, 回填 %d 字节到 %s" % (len(dst_data), so_name))

del binary

免责声明

本博客及其内容仅供合法、正当、健康的用途,旨在提供信息参考与学习交流之用。读者在使用、引用或转载本博客内容时,应自行判断合法性与适用性,确保遵守当地法律法规。
对于因使用本博客内容而产生的任何直接或间接损失、法律责任或纠纷,本博客及作者概不负责。
读者一旦使用或访问本博客,即视为已同意遵守上述条款。
感谢您的理解与配合!

版权信息

文章作者: Catluo
文章链接: 对某梆企业加固壳分析
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 授权协议
转载请注明来源 Catluo | Android 逆向与安全研究