在CTF的逆向中我们需要的是找到加密的主函数,结合了yara的识别原理,通过对常量数组的引用的查找,一步步递归构建调用树。调用树根部就是可能的密码算法主函数。

由于这种办法需要常量分布于算法的各个步骤中,所以尝试选取DES算法

一、DES算法识别的主要流程

1.1 背景介绍

密码学算法识别在很早之前就已经有成熟的实现。我遇到过的实现有如下几种:

  • 对于内嵌的代码,典型的有PEiD的KryptoAnalyzer插件。原理很简单,一般的密码学算法都有特定的常量数组,例如MD5的state(0123456789ABCDEFFE…10),DES的P_Box等等。找到该算法的一个常量数组就可以判定存在该密码学算法。

  • 对于使用第三方库,典型的有使用IDA的FILRT签名的快速识别,将常见的密码学库做成签名。那么调用的这个第三方库的所有加密函数都会被识别。

这篇文章主要讨论了第一种算法的实现与优化(因为KryptoAnalyzer只针对Windows平台,所以该算法实现对于辅助elf文件分析是有意义的)。

1.2 实现原理

对于第一种算法,以KryptoAnalyzer为例,它只会给出一个p_box识别的位置以及调用该常量的位置

而事实上例如DES之类的算法存在非常多的常量,我们完全可以尝试根据这些常量的位置,调用关系构建调用树,最终找到可能的主函数。

例如常量const1,const2,const3被addr1,addr2,addr3处的代码引用,这三处代码分别属于func1,func2,func3,而三个函数调用关系为func3调用func2,func1,我们可以根据常量、调用常量的位置(所属函数)以及调用这些调用常量的函数的函数构建关系图,最终找到可能的主函数func3。

1.3 实现流程

那么我们的实现流程如下:

  • 选择需要的常量

  • 查找各个常量所在位置

  • 查找引用各个常量的代码地址,查找这些地址所属函数,以及调用这些函数的地址以及其所属函数,构建调用树

1.4 思路局限性

当前思路由于需要大量常量,所以目前只适用于常量较多且分布于算法实现各个步骤的算法,因此本次实现选择了DES。

另外,即使构建了调用树,也无法百分百确定这个调用树的根就是算法的主函数,例如根为func,则主函数有可能是调用func的func1,需要使用者自行动态调试判断。且存在算法被篡改的可能性,此时就需要具体分析以寻找被篡改部分了。

需要注意的是,验证过程中注意输入类型,输入类型可能是一个String格式,有可能是自定义类型,一切需要具体情况具体分析。

二、DES算法

2.1 DES算法简介

DES算法为密码体制中的对称密码体制,又被称为美国数据加密标准。

DES是一个分组加密算法,典型的DES以64位为分组对数据加密,加密和解密用的是同一个算法。

密钥长64位,密钥事实上是56位参与DES运算(第8、16、24、32、40、48、56、64位是校验位,使得每个密钥都有奇数个1),分组后的明文组和56位的密钥按位替代或交换的方法形成密文组。

对于DES算法,我将其简单分为两大部分:秘钥处理部分和密文加密部分

1.2 秘钥处理流程

第一步是秘钥初始变换,输入的秘钥按照下文的常量表来完成一个变换

之后变换完输出的秘钥拆分成左右两部分C0与D0,C0与D0按照下表分别进行移位

移位完成后得到16个左右变换后的子秘钥C0-C15,D0-D15,将C0与D0,C1与D1…Ci与Di合并,按照下表压缩

这样我们得到的16个结果就是最终需要的16个子秘钥。

最终用伪代码阐释一遍流程

# 秘钥初始变换,输出结果拆分为

2.3 密文处理流程

首先我们扩充密文到64位

之后我们将输出结果拆分为左右两部分L0与R0,进行16轮运算

第一步是使用下表扩展Ri

之后引入子秘钥$subkey[i]$,与扩展后的Ri进行异或运算

