专栏首页玄魂工作室Windows黑客编程技术详解 --2.3 病毒木马资源释放技术(内含赠书福利)

Windows黑客编程技术详解 --2.3 病毒木马资源释放技术(内含赠书福利)

本文经原作者授权,节选自《Windows黑客编程技术详解》一书。文末有福利哦!!

-----------------------------------------------------------------

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

2.3.1 资源插入的步骤

在介绍资源释放技术之前,先介绍如何向程序中插入资源。资源插入不需要编码操作,只需手动设置VS开发环境即可完成。

本节以“520”这个没有文件类型的文件作为演示实例,向大家介绍文件作为资源插入到程序中的步骤,其他类型的插入也是类似的。其中,“520”的文件内容如图2-5所示。

打开项目工程之后,在解决方案中,选择“添加”,选中“资源”。本节演示的是插入自定义资源,所以单击“自定义(C)...”按钮。资源添加对话框,如图2-6所示。

然后,在“新建自定义资源”对话框中,输入“资源类型”,如“MYRES”,然后单击“确定”。新建自定义资源对话框,如图2-7所示。

在设置好自定义资源的类型之后,接着回到“添加资源”对话框。选中刚新建的“MYRES”资源类型,然后单击右侧的“导入(M)...”按钮来选择导入文件。

经过上述步骤后便完成了插入资源的操作。

2.3.2 函数介绍

1.FindResource函数

确定模块中指定类型和名称的资源所在位置。

函数声明

HRSRC FindResource(

HMODULE hModule,

LPCWSTR lpName,

LPCWSTR lpType)

参数

hModule[in]

处理包含资源的可执行文件模块。若hModule为NULL,则系统从当前进程的模块中装载资源。

lpName[in]

指定资源名称。

lpType[in]

指定资源类型。

返回值

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

2.SizeofResource函数

获取指定资源的字节数。

函数声明

DWORD SizeofResource(

HMODULE hModule,

HRSRC hResInfo)

参数

hModule[in]

包含资源的可执行文件模块的句柄。若hModule为NULL,则系统从当前进程的模块中装载资源。

hResInfo[in]

资源句柄。此句柄必须由函数FindResource或FindResourceEx来创建。

返回值

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

3.LoadResource函数

装载指定资源到全局存储器。

函数声明

HGLOBAL LoadResource(

HMODULE hModule,

HRSRC hResInfo)

参数

hModule[in]

处理资源可执行文件的模块句柄。若hModule为NULL,则系统从当前进程的模块中装载资源。

hResInfo[in]

资源句柄。此句柄必须由函数FindResource或FindResourceEx来创建。

返回值

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

4.LockResource函数

锁定资源并得到资源在内存中第一个字节的指针。

函数声明

LPVOID LockResource(

HGLOBAL hResData)

参数

hResData[in]

装载资源的句柄。函数LoadResource可以返回这个句柄。

返回值

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

2.3.3 实现原理

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

首先,通过FindResource定位程序里的资源,主要是根据“资源类型”和“资源名称”进行定位,从而获取资源信息块的句柄。

其次,根据上面获取的资源信息块的句柄,利用SizeofResource获取资源的大小之后,再通过LoadResource把资源加载到程序内存中。

接着,通过LockResource锁定加载到内存中的资源,防止程序中的其他操作影响这块内存。其中,返回值就是资源在进程内存中的起始地址。

最后,根据资源大小以及进程内存的起始地址,可将资源数据读取出来并保存为本地文件。

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

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

2.3.4 编程实现

BOOL FreeMyResource(UINT uiResouceName, char *lpszResourceType, char *lpszSaveFileName)

