[网络安全自学篇] 八十四.《Windows黑客编程技术详解》之VS环境配置、基础知识及DLL延迟加载详解(1)

从这篇文章开始,作者将带着大家来学习《Windows黑客编程技术详解》,其作者是甘迪文老师,推荐大家购买来学习。作者将采用实际编程和图文结合的方式进行分享,并且会进一步补充知识点,希望对您有所帮助。第一篇文章主要包括两部分内容,开发环境(VS、编译设置)、基础技术、运行单一实例(互斥对象示例)、DLL延迟加载(skin++换皮肤示例)、资源释放(MFC示例)。

我们在使用计算机的应用程序时,如截屏软件、音乐播放器、图片查看器等,都是运行在用户层的,属于用户程序。在Windows系统上开发的用户程序,本质上是通过调动WIN32 API函数来实现程序功能的。WIN32 API是一些预先定义的函数,目的是提升开发人员的开发效率,无需访问源码或理解内部工作机制的细节。

与普通的用户程序一样,病毒木马也是通过调用WIN32 API函数来实现窃取用户数据的。实质上,它也是一个应用程序,是一个隐蔽而特殊的软件。本书根据病毒木马运行在用户层或内核层,分成了用户篇和内核篇两部分。第一篇文章将介绍开发环境、基础技术及注入技术,希望对您有所帮助。


本书的内容如下,第1-11章为用户篇,第12-18篇为内核篇。

  • 第1章:开发环境。 主要介绍VS 2013开发环境的安装、工程项目的设置。
  • 第2章,基础技术。 介绍运行单一示例、DLL延迟加载和资源释放等内容。
  • 第3章,注入技术。 介绍全局狗子、远线程注入、突破SESSON 0隔离的远线程注入、APC注入等内容。
  • 第4章,启动技术。 介绍了创建进程API、突破SESSON 0隔离创建用户进程、内存直接加载运行等知识。
  • 第5章,自启动技术。 涵盖了注册表、快速启动目录、计划任务和系统服务等内容。
  • 第6章,提权技术。 包含进程访问令牌权限提升、Bypass UAC等内容。
  • 第7章,隐藏技术。 讲解了进程伪装、傀儡进程、进程隐藏、DLL劫持等知识。
  • 第8章,压缩技术。 介绍了数据压缩API、ZLIB压缩裤等知识。
  • 第9章,加密技术。 介绍了Windows自带的加密库、Crypto++密码库等知识。
  • 第10章,传输技术。 介绍了Socket通信、FTP通信、HTTP通信、HTTPS通信等知识。
  • 第11章,功能技术。 讲解了进程遍历、文件遍历、桌面截屏、按键记录、远程CMD、U盘监控、文件监控、自删除等知识。
  • 第12章,开发环境。 介绍了内容开发环境的配置、驱动程序开发与测试、驱动无源码调试、32位和64位驱动开发等知识。
  • 第13章,文件管理技术。 介绍了文件管理中用到的内核API、IRP、NTFS解析等知识。
  • 第14章,注册表管理技术。 讲解了注册表管理中用到的API、HIVE文件解析等知识。
  • 第15章,HOOK技术。 介绍了SSDT HOOK、过滤驱动等知识。
  • 第16章,监控技术。 讲解了进程创建监控、模块加载监控、注册表监控、对象监控、Minifilter文件监控、WFP网络监控等内容。
  • 第17章,反监控技术。 与第16章相反,它介绍了反进程创建监控、反线程创建监控、反模块加载监控、反注册表监控、反对象监控、反Minifilter文件监控等内容。
  • 第18章,功能技术。 介绍了过PatchGuard的驱动隐藏、过PatchGuard的进程隐藏、TDI网络通信、强制结束进程、文件保护、文件强删等知识。

在这里插入图片描述


PS:本文主要参考甘迪文老师的《Windows黑客编程技术详解》书籍,并结合自己的经验、网络资料和实践进行撰写,也推荐大家阅读参考文献。

作者的github资源:
软件安全:https://github.com/eastmountyxz/Software-Security-Course
其他工具:https://github.com/eastmountyxz/NetworkSecuritySelf-study
Windows-Hacker:https://github.com/eastmountyxz/Windows-Hacker


声明:本人坚决反对利用教学方法进行犯罪的行为,一切犯罪行为必将受到严惩,绿色网络需要我们共同维护,更推荐大家了解它们背后的原理,更好地进行防护。

