Windows黑客编程之释放资源

描述

  • 将dll作为资源插入到程序中,程序运行过程中将资源加载到内存,作为dll释放,这种方式配合延迟加载dll,可以降低被发现的风险
  • 原书里的程序用mfc写了个界面,我替换成了qt的版本,但是qt打包出来后程序过大,所以又用vs写了个不带界面版本的

win32 api原生版本

工具链

  • 使用vs工具库编写,vc++的msvc编译器,调用win32原生api
  • 去掉mfc界面部分的代码,去掉其预编译头文件stdafx.h

资源插入

  • 折腾了好久才搞清楚,第一次点击添加资源时会报错
  • 不用管,再次点击添加资源,此时成功进入添加面板,选择自定义类型,输入类型名
  • 输入类型名确定后窗口会关闭,此时再次点击添加资源,点击导入,选择资源文件和刚才的类型名
  • 成功导入文件后,点击resourse.h文件,查看插入资源文件的编号,下图中第二个编号即IDR_MYAPP2,就可以用来定位到插入的文件

代码

#include "ResourceFree.h"

void ShowError(const char* pszText)
{
	char szErr[200] = { 0 };
	::wsprintf(szErr, "%s Error [%d]\n", pszText, ::GetLastError());
	::MessageBox(NULL, szErr, "ERROR", MB_OK | MB_ICONERROR);
}

BOOL FreeResource(UINT ResourceName, const char* ResourceType, const char* FileName)
{
	HRSRC hRsrc = ::FindResource(NULL, MAKEINTRESOURCE(ResourceName), ResourceType);
	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, FileName, "wb+");
	if (NULL == fp)
	{
		ShowError("WriteResource");
		return FALSE;
	}
	fwrite(lpVoid, sizeof(char), dwSize, fp);
	fclose(fp);
	return TRUE;
}

int main(int argc, char* argv[])
{
	char fileName[200] = "520.txt";
	BOOL bRet = FreeResource(IDR_MYRES2, "MYRES", fileName);
	if (bRet == FALSE)
	{
		::MessageBox(NULL, "Free Resource Error!", "ERROR", MB_OK);
	}
	else
	{
		::MessageBox(NULL, "Free Resource OK!", "OK", MB_OK);
	}
}

运行结果

  • 可以看到exe只有12.5KB,双击运行exe后,成功在当前目录释放资源文件520.txt

qt界面版

工具链

  • 使用qt库来编写界面程序,qt库是对win32 api的上层封装,由于qt库不是系统自带的,打包后需要将整个程序连带库文件放置到目标机器,占据磁盘空间较大
  • IDE使用Qt Creator,编译器使用mingW
  • 代码中字符串转换报错的话,需要在pro文件中添加下面这行代码:
    DEFINES += QT_DEPRECATED_WARNINGS
  • 如果要使用原生win32 api,需要在pro文件中添加库支持
    LIBS += "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0\um\x64\User32.Lib"

资源插入

  • 新建Resources文件夹,右键点击添加资源文件
  • 为资源文件添加前缀
  • 右键资源文件,选择导入现有文件520
  • 成功插入资源后的界面,之后在代码中就可以用:/res/520来访问该资源文件了

代码

  • 界面用Qt Designer设计,拖拽一个按钮控件,绑定释放资源的槽函数,槽函数中,用qt库中的file.copy函数,可将资源文件释放到本地
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::OnButtonClicked);
}

void MainWindow::OnButtonClicked()
{
    QString resProfix = "res";
    QString resFileNmae = "520";
    QString destFile = "./520.txt";
    ReleaseSource(resProfix, resFileNmae, destFile);
}

void MainWindow::ReleaseSource(QString resProfix, QString resFileName, QString destFullPathFileName)
{
    QString resFile;
    resFile = ":"+resProfix+"/"+resFileName;
    QFile file;
    file.copy(resFile, destFullPathFileName);
}

MainWindow::~MainWindow()
{
    delete ui;
}

结果

  • 构建程序后,把生成的exe放到一个新文件夹,运行qt desktop命令行工具,进入新目录下,运行windeployqt ResourceFree.exe,即可完成程序打包
  • 程序打包后的文件夹有47M,其中包含了QtCore等核心库文件,要移植到目标机器使用需要将整个文件夹都复制过去
  • 运行程序,点击释放资源按钮,在本目录下释放出520.txt文件

总结

  • Qt:写界面很方便,上层的API用起来更简单舒适,但是打包后的程序很大,适合写通信程序的本地服务端
  • win32 api: 使用系统自带的dll,打包后的程序很小,可以使用强大的vs来编写,且底层api能实现更细腻的功能,适用于编写在目标机器上运行的控制台程序
posted @ 2023-02-18 16:53  z5onk0  阅读(54)  评论(0编辑  收藏  举报