20145302张薇 《网络对抗技术》 恶意代码伪装技术实践
20145302张薇 《网络对抗技术》 恶意代码伪装技术实践
实验内容
- DLL注入技术实现后门注入
实验原理
DLL文件是什么
- DLL(Dynamic Link Library)文件为动态链接库文件,又称“应用程序拓展”,是软件文件类型。在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件,放置于系统中。当我们执行某一个程序时,相应的DLL文件就会被调用。一个应用程序可使用多个DLL文件,一个DLL文件也可能被不同的应用程序使用,这样的DLL文件被称为共享DLL文件。
DLL特点
- 占用的资源少。当多个程序使用同一个函数库时,DLL 可以减少在磁盘和物理内存中加载的代码的重复量。这不仅可以大大影响在前台运行的程序,而且可以大大影响其他在 Windows操作系统上运行的程序。
- 推广模块式体系结构 DLL 有助于促进模块式程序的开发。这可以帮助您开发要求提供多个语言版本的大型程序或要求具有模块式体系结构的程序。模块式程序的一个示例是具有多个可以在运行时动态加载的模块的计帐程序。
- 简化部署和安装 当 DLL 中的函数需要更新或修复时,部署和安装 DLL 不要求重新建立程序与该 DLL 的链接。此外,如果多个程序使用同一个 DLL,那么多个程序都将从该更新或修复中获益。
实验基础
- 要想实现dll后门注入,我们至少需要知道自己如何创建一个简单的dll并使用。
- 嘻嘻,虽然弄的这个东西很简单,但是整整花了我一天的时间才调通:),出现的问题太多了!!!
1.首先我们打开vs 2013新建一个项目
-
选择win32控制台应用程序
-
点击下一步,应用程序类型选择DLL,附加选项勾选导出符号、预编译头和安全开发声明周期(SDL)检查这三项(导出符号只是会给你一些提示性的语句,告诉你每部分是用来干什么的,可以不选),随后点击完成即可。
2.生成一个dll文件,其函数用于计算1-n的数字和
-
工程的文件目录结构如下:
-
在SUMDLL.cpp文件中写入求和函数,代码如下:
// SUMDLL.cpp : 定义 DLL 应用程序的导出函数。
#include "stdafx.h"
#include "SUMDLL.h"
#include <iostream>
using namespace std;
// 这是导出变量的一个示例
SUMDLL_API int nSUMDLL = 0;
// 这是导出函数的一个示例。
SUMDLL_API int fnSUMDLL(void)
{
return 42;
}
// 这是已导出类的构造函数。
// 有关类定义的信息,请参阅 SUMDLL.h
CSUMDLL::CSUMDLL()
{
return;
}
SUMDLL_API void SUM()//这边为SUM()的内容,很简易
{
int val = 0;
int sum = 0;
cout << "input a number! " << endl;
cin >> val;
if (val > 0)
for (int j = 0; j <= val; ++j)
sum += j;
cout << "The result is: " << sum << endl;
}
- 在SUMDLL.h头文件中声明调用的函数,代码如下:
// 下列 ifdef 块是创建使从 DLL 导出更简单的
// 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 SUMDLL_EXPORTS
// 符号编译的。在使用此 DLL 的
// 任何其他项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将
// SUMDLL_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的
// 符号视为是被导出的。
#ifdef SUMDLL_EXPORTS
#define SUMDLL_API __declspec(dllexport)
#else
#define SUMDLL_API __declspec(dllimport)
#endif
// 此类是从 SUMDLL.dll 导出的
class SUMDLL_API CSUMDLL {
public:
CSUMDLL(void);
// TODO: 在此添加您的方法。
};
extern SUMDLL_API int nSUMDLL;
SUMDLL_API int fnSUMDLL(void);
SUMDLL_API void SUM(); //此处是我们增添的内容
- 在“生成”标签栏选择生成SUMDLL即可成功生成DLL文件
3.实现在程序中调用DLL
- 在此解决方案下右键选择“添加”-“新建项目”-“win32控制台应用程序”,并命名为UseDLL
- 在应用程序类型中选择控制台应用程序即可完成新建
- 在UseDLL.cpp中我们写调用的dll文件与函数名称,代码如下:
// UseDLL.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
using namespace std;
typedef void(*FUN)(); //定义一个函数指针
//extern void SUM();
int main()
{
const char* dllname = "SUMDLL.dll"; //dll的名称
const char* funname = "SUM"; //SUMDLL.cpp中函数名称
HMODULE hDLL = LoadLibrary(dllname);
if (hDLL != NULL) {
FUN fp = FUN(GetProcAddress(hDLL, funname));
if (fp != NULL)
fp();
else cout << "Can not Find: " << funname << endl;
FreeLibrary(hDLL);
}
else
cout << "Can not find: " << dllname;
//SUM();
return 0;
}
-
上述代码是用于加载我们建立的SUMDLL.dll,并使用GetProcAddress函数验证是否可找到该DLL文件,失败则fp为空即无法找到文件,成功则加载该DLL文件,加载完后释放,避免不必要的占用内存
-
我在调试上述代码时,在使用LoadLibrary函数那里,dllname一直出错,因为const char* dllname不是该函数参数匹配的类型,解决方法为:
- 在UseDLL工程处右键选择属性
- 找到配置属性-常规-项目默认值-字符集
- 将字符集选择为:使用多字节字符集
-
在我们的解决项目右键选择属性,并在单启动项目中选择UseDLL。(因为DLL文件是无法自己运行的,我们需要使用一个程序作为启动项目去调用他)
-
Ctrl+F5
调试运行一下,得到以下结果:
-
我们找不到SUM函数,这是为何?
-
这是因为导出函数经过编译器的“加工”,它的名称会与原文件中声明的名称变得不同。
-
那么名称变成了什么呢?我们使用vs自带的工具——dumpbin来查看一下,在命令行下进行以下操作
- vcvar32.bat //通过加载bat文件,仅在本次cmd会话中快速调用dumpbin
- dumpbin //查看dumpbin工具拥有哪些功能
- dumpbin –exports SUMDLL.dll //列出导出函数
-
通过上图我们发现原文件中的函数名称
SUM
变为?SUM@@YAXXZ
解决方法如下:
第一种:直接将UseDLL.cpp文件里面的const char* funname = "SUM"处的SUM改为导出函数名?SUM@@YAXXZ即可
第二种:1.建立模块定义文件SUMDLL.def,代码内容为:
- LIBRARY SUMDLL //用于声明def文件的名称
- EXPORTS //必不可少的部分
- SUM = ?SUM@@YAXXZ //自己定义的内容
2.创建文件后在项目-UseDLL属性-配置属性-链接器-输入-模块定义文件项中编辑添加SUMDLL.def文件并确定。
3.将SUMDLL.h头文件中的#define SUMDLL_API __declspec(dllexport)修改为#define SUMDLL_API
- 修改后我们再次启动编译,得到以下结果,即成功调用DLL文件