前文学习:
[网络安全自学篇] 一.入门笔记之看雪Web安全学习及异或解密示例
[网络安全自学篇] 二.Chrome浏览器保留密码功能渗透解析及登录加密入门笔记
[网络安全自学篇] 三.Burp Suite工具安装配置、Proxy基础用法及暴库示例
[网络安全自学篇] 四.实验吧CTF实战之WEB渗透和隐写术解密
[网络安全自学篇] 五.IDA Pro反汇编工具初识及逆向工程解密实战
[网络安全自学篇] 六.OllyDbg动态分析工具基础用法及Crakeme逆向
[网络安全自学篇] 七.快手视频下载之Chrome浏览器Network分析及Python爬虫探讨
[网络安全自学篇] 八.Web漏洞及端口扫描之Nmap、ThreatScan和DirBuster工具
[网络安全自学篇] 九.社会工程学之基础概念、IP获取、IP物理定位、文件属性
[网络安全自学篇] 十.论文之基于机器学习算法的主机恶意代码
[网络安全自学篇] 十一.虚拟机VMware+Kali安装入门及Sqlmap基本用法
[网络安全自学篇] 十二.Wireshark安装入门及抓取网站用户名密码(一)
[网络安全自学篇] 十三.Wireshark抓包原理(ARP劫持、MAC泛洪)及数据流追踪和图像抓取(二)
[网络安全自学篇] 十四.Python攻防之基础常识、正则表达式、Web编程和套接字通信(一)
[网络安全自学篇] 十五.Python攻防之多线程、C段扫描和数据库编程(二)
[网络安全自学篇] 十六.Python攻防之弱口令、自定义字典生成及网站暴库防护
[网络安全自学篇] 十七.Python攻防之构建Web目录扫描器及ip代理池(四)
[网络安全自学篇] 十八.XSS跨站脚本攻击原理及代码攻防演示(一)
[网络安全自学篇] 十九.Powershell基础入门及常见用法(一)
[网络安全自学篇] 二十.Powershell基础入门及常见用法(二)
[网络安全自学篇] 二十一.GeekPwn极客大赛之安全攻防技术总结及ShowTime
[网络安全自学篇] 二十二.Web渗透之网站信息、域名信息、端口信息、敏感信息及指纹信息收集
[网络安全自学篇] 二十三.基于机器学习的恶意请求识别及安全领域中的机器学习
[网络安全自学篇] 二十四.基于机器学习的恶意代码识别及人工智能中的恶意代码检测
[网络安全自学篇] 二十五.Web安全学习路线及木马、病毒和防御初探
[网络安全自学篇] 二十六.Shodan搜索引擎详解及Python命令行调用
[网络安全自学篇] 二十七.Sqlmap基础用法、CTF实战及请求参数设置(一)
[网络安全自学篇] 二十八.文件上传漏洞和Caidao入门及防御原理(一)
[网络安全自学篇] 二十九.文件上传漏洞和IIS6.0解析漏洞及防御原理(二)
[网络安全自学篇] 三十.文件上传漏洞、编辑器漏洞和IIS高版本漏洞及防御(三)
[网络安全自学篇] 三十一.文件上传漏洞之Upload-labs靶场及CTF题目01-10(四)
[网络安全自学篇] 三十二.文件上传漏洞之Upload-labs靶场及CTF题目11-20(五)
[网络安全自学篇] 三十三.文件上传漏洞之绕狗一句话原理和绕过安全狗(六)
[网络安全自学篇] 三十四.Windows系统漏洞之5次Shift漏洞启动计算机
[网络安全自学篇] 三十五.恶意代码攻击溯源及恶意样本分析
[网络安全自学篇] 三十六.WinRAR漏洞复现(CVE-2018-20250)及恶意软件自启动劫持
[网络安全自学篇] 三十七.Web渗透提高班之hack the box在线靶场注册及入门知识(一)
[网络安全自学篇] 三十八.hack the box渗透之BurpSuite和Hydra密码爆破及Python加密Post请求(二)
[网络安全自学篇] 三十九.hack the box渗透之DirBuster扫描路径及Sqlmap高级注入用法(三)
[网络安全自学篇] 四十.phpMyAdmin 4.8.1后台文件包含漏洞复现及详解(CVE-2018-12613)
[网络安全自学篇] 四十一.中间人攻击和ARP欺骗原理详解及漏洞还原
[网络安全自学篇] 四十二.DNS欺骗和钓鱼网站原理详解及漏洞还原
[网络安全自学篇] 四十三.木马原理详解、远程服务器IPC$漏洞及木马植入实验
[网络安全自学篇] 四十四.Windows远程桌面服务漏洞(CVE-2019-0708)复现及详解
[网络安全自学篇] 四十五.病毒详解及批处理病毒制作(自启动、修改密码、定时关机、蓝屏、进程关闭)
[网络安全自学篇] 四十六.微软证书漏洞CVE-2020-0601 (上)Windows验证机制及可执行文件签名复现
[网络安全自学篇] 四十七.微软证书漏洞CVE-2020-0601 (下)Windows证书签名及HTTPS网站劫持
[网络安全自学篇] 四十八.Cracer第八期——(1)安全术语、Web渗透流程、Windows基础、注册表及黑客常用DOS命令
[网络安全自学篇] 四十九.Procmon软件基本用法及文件进程、注册表查看
[网络安全自学篇] 五十.虚拟机基础之安装XP系统、文件共享、网络快照设置及Wireshark抓取BBS密码
[网络安全自学篇] 五十一.恶意样本分析及HGZ木马控制目标服务器
[网络安全自学篇] 五十二.Windows漏洞利用之栈溢出原理和栈保护GS机制
[网络安全自学篇] 五十三.Windows漏洞利用之Metasploit实现栈溢出攻击及反弹shell
[网络安全自学篇] 五十四.Windows漏洞利用之基于SEH异常处理机制的栈溢出攻击及shell提取
[网络安全自学篇] 五十五.Windows漏洞利用之构建ROP链绕过DEP并获取Shell
[网络安全自学篇] 五十六.i春秋老师分享小白渗透之路及Web渗透技术总结
[网络安全自学篇] 五十七.PE文件逆向之什么是数字签名及Signtool签名工具详解(一)
[网络安全自学篇] 五十八.Windows漏洞利用之再看CVE-2019-0708及Metasploit反弹shell
[网络安全自学篇] 五十九.Windows漏洞利用之MS08-067远程代码执行漏洞复现及shell深度提权
[网络安全自学篇] 六十.Cracer第八期——(2)五万字总结Linux基础知识和常用渗透命令
[网络安全自学篇] 六十一.PE文件逆向之数字签名详细解析及Signcode、PEView、010Editor、Asn1View等工具用法(二)
[网络安全自学篇] 六十二.PE文件逆向之PE文件解析、PE编辑工具使用和PE结构修改(三)
[网络安全自学篇] 六十三.hack the box渗透之OpenAdmin题目及蚁剑管理员提权(四)
[网络安全自学篇] 六十四.Windows漏洞利用之SMBv3服务远程代码执行漏洞(CVE-2020-0796)复现及详解
[网络安全自学篇] 六十五.Vulnhub靶机渗透之环境搭建及JIS-CTF入门和蚁剑提权示例(一)
[网络安全自学篇] 六十六.Vulnhub靶机渗透之DC-1提权和Drupal漏洞利用(二)
[网络安全自学篇] 六十七.WannaCry勒索病毒复现及分析(一)Python利用永恒之蓝及Win7勒索加密
[网络安全自学篇] 六十八.WannaCry勒索病毒复现及分析(二)MS17-010利用及病毒解析
[网络安全自学篇] 六十九.宏病毒之入门基础、防御措施、自发邮件及APT28样本分析
[网络安全自学篇] 七十.WannaCry勒索病毒复现及分析(三)蠕虫传播机制分析及IDA和OD逆向
[网络安全自学篇] 七十一.深信服分享之外部威胁防护和勒索病毒对抗
[网络安全自学篇] 七十二.逆向分析之OllyDbg动态调试工具(一)基础入门及TraceMe案例分析
[网络安全自学篇] 七十三.WannaCry勒索病毒复现及分析(四)蠕虫传播机制全网源码详细解读
[网络安全自学篇] 七十四.APT攻击检测溯源与常见APT组织的攻击案例
[网络安全自学篇] 七十五.Vulnhub靶机渗透之bulldog信息收集和nc反弹shell(三)
[网络安全自学篇] 七十六.逆向分析之OllyDbg动态调试工具(二)INT3断点、反调试、硬件断点与内存断点
[网络安全自学篇] 七十七.恶意代码与APT攻击中的武器(强推Seak老师)
[网络安全自学篇] 七十八.XSS跨站脚本攻击案例分享及总结(二)
[网络安全自学篇] 七十九.Windows PE病毒原理、分类及感染方式详解
[网络安全自学篇] 八十.WHUCTF之WEB类解题思路WP(代码审计、文件包含、过滤绕过、SQL注入)
[网络安全自学篇] 八十一.WHUCTF之WEB类解题思路WP(文件上传漏洞、冰蝎蚁剑、反序列化phar)
[网络安全自学篇] 八十二.WHUCTF之隐写和逆向类解题思路WP(文字解密、图片解密、佛语解码、冰蝎流量分析、逆向分析)
[网络安全自学篇] 八十三.WHUCTF之CSS注入、越权、csrf-token窃取及XSS总结