之后将异或结果拆分为$8*6$bit分组,每个分组用下面S盒变换后组合

最终将8个s盒输出重新组合,输入下表处理

最终输出的就是Li+1,也就是说将Ri进行三个变换后作为下一轮Li+1输入

经过16轮运算后,将最终的L15与R15组合,进行一次置换

用伪代码阐释一下

# 初始置换L[0],R[0]=sub_key_permutation(plaintext)# 16轮循环处理for i in range(16):    # message_expansion扩展
exp_r=message_expansion(Ri) # 与子秘钥异或
xor_r=exp_r^subkey[i] # S盒变换
s_r=S[xor_r] # 处理S盒输出
L[i+1]=right_sub_message_permutation(s_r)
R[i+1]=L[i]# 最终逆变换final_message_permutation(L[15],R[15])

三、常量查找

在第一部分的DES算法简介中,我们已经了解了DES算法中涉及到的所有常量。那么我们接下来就是在IDA中查找对应的数据了。

3.1 为什么是IDA Python

在这边我们首先要搞明白一个虚拟内存和磁盘的概念。一般我们的可执行文件在操作系统中是以文件形式存在的,也就是存储在磁盘中。而运行时操作系统会将其装载到虚拟内存中(真正执行还需要装载到物理内存中,但与本文无关,此处也不做讨论)。在虚拟内存和磁盘中文件内容是不变的,但是占用大小发生了改变。如下图:

最主要的改变就是对齐大小发生改变。原先在磁盘中每个区会被补全为$FileAligmnetn$大小,而在内存中则补全为$SectionAlignmentn$的大小(n为正整数)。因此我们可以在磁盘中以文件形式读取可执行文件查找,但是查找到的常量位置是文件偏移。需要转换为虚拟内存地址后才能使用。

而在IDA中,可执行文件直接按照内存中的排列显示。因此省去了转换虚拟内存地址的过程。

此外,我们需要查找引用这些常量的代码地址,因此我们需要使用到IDA的查找交叉引用过程,这个是IDA的一个非常强大的功能,能够定位所有显式调用的代码地址。(例如 call 0x401000就是显示调用,而call eax,eax=0x401000则无法在静态分析中得到)

IDA Python并非IDA的原生脚本语言,但是IDA Python支持所有IDA原生语言idc的特性,并且可以使用所有Python 2的库(建议添加系统路径):

关于IDA python的基础知识,此处就不再赘述了,有兴趣的可以找一下IDA Python-Book的文档查看一下

3.2 确定查找范围

对于查找范围,简单粗暴的办法就是用MinEA()到MaxEA(),也就是最小的虚拟地址到最大的虚拟地址。不过这种方法效率不是很高,而且存在误报风险。

一般常量存放在.rdata段,也有少量在.data段,因此搜索两个段足以。注意,此处可能存在文件将段名修改的情况,例如.data段换为DATA段,所以建议先查看下段名之后指定

3.3 编写查找常量

查找函数非常简单,但是有一些点需要注意:

  • 常量存储不一定都是BYTE格式,有很大可能是WORD、DWORD乃至QWORD,因此需要能够支持指定数据格式类型的匹配。

  • 在密码学中我们的索引下标(压缩或扩展变换中使用的数组)都是从1开始的,而在C语言中是从0开始的,所以匹配时需要注意可能存在一个单位的偏移。

def findCrypt(pattens,size=1):
   # 目前已支持搜索data,rdata段,支持由于C语言数组下标造成的偏移的矫正,支持Crypto的单个数据单位大小指定

四、构建调用树

那么在先前我们找到了所有的常量数组的地址。之后就是查找交叉引用了。

IDAPython 对此提供了DataRefsTo的API,表示查找调用此处的代码地址,并将代码地址所属的函数地址保存,下面代码中func_dict的key是函数地址,而键值是该函数调用的常量数组

