[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解

陪伴,九月加油^_^

最近真的太忙了,天天打仗一样,感谢大家的支持和关注,继续加油!该系列文章将系统整理和深入学习系统安全、逆向分析和恶意代码检测,文章会更加聚焦,更加系统,更加深入,也是作者的慢慢成长史。漫漫长征路,偏向虎山行。享受过程,一起奋斗~

前文详细介绍2020 Coremail钓鱼邮件识别及分析内容。这篇文章是作者2022年参加清华大学、奇安信举办的DataCon比赛,主要是关于涉网FZ分析,包括恶意样本IOC自动化提取和攻击者画像分析两类题目。这篇文章来自L师妹的Writeup,经同意后分享给大家,推荐大家多关注她的文章,也希望对您有所帮助。非常感谢举办方让我们学到了新知识,DataCon也是我比较喜欢和推荐的大数据安全比赛,我连续参加过四届,很幸运,我们团队近年来获得过第1、2、4、6、7、8名,不过也存在很多遗憾,希望更多童鞋都参加进来!感恩同行,不负青春,且看且珍惜!

  • 原文地址:https://www.wolai.com/iSjeGgwKtdGjeLzryhmn3S

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解

文章目录:

  • 一.题目介绍

  • 二.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


作者作为网络安全的小白,分享一些自学基础教程给大家,主要是关于安全工具和实践操作的在线笔记,希望您们喜欢。同时,更希望您能与我一起操作和进步,后续将深入学习网络安全和系统安全知识并分享相关实验。总之,希望该系列文章对博友有所帮助,写文不易,大神们不喜勿喷,谢谢!如果文章对您有帮助,将是我创作的最大动力,点赞、评论、私聊均可,一起加油喔!

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解


声明:本人坚决反对利用教学方法进行犯罪的行为,一切犯罪行为必将受到严惩,绿色网络需要我们共同维护,更推荐大家了解它们背后的原理,更好地进行防护。(参考文献见后)


一.题目介绍

DataCon官网题目:

  • https://datacon.qianxin.com/opendata/openpage?resourcesId=34

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解

目标:实现一个提取恶意样本IOC信息的自动化工具,即针对跨架构的Mirai僵尸网络,提取加密字符串、C2的host/port。

题目提供了967个Mirai二进制样本,其架构分布如下:

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解

针对以上样本,具体要求如下:

  • 自动识别出Mirai家族样本,非Mirai家族样本不做提取
  • 单个Mirai样本的平均提取时间不超过20秒
  • 提取Mirai C2的域名/IP及对应端口信息
  • 提取Mirai加密字符串信息

二.Mirai-bot源码分析

Mirai家族是针对IOT设备的僵尸网络,运行在受感染设备的bot源码主要分为以下四个模块:

  • attack模块:解析C2下发的攻击命令、对Victim发起DoS攻击

  • scanner模块:扫描其它可能受感染的设备,将爆破口令上报给C2

  • kill模块:关闭特定端口并占用、删除特定文件并kill对应进程(排除异己)

  • public模块:实现了公共函数,供其它模块调用

因此,为提取加密字符串和C2的host/port,将重点分析字符串加解密函数(public模块table.c的相关函数)、host/port的设置函数(main.c中resolve_cnc_addr函数)

1.字符串加解密函数

为增大逆向分析的难度,Mirai对使用的字符串加密写入数组 table 中,其结构定义如下:

struct table_value table[TABLE_MAX_KEYS];struct table_value {    char *val;              //字符串指针    uint16_t val_len;       //字符串长度    BOOL locked;            //字符串是否加密};

table.c中共有以下五个函数。首先,调用table_init初始化所有table中的字符串成员,针对每个字符串,调用add_entry添加到table中。在使用table[id]对应字符串前,调用table_unlock_val对table[id]解密。使用时,调用table_retrieve_val取出table[id]对应的字符串。使用完后,调用table_lock_val对table[id]重新加密。其中,加解密函数调用了toggle_obf对字符串进行异或操作。

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中的字符串

其中,toggle_obf函数的实现如下,即对字符串的每个字节,使用密钥table_key的每个字节和它进行异或。由于是异或操作,加密函数table_lock_val和解密函数table_unlock_val完全相同。

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}

对应PPT介绍如下:

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解


2.C2 host/port的设置函数

为防止动态调试,bot设置了SIGTRAP信号处理函数anti_gdb_entry,并raise(SIGTRAP)主动触发该信号。

  • 如果程序正在被调试,该信号将被发送给调试进程,处理函数无法执行。

  • 如果没被调试,bot才会收到该信号,执行anti_gdb_entry函数,该函数的功能很简短,即把实际C2 host/port的设置函数resolve_cnc_addr赋值给函数指针resolve_func。

static void anti_gdb_entry(int sig){    resolve_func = resolve_cnc_addr;}

在与C2通信时,调用resolve_cnc_addr函数设置srv_addr变量。首先从table中获取域名,调用resolv_lookup向DNS服务器查询其可能的IP,设置sin_addr整型IP(4字节)。再从table中获取端口,设置sin_port(2字节)

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}