前文欣赏:
[渗透&攻防] 一.从数据库原理学习网络攻防及防止SQL注入
[渗透&攻防] 二.SQL MAP工具从零解读数据库及基础用法
[渗透&攻防] 三.数据库之差异备份及Caidao利器
[渗透&攻防] 四.详解MySQL数据库攻防及Fiddler神器分析数据包



一.开发环境

俗话说“工欲善其事,必先利其器”,选择一个好的开发平台会让我们的程序开发事半功倍。对于Windows黑客来说,首选的开发平台自然是VS“大礼包”——Microsoft Visual Studio。它在Windows程序开发路上是一块不错的“垫脚石”,可以使编程过程更加灵活、得心应手。

VS是流行的Windows开发应用程序的集成环境,它包括了整个软件生命周期中所需要的大部分工具,如UML工具、代码管控工具、集成开发环境(IDE)等。所写的目标代码适用于微软支持的所有平台,包括Microsoft Windows、Windows Mobile、Windows CE、.NET Framework、Microsoft Silverlight及Windows Phone。接下来我们将介绍VS开发项目过程的基本设置及注意事项。

在这里插入图片描述


个人感受
我最早接触的程序语言是C,采用的软件正是MFC和VS。在编程路上大家或多或少都会接触VS工具,尤其是Windows开发应用程序。虽然之后我也陆续接触了OC、JAVA、PHP、C#、Python、GO等,但C和C++始终是基础,很多底层的开发及API调用、性能提升还是需要它们来完成,而Python更多是调包,以其轻量型的IDE和语法颇受好评。但当我们要完成Windows黑客编程,开发一套远控软件或分析恶意样本时,VS工具始终都是首先,虽然它也存在很多缺点,比如工具太“重”、安装配置麻烦、兼容性及WEB开发弊端等。如果你从事系统安全或软件安全,如果你对独立开发一款Windows远控软件感兴趣,那么接下来的文章会非常合你的胃口,让我们一起加油~

Windows安装过程这里不详细介绍,读者请自行安装。
下载地址:https://visualstudio.microsoft.com/zh-hans/downloads/

在这里插入图片描述

在这里插入图片描述


初学编程时,大多数教程使用的开发环境都是VC6.0。VC6.0编译的是控制台程序或DLL,直接编译出来就可以在其他平台上运行或调用,不需要额外加载运行库DLL等。若想使用VC6.0编译出来的MFC程序,编译的时候设置在静态库中使用MFC,即将MFC所需的DLL组建静态编译到程序里,这样程序在任意平台上运行时都不需要额外附件MFC所需的DLL文件。

随着技术提升,高效而稳定的开发环境成为大家追求的目标,因此VC6.0慢慢淡出了视线,转而使用VS2010、VS2012、VS2017、VS2019等。尽管VS系统开发环境的功能确实比较全面,能够提升开发效率,但是VC6.0中一些习以为常的习惯(如编译设置等)都存在区别。所以我们需要先介绍VS开发环境的设置。

在这里插入图片描述


1.控制台程序和DLL程序的编译设置

作者将控制台程序和DLL程序的编译设置放一起,是因为它们的设置是一样的。具体步骤如下:

