用户
搜索
  • TA的每日心情
    慵懒
    2 小时前
  • 签到天数: 158 天

    连续签到: 1 天

    [LV.7]常住居民III

    版主

    Rank: 7Rank: 7Rank: 7

    26

    主题

    107

    帖子

    3509

    魔法币
    收听
    1
    粉丝
    3
    注册时间
    2015-11-20

    i春秋签约作者春秋文阁

    发表于 2018-2-1 12:57:19 47483
    本帖最后由 icq5f7a075d 于 2018-2-1 12:58 编辑

    本文原创作者:icq5f7a075d,本文属i春秋原创奖励计划,未经许可禁止转载!
    本文如果出现错误,欢迎指出,感激不尽!
    本文中的所有程序请在虚拟机中运行。
    本文分析的样本SHA-12016a96099dfac40e4959b1ecf729d30869bff61
    1. CSP介绍
    既然是分析使用CSP容器的勒索病毒,那么肯定要了解CSP。
    CSP,全名为“加密服务提供者(Cryptographic Service Provider)”,是微软定义的一套密码服务API。微软公司提供了一套完整的Crypto API的函数,支持密钥交换,数据加密解密,数字签名,给程序员带来了很大方便,用户在对软件进行保护的时候可以直接利用Crypto API来完成这些工作。许多勒索软件也直接利用Crypto API实现加解密功能。
    微软提供的Crypto API主要在“Wincrypt.h”和“Advapi32.lib”这两个库中。有了这两个库,我们就可以写自己的CSP程序了。使用CSP进行加解密一般会进行如下操作:
    ①产生CSP容器;
    ②生成密钥;
    ③加解密;
    ④销毁容器;
    接下来我们逐步分析。
    (1)产生CSP容器
    调用CryptAcquireContextA()创建/获取CSP的密钥容器:
    [C++] 纯文本查看 复制代码
    BOOL WINAPI CryptAcquireContext(//这个函数是获取有某个容器的CSP模块的指针,成功返回TRUE。
      _Out_ HCRYPTPROV *phProv, //指向一个CSP模块句柄指针,里面用指定的容器
      _In_  LPCTSTR    pszContainer, //指定容器的名称,也可以使用缺省的
      _In_  LPCTSTR    pszProvider, //这个参数一般是缺省值,指得是缺省得CSP模块,你也可以传入一个LPCTSTR类型的字符串,指定CSP模块
      _In_  DWORD      dwProvType,//确定密钥的类型
      _In_  DWORD      dwFlags
    );
    比较重要的参数是dwProvType和dwFlags,dwProvType常见值:
    图片1.png
    dwFlags常见值:
    图片2.png
    (2)生成密钥
    生成密钥的方式只有两种,调用CryptGenKey生成随机密钥或调用CryptImportKey导入密钥:
    [C++] 纯文本查看 复制代码
    BOOL WINAPI CryptGenKey(
      _In_  HCRYPTPROV hProv,
      _In_  ALG_ID     Algid,
      _In_  DWORD      dwFlags,
      _Out_ HCRYPTKEY  *phKey
    );
    比较重要的参数是Algid,其中CALG_AES_256=0x00006610比较常见
    [C++] 纯文本查看 复制代码
    BOOL WINAPI CryptImportKey(
      _In_ HCRYPTPROV hProv,
      _In_ BYTE * pbData,
      _In_ DWORD dwDataLen,
      _In_ HCRYPTKEY hPubKey,
      _In_ DWORD dwFlags,
      _Out_ HCRYPTKEY * phKey
    );
    3加解密
    加密使用CryptEncrypt():
    [C++] 纯文本查看 复制代码
    BOOL WINAPI CryptEncrypt(
      _In_    HCRYPTKEY  hKey,
      _In_    HCRYPTHASH hHash,
      _In_    BOOL       Final,
      _In_    DWORD      dwFlags,
      _Inout_ BYTE       *pbData,
      _Inout_ DWORD      *pdwDataLen,
      _In_    DWORD      dwBufLen
    );
    解密使用CryptDecrypt()
    [C++] 纯文本查看 复制代码
    BOOL WINAPI CryptDecrypt(
      _In_    HCRYPTKEY  hKey,
      _In_    HCRYPTHASH hHash,
      _In_    BOOL       Final,
      _In_    DWORD      dwFlags,
      _Inout_ BYTE       *pbData,
      _Inout_ DWORD      *pdwDataLen,
      _In_    DWORD      dwBufLen
    );
    可以看到CryptEncrypt/CryptDecrypt的参数中没有HCRYPTPROV数据,但是有HCRYPTKEY数据,判断加解密时关键是要追踪HCRYPTKEY。
    4销毁容器
    销毁容器使用CryptDestroyKey()。
    除了上述几个基础API,还有一些经常会用到的
    ①CryptExportKey导出密钥
    [C++] 纯文本查看 复制代码
    BOOL WINAPI CryptExportKey(
      _In_    HCRYPTKEY hKey,
      _In_    HCRYPTKEY hExpKey,
      _In_    DWORD     dwBlobType,
      _In_    DWORD     dwFlags,
      _Out_   BYTE      *pbData,
      _Inout_ DWORD     *pdwDataLen
    );
    参数dwBlobType指定了导出的是哪一个密钥,有如下值:
    图片3.png
    导出的数据是PUBLICKEYSTRUC结构体的数据
    图片4.png
    ②CryptSetKeyParam设置容器参数
    [C++] 纯文本查看 复制代码
    BOOL WINAPI CryptSetKeyParam(
      _In_       HCRYPTKEY hKey,
      _In_       DWORD     dwParam,
      _In_ const BYTE      *pbData,
      _In_       DWORD     dwFlags
    );
    dwParam=4=KP_MODE,设置密码模式
    dwParam=3=KP_PADDING,设置填充模式
    dwParam=1=KP_IV设置IV向量
    ③CryptGetProvParam()获取CSP的属性,比如该CSP具有的容器名、实现类型、支持算法等等。
    2. 快速分析rapid勒索病毒
    先拍个快照,运行病毒程序,掌握病毒的主要行为。程序运行后,电脑内大多数文件都被加密(实际上,除了几个重要的系统文件夹,所有文件夹里的文件都被加密了),随后程序弹出了勒索信息:
    图片5.png
    图片6.png
    一个很“正常”的勒索软件,接下来我们还原系统,在IDA和OD 中分析病毒。

    IDA中显示的导出函数列表中含有很多CSP的API,我们可以猜测,病毒程序使用CSP进行文件加密:
    图片7.png
    打开OD加载病毒程序,在CryptAcquireContextA、CryptDecrypt、CryptDestroyKey、CryptEncrypt、CryptExportKey、CryptGenKey、CryptImportKey、CryptSetKeyparam处下断点,执行程序。
    图片8.png
    程序首先断在了CryptAcquireContextA处,我们在栈顶函数返回地址处右键选择“反汇编窗口跟随”,这样我们就来到了程序调用CryptAcquireContextA的地方,本实例中是0xF7D6DE:
    图片9.png
    CryptAcquireContextA中的第四个参数值为1,对照前文查看发现是PROV_RSA_FULL。
    我们在IDA中来的相应的地方,需要注意的是OD和IDA加载基址可能不一样,IDA中的地址是0x40D6DE:
    图片10.png
    之后F5查看IDA反编译出的代码:
    图片11.png
    流程就比较清晰了。
    打开OD继续运行程序,这次程序断在了CryptImportKey,就是上图中的那个CryptImportKey,而导入的数据pbData来自“BgIAA..”这段字符串,经过分析发现这段数据是Base64加密之后的数据,CryptImportKey导入的key就是解密后的数据。
    我们就很清楚的了解到,这里导入了RSA公钥,公钥信息硬编码写入程序。
    继续运行OD,程序又断在了CryptAcquireContextA处,程序又创建了一个CSP容器,类型是PROV_RSA_FULL。我们将前一个CSP容器命名为csp1,将这个命名为csp1,
    图片12.png
    在IDA中分析这个CryptAcquireContextA:
    图片13.png
    可以看到程序接下来会获取注册表“local_public_key”的值,如果成功获取数据,就会调用CryptImportKey。
    我们在OD中继续运行程序,发现程序没有断在CryptImportKey,而是断在了CryptAcquireContextA,这一次创建了CSP容器并生成了RSA密钥对:
    图片14.png
    在OD中继续跟踪,配合IDA分析,接下来程序导出刚刚生成的RSA密钥对的私钥,使用最初硬编码的RSA公钥加密,并将其加入注册表“local_enc_private”,之后获取RSA密钥对的公钥,添加进注册表:
    图片15.png
    随后程序销毁csp2,再次来到刚刚创建csp2的地方,重新创建csp2并导入公钥数据,这次成功导入:
    图片16.png
    继续运行程序,再次暂停在CryptAcquireContextA,不过这次创建的是PROV_RSA_AES类型:
    图片17.png
    我们在IDA中定位,分析程序流程,结合OD分析发现,这里随机生成了密钥,并设置了工作模式“CBC”,填充方式“PKCS5_PADDING”,IV初始向量为0,随后导出AES密钥,并使用前文生成的RSA公钥进行加密:
    图片18.png
    随后使用数字签名算法对文件进行加密,并将加密数据写入文件:
    图片19.png
    至此,勒索病毒的文件加密过程基本理清。本病毒使用RSA公钥加密数字签名中使用的私钥,然后使用数字签名算法对文件进行加密,在没有RSA私钥的情况下,很难获取数字签名的私钥,也就无法解密文件。
    3. 总结
    本文介绍了CSP,并简单快速地分析了rapid病毒,当然本文只是蜻蜓点水,关于rapid病毒的分析还有很多地方可以深挖,我们并没有分析病毒的其他行为,病毒是不是会进行网络传播?有没有设置内存常驻?而且哪些文件会被加密,哪些不会我们也不清楚。

    发表于 2018-2-1 15:39:21
    沙发沙发
    使用道具 举报 回复
    发表于 2018-2-1 16:23:13
    板凳板凳
    逆向/破解/病毒分析板块  专属QQ交流群:496266893

    https://bbs.ichunqiu.com/forum-60-1.html
    使用道具 举报 回复
    地板地板
    使用道具 举报 回复
    口怕……要不是老夫幼儿园毕业了,老夫差点就让吓到了
    使用道具 举报 回复
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册