浅析FeiQ解密函数的使用
2020-03-06 18:59:00 Author: mp.weixin.qq.com(查看原文) 阅读量:145 收藏

本文为看雪论坛优秀文章

看雪论坛作者ID:dayday向上8

分析目的
此次分析并不涉及到具体的算法是如何实现的,只是浅析位于模块cryptsp.dll中几个自认为比较重要的加密与解密函数在飞秋中的使用,函数名如下:
  • CryptAcquireContexA/W

  • CryptGenKey

  • CryptImportKey

  • CryptExportKey

  • CryptGetUserKey

  • CryptDecrypt

  • CryptEncrypt

预先了解
cryptsp.dll模块:是一个专门用来实现加密与解密算法的模块,上述函数都属于其导出函数:


CSP:Cryptographic Service Providers,据MSDN解释可以知道,CSP为我们实现了加密算法和秘钥的存储,类似于供应商,当然每个供应商都有自己独一无二的名字,但是类型不一。
举个栗子,冠状病毒可能有好几种类型,每种类型的病毒的入侵方式,潜伏期都不尽相同,同样类型不同,同一家供应商的各种算法,数据填充都不一样,在使用函数的时候我们可以自己指定。
此处先列出本次出现的CSP名称:由于这两家供应商的功能实现相同,增强的提供程序通过更长的密钥和其他算法来支持更强的安全性,微软将其统称为基本的提供程序,不过也无所谓了。
Microsoft Base Cryptographic Provider v1.0
Microsoft Strong Cryptographic Provider v1.0
BLOB:分为头BLOBHEADER和身体,后面我就称呼他为秘钥块啦,身体其实就是秘钥本体,那BLOBHEADER其实是一个结构体也可以说是这个秘钥的身份证,如下所示:
typedef struct _PUBLICKEYSTRUC {  BYTE   bType;                 //我是啥类型的秘钥,公钥?私钥?会话秘钥等?  BYTE   bVersion;              //版本号  WORD   reserved;              //必须为零  ALG_ID aiKeyAlg;                //我使用了啥算法RC2/RC4等} BLOBHEADER, PUBLICKEYSTRUC;
分析工具
  • CE

  • OD

  • IDA32

  • 使用的飞秋版本2013正式版(可以直接在网上下载)

具体分析
本次分析的整体思路就是先分析消息的接收方如何对消息进行解密的,通过定位消息内容在内存中的位置,进而找到对应的代码位置,再通过栈回溯找到解密函数。入手点我借鉴了鬼手56的一篇微信分析方法,使用CE对发送内容在内存的位置进行查找。
虽然此处有两个位置存在消息,我通过依次对两个位置进行下内存写入断点,结果发现如果在0x119F64位置下断,由于我在接收方进行调试导致消息接收延迟,在没有调试到正确位置的时候,发送方会出现发送不成功的通知,最后接收不到消息,导致调试失败,当在第二个位置下断的时候成功。
删除内存断点,在出现明文附近的函数下断,通过栈回溯,找到将密文转换为明文的CALL,方法也很简单,在每个函数下断,函数肯定会有一个字符串指针参数,观察字符串的变化。
可以通过WireShark对其进行抓包来验证参数是真的直接发送过来的密文:



下面要进行的就是单独对这个解密函数中的各个CALL进行分析。

函数0x00768B10

参数一:密文字符串指针

参数二:0x3A(分析发现是一个分割标志,按照“:”进行分割)

参数三:out输出参数




返回值:EAX指向字符串1001,输出参数指向了密文1001后面的字符串
函数总结:按照0x3A将密文进行了分割。

函数0x00D7F56E

函数总结:此函数是一个C语言函数,可以将字符串转换为长整型正数,将字符串1001转换为整形0x1001。

再次调用函数0x00768B10

参数一:0

参数二:0x3A

参数三:out

函数总结如下图:

再次调用函数0x00768B10

参数一:0

参数二:0

参数三:out

函数总结如下图:

调用函数0x007688C0

参数一:待解密的BLOB的身体部分,也就是上个函数EAX指向的位置开始到字符串结尾

参数二:获取解密完成的BLOB算是一个输出参数

参数三:固定值0x3F4

参数四:输出值,用来存放解密完成之后BLOB身体部分的字节数

函数总结:通过特定的算法解密消息中的BLOB部分。

函数sub_768870

参数一:加密的BLOB中的字节码

调用函数CryptImportKey

参数一:CSP句柄

参数二:秘钥块指针

参数三:秘钥块大小

参数四:用于解密秘钥块中的秘钥

参数五:标志位

参数六:out返回导入秘钥的句柄

下面我会逐个解释我所理解的参数含义,以及这些参数从何而来。

参数二:秘钥块的指针

在执行函数0x007688C0获取BLOB身体之前执行了如下代码,其实就是在给BLOB头进行赋值操作。


下图就是一个完整的秘钥块,这个秘钥块其实是被加密过的秘钥块,需要参数四来进行解密,大小是0x4C。
让我们简单看看这个秘钥头:
typedef struct _PUBLICKEYSTRUC {  BYTE   bType;  BYTE   bVersion;  WORD   reserved;  ALG_ID aiKeyAlg;} BLOBHEADER, PUBLICKEYSTRUC;
ALG_ID:
这里使用了两种算法,我的理解是RC2算法是针对通信内容的,RSA公钥交换算法是针对会话密钥而言,因为会话密钥也是被加密了的,他需要公钥去进行解密。
至于为什么是公钥交换,只是我在全部弄完之后所理解的,接收方和发送方在添加好友(飞秋会自动添加局域网内的人)的时候就进行了PY交易,互相交换了公钥。
所以在发送消息的时候,发送方会通过接收方当初给他的公钥对会话密钥进行加密,接收方也就可以通过相同的公钥对会话密钥进行解密。如果有大佬觉得不对的话,还希望能指点一二,感谢!

参数三:秘钥块的大小

函数0x007688C0的参数四在执行完成之后就是秘钥块身体的大小,只要在加上秘钥头0XC个字节就行了。

参数五:标志位

此时为固定值零,这里不做分析。

参数一:CSP句柄

通过CryptAcquireContext函数获得的CSP的句柄。需要注意的是句柄在飞秋进行初始化的时候就已经获得了。

先简单补充下CryptAcquireContext函数的用法:

继续运行,初始化完成之后向其发送一条消息,断在正在分析的位置,发现两个CSP句柄是现同的,可以证明句柄就是在初始化的时候获取的。
参数四:用于解密会话密钥的密钥句柄

此参数起始也是来自于初始化中,调用函数CryptGetUserKey获得:
BOOL CryptGetUserKey(  HCRYPTPROV hProv,  DWORD      dwKeySpec,  HCRYPTKEY  *phUserKey参数1:CSP句柄,CryptImportKey函数要求用于**解密会话密钥的密钥句柄(参数四)**就是来自参数一所指的CSP,根据一脉相承的原理,所以这里的CSP句柄同样是在初始化时调用的CryptAcquireContext函数。参数2:它可以是AT_KEYEXCHANGE或AT_SIGNATURE,本例中使用的是AT_KEYEXCHANGE参数3:输出参数接收检索到的密钥句柄);
关于这个函数的返回值我还是有些疑问的,希望有了解的大佬能够指点一二,因为这个函数的返回值在函数CryptImportKey和函数CryptExportKey函数中都有使用,但是却不尽相同。
如下,在函数CryptImportKey中如果会话密钥的加密方式是公钥/私钥对,那这个参数就是公钥/私钥对的句柄,还举了个SIMPLEBLOB的例子,根据刚才分析BLOBHEADER的时候,我认为SIMPLEBLOB就是修饰整个密钥快的是一个会话密钥,难道还能用来修饰会话密钥使用的什么方式加密了
在函数CryptExportKey中的使用就更有意思了,比如其第二个参数:
要想使用这个参数,得先使用CryptGetUserKey获得句柄之后,在使用CryptExportKey按照公钥的方式将其导出,在使用CryptImportKey将这个密钥块导入到CSP并获取其句柄才能使用。最后我会附上一张表来说明。(可点击阅读原文到论坛下载表的附件
 
下图是在初始化图中调用的函数CryptGetUserKey:
同理,初始化完成后再次向其发送一条消息,让其断在正在分析位置:
可以看到句柄是相同的 可以验证此参数就是在初始化的时候调用CryptGetUserKey获得的。

调用函数0x007687E0

函数总结:对发送过来的密文的最后一段进行解密,但是仍然不是明文,需要进一步调用函数CryptDecrypt。

调用函数CryptDecrypt

参数一:用于解密的密钥句柄

参数二:哈希对象句柄,此例为零

参数三:一个布尔值,指定这是否是要解密的系列中的最后一个部分(RC2是块加密解密)

参数四:标志值,不太了解,此例为零

参数五:缓冲区

参数六:缓冲区大小

参数一:用于解密的密钥句柄

来自上面的函数CryptImportKey导出的句柄

参数五:缓冲区

用于解密的密文,由上述函数0x007687E0的第二个参数指定:

最后解密成功!明文出现。
最终说明
我记录了飞秋在初始化过程中调用的一些函数,顺序以及参数,如果对兄弟们有些帮助,那就很开心了。
我会将附件(附件可阅读原文前往论坛下载)上传,红色以上是完整的嗲用顺序,红色以下是我觉得此次分析对我有所帮助的。

求饶部分:其实在分析之前,我完全不了解这一块,百分之九十靠的是MSDN上的解释,有的翻译可能很晦涩难懂,所以在分析的途中难免会有些错误,以及分析不到位的情况,所以还请大佬们轻喷,哈哈!总之虽说有些困难,但是最终能够学会些东西还是很开心的,坚持终究会有收获,就酱!
- End -

看雪ID:dayday向上8

https://bbs.pediy.com/user-868245.htm 

*本文由看雪论坛 dayday向上8 原创,转载请注明来自看雪社区。

推荐文章++++

App隐藏大师绕过密码与多开分析

CVE-2013-2551漏洞分析(整数溢出)

Android安全技术点小结

游戏安全之游戏Call检测的对抗与防护

VC黑防日记:DLL隐藏和逆向(续)

好书推荐


公众号ID:ikanxue
官方微博:看雪安全
商务合作:[email protected]
“阅读原文”一起来充电吧!

文章来源: http://mp.weixin.qq.com/s?__biz=MjM5NTc2MDYxMw==&mid=2458303919&idx=1&sn=b4f9f3af7fd6561988f27f8ccf3e7db6&chksm=b1818d2586f604336cb1ad561db985b13b90c856b9330dca7ab5ace20d3eefcf6549d187c8e3#rd
如有侵权请联系:admin#unsafe.sh