第一步,创建项目。
安装成功之后如下图所示,我们首先需要点击“创建新项目”。

在这里插入图片描述

选择“空项目”并点击“下一步”。

在这里插入图片描述

接着配置新项目,项目名称为“Project001”。

在这里插入图片描述

此时项目创建成功,主界面如下图所示:

在这里插入图片描述


第二步,创建代码。
选中“源文件”天价“添加”,然后新增一个“main.cpp”文件。

在这里插入图片描述

在这里插入图片描述

编写代码并运行,第一个代码当然是“Hello World”。

在这里插入图片描述

输出结果如下图所示:

在这里插入图片描述

如果在运行过程中提示错误缺失DLL文件,我们只需要进行网上下载,并将vcruntime140d.dll复制到C:\Windows\SysWOW64目录下即可。

在这里插入图片描述


第三步,打开工程属性。
打开项目工程后,右击项目工程,选中并点击“属性”,打开属性页。

在这里插入图片描述

属性页如下图所示:

在这里插入图片描述


第四步,设置兼容XP。
在“平台工具集”中选择包含“XP”字样的选项,这里表示程序兼容XP系统,它可以在XP系统下正常运行。

在这里插入图片描述


第五步,选择运行库。
接着端基左侧“C/C++”并选择“代码生成”选项,这时可以看到右侧页面的“运行库”默认值为“MDd”。如果此时你的项目是Debug模式,则选择“MTd”;若是Release模式,则选择“MT”。其中MT是“Multithread Static Version”的缩写,即多线程静态版本;d是“Debug”的缩写,即Debug模式。运行库的界面如下图所示:

在这里插入图片描述

根据上面操作,设置兼容XP系统和静态编译运行库,编译出来的控制台程序和DLL程序就能直接在Windows系统加载运行。



2.MFC程序编译设置

对于MFC程序,除了上面两个操作外,还需要额外的操作,就是在“MFC的使用”选项中设置“在静态库中使用MFC”。这样,VS开发环境就会把MFC所需的DLL文件都静态编译到程序中,因此生成的文件也自然会变大。但是,这样的程序就可以直接在其他Windows系统的计算机上运行,并且不需要额外加载其他文件。

在这里插入图片描述

通过上述设置所生成的程序就可以不依赖于开发环境而独立运行在其他Windows系统之上。



3.安装的VS没有MFC

这里可能存在一个新问题——安装VS2019时没有安装MFC,那么怎么办呢?

第一步,在“创建新项目”右边的竖直移动条拉到底部,点击“安装多个工具和功能”选项。

在这里插入图片描述

第二步,选中“使用C++桌面开发”,在右侧选中相关功能添加“C++ MFC(x86和x64)”选项,最后点击修改即可。

在这里插入图片描述

第三步,接着系统会下载和安装。

在这里插入图片描述

第四步,安装成功之后即可创建MFC程序,如下图所示。

在这里插入图片描述

项目名称为“MFCApplication1”,点击“创建”即可。

在这里插入图片描述

选择单文档。

在这里插入图片描述

第五步,运行代码,显示如下图所示。

在这里插入图片描述



4.Debug和Release模式

大家在使用VS时,通常会遇到程序在Debug模式下正常运行,但在Release模式下运行却会出错。这是为什么呢?

在VS开发环境中,Debug模式和Release模式并没有本质区别,他们编译使用的都是同一份源码,这是众所周知的。其中,Debug通常称为调试版本,通过一些列编译选项的配合,编译结果通常包含调试信息,而不进行任何优化,这为开发人员提供强大的应用程序调试能力。而Release通常称为发布版本,是为用户使用的。通常情况下,客户不允许在发布版本上进行调试,所以它不保存调试信息,同时它往往进行各种优化,以期达到代码量最小和速度最优,为用户的使用提供便利。

换句话说,Debug模式和Release模式的唯一区别就是在VS开发环境里编译选项的区别。

该问题也就是由于一些编译设置的问题所导致的。考虑到程序可能使用到开源的第三方库,而且第三方库 自己编译出来的。在Release模式下出错的位置,也是在执行第三方库代码时候报错的位置,从而确定出错的原因,即在调用第三方库时,Debug模式和Release模式的编译选项和第三方库的编译选项可能没有对应,这可能是运行库的设置问题。

在这里插入图片描述

解决方法是,在Release模式下打开项目工程属性页,展开“C/C++”选择“代码生成”,更改“运行库”里的选项,更改为“多线程调试(MTd)”时,生成的程序可以正常运行,问题得以解决。



二.基础技术

该部分的内容是病毒木马中最为常见、最为基础的技术,其技术变化不大,所以不对每个技术单独归类,而是统一进行讲解。作为本书病毒木马技术详解的开辟,主要是带着大家由浅入深、循序渐进地了解病毒木马的各类实现技术。大多数病毒木马在成功植入用户计算机之后,在执行核心恶意代码之前,会先进性初始化操作,这些操作的技术点就包括运行单一实例、DLL延迟加载和资源释放。

1.运行单一实例——互斥对象示例

在使用各种手段将病毒木马植入到用户计算机后,它也会使用浑身解数来使用户激活它。但是,如果病毒木马被多次重复运行,系统中会存在多份病毒木马的进程,那么这就有可能增加暴露的风险。所以,要想解决上述问题,就要确保系统上只运行一个病毒木马的进程实例。确保运行一个进程实例的实现方式有很多,包括:

  • 可以通过扫描进程列表来实现
  • 可以通过枚举程序窗口的方法来实现
  • 可以通过共享全局变量来实现

下面介绍一种使用广泛而且简单的方法,即通过创建系统命名互斥对象的方式来实现。


