萌新对C++编写的动态库逆向分析
0x00 样本信息
病毒名称:DLL.dll
MD5 值:9810a578f60f8ff2e376769adac9ef38
SHA1:c605455357fe22654a7b974a2a7d301a1b0d064e
SHA256:57e486fe50782e9fdfe73974baa88b553ba58eb5f99ef7386817a3d2e27430f5
0x01 行为分析
在分析的过程中,发现代码中使用了大量的 ECX 寄存器(thiscall调用约定使用ECX寄存器传递this指针),并且在给ECX寄存器赋值之后马上调用了函数,所以我断定这应该是一个使用C++编写的样本。下面我将开始正式的分析。
我们查看其导出表,发现只导出了一个函数Run911(),所以,我们从这个函数入手分析这个样本。
当有程序加载这个动态库时,首先会给将DLL模块句柄保存到全局变量中。
Run911()函数,首先创建了一个线程。
1、线程中初始化一个与通信有关的类CCommunicate:
2、调用CCommunicate类的成员函数ConnectServer连接到服务器:
3、如果连接成功,创建了一个与通信有关的线程。
(1)该线程使用选择模型与服务器进程通信:
(2)如果接收到的数据长度小于等于0,则销毁当前类:
(3)否则调用CCommunicate类的DealPacket函数对接收到的数据包处理。
(4)DealPacket函数对收到的数据进行存储、解码、存储解码后的数据,解析获得真正的数据,存储要传送的真正的数据。
(5)在完成对数据包的解析后调用CCommunicate类中的成员变量this[33],该变量是个函数指针,但是该指针在类的构造函数中并没有初始化,该成员变量的初始化是在CManager类中进行初始化的,将CManager类this指针传递给CCommunicate类中this[33]进行保存。
4、如果与服务器连接成功则发送本机的信息到服务器。
5、构造了一个CManager类的派生类CKernelManager类,在虚基类CManager中会保存当前通信类的this指针,将CKernelManager类的this指针保存至通信类的成员变量this[33]中,而CKernelManager类的this指针保存的是CKernelManager的虚表地址,所以每当通信类收到数据时,就会调用虚表在中的函数。
CKernelManager的虚表中的函数AnalyseReceiveData_KernelManager()实现的功能是根据接收到的数据的第一个字节的不同而选择不同的功能
Case 0:CMD管理,创建一个线程执行CMD管理功能。
Case 10:进程管理,创建一个线程执行进程管理功能
Case 30:窗口管理,创建一个线程执行窗口管理功能。
Case 50:文件管理,创建一个线程执行文件管理功能。
Case 51:通知管理,创建一个线程执行通知管理功能。
Case 80:桌面管理,创建一个线程执行桌面管理功能。
Case 204:回传204。
6、循坏等待退出信号。
对上面的6个不同的功能线程进行分析。
1、Case 0:Cmd管理:
创建一个新的通信类对象,用来接收服务器发送的有关CMD管理的数据。
连接至服务器
创建CManager的派生类CCmdManager的对象。
(1)初始化成员变量,CCmdManager的成员变量如下:
(2)创建了两条管道,分别用于向CMD输入数据和从CMD中读出数据。
(3)获得cmd.exe的完整路径:
(4)以隐藏的方式启动cmd.exe进程,并且设置标准输入输出为管道。
(5)向服务器发送数据1;
(6)启动一个CmdManagerWorkThread线程对管道中的数据进行处理,管道中的数据并且将管道中的数据发送到服务器。
等待退出信号:
CCmdManager的虚表中的函数AnalyseReceiveData_CmdManager()实现的功能:如果接收到的数据第一个字节为2,设置this[2]的Event为授信,否则,将收到的数据写入到CMD管道中。
2、Case 10,30:进程窗口管理(进程管理与窗口管理使用相同的回调函数,只是传入的参数不同,所以此处放在一起分析,)
前面的初始化过程和CMD管理相同,同样是创建一个通信类的对象,服务器连接,接收与进程窗口相关的数据。
创建CManager的派生类CCmdManager的对象,根据回调函数传入的参数不同,使用不同的初始化函数。
如果为10,使用SendLocalProcessInfo函数枚举本机的进程信息并将其发送给服务器。
如果为30,使用SendLocalWindowInfo函数枚举本机的窗口信息并将其发送给服务器。
CProcessWindowManager的虚表中的函数AnalyseReceiveData_ProcessWindowManager根据接收到数据的第一个字节使用不同的功能。
Case 11调用SendLocalProcessInfo发送本地进程信息,重新枚举当前进程信息,然后发送给服务器(和初始化时使用同一个函数)。
Case 13调用TerminateProcessByProcessID函数杀死指定的进程。
Case 31 调用SendLocalWindowInfo发送本地进程信息,重新枚举当前窗口信息,然后发送给服务器(和初始化时使用同一个函数)。
Case 33 调用ShowWindowByWindowHandle函数显示指定窗口。
Case 34 发送杀死窗口的消息,然后向服务器发送本地窗口信息。
3、Case 50 文件管理
前面的初始化过程和CMD管理相同,同样是创建一个通信类的对象,服务器连接,接收与进程窗口相关的数据。
创建CManager的派生类CFileManager的对象。
(1)初始化成员变量,CFileManager成员变量如下:
(2)调用CFileManagerWork函数遍历本机所有磁盘中的对象并且获得磁盘存储空间及可用空间的信息,并将其发送给服务器。
CFileManager的虚表中的函数AnalyseReceiveData_FileManager根据接收到数据的第一个字节使用不同的功能。
Case 52 调用FindFilesInSpecificDirectory在指定的目录下搜索文件。
Case 54 调用CreateFileInSpecificDircetory 在指定的目录下创建文件。
Case 55 调用FullFileInSpecificDirectory存储文件。
Case 58 调用CreatFile函数在当前目录下创建一个文件。
Case 59 调用MoveFileDirectory函数移动函数的目录。
Case 60 打开或执行文件。
4、Case 51 通知管理
前面的初始化过程和CMD管理相同,同样是创建一个通信类的对象,服务器连接,接收与进程窗口相关的数据,创建CManager的派生类CTalkManager的对象。
CTalkManager的虚表中的函数AnalyseReceiveData_Talkger接收到数据的第一个字节为30 设置当前事件授信,调用DialogBoxParamA显示一个DialogBox对话框。
5、Case 80 桌面管理
前面的初始化过程和CMD管理相同,同样是创建一个通信类的对象,服务器连接,接收与进程窗口相关的数据,创建CManager的派生类CScreenManager的对象。
(1) 初始化成员变量
(2)创建一个线程用于发送桌面截图。
CScreenManager的虚表中的函数AnalyseReceiveData_ScreenManager根据接收到数据的第一个字节使用不同的功能。
Case 21 阻止键盘和鼠标输入事件到达应用
Case 82 设置退出事件授信
Case 85解除键盘和鼠标事件并且将鼠标和键盘事件发送至服务器
Case 87 将剪贴板的内容发送至服务器
Case 89 向剪贴板中填写内容
0x02 总结
本次分析的动态库在总体思路上不是很难,但是由于是由C++编写的,涉及到了很对有关类和对象的知识,所以在继承多态这卡了好久,最后是参考《C++反汇编及逆向技术分析》这本书才将整个程序搞清楚的,其中设计到的很多逆向C++的方法我将在后面专门整理一下。
- End -
看雪ID:XCCCC
https://bbs.pediy.com/user-805198.htm
本文由看雪论坛 XCCCC 原创
转载请注明来自看雪社区
热门图书推荐:
征题正在火热进行中!
(晋级赛Q1即将于3月10日开启,敬请期待!)
热门文章阅读
热门课程推荐
公众号ID:ikanxue
官方微博:看雪安全
商务合作:wsc@kanxue.com