{

// 获取指定模块里的资源

HRSRC hRsrc = ::FindResource(NULL, MAKEINTRESOURCE(uiResouceName), lpszResourceType);

if (NULL == hRsrc)

{

ShowError("FindResource");

return FALSE;

}

// 获取资源的大小

DWORD dwSize = ::SizeofResource(NULL, hRsrc);

if (0 >= dwSize)

{

ShowError("SizeofResource");

return FALSE;

}

// 将资源加载到内存里

HGLOBAL hGlobal = ::LoadResource(NULL, hRsrc);

if (NULL == hGlobal)

{

ShowError("LoadResource");

return FALSE;

}

// 锁定资源

LPVOID lpVoid = ::LockResource(hGlobal);

if (NULL == lpVoid)

{

ShowError("LockResource");

return FALSE;

}

// 保存资源为文件

FILE *fp = NULL;

fopen_s(&fp, lpszSaveFileName, "wb+");

if (NULL == fp)

{

ShowError("LockResource");

return FALSE;

}

fwrite(lpVoid, sizeof(char), dwSize, fp);

fclose(fp);

return TRUE;

}

2.3.5 测试

本节创建一个MFC工程项目,按照上述步骤插入资源,并按照上述的实现原理来编码实现,调用封装好的资源释放函数进行资源释放的测试。资源释放的时候,将其保存为txt格式文件。

单击对话框中“释放”按钮后,提示资源释放成功,如图2-8所示。然后查看目录,本地成功地生成“520.txt”文件,打开文件查看内容,它与之前插入的“520”文件中的内容相同,如图2-9所示。资源释放成功。

2.3.6 小结

资源释放技术的实现原理并不是很复杂,只需理清WIN32 API函数的调用关系以及函数作用即可。要特别注意一点,明确资源所在的模块,如果资源包含在DLL文件中,则可以在DllMain中或是通过GetModuleHandle函数获取DLL模块的句柄。

安全小贴士

可以根据PE结构中的资源表IMAGE_RESOURCE_DIRECTORY来解析PE文件中包含的所有资源,并且获取资源的偏移地址及数据大小。例如,常用的资源编辑工具eXeScope就是根据资源表来枚举PE文件中的资源的。

本文分享自微信公众号 - 玄魂工作室(xuanhun521),作者:甘迪文

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-04-20

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 渗透测试入门指南与路线规划(全文版)

    我本非安全大牛,水平有限,所以自然亲民,和许多渗透测试的初学者打得火热。这其中大部分是大学生,还有工作多年,但一直对网络安全热情不减的热血之人。许多同学一直在努...

    用户1631416
  • 如何学python 第十一课 元组与字典

    第十一课 元组与字典 欢迎回来。上一期的如何学python里,我们讨论了函数。我们今天将要学习的是两种类似于列表(list)类型的数据类型。我们先介绍’元组’...

    用户1631416
  • Linux版awvs破解详细步骤

    环境:ubuntu16.04lts 镜像下载链接:https://pan.baidu.com/s/15ZxSxkfaSIdMzdnDjlOTQg

    用户1631416
  • 2-1.死锁-经典同步问题

    Need[i, j]=Max[i, j]-Allocation[i, j] #尚需要的资源量=最大资源需求量-已分配资源量

    见贤思齊
  • Flume入门 | 基本概念及架构说明

    今天,给大家分享一下Flume的基础知识。本篇文章主要是对Flume的基本概念及架构进行一些说明。

    create17
  • Android插件化技术之旅 1 开篇 - 实现启动插件与调用插件中的Activity和Service

    Android技术如今已很成熟了,组件化、插件化、热修复等等框架层出不穷,如果只停留在单纯的会用框架上,技术永远得不到成长,只有懂得其原理,能够婉婉道来,能够自...

    用户3045442
  • Python-入门-05-元组

    zishendianxia
  • [Spring] Spring 容器事件

    顾名思义:事件源即被传播的消息体,事件监听者都需要在事件监听注册表中登记。这样,在事件到来时,事件广播器负责将事件源信息根据监听表中登记的信息,进行分发。

    架构探险之道
  • SpringBoot2.0之CORS跨域配置并保持登录

    在前后分离的项目中,前端项目往往和后端项目是分开开发。前端有自己的服务器来访问页面比如http://127.0.0.1:8080,然后通过网络库(Axios)来...

    用户6182664
  • 8种网站防盗链秘籍

    作为普通的网民来说,一般不需要知道也不用关心什么是盗链,不过如果你是网站的开发者或维护者,就不得不重视盗链的问题了。如果你刚刚开发完一个没有防盗...

    php007

扫码关注云+社区

领取腾讯云代金券