• 数据加密是指以隐藏真实意图为目的的内容修改

13.1 分析加密算法的目的

  • 分析目的:
    • 隐藏配置信息
      • 如:命令和控制服务器的域名
    • 窃取之前将信息保存到临时文件
    • 存储恶意代码需要使用的字符串,并在使用前对其解密
    • 将恶意代码伪装成合法的工具,隐藏可疑的字符串
  • 分析目标:识别加密算法,进行解密

13.2 简单的加密算法

  • 简单的加密技术常被用来隐藏内容, 从而让内容看起来 不明显、不可读
  • 为什么还会使用简单加密?
    • 它们容易被破解,但是,它们足够小,所以可以用在空间受限的环境中,如漏洞利用的shellcode
    • 它们没有复杂加密算法那么明显
    • 它们开销低,因此它们对性能几乎没有影响
    • 是混淆而不是加密
      • 它们使得识别数据变得困难,但不能免于被探测,只是用来阻止基本的分析(自动化分析)
  • 凯撒密码
    • 循环右移三位
  • XOR
    • 易于使用,加解密仅需单机器码指令
    • 加密解密方法相同
    • 数据: 0100 1000 0100 1001 秘钥: 0011 1100 0011 1100 结果: 0111 0100 0111 0101
    • 暴力破解 XOR 加密:如果秘钥是一个字节,只有256个可能的秘钥
    • 暴力破解多个文件:查找常见字符串,如:”This Program”,用每一个可能的XOR值生产原始字符串所有可能的排列,然后作为特征集合
      12.5.jpg
    • XOR 和空字节:
      • 空字节暴漏了秘钥,因为0x00 XOR KEY = KEY,如果加密内容中有大量的NULL字节,那么单字节密钥变得十分明显
      • 解决方法:
        • 如果明文中字符是NULL或者密钥本身,跳过
    • 用IDA pro识别xor循环
      • 小内循环内使用XOR指令
      1. 打开“IDAView”(查看代码)
      2. 选择Search->Text
      3. 输入xor并选中Findalloccurrences
      • 搜索到XOR指令并不意味着它一定用于加密,XOR指令以三种形式存在
        • 用一个寄存器XOR自身,如 xor edx, edx
          • 寄存器清零的常用方式
        • 用一个常数XOR一个寄存器或一个内存引用
          • 可能是个加密循环,秘钥就是那个常数
        • 使用一个寄存器或内存引用XOR一个不同的寄存器或内存引用
          • 可能是一个加密循环,秘钥并不明显
            13.1.jpg
  • 其他一些简单的加密策略
    13.3.jpg
  • Base64
    • 用ASCII字符串格式表示二进制数据,广泛用于HTTP和XML
    • 原理:将二进制数据转换成64个字符的有限字符集,另外通常用一个额外字符表示填充,通常是“=”
    • 最常用的字符集是MIME Base64,它使用 AZ、az和0~9作为前62个值,+和/作为最 后两个值。 =表示填充
    • 数据转化成base64:
      • 把三个字节(3x8=24位)构成的块,分成四个字节(4x6)构成的块,把每一个块转换成Base64(通过十进制索引参 考字符串得出字符:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ )
        13.2.jpg
    • 将base64解密
      • 每个字符转换成6个比特位放在一起,8个一组读取,表示原来的字节
      • 解密时如果位数不对尝试用“=”(填充字符)填充后再解密
      • 有时会使用自定义的字符集
    • 查找Base64加密函数
      • 先查找实现算法常用的64字节长度的字符串。因为base64加密的实现通常使用索引字符串,所以含有base64加密的代码经常会存在这个64字符组成的加密字符串
      • 查找单独的填充字符(常为=),该字符被 硬编码到函数中

13.3 现代加密算法

  • 现代的加密算法考虑了增加指数级的计算能力,并且确保设计的算法需要大量的计算能力,从而使破解它们不切实际
  • 优点:足以抵抗暴力攻击
  • 缺点:
    • 需要很大的加密库
    • 降低代码的可移植性
    • 标准加密库容易被探测出来
      • 通过函数导入表、函数匹配或加密常量识别
    • 对称加密需要隐藏秘钥
  • 识别标准加密方法——识别字符串和导入表
    • 一种识别标准加密算法的方法是识别涉及加密算法使用的字符串。
      • 例如:采用OpenSSL加密的恶意代码中发现的字符串
        13.4.jpg
    • 另一种是识别引用表导入的加密函数
      • 大多以Crypt、CP、Cert为前缀
  • 识别标准加密方法——查找加密常量
    • IDAPro的FindCrypt2插件
      • 查找神秘的常量 (Magic Bytes,与基本加密算 法结构相关的一些固定位串,可作为加密例程的二进制特征)
      • 无法找到RC4 或IDEA 例程,因为它们没有使用 神秘的常量
      • RC4常被恶意代码使用,因为它小且易于实现,并且没有明显的加密常量
        • RC4是对称加密算法,解密和加密使用相同的密码;RC4是伪随机密码生成算法,相同原文和密码生成 的密文通常每次均不一样;通常使用RC4加密后,再用Base64编码为可见字符
    • Krypto ANALyzer (PEiD 插件)
      • 拥有一个比FindCrypt2范围更广的常量集合,但是易产生误报
      • 还能识别Base64 编码表和加密相关的导入 函数
  • 识别标准加密方法——查找高熵值内容
    • 熵表示混乱程度
    • 计算熵,只需要从0到255每个字节出现的 次数,计算每个字符出现的概率Pi ,然后从0到255对Pilog2Pi求和,最后取相反数
    • 如果所有字节出现概率相同,熵就是8 (-log21/256=8,最大混乱度,熵最高)
    • 如果所有的字节相同,为有序状态,熵为0
    • 查找高熵内容
      • IDAPro的熵插件,熵图绘制
        13.5.jpg
      • 查找高熵的区域,表明该区域被加密或压缩
    • 熵值检查中建议选取的块大小
      • Chunk size: 64(0~63:所有可见字符) Max. Entropy: 5.95 (高于max判定为异常)
        • 有利于发现许多常量
        • 包括 Base64编码的字符串
      • Chunk size: 256(可见字符+非可见字符) Max. Entropy: 7.9
        • 查找非常随机的区域

13.4 解密

  • 查找并且分离加密函数是恶意代码分析过程中很重要的一部分,但是通常情况下还需要继续解密隐藏的内容
  • 重现恶意代码中加解密函数的方法:
    • 重写
    • 借用原有函数
  • 自解密
    • 程序正常 活动期间自己完成解密
    • 并在解密例程之后直接设置断点获得解密数据
    • 缺点:不好定位解密函数,解出的内容不是期望得到的
  • 手动编写解密函数
    • python脚本(PyCrypto)
  • 使用通用的解密规范(用恶意代码进行解密<前提是可逆的算法>)
    1. 在调试器中启动恶意代码
    2. 准备读取的加密文件和准备写入的输出文件
    3. 在调试器中分配内存空间,让恶意代码能够引用 这块内存
    4. 加载加密文件到分配的内存区域
    5. 为恶意代码的加密函数设置合适的变量和参数
    6. 运行加密函数执行加密
    7. 将新解密的存储区写入到输出文件
    • 工具:Immunity Debugger
      13.6.jpg
      • rb:确保正确度读入二进制字符
      • cfile.read:将加密文件读入Python缓冲区
      • imm.writeMemory:将python缓冲区的内存复制到被调试进程的内存中
      • imm.getRegs:获取当前寄存器的值,使EBP定位两个关键参数-解密内存缓冲区及其大小
      • imm.readMemory:读出