(1) 函数介绍
CreateMutex函数:创建或打开一个已命名的互斥对象。

HANDLE WINAPI CreateMutex(
	LPSECURITY_ATTRIBUTES lpMutexAttributes,  //指向安全属性的指针
	BOOL bInitialOwner,                       //初始化互斥对象的所有者
	LPCTSTR lpName                            //指向互斥对象名的指针
);

参数

  • lpMutexAttributes [in, optional] 指向SECURITY_ATTRIBUTES结构的指针,如果次参数为NULL,则该句柄不能由子进程继承。
  • bInitialOwner: 如果此值为TRUE并且调用者创建了互斥锁,则调用线程将获得互斥锁对象的初始所有权。否则,调用线程不会获得互斥锁的所有权。
  • lpName:互斥对象的名称。该名称仅限于MAX_PATH字符,名称区分大小写,如果为NULL则会创建不带名称的互斥对象。 如果lpName与现有事件、信号量、等待定时器、作业或文件映射对象的名称匹配,且这些对象共享相同的名称空间,则该函数将失败,并且GetLastError函数返回ERROR_INVALID_HANDLE。

返回值

  • 如果函数成功,则返回值是新创建的互斥对象的句柄。
  • 如果函数失败,则返回值为NULL。要获得扩展的错误信息,请调用GetLastError。
  • 如果互斥锁是一个已命名的互斥锁,并且该对象在此函数调用之前就存在,则返回值是现有对象的句柄,GetLastError返回ERROR_ALREADY_EXISTS。

解释
CreateMutex只是创建了一把锁, 这把锁你用来锁门还是锁抽屉都由你自己决定。lpName是指定这把锁的名字,你要不给这把锁取个名字也可以,只是有了相同的名字, 在跨进程加锁的时候,就可以得到同一把锁。HANDLE m_hMutex = CreateMutex(NULL,TRUE,“cplusplus_me”); 只是创建了一把锁,到目前这句完成但没有锁任何东西。


(2) 实现原理
通常情况下,系统中的进程是相互独立的,每个进程都拥有自己的独立资源和地址空间,进程间互不影响。所以,同一个程序可以重复运行,但系统上的进程互不影响。但是,在一些特殊情况下,程序在系统上需要只保留一份进程实例,这就引出了进程互斥的问题。

微软提供了CreateMutex函数来创建或打开一个已命名或未命名的互斥对象,程序在每次运行的时候,通过判断系统中是否存在相同命名的互斥对象来确定程序是否重复运行。

CreateMutex函数共有3个参数:

  • 第一个参数表示互斥对象的安全设置,是一个指向SECURITY_ATTRIBUTES结构的指针,在该程序中直接设置为NULL即可。
  • 第二个参数表示线程是否获得互斥锁对象的初始所有权,在该程序中,无论该参数为TRUE还是FALSE,均不影响程序的正常运行。
  • 第三个参数表示互斥对象的名称,对于通过互斥对象来判断进程实例是否重复运行的程序来说,该参数一定要设置,而且要保证设置名称的唯一性。

程序的判断原理是通过CreateMutex函数创建一个命名的互斥对象,如果对象创建成功,而且通过调用GetLastError函数获取的返回码为ERROR_ALREADY_EXISTS,则表示该命名互斥对象存在,即程序重复运行。否则,认为程序是首次运行。


(3) 编程实现
代码如下:

#include <stdio.h>
#include <windows.h>
#include <iostream>
using namespace std;

//判断是否重复运行
BOOL IsAlreadyRun()
{
	//创建互斥对象
	HANDLE hMutex = NULL;
	hMutex = ::CreateMutex(NULL, FALSE, "TEST Eastmount");

	//如果互斥对象创建成功则返回命名互斥对象存在 表示程序重复运行
	if (hMutex) {
		if (ERROR_ALREADY_EXISTS == ::GetLastError()) {
			return TRUE;
		}
	}
}

int main()
{
	//判断是否重复运行
	if (IsAlreadyRun()) {
		printf("Already RUN!!!\n");
	}
	else {
		printf("NOT Already RUN!!!\n");
	}
	Sleep(100000);
	
	//system("pause");
	return 0;
}

直接运行程序,第一次运行的时候,程序返回结果“NOT Already RUN!!!”,它表示系统没有运行该实例。

在这里插入图片描述

在不关闭上述进程的前提下,继续双击执行程序,这次程序提示“Already RUN!!!”,表示系统已经存在该实例且正在运行,所以该程序能判断程序是否重复运行。

在这里插入图片描述

注意,在撰写“hMutex = ::CreateMutex(NULL, FALSE, “TEST Eastmount”);”代码时,如果提示错误“const char *类型的实参与LPCWSTR类型的形参不兼容”。我们只需要在项目属性的字符集中设置“未设置”即可解决,不设置编码方式。

在这里插入图片描述


(4) 逆向分析
下面作者简单讲解该程序的逆向分析,参考文章 “逆向入门分析实战(一)”。我们通过IDA静态分析程序,包括子程序和主程序。在病毒木马分析中,其中一点比较重要的是分析call函数,只要将这个程序所调用的函数分析清楚了,那么就知道这个病毒木马在做什么了。与此同时要弄清楚它的逻辑结构,比如什么时候跳转到哪执行,作者之前的博客也都有讲解逆向分析的基础,下面给出其中的4篇文章。

通过IDA打开“Project001.exe”程序,其主函数如下图所示:

在这里插入图片描述

我们按下F5可以看到对应的反汇编代码,其中sub_44EF45(&unk_519032) 和 sub_44E8E7() 是我们的关注点。

在这里插入图片描述

