作者:single | 来源:互联网 | 2024-10-20 11:28
一、运行单一实例通过创建系统命名互斥对象的方式来实现1、实现原理通过CreateMutex函数创建一个命名的互斥对象,如果对象创建成功,而且通过调用GetLastError函数获取
一、运行单一实例
通过创建系统命名互斥对象的方式来实现
1、实现原理
通过CreateMutex函数创建一个命名的互斥对象,如果对象创建成功,而且通过调用GetLastError函数获取的返回码为ERROR_ALREADY_EXISTS,则表示该命名互斥对象存在,即程序重复运行。否则,认为程序首次运行。
2、API
CreateMutex
https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-createmutexa
3、实现代码如下
#include
#include
#include
BOOL IsAlreadyRun()
{
HANDLE hMutex = NULL;
hMutex = ::CreateMutex(NULL, FALSE, _T("TEST"));
if (hMutex)
{
if (ERROR_ALREADY_EXISTS == ::GetLastError())
{
return true;
}
}
return false;
}
int main()
{
if (IsAlreadyRun())
{
printf("Already RUN");
system("pause");
}
else
{
printf("NOT Already Run");
system("pause");
}
}
4、小结
这个程序实现起来并不难,关键是熟悉CreateMutex函数的调用。在调用CreateMutex函数来创建命名的互斥对象时,注意互斥对象的名称不要与现有事件、信号量或者文件映射对象等名称相同,否则创建互斥对象会失败。
在实现过程中,特别要注意,程序一定不要调用CloseHandle函数来关闭由CreateMutex函数创建出来的互斥对象的句柄,否则会导致互斥对象判断失败。因为CloseHandle函数会关闭互斥对象的句柄,释放资源。这样,系统上便不会存在对应的命名互斥对象了,通过CreateMutex创建的命名互斥对象都是不会重复的。
5、安全小贴士
使用CreateMutex函数创建的互斥对象,可以通过调用CloseHandle函数来关闭互斥对象的句柄,从属于它的所有句柄都关闭后,就会删除该对象。
在线程同步操作中, ReleaseMutex函数可以释放线程对互斥对象的控制权。
二、DLL延迟加载
使用延迟加载方式编译链接可执行文件
1、实现原理
本程序以加载第三方库——skin++库为例进行讲解演示。首先导入skin++库文件,然后编码,最后对程序编译链接生成exe可执行文件。使用PE查看器PEview.exe查看可执行文件的导入表,便可知道可执行文件必需的DLL文件了。
这样做的好处是可以把必需的DLL文件以资源形式插入到程序中,并使用DLL延迟加载技术延迟加载。在正式调用必需的DLL之前,程序都是可以正常执行的。程序可以在这段时间内,把资源中的DLL释放到本地,等到正式调用DLL的时候释放的文件就会正确地加载执行。这样当使用程序的时候,只需把exe文件发送给用户,而不需要附加DLL文件了,也不需要担心程序会丢失DLL文件。
DLL延迟加载的具体设置步骤为:
属性-->链接器-->输入-->延迟加载的DLL-->输入:SkinPPWTL.dll
2、小结
DLL延迟加载技术不需要编码来实现,只需对VS开发环境设置链接器即可完成。DLL延迟加载技术,配合资源释放技术,可以使程序变得更加方便易用。
3、安全小贴士
在PE结构中, DLL延迟加载的信息存储在ImgDelayDescr延迟导入表中,可以通过数据目录DataDirectory中的IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT项获取延迟导入表RVA相对的偏移地址和数据大小。
三、资源释放
病毒木马之所以会广泛使用资源释放技术,是因为它可以使程序变得更简洁。如果程序额外需要加载一些DLL文件、文本文件、图片文件,或者其他的音/视频文件等,则可以把它们作为资源插入到程序里,等到程序运行后,再把它们释放到本地上。这样做的好处是编译出来的程序只有一个exe文件,而不需要附带其他文件,因而程序变得很简洁。只需把exe植入到用户计算机上,而不需要连同其他文件一起植入,这降低了被发现的风险。
1、资源插入步骤
首先新建一个资源520.txt
再自定义添加对话框
最后,导入该对话框
2、API
FindResource 确定模块中指定类型和名称的资源所在位置
https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-findresourcea
sizeofResource 获取指定资源的字节数
https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-sizeofresource
LoadResource 装载指定资源到全局存储器
https://docs.microsoft.com/en-us/previous-versions/ms915421(v=msdn.10)
LockResource 锁定资源并得到资源在内存中第一个字节的指针
https://docs.microsoft.com/en-us/previous-versions/aa932898(v=msdn.10)
3、实现原理
首先,通过FindResource定位程序里的资源,主要是根据"资源类型"和"资源名称"进行定位,从而获取资源信息块的句柄.
其次,根据上面获取的资源信息块的句柄,利用sizeofResource获取资源的大小之后,再通过LoadResource把资源加载程序内存中.
接着,通过LockResource锁定加载到内存中的资源,防止程序中的其他操作影响这块内存。其中,返回值就是资源在进程内存中的起始地址。
最后,根据资源大小以及进程内存的起始地址,可将资源数据读取出来并保存为本地文件。
注意:要必须明确资源所在的模块,要指明所在模块句柄并且统一。
4、实现代码如下
#include
#include
#include "resource.h"
void FreeRes_ShowError(char* pszText)
{
char szErr[MAX_PATH] = { 0 };
wsprintf(szErr, "%s Error[%d]\n", pszText, ::GetLastError());
}
BOOL FreeMyResource(UINT uiResourceName, char* lpszResourceType, char *lpszSaveFileName)
{
//获取指定模块里的资源
HRSRC hRsrc = ::FindResource(NULL, MAKEINTRESOURCE(uiResourceName), lpszResourceType);
if (NULL == hRsrc)
{
FreeRes_ShowError("FindResource");
return FALSE;
}
// 获取资源的大小
DWORD dwSize = ::SizeofResource(NULL, hRsrc);
if (0 >= dwSize)
{
FreeRes_ShowError("SizeofResource");
return FALSE;
}
// 将资源加载到内存里
HGLOBAL hGlobal = ::LoadResource(NULL, hRsrc);
if (NULL == hGlobal)
{
FreeRes_ShowError("LoadResource");
return FALSE;
}
// 锁定资源
LPVOID lpVoid = ::LockResource(hGlobal);
if (NULL == lpVoid)
{
FreeRes_ShowError("LockResource");
return FALSE;
}
// 保存资源为文件
FILE* fp = NULL;
fopen_s(&fp, lpszSaveFileName, "wb+");
if (NULL == fp)
{
FreeRes_ShowError("LockResource");
return FALSE;
}
fwrite(lpVoid, sizeof(char), dwSize, fp);
fclose(fp);
return TRUE;
}
int main(){
char szSaveName[MAX_PATH] = "520.txt";
// 释放资源
BOOL bRet = FreeMyResource(IDR_MYRES2, "MYRES", szSaveName);
if (FALSE == bRet)
{
MessageBox(NULL, "Free Resource Error!", "ERROR", MB_OK);
}
else
{
MessageBox(NULL, "Free Resource OK!", "OK", MB_OK);
}
return 0;
}