陪伴,九月加油^_^
最近真的太忙了,天天打仗一样,感谢大家的支持和关注,继续加油!该系列文章将系统整理和深入学习系统安全、逆向分析和恶意代码检测,文章会更加聚焦,更加系统,更加深入,也是作者的慢慢成长史。漫漫长征路,偏向虎山行。享受过程,一起奋斗~
-
一.题目介绍
-
二.Mirai-bot源码分析
-
1.字符串加解密函数
-
2.C2 host/port的设置函数
-
三.二进制样本分析
-
1.签到题3(附件2)
-
1.1 提取解密字符串
-
1.2 提取C2 host/port
-
2.签到题4(附件3、4)
-
四.自动化思路
-
1.脱壳
-
2.提取解密字符串
-
3.提取C2 host/port
-
3.1 查找相关函数和变量
-
3.2 模拟执行获取host/port
-
五.小结与展望
作者的github资源:
-
逆向分析:
-
https://github.com/eastmountyxz/
SystemSecurity-ReverseAnalysis
-
网络安全:
-
https://github.com/eastmountyxz/
NetworkSecuritySelf-study
二.Mirai-bot源码分析
1.字符串加解密函数
struct table_value table[TABLE_MAX_KEYS];
struct table_value {
char *val; //字符串指针
uint16_t val_len; //字符串长度
BOOL locked; //字符串是否加密
};
void table_init(void); //初始化table中的成员
void table_unlock_val(uint8_t id); //解密table中对应id的成员
void table_lock_val(uint8_t id); //加密table中对应id的成员
char *table_retrieve_val(int id, int *len); //取出table中对应id的成员
static void add_entry(uint8_t id, char *buf, int buf_len); //向table中添加成员
static void toggle_obf(uint8_t id); //和密钥key异或,即加解密table中的字符串
static void toggle_obf(uint8_t id)
{
int i;
struct table_value *val = &table[id];
uint8_t k1 = table_key & 0xff,
k2 = (table_key >> 8) & 0xff,
k3 = (table_key >> 16) & 0xff,
k4 = (table_key >> 24) & 0xff;
for (i = 0; i < val->val_len; i++)
{
val->val[i] ^= k1;
val->val[i] ^= k2;
val->val[i] ^= k3;
val->val[i] ^= k4;
}
#ifdef DEBUG
val->locked = !val->locked;
#endif
}
2.C2 host/port的设置函数
static void anti_gdb_entry(int sig)
{
resolve_func = resolve_cnc_addr;
}
struct sockaddr_in srv_addr;
struct resolv_entries {
uint8_t addrs_len;
ipv4_t *addrs;
};
static void resolve_cnc_addr(void)
{
struct resolv_entries *entries;
table_unlock_val(TABLE_CNC_DOMAIN);
entries = resolv_lookup(table_retrieve_val(TABLE_CNC_DOMAIN, NULL));
table_lock_val(TABLE_CNC_DOMAIN);
if (entries == NULL)
{
#ifdef DEBUG
printf("[main] Failed to resolve CNC addressn");
#endif
return;
}
srv_addr.sin_addr.s_addr = entries->addrs[rand_next() % entries->addrs_len];
resolv_entries_free(entries);
table_unlock_val(TABLE_CNC_PORT);
srv_addr.sin_port = *((port_t *)table_retrieve_val(TABLE_CNC_PORT, NULL));
table_lock_val(TABLE_CNC_PORT);
#ifdef DEBUG
printf("[main] Resolved domainn");
#endif
}
三.二进制样本分析
1.签到题3(附件2)
1.1 提取解密字符串
1.2 提取C2 host/port
struct sockaddr_in {
short int sin_family;
unsigned short int sin_port; //2字节
struct in_addr sin_addr; //整型IP,4字节
unsigned char sin_zero[8];
};
2.签到题4(附件3、4)
struct l_info // 12-byte trailer in header for loader
{
uint32_t l_checksum; // checksum
uint32_t l_magic; // UPX! magic [55 50 58 21]
uint16_t l_lsize; // loader size
uint8_t l_version; // version info
uint8_t l_format; // UPX format
};
struct p_info // 12-byte packed program header follows stub loader
{
uint32_t p_progid; // program header id [00 00 00 00]
uint32_t p_filesize; // filesize [same as blocksize]
uint32_t p_blocksize; // blocksize [same as filesize]
};
四.自动化思路
1.脱壳
2.提取解密字符串
b) 部分样本没有其它引用table的函数,则table以立即数写入,需逐函数查找。
3.提取C2 host/port
3.1 查找相关函数和变量
b) 部分样本的
resolve_cnc_addr
函数内嵌在了main函数里,也可将找初始化函数resolve_cnc_addr
转换为找类似功能的基本块。
3.2 模拟执行获取host/port
ADDRESS = idaapi.get_imagebase()
mu = Uc(UC_ARCH_ARM, UC_MODE_LITTLE_ENDIAN)
2 * 1024 * 1024)
for segm_ea in idautils.Segments():
segm = idaapi.getseg(segm_ea)
data = idc.get_bytes(segm.start_ea, segm.size())
data)
mu.mem_map(STACK_ADDR, STACK_SIZE)
mu.reg_write(UC_ARM_REG_SP, STACK_ADDR + (STACK_SIZE//2))
mu.mem_map(HEAP_ADDR, HEAP_SIZE)
unicorn_heap = [HEAP_ADDR]
ret = mu.reg_read(UC_ARM_REG_R14)
mu.reg_write(UC_ARM_REG_PC, ret)
arg0 = mu.reg_read(UC_ARM_REG_R0) #malloc请求UserData的大小
addr = unicorn_heap[-1] #在unicorn_heap中分配内存
unicorn_heap.append(unicorn_heap[-1] + arg0) #更新最后一个块的结束地址
mu.reg_write(UC_ARM_REG_R0, addr) #返回分配的内存地址
ret = mu.reg_read(UC_ARM_REG_R14)
mu.reg_write(UC_ARM_REG_PC, ret)
arg0 = mu.reg_read(UC_ARM_REG_R0)
if arg0 in unicorn_heap:
ip_domain_index = unicorn_heap.index(arg0)
if len(configs) > ip_domain_index:
ip_domain = configs[ip_domain_index][1]
ip_domain = ''.join([chr(i) for i in ip_domain])
elif idc.get_segm_name(arg0) == '.rodata':
ip_domain = read_str_until_zero(arg0)
entries_ptr = unicorn_heap[-1] #指向entries
unicorn_heap.append(unicorn_heap[-1] + 0x8)
addrs_ptr = unicorn_heap[-1] #指向entries.addrs
unicorn_heap.append(unicorn_heap[-1] + 0x4)
entries = p32(1) + p32(addrs_ptr)
addrs = p32(0x01020304)
mu.mem_write(entries_ptr, entries + addrs)
mu.reg_write(UC_ARM_REG_R0, entries_ptr)
五.小结与展望
-
逆向分析:
-
https://github.com/eastmountyxz/
SystemSecurity-ReverseAnalysis
-
网络安全:
-
https://github.com/eastmountyxz/
NetworkSecuritySelf-study
尽管激情已去,但自己还是鼓起勇气开了《文本挖掘和知识发现》新专栏写了篇文章,也希望督促自己坚持,争取能成为小珞的“榜样”,第一篇主题演化分析是图情和数据科学方向学生必备的知识,万字长文的系列文章希望对初学者有所帮助。希望后浪们继续加油,希望小珞珞健康快乐成长,学会脚踏实地、知行合一、砥砺前行,未来是你们的。最近爸爸妈妈都忙,小宝也不在身边,我们爱你喔。
前文回顾(下面的超链接可以点击喔):
-
[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解
原文始发于微信公众号(娜璋AI安全之家):[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解