感谢2023年的陪伴,2024年继续加油^_^
该系列文章将系统整理和深入学习系统安全、逆向分析和恶意代码检测,文章会更加聚焦,更加系统,更加深入,也是作者的慢慢成长史。漫漫长征路,偏向虎山行。享受过程,一起奋斗~
前文介绍了软件来源分析,结合网络攻击中常见的判断方法,利用Python调用扩展包进行区域溯源。这篇文章将开启IDA Python学习,首先介绍IDA Python配置过程和基础用法,然后尝试地区恶意软件的控制流图(CFG),再为后续的恶意软件家族分类或溯源提供帮助。由于作者是初学者,因此会遇到很多问题,欢迎各位大佬和读者指导。基础性基础,且看且珍惜。
文章目录:
-
一.测试样本生成
-
二.IDA手动提取CFG
-
1.IDA概述
-
2.IDA手动保存CFG
-
3.GDL转换为图片格式
-
三.IDA Python基础用法
-
1.官方文档介绍
-
2.IDA如何运行Python代码
-
3.基础用法
-
4.他山之石
-
四.IDA Python自动生成控制流图
-
五.总结
作者的github资源:
作者作为网络安全的小白,分享一些自学基础教程给大家,主要是关于安全工具和实践操作的在线笔记,希望您们喜欢。同时,更希望您能与我一起操作和进步,后续将深入学习网络安全和系统安全知识并分享相关实验。总之,希望该系列文章对博友有所帮助,写文不易,大神们不喜勿喷,谢谢!如果文章对您有帮助,将是我创作的最大动力,点赞、评论、私聊均可,一起加油喔!
声明:本人坚决反对利用教学方法进行犯罪的行为,一切犯罪行为必将受到严惩,绿色网络需要我们共同维护,更推荐大家了解它们背后的原理,更好地进行防护。(参考文献见后)
一.测试样本生成
首先,我们编写一段C语言程序并生成对应的可执行文件。如下图所示:
该程序逻辑比较简单,包含一个条件语句、一个循环语句和一个函数调用。
#include <stdio.h>
int sub_num(int a, int b) {
int s;
s = a + b;
printf("函数运算结果: %dn",s);
return s;
}
int main() {
int i,m,n;
int result=0;
scanf("%d %d",&m,&n);
printf("输入的数字为:%d %d",m,n);
if (m>10) {
printf("数字大于10n");
}
else {
printf("数字小于等于10n");
}
for (i=0; i<=10; i++) {
result += i;
i++;
}
printf("1 + 2 + ... + 10 = %dn",result);
result = result + sub_num(m,n);
printf("最终输出结果: %dn",result);
return 0;
}
输出结果如下图所示:
编译生成的中间文件如下所示:
二.IDA手动提取CFG
接着介绍IDA Python配置过程,并讲解如何实现IDA手动提取控制流图(CFG)。
1.IDA概述
IDA Pro(Interactive Disassembler Professional)简称“IDA”,是Hex-Rays公司出品的一款交互式反汇编工具,是目前最棒的一个静态反编译软件,为众多0day世界的成员和ShellCode安全分析人士不可缺少的利器。IDA Pro具有强大的功能,但操作较为复杂,需要储备很多知识,同时,它具有交互式、可编程、可扩展、多处理器等特点,可以通过Windows或Linux、MacOS平台来分析程序, 被公认为最好的逆向工程利器之一。
第一步,打开IDA Pro32软件选择一个exe文件载入,它将是我们要进行分析的程序,所分析的程序时上面撰写的C语言代码。
IDA反汇编包括两个阶段,首先将程序的代码和数据分开,分别标记函数并分析参数调用、跳转、指令关系等;接着如果IDA能识别文件的编译类型,就装载对应的编译器特征文件,给各函数赋名。同时,IDA会创建一个数据库,其组件分别保存在“.id0”、“.id1”、“.nam”和“.til”的文件里。
第二步,在弹出确认窗口中选择“Don’t show this message again”选项,在“Check for Hex-Rays product updates”中点击“OK”。运行结果如下图所示,接着可以开始我们的逆向分析。
第三步,选择“_main_0”函数查看程序的控制流图,下图可以看到代码及部分注释。
第四步,按下F5能够查看对应的源代码,另一个自定义函数为,可以查看其加分操作。
第五步,可以在Graph View和Text View中切换。
最后,关闭IDA Pro并保存数据库文件,下次载入时,可以直接加载数据库文件,获取之前分析的状态。
2.IDA手动保存CFG
函数调用图
在菜单栏中点击“view–>graphs–>Function calls”,查看函数调用图。
显示结果如下图所示:
-
为啥显示这么复杂呢?
-
如何提取关键函数的调用关系呢?
函数流程图
在菜单栏中点击“view–>graphs–>flowt chart”,查看函数流程图,其显示效果与IDA自带的反汇编流程视图相似。
在WinGraph中点击“file–>save as”,将调用关系另存为GDL(graph discription language)文本为test01.gdl。
保存的文件结果显示如下:
3.GDL转换为图片格式
读者可以尝试安装EasyGraph扩展包,将GDL转换为DOT格式,或利用GraphViz绘制图片。
示例代码:
from easygraph.datasets import get_graph_karateclub
import easygraph as eg
G = get_graph_karateclub()
shs = eg.common_greedy(G, 5)
eg.draw_SHS_center(G, shs)
eg.plot_Followers(G, shs)
如何实现如下效果呢?推荐文章:
三.IDA Python基础用法
下面介绍IDA Python的基础用法。
1.官方文档介绍
推荐读者学习IDA Python官方文档,尤其是需要了解和查询某个函数的用法时。
-
https://github.com/idapython
-
https://www.hexrays.com/products/ida/support/idapython_docs/
-
《The Beginner’s Guide to IDAPython》 by Alexander Hanel
下面官网中包含各种API以及返回值数据类型,都还蛮详细的,推荐大家学习。
2.IDA如何运行Python代码
IDA Python是IDA6.8后自带插件,可以使用Python做很多的辅助操作。作者所使用的IDA版本为7.5,其支持Python3(7.0往前只支持Python2)。
第一步,在IDA中下部的Output Window中有个终端界面,包含python终端和IDC终端。
比如,我们输入Python代码即可打印,如下所示:
第二步,我们尝试调用IDA Python并输出代码对样本进行分析。
关键代码如下:
Python>DataRefsTo(here())
<generator object refs at 0x00000197D0679B48>
Python>import idautils
Python>idautils.DataRefsTo(here())
<generator object refs at 0x00000197D0679B48>
提问:如何在IDA中调用Python脚本呢?并且实现批量处理。
3.基础用法
IDAPython创建于2004年,其是Gergely Erdelyi和 Ero Carrera的共同努力结果。他们的目标是将Python的强大功能与IDA的IDC C类脚本语言的分析自动化结合起来。IDA Python由三个独立的模块组成。
- idc:负责提供IDA中的所有函数功能
- idautils:负责提供大量实用函数
- idaapi:负责访问核心IDA API
Python>info = idaapi.get_inf_structure()
Python>print(info)
<ida_ida.idainfo; proxy of <Swig Object of type 'idainfo *' at 0x000001C3E0E48330> >
推荐大家阅读这部书《The Beginner’s Guide to IDAPython —— Alexander Hanel》 。比如:
-
idc.ScreenEA()函数或here()函数:获取当前光标所在地址
-
idc.SegName(ea):获取当前地址所在的段(segment)名称
-
idc.GetDisasm(ea):获取当前地址的反汇编语句
-
idc.GetMnem(ea):获取当前反汇编语句的操作符
-
idc.GetOpnd:获取操作数
-
idaapi.MinEA():获取载入程序的最小的有效地址
-
idaapi.MaxEA():获取载入的程序最大的有效地址
4.他山之石
下面补充CFT师弟的IDA笔记供大家学习,非常不错的记录,在此感谢。
(1) idapython python3 关键函数所在库
##################################
# idaapi
##################################
get_inf_structure() # info = get_inf_structure(), info.is32bit(), info.procName是处理器架构
FlowChart(get_func(ea)) #
##################################
# idautils
##################################
Functions() # 列出所有的函数,返回的是一个迭代器,其中的所有元素都是函数起始地址
Strings() # 列出所有字符串,每个字符串都有ea, length和strtype属性
Names() # 所有的name,包括函数名,字符串名
##################################
# ida_auto
##################################
auto_wait() # 批量处理脚本时用的,等待自动分析完成再进行分析,尽可能加,否则脚本可能无法完整执行
##################################
# ida_bytes
##################################
ida_bytes.get_byte(ea) # 获取一个字节
ida_bytes.get_word(ea) # 获取两个字节
ida_bytes.get_dword(ea) # 获取四个字节
# 修改数据类型,相当于手动操作时在对应位置按"D"
# 这里也可以循环操作,比如一大块内存都是通过bytes表示的,需要换成8bit、16bit或32bit表示可以这样
create_byte(ea, 1)
create_16bit_data(ea, 2) # 第二个参数搞不懂有啥用,就按字节数保持不变通过循环实现吧
create_32bit_data(ea, 4)
##################################
# ida_funcs
##################################
get_func(ea) # 返回当前地址对应的函数的一些信息,其中start_ea是起始地址,end_ea是结束地址
get_func_name(ea) # 获取这个地址对应的函数名
##################################
# ida_nalt
##################################
get_root_filename() # 获取当前二进制文件的名字
get_imagebase() # 获取加载基址
##################################
# ida_pro
##################################
qexit(code) # 退出当前界面,相当于exit
##################################
# ida_search
##################################
find_text(ea, 0, 0, string, ida_search.SEARCH_DOWN) # ea是地址,string是要找的字符,其它的不动就行
# 要跳到下一个位置需要如此更新: ea = idc.next_head(ea)
##################################
# ida_ua
##################################
create_insn(ea) # 将ea开始的数据转化为代码,注意得先用create_byte把所有数据都转成byte,否则不能用
##################################
# ida_xref
##################################
get_first_fcref_to(addr) # 找到第一个引用addr的地址,没有则返回-1(也可能是BADADDR=2^32 - 1)
get_next_fcref_to(addr) # 调用上面的函数之后可以一直调用直到返回-1
get_first_cref_to(addr) # 找第一个代码引用
get_next_cref_to(addr)
get_first_dref_to(addr) # 找第一个数据引用
get_next_dref_to(addr)
##################################
# idc
##################################
find_func_end(ea) # 给定一个IDA能够识别的函数的开头,返回函数结尾
prev_head(ea) # ea位置上一条指令的地址(只能看相邻的地址,不能看跳转过来的位置)
next_head(ea) # 下一条指令的地址
get_operand_type(ea, n) # ea是指令地址,n代表第几个参数,感觉这个没啥用
get_operand_value(ea, n) # 获取参数的值
get_strlit_content(ea) # 获取ea位置的字符串,估计这个库在写的时候漏了一个l
print_insn_mnem(ea) # 打印操作码,实用的多,要是一个地址没有数据,那么就会返回空字符串(即'',而不是None)
print_operand(ea, n) # 打印操作数,n从0开始(第0个不是操作码,而是第一个操作数),超出下标的是空字符串''
(2) 获取所有函数的名字
from idautils import Names, Strings, Functions
for name in Names():
for string in Strings():
if int(name[0]) = int(string.ea):
print(hex(name[0]),str(name[1]),str(string))
(3) patch程序
from idc import GetDisasm, print_insn_mnem, get_operand_value
from ida_bytes import next_head
from ida_bytes import patch_byte
start = 0x798
end = 0xf67
ea = start
while ea < end:
old_ea = ea
instr1 = GetDisasm(ea)
op1 = print_insn_mnem(ea)
ea = next_head(ea, end)
instr2 = GetDisasm(ea)
op2 = print_insn_mnem(ea)
if (op1 = 'jb' and op2 = 'jnb') or (op1 = 'jnb' and op2 = 'jb'):
value1 = get_operand_value(old_ea, 0)
value2 = get_operand_value(ea, 0)
if value1 = value2:
print(hex(old_ea), instr1)
print(hex(ea), instr2)
print(hex(value1), hex(value2))
print('-' * 30)
old_ea = next_head(ea, end)
ea = value1
for i in range(old_ea, ea):
patch_byte(i, 0x90)
(4) ida脚本批量处理程序
import os
import subprocess
IDA_PATH = "E:\Apps\IDAPro7.5\ida64.exe"
PLUGIN_PATH = ".\get_end.py"
ELF_PATH = 'E:\feature-extractor\heart\'
elfs = os.listdir(ELF_PATH)
print('number of elfs:', len(elfs))
for elf in elfs:
elf_path = ELF_PATH + elf
cmd = IDA_PATH + " -c -A -S" + PLUGIN_PATH + " " + elf_path
subprocess.call(cmd)
(5) ida脚本传入参数
import idc
def main(A, B, C):
pass
if _ name _ = " _ main _ ":
idc.Wait()
main(idc.ARGV[1], idc.ARGV[2], idc.ARGV[3])
idc.Exit(0)
四.IDA Python自动生成控制流图
如何打开Python脚本进行批量处理呢?
在File中通过Script file打开指定脚本,比如获取当前程序的函数列表文件。
其代码如下:
from idaapi import *
functions = [get_func_name(x) for x in Functions()]
for function in functions:
print(function)
运行结果如下图所示,函数名称被获取。
接下来,如何利用IDA Python自动生成恶意样本的控制流图呢?我们将在下一篇博客中介绍,将继续探索。同时存在问题包括,感谢与师弟师妹们的探讨。
五.总结
写到这里,这篇文章就介绍完毕,希望对您有所帮助。
感谢大家2023年的支持和关注,让我们在2024年继续加油!分享更多好文章,感恩,娜璋白首。
(By:Eastmount 2024-01-30 夜于火星)
参考文献如下,感谢师弟师妹们的帮助和耐心解答。
-
[1] 《The Beginner’s Guide to IDAPython》 by Alexander Hanel
-
[2] 项目地址:https://github.com/idapython
-
[3] 官方IDA Python手册:https://www.hexrays.com/products/ida/support/idapython_docs/
-
[4] 《IDA pro权威指南》
-
[5] [安全工具][原创]保存IDA Pro中生成的函数调用关系(图)- GreatDane
-
[6] Easygraph:全面高效的图分析与社会计算开源工具 – PeppaRan
-
[7] Genius 二进制文件函数特征提取的复现 – Erio
-
[8] IDA Python安装与使用 – 17bdw
-
[9] ida运行python脚本 – 51cto
-
[10] 恶意功能定位 – 刘师妹
-
[11] 比较简单的IDAPython脚本 – 知乎
前文回顾(下面的超链接可以点击喔):
原文始发于微信公众号(娜璋AI安全之家):[系统安全] 五十五.恶意软件分析 (7)IDA Python基础用法及CFG控制流图提取详解[上]