之后我们可以进一步使用CodeRefsTo来查找调用这些函数的代码地址以及这些代码地址所属的函数来构建调用树,其中CodeRefsTo的第二个参数0表示正常流顺序。调用树结构用list的嵌套来表示从属关系。

最终我们得到调用树结构,并将其打印出来

# 绘制树状图格式'''
href http://paste.ubuntu.org.cn/104713
'''blank=[chr(183)]##此处为空格格式;Windows控制台下可改为chr(12288) ;linux系统中可改为chr(32)【chr(32)==' ' ;chr(183)=='·' ;chr(12288)==' '】tabs=['']def tree(lst):
l=len(lst) if l==0:print('─'*3) else: for i,j in enumerate(lst): if i!=0: print tabs[0], if l==1:
s='─'*3
elif i==0:
s='┬'+'─'*2
elif i+1==l:
s='└'+'─'*2
else:
s='├'+'─'*2
print s, if type(j)==type([]) or isinstance(j,tuple): if i+1==l:
tabs[0]+=blank[0]*3
else:
tabs[0]+='│'+blank[0]*2
tree(j) else: try:
j='sub_%08x'%j; except: 1+1;
print(j);
tabs[0]=tabs[0][:-3]
tree(final_tree)

最终成功得到图的结构,得到调用图如下:

┬── ┬── sub_004026a0
│ └── ┬── sub_00402590
│ └── ┬── sub_00402140
│ ├── ─── initial_message_permutation
│ ├── ┬── sub_004023b0
││ └── ┬── sub_00402280
││ └── ─── right_sub_message_permutation
│ ├── ┬── S
││ └── message_expansion
│ ├── sub_004021e0
│ └── ─── final_message_permutation
│ └── ┬── sub_00402310
│ └── ┬── sub_key_permutation
│ ├── initial_key_permutaion
│ └── initial_key_permutaion

最终判断出各个函数的调用关系。

五、总结

通过IDA Python实现了调用图生成,完成了对DES的识别与分析。

六、参考文献

FLIRT 常见库地址

https://github.com/Maktm/FLIRTDB

https://github.com/push0ebp/sig-database

IDA Python-book 翻译版地址

https://bbs.pediy.com/thread-225920.htm

DES 算法参考

https://github.com/dhuertas/DES

调用图绘制

http://paste.ubuntu.org.cn/104713

IDAPython实战项目——DES算法识别的更多相关文章

  1. 基于DES算法加密的防撞库密码系统项目总结

    项目内容:基于DES算法加密的防撞库密码系统 小组名:zqhzkzkj 目标:1.对用户输入的8位字符进行DES加密,要求用户输入8位密钥 2.对于不同的网站,不同的用户名生成不同的密码 小组成员:周 ...

  2. 再一波Python实战项目列表

    前言: 近几年Python可谓是大热啊,很多人都纷纷投入Python的学习中,以前我们实验楼总结过多篇Python实战项目列表,不但有用还有趣,最主要的是咱们实验楼不但有详细的开发教程,更有在线开发环 ...

  3. 深度学习之PyTorch实战(3)——实战手写数字识别

    上一节,我们已经学会了基于PyTorch深度学习框架高效,快捷的搭建一个神经网络,并对模型进行训练和对参数进行优化的方法,接下来让我们牛刀小试,基于PyTorch框架使用神经网络来解决一个关于手写数字 ...

  4. KNN (K近邻算法) - 识别手写数字

    KNN项目实战——手写数字识别 1. 介绍 k近邻法(k-nearest neighbor, k-NN)是1967年由Cover T和Hart P提出的一种基本分类与回归方法.它的工作原理是:存在一个 ...

  5. Python实战项目网络爬虫 之 爬取小说吧小说正文

    本次实战项目适合,有一定Python语法知识的小白学员.本人也是根据一些网上的资料,自己摸索编写的内容.有不明白的童鞋,欢迎提问. 目的:爬取百度小说吧中的原创小说<猎奇师>部分小说内容 ...

  6. MFC 简单实现 DES 算法

    前言 徐旭东老师说过学者就应该对知识抱有敬畏之心,所以我的博客的标题总喜欢加上"简单"二字,就是为了提醒自己,自己所学知识只是皮毛,离真理还远矣. DES 算法 DES算法是密码体 ...

  7. FaceRank,最有趣的 TensorFlow 入门实战项目

    FaceRank,最有趣的 TensorFlow 入门实战项目 TensorFlow 从观望到入门! https://github.com/fendouai/FaceRank 最有趣? 机器学习是不是 ...

  8. TensorFlow 中文资源全集,官方网站,安装教程,入门教程,实战项目,学习路径。

    Awesome-TensorFlow-Chinese TensorFlow 中文资源全集,学习路径推荐: 官方网站,初步了解. 安装教程,安装之后跑起来. 入门教程,简单的模型学习和运行. 实战项目, ...

  9. [深度应用]·实战掌握Dlib人脸识别开发教程

    [深度应用]·实战掌握Dlib人脸识别开发教程 个人网站--> http://www.yansongsong.cn/ 项目GitHub地址--> https://github.com/xi ...

随机推荐

  1. C# winform中使用Panel调节窗口变化是各控件的位置(转)

    我的目的是在窗口上有些控件,在窗口大小变化时,上面的控件位置不动,大小也不动.下面的控件随着窗口的大小变化而变大. 做法是用两个panel,panelTop和panelFill.上面的控件都放到pan ...

  2. tp5.1 where 时间查询

    $where_time = []; if ($_GET['s_time'] && !isset($_GET['e_time'])){ $where_time = ['add_time' ...

  3. nginx利用fastcgi_cache模块缓存

    nginx不仅有个大家很熟悉的缓存代理后端内容的proxy_cache,还有个被很多人忽视的fastcgi_cache.proxy_cache的作用是缓存后端服务器的内容,可能是任何内容,包括静态的和 ...

  4. 利用PHP应用程序中的远程文件包含(RFI)并绕过远程URL包含限制

    来源:http://www.mannulinux.org/2019/05/exploiting-rfi-in-php-bypass-remote-url-inclusion-restriction.h ...

  5. iOS-25个小技巧

    (一)关于UITableView  方法flashScrollIndicators:这个很有用,闪一下滚动条,暗示是否有可滚动的内容.可以在ViewDidAppear或[table reload]之后 ...

  6. 【Linux内核】编译与配置内核(x86)

    [Linux内核]编译与配置内核(x86)  https://www.cnblogs.com/jamesharden/p/6414736.html

  7. 【最后一战】NOI2019游记

    NOI2019 游记 报到日 -1 打了一场LOJ发现rk5,听完cy讲T1后感觉自己非常智障--AK的那位老哥好强啊qwq 窝在宾馆里打打游戏敲敲板子 饥荒真好玩 等着明天去报道 要退役了反而心情平 ...

  8. FZU - 2295 Human life (最大权闭合子图)

    题目链接 FZU - 2295 Human life 题目分析 题意:你在玩一个游戏,在其中你可以通过学习一些技能,但是学习某些技能之前,可能还要学习一些其他的技能,并且学习任何技能都有一定的花费: ...

  9. EXIT(外部中断)控制实验

    实验目的 设计使用外接的按键来作为触发源,使得控制器产生中断,并在中断服务函数中实现控制小灯的亮灭. 按键硬件点路 编程要点 初始化用来产生中断的 GPIO: 初始化 EXTI: 配置 NVIC: 编 ...

  10. 关于typecho发布文章后的错位

    今天发布了一篇文章,发布后发现,what?主页错位了,安装控制变量法知道,肯定是这篇文章有什么不可告人的秘密. 所以,顺便使用一下二分法查找一下为啥,最后找到是因为使用了---------->( ...