使用工具: CAPEv2, x64dbg, dotPeek, Detect It Easy, IDA
这道题因为是用的系统API加密,比赛的时候用本地的CAPEv2一把梭了,后来听说有很多坑重新手搓了一遍,确实。
先查下程序信息。首先这里要能根据文件信息判断这是一个捆绑CLR运行时的单文件.NET程序,有些老的查壳工具可能看不出来。
Detect It Easy能扫到.NET Core(Loader)的库。
如果这一步没发现是.NET程序,后续分析看到pdb路径或者CLR_UEF段也要及时发现,不然就走远了。

33、分析程序“MicroSoft-Edge.zip”,实现“对桌面文件遍历并加密”逻辑的动态链接库文件为?
答案:encrypt.dll
看沙箱中释放文件的记录或者筛选运行记录中的文件操作,可以看到就释放了encrypt.dll这一个库文件。
| API | Arguments |
|---|---|
| NtCreateFile | FileHandle: 0x0000063c |
| DesiredAccess: GENERIC_WRITE | |
| FileName: C:\Users\win-msa2\AppData\Local\Temp\encrypt.dll | |
| CreateDisposition: FILE_OVERWRITE_IF | |
| ShareAccess: FILE_SHARE_READ | |
| FileAttributes: 0x00000000 | |
| ExistedBefore: no | |
| StackPivoted: no | |
| NtWriteFile | FileHandle: 0x0000063c |
| HandleName: C:\Users\win-msa2\AppData\Local\Temp\encrypt.dll | |
| Buffer: MZ\x90\x00\x03…… | |
| Length: 131072 | |
| NtWriteFile | FileHandle: 0x0000063c |
| HandleName: C:\Users\win-msa2\AppData\Local\Temp\encrypt.dll | |
| Buffer: (_]\xc3\xcc\xcc\xcc…… | |
| Length: 94720 | |
| NtClose | Handle: 0x0000063c |
看一眼encrypt.dll的导入函数,都是wincrypt.h的CryptoAPI函数 (2025年了该考考CNG了),导出函数名是加解密文件夹。
如果这里通过逆向分析MicroSoft-Edge.exe来做,需要用ILSpy或者dotPeek,dnSpy没有对.NET6以上的支持,dnSpyEx对单文件的支持好像有一些问题,我试了原版和几个修改版都无法解析文件。反编译文件,也没有混淆什么的,可以看到Form1中的关键代码。
1 | private void button1_Click(object sender, EventArgs e) |
外层代码很简单,用户点击按钮后,将资源文件MicroSoft_Edge.Resources.encrypt.dll释放到Temp目录的encrypt.dll,调用动态链接库的EncryptFolder函数,传入参数桌面路径和HiBroIamhere!!!!。
其中Environment.SpecialFolder为0时的含义可以直接PowerShell查询。
1 | PS > [System.Environment+SpecialFolder] 0 |
34、分析程序“MicroSoft-Edge.zip”,程序从DLL中获取函数指针后,使用哪个API将其转换为委托并执行(区分大小写并完全匹配)?(答案格式:按实际值i填写,如FunA)
答案:GetDelegateForFunctionPointer
沙箱无法直接获取CLR的API调用,需要反编译程序或者用.NET的调试器。或者这里如果题目问的是EncryptFolder的参数,沙箱也没法一把梭出来,需要加调试脚本再运行,或者启动时加载frida脚本获取。
通过静态分析做,看上一题反编译的代码就能知道调用EncryptFolder的过程。
1 | IntPtr hModule = Form1.LoadLibrary(lpFileName); |
使用LoadLibrary加载库,使用GetProcAddress获取指定函数的指针,使用GetDelegateForFunctionPointer将非托管函数指针转换为可由.NET直接调用的委托,是一个典型的P/Invoke平台调用。
35、分析程序“MicroSoft-Edge.zip”,接上题,该动态链接库文件用于加密文件的加密算法为?(答案格式:RC4-128)
答案:AES-256
在沙箱的运行记录中筛选加解密相关的API,首先是一段RC4,密码是传入的参数HiBroIamhere!!!!,加密的数据是Guessifthisisit?,没有读取文件,也没有加密文件数据。可能是文件加密密钥的生成,先不管继续往后看。
| API | Arguments |
|---|---|
| CryptAcquireContextA | Container: |
| Provider: | |
| Flags: 0xf0000000 | |
| CryptImportKey | Type: 0x00000008 |
| Version: 0x00000002 | |
| Algid: RC4 | |
| KeyBlob: \x08\x02\x00\x00\x01h\x00\x00\x10\x00\x00\x00HiBroIamhere!!!! | |
| Flags: 0x00000000 | |
| CryptKey: 0x21dbd77b540 | |
| Length: 28 | |
| CryptEncrypt | CryptKey: 0x21dbd77b540 |
| CryptHash: 0x00000000 | |
| Buffer: Guessifthisisit? | |
| Length: 16 | |
| Final: 1 | |
| CryptDestroyKey | CryptKey: 0x21dbd77b540 |
接着遍历桌面文件并读取内容。
| API | Arguments |
|---|---|
| FindFirstFileExW | FileName: C:\Users\win-msa2\Desktop* |
| FirstCreateTimeLow: 0x65f281ca | |
| FirstCreateTimeHigh: 0x01dc5a89 | |
| NtCreateFile | FileHandle: 0x00000638 |
| DesiredAccess: GENERIC_READ | |
| FileName: C:\Users\win-msa2\Desktop\desktop.ini | |
| CreateDisposition: FILE_OPEN | |
| ShareAccess: FILE_SHARE_READ | |
| FileAttributes: FILE_ATTRIBUTE_NORMAL | |
| ExistedBefore: yes | |
| StackPivoted: no | |
| NtReadFile | FileHandle: 0x00000638 |
| HandleName: C:\Users\win-msa2\Desktop\desktop.ini | |
| Buffer: \xff\xfe…… | |
| NtClose | Handle: 0x00000638 |
读取文件后就是加密文件的过程了,加密后写入加密数据。
| API | Arguments |
|---|---|
| CryptAcquireContextW | Container: |
| Provider: | |
| Flags: 0xf0000000 | |
| CryptCreateHash | Algid: SHA_256 |
| CryptKey: 0x00000000 | |
| Hash object: 0x21dbd77c2d0 | |
| CryptHashData | CryptHash: 0x21dbd77c2d0 |
| Buffer: <#\x89\xb9\xd7\xe0H\x85\xb5\xf8]j0\xbf\xcc | |
| \xb8\xb0\xd2\xade\xb3\x130\xc0/e\xf8\xa9\xf6T\xab\x9a | |
| Length: 32 | |
| CryptDeriveKey | Algid: AES_256 |
| BaseData: 0x21dbd77c2d0 | |
| CryptKey: 0x21dbd77bcb0 | |
| CryptSetKeyParam | CryptKey: 0x21dbd77bcb0 |
| Param: KP_IV | |
| Buffer: 0701080109091001 | |
| Flag: 0 | |
| CryptEncrypt | CryptKey: 0x21dbd77bcb0 |
| CryptHash: 0x00000000 | |
| Buffer: R\x8d\xb2……\ | |
| Length: 288 | |
| Final: 1 | |
| CryptDestroyKey | CryptKey: 0x21dbd77bcb0 |
| CryptDestroyHash | CryptHash: 0x21dbd77c2d0 |
根据运行记录中的加密逻辑,加密过程先调用CryptCreateHash创建了SHA-256哈希对象,调用CryptHashData将下面的数据添加到哈希对象。
1 | <#\x89\xb9\xd7\xe0H\x85\xb5\xf8]j0\xbf\xcc\xb8\xb0\xd2\xade\xb3\x130\xc0/e\xf8\xa9\xf6T\xab\x9a |
调用CryptDeriveKey用哈希对象派生AES-256的密码。调用CryptSetKeyParam设置IV为0701080109091001。没有设置KP_MODE,所以使用的是默认的加密模式,按CryptoAPI文档是CRYPT_MODE_CBC。那么后面两题的答案也就都有了。
这道题其实还有个坑在,比赛完听很多选手说这个程序运行没有反应,没有加密文件。其实是因为缺少动态链接库,我的沙箱虚拟机是直接用Windows Development Environment改的,刚好避开了这个坑。运行起来挂上调试器,设置用户DLL自动断点,如果环境中缺少动态链接库很容易发现encrypt.dll没有载入成功,调试器没能进入encrypt.dll,调试器里能看到DLL在尝试载入后立即被卸载了。
查看调用堆栈,设置断点到加载encrypt.dll的LoadLibraryA调用后,可以看到LoadLibraryA的返回值为0,异常是ERROR_MOD_NOT_FOUND,STATUS_DLL_NOT_FOUND。