进一步分析,定位到sub_4534D0()函数,它则为创建互斥对象CreateMetexA。

在这里插入图片描述

同样,我们可以通过OD软件进一步动态调试分析,比如核心汇编代码,通过call函数调用sub_44EF45()和sub_44E8E7(),然后jz判断结果为TRUE或FALSE,即表示是否创建互斥对象,最终输出“Already RUN!!!”或“NOT Already RUN!!!”。

.text:00453700                 push    ebp
.text:00453701                 mov     ebp, esp
.text:00453703                 sub     esp, 0C0h
.text:00453709                 push    ebx
.text:0045370A                 push    esi
.text:0045370B                 push    edi
.text:0045370C                 lea     edi, [ebp+var_C0]
.text:00453712                 mov     ecx, 30h
.text:00453717                 mov     eax, 0CCCCCCCCh
.text:0045371C                 rep stosd
.text:0045371E                 mov     ecx, offset unk_519032
.text:00453723                 call    sub_44EF45
.text:00453728                 call    sub_44E8E7
.text:0045372D                 test    eax, eax
.text:0045372F                 jz      short loc_453740
.text:00453731                 push    offset aAlreadyRun ; "Already RUN!!!\n"
.text:00453736                 call    sub_44D3ED
.text:0045373B                 add     esp, 4
.text:0045373E                 jmp     short loc_45374D
.text:00453740
.text:00453740 loc_453740:                             ; CODE XREF: sub_453700+2F↑j
.text:00453740                 push    offset aNotAlreadyRun ; "NOT Already RUN!!!\n"
.text:00453745                 call    sub_44D3ED
.text:0045374A                 add     esp, 4

写到这里,一个简单的逆向分析代码就讲解结束,希望您喜欢。为什么要讲解这部分内容呢?因为Windows黑客编程,对木马病毒进行逆向分析是非常重要的基础,而且是绕不过去的,后面的文章也会结合该知识点深入。



2.DLL延迟加载——skin++换皮肤示例

在开发程序的时候,通常会使用第三方库。但是,并不是所有的第三方库都会提供静态库文件,大多数会提供动态库DLL文件。这样,程序需要相应的DLL文件才能加载启动。这部分讲介绍一种被病毒木马广泛使用的DLL延迟加载技术,使用延迟加载方式编译链接可执行文件。这样可执行程序就可以先加载执行,所以来的DLL正在调用时再加载进来。

优点:

  • 好处是可以把必需的DLL文件以至于形式插入到程序中,并使用DLL延迟加载技术延迟加载。在正式调用必需的DLL之前,程序都可以正常执行。程序可以在这段时间内,把资源中的DLL释放到本地,等到正式调用DLL时释放的文件就会正常地加载执行。这样当使用程序时只需把exe文件发送给用户,而不需要附加DLL文件,也不需要担心程序会丢失DLL文件。

示例实现:
首先我们通过VS2019创建一个对话框示例,选择“基于对话框”类型。

在这里插入图片描述

在“资源视图”中修改内容如下图所示:

在这里插入图片描述

此时运行如下图所示:

在这里插入图片描述

接着准备如下文件:

  • SkinPlusPlusDLL.dll
  • SkinPlusPlusDLL.lib
  • SkinPlus Plus .h
  • 三个*.ssk皮肤

在这里插入图片描述

将上述工具文件拷贝到工程目录下。

在这里插入图片描述

(1) 在你的程序MFCApplication2.cpp和MFCApplication2Dlg.cpp中包含头文件。

#inlcude "SkinPlusPlus.h"

(2) 在程序MFCApplication2.cpp中加入初始化语句CMFCApplication2App::InitInstance()。

InitializeSkin(("Minimized.ssk"));

在这里插入图片描述

(3) 在程序的卸载函数中加入ExitInstance()。注意,这里需要从类向导中添加,建议大家可以去熟悉下MFC基本用法,作者2013年的MFC系列博客。

在这里插入图片描述

选择“类向导”,然后添加虚函数“ExitInstance”。

在这里插入图片描述

在生成的函数中添加如下代码:

int CMFCApplication2App::ExitInstance()
{
	// TODO: 在此添加专用代码和/或调用基类
	ExitSkin();
	return CWinApp::ExitInstance();
}

(4) 执行函数LoadSkin即可以实现动态换肤。继续通过类向导增加自定义方法OnSkin1。

在这里插入图片描述

然后生成如下OnSkin1函数。

在这里插入图片描述

在MFCApplication2Dlg.cpp中生成的函数中添加载入皮肤函数。

  • InitializeSkin(皮肤文件名);
    InitializeSkin是SKin++的初始化函数。
  • LoadSkin(皮肤文件名);
    可以通过该函数加载Skin++,注:如果皮肤文件名中没有路径则采用当前目录。
void CMFCApplication2Dlg::OnSkin1()
{
	// TODO: 在此处添加实现代码.
	LoadSkin(("Minimized.ssk"));
}

最终运行效果如下图所示,读者还可以加载其他的皮肤,如:

  • LoadSkin((“XPCorona.ssk”)); InitializeSkin((“XPCorona.ssk”));
  • LoadSkin((“SoftCrystal.ssk”)); InitializeSkin((“SoftCrystal.ssk”));
  • LoadSkin((“Minimized.ssk”)); InitializeSkin((“Minimized.ssk”));

在这里插入图片描述

写到这里一个MFC替换皮肤的代码就介绍完毕,接下来我们开始分析代码。