对应PPT介绍如下:

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解


三.二进制样本分析

1.签到题3(附件2)

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解

1.1 提取解密字符串

观察到,.rodata节中有一系列加密字符串。

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解

查看这些加密字符串的引用,可以找到table_init函数。该函数很长,不断地分配内存和add_entry,且只有一个基本块。通过分析其它样本,这里需要注意的是:

  • add_entry时,.bss段中数组table的顺序和.rodata中字符串列表rodataTable中的顺序并不一致

  • 通过对其它样本分析,加密字符串的长度并不以作为结束,而是由这里设置的table.val_len决定

  • table的id是以1开始的

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解

查看table的引用,发现有4个函数使用了该变量。有两个函数完全相同,即table_lock_valtable_unlock_val,另外一个则是table_retrieve_val

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解

查看table_lock_val,它访问了.data节中的key

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解

还原加解密算法,于是可以对.rodata中的字符串解密,得到字符串明文configs如下:

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解

对应PPT介绍如下:

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解


1.2 提取C2 host/port

从源码分析中可知,anti_gdb_entry函数很短,就一个赋值语句,可按长度和操作码对其筛选如下:
[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解

于是可以找到resolve_cnc_addr如下。该函数设置了0x22C7C处的srv_addr的变量。

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解

srv_addr变量的类型是0x10字节的struct sockaddr_in,定义如下:

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]; }; 

srv_addr+0x2为port,srv_addr+0x4为整型ip。这里的ip使用的是局部变量0xAB92572F,port是table[1]中的内容b’x05x16’。由于网络字节序是大端字节序,因此host为47.xx.xx.171,port为1302。

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解


2.签到题4(附件3、4)

附件3可以使用upx.exe成功脱壳,附件4的壳无法识别。

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解

UPX壳包含以下两个关键的结构体:

  • l_version,l_format

  • p_filesize,p_blocksize

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]};

upx.exe在识别壳、脱壳时,需满足以下3个规则:

  • 在1)头部l_info.l_versionl_info.l_format3)尾部-0x20的2字节:版本和格式信息均相等

  • 在1)头部l_info.l_magic2)尾部-0x243)尾部-0x2C的4字节:均有l_magic(UPX!)

  • 在1)头部p_info.p_filesize2)头部p_info.p_blocksize3)尾部-0xC的4字节:均相等

(尾部上面一个magic的偏移不一定是-0x2C,可能是-0x29-0x2F

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解

附件4如下:

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解

发现尾部-0x20的2字节和附件3一样,应该是UPX版本和格式相同,然后搜索"0D 17",发现开头也有,于是可以还原UPX头部和尾部的格式。

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解

根据上述提到的3个规则,将0填充对应值,还原后如下:

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解

于是可以使用upx.exe脱壳

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解


四.自动化思路

自动化包括脱壳、提取解密字符串、提取C2三个阶段。

1.脱壳

(1)识别UPX壳,满足

  • 函数个数小于4(IDAPython)

  • 字节序列中包含version_format(0D 17或0D 0C)

(2)修复UPX壳

  • 根据第一个version_format定位UPX头部,最后一个定位UPX尾部

  • 根据尾部的version_format,去掉尾部多余字符

  • 填充UPX! 55 50 58 21

  • 根据尾部,填充头部的p_info.p_filesizep_info.p_blocksize

(3)使用 upx.exe脱壳

基本思路如下图所示:

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解


2.提取解密字符串

(1)找初始化函数 init_table

特征:(从小到大遍历所有函数,找到满足以下两点的最长函数)

  • 只含一个基本块

  • 内存访问只有.rodata和.bss

  • 代码很长

部分样本的init_table函数内嵌在了main函数里,也可将找初始化函数init_table转换为找相同初始化功能的基本块。

(2)记录密文字符串 rodataTable_addrs

分析init_table函数:

  • 记录.rodata段中的密文字符串的所有地址rodataTable_addrs

  • 记录.bss段table中的所有元素地址table_addrs,从而确定table的起始地址

  • 记录密文字符串长度strlens(malloc函数的参数)

部分样本的init_table函数中调用了add_entry函数,在init_table中只有table元素的偏移,得在add_entry中找table的起始地址。

(3)找解密函数 table_unlock_val
查看table的函数引用,两个完全相同的函数为加解密函数。同时,确定table_retrieve_val函数。

a) 部分样本中,table的引用还有两个函数,则还有toggle_obf函数,且table_retrieve_valtoggle_obf存在调用关系,可以确定调用函数是table_retrieve_val,被调函数是toggle_obf

