上次祥云杯遇到了利用WinCrypt库模拟勒索病毒加密的程序。虽然这个库被微软官方认为已经过时了,但还是大致来了解一下。
WinCrypt库使用
0x00 简介
wincrypt
库是微软推出的加密库,里面由几个内置的加密API,能够比较方便的加密文件,而不需要去探索加密算法的内核。
当然这个库已经开始要被微软淘汰了,不过现在大部分的病毒,勒索软件,或者是一些老软件用的还是这个库,所以还是了解一下吧。
关于新一代加密API,详见:
Cryptography API: Next Generation - Win32 apps | Microsoft Docs
本文通过研究一个别人写的Demo,稍微探讨一下这个加密库。
0x01 举例分析
我选择直接从一个别人已经写好的C++源码中分析加密流程。
原链接在最后的参考部分给出了。
0x02 成员体
1 | class CMyCryptOpt{ |
private域的成员元素保存了实现文件加密的所有必要变量。
文件指针
首先声明了两个FILE*
指针,这是两个文件指针。
1 | FILE* m_hSource; |
一个指向源文件,一个指向目标文件。
对这两个文件指针进行初始化,读取,写入,关闭等操作,由
1 | // 打开/创建/覆写/读取文件(取决于_Mode类型) |
这些函数进行。
当然在Windows平台上,这些C语言库函数,实际上最后调用的都是Windows API。
比如fopen(), fread()
,最后还是会调用CreateFile(), ReadFile()
函数等。
加密提供者句柄(HCRYPTPROV)
1 | HCRYPTPROV m_hCryptProv; |
这个HCRYPTPROV
我暂且解释成Crypt Provider Handle
,也就是一个加密提供者句柄。
翻了一下MSDN,HCRYPTPROV
实际上叫做Cryptography Service Provider(CSP)
,定义是:
(CSP) An independent software module that actually performs cryptography algorithms for authentication, encoding, and encryption.
也就是对一个加密模块的抽象与包装。
当然实际上,
1 | typedef ULONG_PTR HCRYPTPROV; |
这些句柄都仅仅是一个长指针罢了,核心是它指向的区域里面塞了什么玩意,也就是没有H
的CRYPTPROV
,即具体的结构体。
不过似乎微软并没有具体公开这个结构体,只给了一个句柄让我们用。
不过我翻到了一个有关Windows栈溢出漏洞,这个文章上似乎搞到了其中一个,HCRYPTKEY
结构体的信息。
1 | // 而HCRYPTKEY指向的是一个包含有多个函数地址的结构体,该结构体内容如下: |
不得不说这个结构体和我调试的时候,点入HCRYPTKEY
变量时发现一大堆函数指针的事实是一致的。
Structure of HCRYPTKEY Data (codeguru.com)
这个帖子里面也说了,这些结构是逆向工程师将cryptsp.dll
进行逆向工程后得到的。
这个句柄是加密流程中最开始需要初始化的。
此句柄使用CryptAcquireContext
函数获取。
1 | BOOL |
这个函数,以及其他重要API,待会儿再阐述。
密钥句柄(HCRYPTKEY)
1 | HCRYPTKEY m_hKey; |
上面刚刚放出了逆向出来的结构体。
MSDN上对于HCRYPTKEY
的解释:
The HCRYPTKEY data type is used to represent handles to cryptographic keys. These handles are used to indicate to the CSP module which key is being used in a specific operation. The CSP module does not enable direct access to the key values. Instead, the user performs functions by using the key value through the key handle.
HCRYPTKEY数据类型用于表示加密密钥的句柄。这些句柄用于向CSP模块指示在一个特定的操作中使用哪个密钥。CSP模块不直接访问密钥值。相反,用户通过密钥句柄使用密钥值来执行功能。
生成密钥
1 | BOOL |
可以使用这些函数(没列举完),根据哈希对象(或者不用),生成会话密钥。
销毁密钥
1 | WINADVAPI |
使用密钥进行加密
1 | WINADVAPI |
哈希对象句柄(HCRYPTHASH)
1 | HCRYPTHASH m_hHash; |
MSDN解释:
The HCRYPTHASH data type is used to represent handles to hash objects. These handles indicate to the CSP module which hash is being used in a particular operation. The CSP module does not enable direct manipulation of the hash values. Instead, the user manipulates the hash values through the hash handle.
HCRYPTHASH数据类型是用来表示哈希对象的句柄。这些句柄向CSP模块表明在一个特定的操作中使用的是哪个哈希值。CSP模块不直接操作哈希值。相反,用户通过哈希句柄来操作哈希值。
对于Hash Objects
的解释
An object used to hash messages or session keys. The hash object is created by a call to
CryptCreateHash()
. The definition of the object is defined by the CSP specified in the call.
创建哈希对象
1 | WINADVAPI |
利用哈希对象
使用输入数据(比如一个密码)产生哈希值
1 | CryptHashData( |
1 | WINADVAPI |
使用哈希对象获得会话密钥
1 | CryptDeriveKey( |
1 | WINADVAPI |
销毁哈希对象
1 | WINADVAPI |
其他对象
1 | PBYTE m_pbBuffer; // 缓冲区,临时存放区 |
0x03 Demo函数分析
1 | class CMyCryptOpt |
构造函数和析构函数
构造函数没啥好讲的,我由于受不了VS的恶俗警告信息,所以迫真初始化了一下变量,全部设置成了NULL。
1 | CMyCryptOpt::CMyCryptOpt(VOID) |
析构函数啥也没干,调用默认销毁。
初始化加密函数和销毁加密函数
InitCrypt
函数调用CryptAcquireContext
和CryptCreateHash
来初始化HCRYPTPROV
和HCRYPTHASH
对象。
1 | // 获得HCRYPTPROV和HCRYPTHASH句柄 |
DestroyCrypt
函数调用了wincrypt
的几个销毁函数,来关闭HCRYPTPROV
,HCRYPTKEY
,HCRYPTHASH
句柄。
1 | VOID CMyCryptOpt::DestroyCrypt(VOID) { |
加密过程函数
流程
- 打开要加密的源文件
- 创建目标文件用于写入加密数据
- 用输入的密码和md5哈希对象产生一个散列
- 通过散列获得会话密钥
- 计算块大小
- 分配临时缓冲区
1 | BOOL CMyCryptOpt::CryptProcess(LPSTR lpSourceFile, LPSTR lpDestFile, LPSTR lpPassword) { |
文件加密函数和解密函数
1 | // 对文件加密 |
0x04 API函数原型
从MSDN上面记录几个遇到的API。
CryptAcquireContext
初始化HCRYPTPROV
句柄。
1 | BOOL |
HCRYPTPROV* phProv
传出HCRYPTPROV
对象。
结束后,释放句柄,使用CryptReleaseContext
函数。
LPCWSTR szContainer
可选项。
密钥容器的名称。这是一个空字符结尾的字符串,用于为CSP标识密钥容器。
如果dwFlags
被设置为CRYPT_VERIFYCONTEXT
,该选项必须设置为NULL。
LPCWSTR szProvider
可选项。
标识CSP用的名称。这是一个空字符结尾的字符串。
如果传入了NULL,则调用了一个默认的Provider。
更多信息,见Cryptographic Service Provider Contexts.
For a list of available cryptographic providers, see Cryptographic Provider Names.
一个应用可以通过CryptGetProvParam
函数来读取dwParam
参数的PP_NAME CSP值,以获取现在使用的CSP的名称。
CSP名称应该被妥当的设置,而不是使用默认CSP。
dwProvType
明确了需要使用的CSP。
dwFlags
0xFE 源码
1 | // rhsEncrypt.h |
1 | // rhsEncrypt.cpp |
0xFF 参考
使用WinCrypt进行简单的对称加密实例_lixiaomin_235的博客-CSDN博客
Structure of HCRYPTKEY Data (codeguru.com)
- 本文作者: Taardis
- 本文链接: https://taardisaa.github.io/2021/09/26/WinCrypt加密库/
- 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!