示例分析:

  • 本程序以加载第三方库——skin++库为例进行讲解演示。首先导入skin++库文件,然后编码,最后对程序编译链接生成exe可执行文件,使用PE查看器PEView.exe查看可执行文件的导入表,可以看到可执行文件必须的DLL文件。
  • 导入表如下图所示。 从图中可以看到可执行程序导入表有SkiinPlusPlusDLL.dll文件,也就是在程序加载运行的时候,SkinPlusPlusDLL.dll文件必须存在,否则程序会因为加载SkinPlusPlusDLL.dll文件失败而不能正常启动。
  • PEView用法参考作者的文章:
    六十一.PE文件逆向之数字签名详细解析及Signcode、PEView、010Editor、Asn1View等工具用法(二)

在这里插入图片描述


设置DLL延迟加载:

  • DLL延迟加载技术的原理就是从导入表中去掉SkinPlusPlusDLL.dll这项,等到正式调用DLL的时候,才会加载DLL文件。这样程序在正式调用DLL之前,都可以正常执行。其中,DLL延迟加载的实现并不需要任何编码,只需要对VS开发环境中的链接选项进行手动设置即可。
  • 本程序设置如下,在属性页面中选择“链接器” -> “输入” -> “延迟加载的DLL”,然后输入:SkinPlusPlusDLL.dll,如下图所示。

在这里插入图片描述

  • 程序经过上述设置后,DLL延迟加载就设置完成,接着再次编译链接生成新的exe可执行程序,并用PEView.exe查看可执行程序的导入表信息,这是导入表中再也没有SkinPlusPlusDLL.dll的信息了。

在这里插入图片描述

总之,DLL延迟加载技术不需要编码来实现,只需duiVS开发环境设置链接器即可。DLL延迟加载技术配合资源释放技术,可以使得程序更加方便易用。在PE结构中,DLL延迟加载的信息存储在ImgDelayDescr延迟导入表中,可以通过数据目录DataDirectory中的IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT项获取延迟导入表RVA相对的偏移地址和数据大小。



3.资源释放——MFC示例

病毒木马之所有会广泛使用资源释放技术,是因为它可以使程序变得更简洁。如果程序额外需要加载一些DLL文件、文本文件、图片文件或者其他的音频视频文件等,则可以把它们作为资源插入到程序中,等到程序运行后,再把它们释放到本地。这样做的好处是编译出来的程序只有一个exe文件,而不需要附带其他文件,因而程序变得很简洁。只需把exe植入到用户计算机上,而不需要连同其他文件一起植入,这降低了被发现的风险。

(1) 资源插入步骤
首先创建MFCApplication3工程,选择“基于对话框”类型。

在这里插入图片描述

为程序设置一个对话框标题,如下图所示。

在这里插入图片描述

运行程序生成Debug文件夹及可执行程序。

在这里插入图片描述

然后在该文件夹中创建csdn.txt,如下图所示,它就是我们要添加的资源。

在这里插入图片描述

接下来由于需要自定义资源,所以在解决方案中选择“添加”->“资源”。

在这里插入图片描述

选择“自定义”按钮,然后再“新建自定义资源”对话框中输入资源类型为“TXT”,然后点击“确定”按钮。

在这里插入图片描述

在设置好自定义资源的类型后,接着回到“添加资源”对话框,选中刚才新建的“TXT”资源类型。

在这里插入图片描述

然后单击右侧的“导入(M)…”按钮选择导入文件,选择“TXT”类型。

在这里插入图片描述

接着选择Debug文件夹下的“csdn.txt”文件,并且在资源类型中点击“TXT”,导入成功如下图所示:

在这里插入图片描述

此时导入成功,如下图所示:

在这里插入图片描述


(2) 函数介绍

  • FindResource函数
    确定模块中指定类型和名称的资源所在位置。
HRSRC FindResource(
	HMODULE hModule,
	LPCWSTR lpName,
	LPCWSTR lpType
);
  • 参数
    hModule[in]表示处理包含资源的可执行文件模块,若hModule为NULL,则系统从当前进程的模块中装载资源。lpName[in]指定资源名称。lpType[in]指定资源类型。

  • 返回值
    如果函数运行成功,那么返回值为指定资源信息块的句柄。可将这个句柄传递给LoadResource函数来获得这些资源。如果函数运行失败,则返回值为NULL。


  • SizeofResource函数
    获取指定资源的字节数。
DWORD SizeofResource(
	HMODULE hModule,
	HRSRC hReslnfo
);
  • 参数
    hModule[in]包含资源的可执行文件模块的句柄,若hModule为NULL,则系统从当前进程的模块中装载资源。hResInfo[in]资源句柄,此句柄必须由函数FindResource或FindResourceEx来创建。

  • 返回值
    如果函数运行成功,那么返回值为资源的字节数;如果函数运行失败,则返回值为零。


  • LoadResource函数
    装载指定资源到全局存储器。
HGLOBAL LoadResource(
	HMODULE hModule,
	HRSRC hReslnfo
);
  • 参数
    hModule[in]处理资源可执行文件的模块句柄,若hModule为NULL,则系统从当前进程的模块中装载资源。hResInfo[in]资源句柄,此句柄必须由函数FindResource或FindResourceEx来创建。

  • 返回值
    如果函数运行成功,那么返回值为相关资源数据的句柄;如果函数运行失败,则返回值为NULL。


  • LockResource函数
    锁定资源并得到资源在内存中第一个字节的指针。
HGLOBAL LockResource(
	HMODULE hResDate
);
  • 参数
    hResDate[in]装载资源的句柄,函数LoadResource可以返回这个句柄。

  • 返回值
    如果装载资源被锁住,则返回值是资源第一个字节的指针,反之则返回NULL。