b) 部分样本没有其它引用table的函数,则table以立即数写入,需逐函数查找。

(4)记录解密密钥 key
分析table_unlock_val函数,记录.data段中的解密密钥key

(5)解密得到configs
rodataTable_addrs的密文字符串,使用密钥key进行异或解密,得到明文字符串。至于configs中的地址为table_addrs

以上重要参数基本上以立即数出现、指令相对统一和简单,并且没有初步的分析不便于设置模拟执行的相关地址和参数,因此在该步骤中仅使用IDAPython分析指令,得到相关函数和变量的地址。

基本思路如下图所示:

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解


3.提取C2 host/port

总体思路是,通过anti_gdb_entry函数,找到resolve_cnc_addr函数,该函数中包含C2 host/port的srv_addr结构。模拟执行init_tableresolve_cnc_addr函数,读取srv_addr中的ip、port。因此,可分为查找相关函数和变量、模拟执行获取host/port两步。

3.1 查找相关函数和变量

第一步,找信号处理函数 anti_gdb_entryC2地址设置函数 resolve_cnc_addr

anti_gdb_entry特征:(从小到大遍历所有函数,找到满足以下两点的函数)

  • 只包含两个变量(一个是.data节的resolve_func函数指针、一个是.text节的resolve_cnc_addr函数地址)

  • 函数大小固定(同一架构下,该赋值操作的指令模式相同,例如ARM里为"LDR", “LDR”, “STR”, “BX”)

a) 部分样本没有找到anti_gdb_entry函数,但是通过分析样本发现,一些resolve_cnc_addr在设置host/port时,会调用table_retrieve_val(1)。因此,可进一步查看table_retrieve_val的引用,找到参数为1的函数即为resolve_cnc_addr

b) 部分样本的resolve_cnc_addr函数内嵌在了main函数里,也可将找初始化函数resolve_cnc_addr转换为找类似功能的基本块。

第二步,找地址变量 srv_addr
分析resolve_cnc_addr函数,记录.bss中的所有变量,包括srv_addrsrv_addr+0x2处的port、srv_addr+0x4处的ip,取最小值即为srv_addr

部分样本还包含srv_addr-0x10的地址,但没有对其0x10范围内的其它引用,可以过滤掉。


3.2 模拟执行获取host/port

下面代码中,以ARM架构为例。

第一步,设置内存布局

  • (1) 将样本的各个节写入内存中,基址为imagebase。

ADDRESS = idaapi.get_imagebase()mu = Uc(UC_ARCH_ARM, UC_MODE_LITTLE_ENDIAN)mu.mem_map(ADDRESS, 2 * 1024 * 1024)for segm_ea in idautils.Segments():    segm = idaapi.getseg(segm_ea)    data = idc.get_bytes(segm.start_ea, segm.size())    mu.mem_write(segm.start_ea, data)
  • (2) 设置栈、栈顶寄存器

