样本中的CryptAPI
0x00 CryptAPI的概述
一个CSP是实现加密操作的独立模块,要实现加密,至少需要一个CSP。每个CSP对CryptAPI的实现是不同的,使用的算法不同,有些包含了对硬件的支持
- CryptAcquireContext 获得指定CSP的密钥容器的句柄
- CryptReleaseContext释放得到的句柄
在此前提下相关的函数如下
- CryptDeriveKey 从一个密码中派生一个密钥
- CryptDestoryKey 销毁密钥
- CryptDuplicateKey 制作一个密钥和密钥状态的精确复制
- CryptGenKey 创建一个随机密钥
- CryptImportKey 把一个密钥BLOB传送到CSP中
用来加解密数据,需要指定一个密钥,这个密钥可以是由CryptGenKey、CryptDuplicateKey、CryptImportKey产生。
- CryptEncrypt 使用指定加密密钥来加密一段信息
- CryptDecrypt 使用指定加密密钥来解密一段密文
完整的解密过程如下
#include #include #pragma comment (lib, "advapi32")int main(){ HCRYPTPROV hCryptProv; HCRYPTHASH hCryptHash; HCRYPTKEY hCryptKey; CryptAcquireContext(&hCryptProv, // CSP句柄的指针 NULL, // 密钥容器名称 MS_DEF_PROV, // CSP名称(如果为NULL,就使用默认的CSP) PROV_RSA_FULL, // CSP类型 CRYPT_VERIFYCONTEXT); // 此选项指出应用程序不需要使用公钥/私钥对 CryptCreateHash(hCryptProv, // CSP句柄 CALG_MD5, // Hash算法的标识符 0, // 如果哈希算法是密钥哈希,如HMAC或MAC算法,就用此密钥句柄传递密钥 0, // 保留,必须为0 &hCryptHash); // 哈希对象的句柄指针 static char szPassword[] = "FSD@#fds23"; // 加密密码 DWORD dwLen = strlen(szPassword); // 计算密码的Hash值 CryptHashData(hCryptHash, (BYTE*)szPassword, dwLen, 0); // 根据密码的Hash值派生一个密钥 CryptDeriveKey(hCryptProv, // CSP句柄 CALG_RC4, // 要产生密钥的对称加密算法 hCryptHash, // 哈希对象的句柄 0, // 密钥类型 &hCryptKey); // 输出密钥句柄指针 // 待加密数据 static char szData[] = "important data"; DWORD dwLenIn = strlen(szData); DWORD dwLenOut = dwLenIn; CryptEncrypt(hCryptKey, // 密钥句柄 0, // 如果在加密的同时需要计算Hash值,传入一个Hash对象句柄 TRUE, // 标识是否是最后一次加密操作 0, // 保留,必须为0 (BYTE*)szData, // 要被加密的数据 &dwLenOut, // [in/out] 传入需要加密的数据长度,传出已经加密的数据长度 dwLenIn); // 指出szData的Buffer长度 CryptDecrypt(hCryptKey, // 秘钥句柄 0, // 如果在加密的同时需要计算Hash值,传入一个Hash对象句柄 TRUE, // 标识是否是最后一个解密操作 0, // 保留,必须为0 (BYTE*)szData, // [in/out] 需要解密数据的地址 &dwLenOut); // [in/out] 传入需要解密的数据长度,传出已经解密的数据长度 // 清理工作 CryptDestroyKey(hCryptKey); CryptDestroyHash(hCryptHash); CryptReleaseContext(hCryptProv, NULL);
0x01 样本中的使用情况
该样本是某组织使用的最新的shellcode,该shellcode先获取计算机名,然后通过计算机名来获得IP地址,最后通过IP来计算hash和秘钥并对下一阶段的shellcode进行解密
具体过程如下
shellcode通过getComputerNamew和GetAddrInfow来获取IP信息,通过遍历addrinfoW链表来获取IP(打码部分为16进制IP地址),经过一次and操作后存入内存,待后续计算hash使用
计算并提取hash的过程如下
- 创建hash对象CryptCreateHash
- 通过上面的16进制IP计算hash CryptHashData
- 查询hash长度CryptGetHashParam(HPHASHSIZE)
- 查询hash值CryptGetHashParam(HPHASHVAL)
其他获取CSP和destroy hash以及释放CSP的常规操作就不多说了
然后用IP的hash值进行拼接,复制到内存中(栈中)组合成key blob.通过CryptImportKey将其导入CSP中,设置以初始向量模式进行解密,将旧shellcode中待解密的部分复制到新内存中,用CryptDecrypt解密
最后还会对解密后的下一阶段shellcode再算一次hash
把这个算出的hash和旧shellcode中存的hash做比较,相同就创建线程去执行下一阶段shellcode
0x02 参考
https://nixwang.com/2013/04/18/windows-cryptoapi/
初始向量模式 https://blog.csdn.net/Vieri32/article/details/48345023)https://blog.csdn.net/weixin45303938/article/details/109012292