(3) 实现原理
为方便开发人员获取程序里的资源,Windows提供了一系列带有操作资源的WIN32 API函数。所以,程序实现也是基于这些WIN32 API函数进行操作的。

  • 首先,通过FindResource定位程序里的资源,主要根据“资源类型”和“资源名称”进行定位,从而获取资源信息块的句柄。
  • 其次,根据上面获取的资源信息块的句柄,利用SizeofResource获取资源的大小之后,再通过LoadResource把资源加载到程序内存中。
  • 接着,通过LockResource锁定加载到内存中的资源,防止程序中的其他操作影响这块内存。其中,返回值就是资源在进程内存中的起始地址。
  • 最后,根据资源大小以及进程内存的起始地址,可将资源数据读取出来并保存为本地文件。

通过上述处理,便可以定位出资源,并将其释放到本地磁盘。它的原理就是通过PE文件结构,确定资源在PE文件中的偏移和大小。

在释放资源过程中,要特别注意一点,必须明确资源所在的模块,要指明所在模块句柄并统一。因为文件可以以资源的形式插入到DLL文件中,所以当DLL加载到其他进程时,资源所在模块仍是该DLL模块。要向成功释放资源,则需要先通过GetModuleHandle函数获取该DLL模块的句柄,否则,资源释放会因为指定了错误模块而失败。


(4) 编程实现

接着设置对话框,新增一个BUTTON按钮,并设置按钮名称为“释放资源”。

在这里插入图片描述

接着双击按钮,在弹出的函数中添加内容。

在这里插入图片描述

点击“资源视图”中的导入文件,发现属性栏中ID为“IDR_TXT2”。

在这里插入图片描述

添加代码,其中ReleaseRes包括三个参数,分别为文本名称、ID和资源类型。

void CMFCApplication3Dlg::OnBnClickedButton1()
{
	if (ReleaseRes("csdn.txt", (WORD)IDR_TXT2, "TXT")) {
		MessageBox("释放文件成功!", "提示", MB_OK);
	}
	else {
		MessageBox("释放文件失败!", "提示", MB_OK);
	}
}

接着打开类向导,然后添加函数ReleaseRes

在这里插入图片描述

添加函数“ResourceRes”,包括三个参数:

  • CString strFileName
  • WORD wResID
  • CString strFileType

在这里插入图片描述

在这里插入图片描述

生成函数如下图所示:

在这里插入图片描述

添加代码如下:

bool CMFCApplication3Dlg::ReleaseRes(CString strFileName, WORD wResID, CString strFileType)
{
	//资源大小
	DWORD dwWrite = 0;
	//创建文件
	HANDLE hFile = CreateFile(strFileName, GENERIC_WRITE, FILE_SHARE_WRITE,
		NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

	if (hFile == INVALID_HANDLE_VALUE) {
		return false;
	}

	//查找资源文件
	HRSRC hrsc = FindResource(NULL, MAKEINTRESOURCE(wResID), strFileType);
	//资源加载到内存
	HGLOBAL hG = LoadResource(NULL, hrsc);
	//获取资源大小
	DWORD dwSize = SizeofResource(NULL, hrsc);

	//写入文件
	WriteFile(hFile, hG, dwSize, &dwWrite, NULL);
	CloseHandle(hFile);
	return true;
}

接着生成新的解决方案,然后点击“开始执行(不调试)”。

在这里插入图片描述

我们将exe程序复制到一个空的文件夹下,然后运行程序。

在这里插入图片描述

运行结果如下图所示,可以看到“csdn.txt”被释放出来,成功完成了该实验。

在这里插入图片描述

该部分内容主要创建了一个MFC工程,插入资源,接着调用封装好的资源释放函数进行资源释放测试,并成功释放txt文件。实际上,释放资源技术实现的原理并不复杂,只需要清理WIN32 API函数的调用关系以及函数作用即可。特别注意,明确资源所在的模块,如果资源包含在DLL文件中,则可以在DllMain中或通过GetModuleHandle函数获取DLL模块的句柄。

在这里插入图片描述

PS:最后提示,该部分代码是作者修改后的代码,与甘老师书中的代码略有不同,但原理大致一样。如果您想根据PE结构中的资源表IMAGE_RESOURCE_DIRECTORY来解析PE文件中包含的所有资源,并且获取资源的偏移地址及数据大小。例如,常见的资源编辑工具eXeScope就是根据资源表来枚举PE文件中的资源。



三.总结

写到这里,这篇文章就介绍完毕,希望对您有所帮助,还是觉得自己菜。学安全近一年,认识了很多安全大佬和朋友,希望大家一起进步。这篇文章中如果存在一些不足,还请海涵。作者作为网络安全初学者的慢慢成长路吧!希望未来能更透彻撰写相关文章。同时非常感谢甘老师和参考文献中的安全大佬们,深知自己很菜,得努力前行。最后还是那句话,人生路上,好好享受陪伴家人的日子,那才是最幸福的事情,爱你~

欢迎大家讨论,是否觉得这系列文章帮助到您!任何建议都可以评论告知读者,共勉。

最近真的特别忙,写博客、学新知识的时间都没有,越做越觉得知识的无边,自己的无知。十年编程生涯过去,又回到了最初的起点——C语言和VS加油!接下来会做一个Windows远控及木马软件,也会挤时间分享新的系列博客(图5),感觉还是挺有意思的。
还未走远,已是思恋武汉返校在即,最近多做点好菜犒劳女神,没有什么比亲情更值得珍惜,图4的新笔记本我也会画出属于我们的2020年蓝天。回廊清风抚白发,一笑弥新仍少年。愿大家都要好好的~

在这里插入图片描述

(By:Eastmount 2020-06-19 晚上8点写于贵阳 http://blog.csdn.net/eastmount/ )



猜你喜欢

转载自blog.csdn.net/Eastmount/article/details/106718606