在下载应用程序时,我们会发现一些特殊的EXE应用程序。当我们运行EXE程序时会同时下载或生成若干个其他应用程序,并自动运行。这个过程通常会以一种静默的方式悄悄地进行。我们将这一技术称之为EXE捆绑。之所以这样做,好的方面是简化程序下载安装的过程。坏的方面是一些流氓软件可以借此牟利,侵犯用户的选择权。本章介绍两种常用的EXE捆绑的实现方法。
本章学习知识概要:
资源捆绑
补丁捆绑
15.1 资源捆绑
是否还记得第七章资源表的内容?我们可以将其他文件以自定义资源的形式添加到EXE文件的.rsrc节区中。当然我们也可以将EXE文件中的资源文件释放到本地磁盘。如果释放的资源文件是一个EXE可执行文件,我们还可以自动运行这个EXE文件。本节我们将介绍EXE资源捆绑的方法。
本节必须掌握的知识点:
资源捆绑实现思路
补丁捆绑示例
15.1.1 资源捆绑实现思路
为了将多个文件以资源的形式添加到一个EXE文件中,我们需要编译一个EXE程序。编译时,以自定义资源的方式将要捆绑的文件添加到EXE的.rsrc资源节区。EXE程序的功能代码为:找到并释放资源节区指定的资源文件到磁盘指定目录,并自动运行该目录中的EXE可执行文件。
■实现EXE资源捆绑的步骤:
●编写EXE程序。
●添加资源文件。
●运行EXE程序,并释放资源文件。
●自动运行释放的可执行文件。
接下来我们将分步骤测试一些基本的功能模块。
■测试一
实验一百零三:测试执行多个进程的文件
示例程序设置了一个文件列表结构数组,并添加了3个文件,其中包含"notepad.exe"和"mspaint.exe"两个EXE文件,和一个配置文件"config.ini"。然后创建一个子线程执行两个EXE程序。
/*------------------------------------------------------------------------
FileName:checkRun.c
实验103:试执行多个进程的文件
(c) bcdaren, 2024
-----------------------------------------------------------------------*/
#include <windows.h>
#define TOTAL_FILE_COUNT 100 //本程序所绑定文件的最大数
struct BinderFileStruct
{
byte inExeSequence; //为0表示非执行文件,为1表示加入执行序列
DWORD dwFileOff; //在宿主中的起始偏移
DWORD dwFileSize; //文件大小
TCHAR name1[256]; //文件名,含子目录
};
//以下为捆绑列表数据结构,一个文件总数的双字和多个BinderFileStruct结构
int dwTotalFile = TOTAL_FILE_COUNT;
struct BinderFileStruct lpFileList[TOTAL_FILE_COUNT];
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
STARTUPINFO stStartUp = { sizeof(stStartUp) };
stStartUp.dwFlags = STARTF_USESHOWWINDOW;//指定wShowWindow成员有效
stStartUp.wShowWindow = TRUE;//此成员设为TRUE的话则显示新建进程的主窗口
PROCESS_INFORMATION stProcInfo;
for (int i = 0;i < dwTotalFile;i++)
{
if (lpFileList[i].inExeSequence == 1)
{
GetStartupInfo(&stStartUp);
BOOL bRet = CreateProcess(NULL, lpFileList[i].name1,NULL,NULL,
FALSE,NORMAL_PRIORITY_CLASS,NULL,NULL,&stStartUp,&stProcInfo);
if (bRet)
{
WaitForSingleObject(stProcInfo.hProcess, INFINITE);
CloseHandle(stProcInfo.hProcess);
CloseHandle(stProcInfo.hThread);
}
}
}
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int nCmdShow)
{
const TCHAR szExeFile[] = TEXT("notepad.exe");
const TCHAR szExeFile1[] = TEXT("mspaint.exe");
const TCHAR szExeFile2[] = TEXT("config.ini");
//初始化捆绑列表,模拟捆绑行为,为捆绑列表赋值
dwTotalFile = 3;
lpFileList[0].inExeSequence = 1;
RtlCopyMemory(lpFileList[0].name1,szExeFile,lstrlen(szExeFile)*2);
lpFileList[1].inExeSequence = 1;
RtlCopyMemory(lpFileList[1].name1, szExeFile1, lstrlen(szExeFile1)*2);
lpFileList[2].inExeSequence = 1;
RtlCopyMemory(lpFileList[2].name1, szExeFile2, lstrlen(szExeFile2)*2);
HANDLE hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
Sleep(5000);
CloseHandle(hThread);
return 0;
}
■测试二
实验一百零四:遍历指定目录文件并执行其中的EXE文件
示例程序遍历指定目录文件,并执行其中的EXE文件。
/*------------------------------------------------------------------------
FileName:searchFIile.c
实验104:遍历指定目录文件并执行其中的EXE文件
(c) bcdaren, 2024
---------------------------------------------------------