mu.mem_map(STACK_ADDR, STACK_SIZE)mu.reg_write(UC_ARM_REG_SP, STACK_ADDR + (STACK_SIZE//2))
  • (3) 设置堆
    这里简化了堆的结构,仅仅在HEAP_ADDR保存了所有的UserData,并用
    unicorn_heap记录所有已分配UserData的起始地址,最后一项为最后一个UserData的结束地址。

mu.mem_map(HEAP_ADDR, HEAP_SIZE)unicorn_heap = [HEAP_ADDR]

第二步,设置hook函数
针对以下三类函数和指令,需设置相应的hook。

  • (1) malloc函数
    针对静态链接,由于库函数代码基本不变且代码较长,可根据函数大小进行筛选,得到hook的地址。针对动态链接,由于只在模拟执行
    init_table时会遇到,可在init_table调用.plt中的地址时进行hook。
    该函数是分配内存,hook以后,利用
    unicorn_heap返回UserData地址即可。

 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)   #返回分配的内存地址
  • (2) resolve_lookup函数
    由于是Mirai的公共函数,大小是固定的几个且代码较长,可根据函数大小进行筛选,得到hook的地址。
    该函数是将域名转为IP,hook以后,根据函数的参数,得到域名字符串的地址。如果该地址在.rodata中,直接提取即可。如果该地址在
    unicorn_heap堆中,可根据UserData的分配顺序,得到域名在configs中的索引ip_domain_index,从而提取host的域名。同时,为避免后面的代码在使用struct resolv_entries *entries;时发生内存访问错误,需简单伪造一下结构体内容。

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] #指向entriesunicorn_heap.append(unicorn_heap[-1] + 0x8)addrs_ptr = unicorn_heap[-1] #指向entries.addrsunicorn_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)
  • (3) 其它发生错误但不为table相关功能的函数和指令(例如"__udivsi3"和"__umodsi3"指令)。

第三步,模拟执行init_table
起始地址为init_table.start_ea,结束地址为init_table.end_ea的函数返回指令。

第四步,模拟执行 resolve_cnc_addr
起始地址为resolve_cnc_addr.start_ea,结束地址为最后一次修改srv_addr的下一条指令。

第五步,读取ip/port
如果没有调用resolve_lookup函数,则host以ip的形式出现,读取srv_addr+4的内存即为ip。port为srv_addr+2的内存内容。

基本思路如下图所示:

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解


五.小结与展望

通过人工分析json对应样本和签到题可以发现,提取configs的关键函数是init_table,提取host/port的关键函数是resolve_cnc_addr。通过模拟执行这两个函数,将字符串的初始化、加解密、提取都交给unicorn,然后读取srv_addr处的内容,能有效提升自动化的准确率,降低IDAPython静态分析的复杂度。

最后,感谢老师和实验室所有小伙伴,感谢DotaCon团队,感谢师妹师弟,感谢DataCon为我们提供这么好的比赛。基础性文章,希望对您有所帮助,感恩遇见,不负青春!

  • 一.题目介绍

  • 二.Mirai-bot源码分析
    1.字符串加解密函数
    2.C2 host/port的设置函数

  • 三.二进制样本分析

  • 四.自动化思路
    1.脱壳
    2.提取解密字符串
    3.提取C2 host/port

  • 五.小结与展望

欢迎大家讨论,是否觉得这系列文章帮助到您!任何建议都可以评论告知读者,共勉。

  • 逆向分析:

    • https://github.com/eastmountyxz/

      SystemSecurity-ReverseAnalysis

  • 网络安全:

    • https://github.com/eastmountyxz/

      NetworkSecuritySelf-study


写了12年的博客,今年确实有点写不动了,一方面确实很忙,另一方面兴趣和精力大不如前,感觉写不了一点,今年只写了36篇,好懈怠打开CSDN看到读者最近的留言,还是有很多读者期待我更新的,也有些老乡或博友陆续找到工作、升学、考研、考博,以及在各自小领域坚持着,并在博客留言中告知我,这些评论总能感动我,尤其看到一位初中学生私信想加我好友,并且撰写了二十多篇算法和C++的博客(图8),挺有趣的,也想到了十多年前充满激情分享博客的自己。

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解
尽管激情已去,但自己还是鼓起勇气开了《文本挖掘和知识发现》新专栏写了篇文章,也希望督促自己坚持,争取能成为小珞的“榜样”,第一篇主题演化分析是图情和数据科学方向学生必备的知识,万字长文的系列文章希望对初学者有所帮助。希望后浪们继续加油,希望小珞珞健康快乐成长,学会脚踏实地、知行合一、砥砺前行,未来是你们的。最近爸爸妈妈都忙,小宝也不在身边,我们爱你喔。

[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解

(By:Eastmount 2023-09-05 夜于火星)


参考链接:

  • Mirai 源码分析 (seebug.org)

  • linux程序安全之反调试反跟踪 - 知乎 (zhihu.com)

  • https://cujo.com/upx-anti-unpacking-techniques-in-iot-malware/

前文回顾(下面的超链接可以点击喔):

原文始发于微信公众号(娜璋AI安全之家):[系统安全] 五十三.DataCon竞赛 (2)2022年DataCon涉网分析之恶意样本IOC自动化提取详解

相关文章

暂无评论

暂无评论...