看了眼导入表才发现程序是动态链接的Debug版本,这勒索病毒只加密程序员的电脑是吧。![]()

从VS目录里找到VC和CRT的Debug版本库放到逆向环境的虚拟机中就可以正常运行,Debug版本库的参考路径如下,版本不同路径会有所差异。
1 | C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Redist\MSVC\14.44.35112\debug_nonredist\x64\Microsoft.VC143.DebugCRT |
解决了无法运行的问题,后面的分析就简单了,根据导入的加密函数定位到解密逻辑,转换Enum提高代码可读性。
设置CryptCreateHash和CryptSetKeyParam两处断点。在CryptHashData断点处读取R8记录的长度0x20,从RDX的地址读取0x20字节,计算数据的SHA-256哈希即为密钥。

在CryptSetKeyParam断点处,从R8寄存器的地址读取16字节,即为IV。

另外还有个要注意的点是调试时桌面需要有可以被加密的文件,如果没有文件不会执行加密逻辑。
36、分析程序“MicroSoft-Edge.zip”,接上题,该加密算法的初始密钥(十六进制)?(答案格式:字母大写)
答案:
BAD9AE9D603867DCE0D6551564F804215AA44ED99D6E774AB6767215225277B9
见第35题解析。
37、分析程序“MicroSoft-Edge.zip”,接上题,该加密算法的初始向量(十六进制)?(答案格式:字母大写)
答案:30373031303830313039303931303031
见第35题解析
38、分析程序“MicroSoft-Edge.zip”,对附件try.txt.enc进行解密,解密后的内容为?(答案格式:按实际值填写)
答案:恭喜
按前面获取的加密参数解密即可。