Windows黑客编程技术详解 --2.1 运行单一实例

2019-05-05 14:58:18 浏览数 (1)

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

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

第二章:基础技术

本章内容是在病毒木马中最为常用、最为基础的技术,技术变化不大,所以不对每个技术单独归类,而是统一划分到本章。作为本书病毒木马技术详解的开篇,本章的目的是引领读者由浅入深、循序渐进地了解病毒木马的各类实现技术。

大多数的病毒木马在成功植入用户计算机之后,在执行核心恶意代码之前,会先进行初始化操作。这些操作对应本章的3个基础技术点:运行单一实例、DLL延迟加载以及资源释放。

2.1 运行单一实例

在使用各种手段将病毒木马植入到用户计算机后,它也会使用浑身解数来使用户激活它。但是,如果病毒木马被多次重复运行,系统中会存在多份病毒木马的进程,那么,这就有可能增加暴露的风险。所以,要想解决上述问题,就要确保系统上只运行一个病毒木马的进程实例。

确保运行一个进程实例的实现方法有很多,它可以通过扫描进程列表来实现,可以通过枚举程序窗口的方式来实现,也可以通过共享全局变量来实现。下面介绍一种使用广泛而且简单的方法,即通过创建系统命名互斥对象的方式来实现。

2.1.1 函数介绍

CreateMutex函数

创建或打开一个已命名或未命名的互斥对象。

函数声明

代码语言:javascript复制
HANDLE WINAPI CreateMutex(

    _In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes,

    _In_     BOOL                  bInitialOwner,

    _In_opt_LPCTSTR               lpName)

参数

lpMutexAttributes [in, optional]

指向SECURITY_ATTRIBUTES结构的指针。如果此参数为NULL,则该句柄不能由子进程继承。

bInitialOwner [in]

如果此值为TRUE并且调用者创建了互斥锁,则调用线程将获得互斥锁对象的初始所有权。否则,调用线程不会获得互斥锁的所有权。

lpName [in, optional]

互斥对象的名称。该名称仅限于MAX_PATH字符,名称区分大小写。如果lpName为NULL,则会创建不带名称的互斥对象。

如果lpName与现有事件、信号量、等待定时器、作业或文件映射对象的名称匹配,且这些对象共享相同的名称空间,则该函数将失败,并且GetLastError函数返回ERROR_INVALID_ HANDLE。

返回值

如果函数成功,则返回值是新创建的互斥对象的句柄。

如果函数失败,则返回值为NULL。要获得扩展的错误信息,请调用GetLastError。

如果互斥锁是一个已命名的互斥锁,并且该对象在此函数调用之前就存在,则返回值是现有对象的句柄,GetLastError返回ERROR_ALREADY_EXISTS。

2.1.2 实现原理

通常情况下,系统中的进程是相互独立的,每个进程都拥有自己的独立资源和地址空间,进程间互不影响。所以,同一个程序可以重复运行,但系统上的进程互不影响。但是,在一些特殊情况下,程序在系统上需要只保存一份进程实例,这就引出了进程互斥的问题。

微软提供了CreateMutex函数来创建或者打开一个已命名或未命名的互斥对象,程序在每次运行的时候,通过判断系统中是否存在相同命名的互斥对象来确定程序是否重复运行。

CreateMutex函数一共有3个参数,第一个参数表示互斥对象的安全设置,是一个指向SECURITY_ATTRIBUTES结构的指针,在该程序中直接设置为NULL即可。第二个参数表示线程是否获得互斥锁对象的初始所有权,在该程序中,无论该参数为TRUE还是FALSE,均不影响程序的正常运行。第三个参数表示互斥对象的名称,对于通过互斥对象来判断进程实例是否重复运行的程序来说,该参数一定要设置,而且要保证设置名称的唯一性。

程序的判断原理是通过CreateMutex函数创建一个命名的互斥对象,如果对象创建成功,而且通过调用GetLastError函数获取的返回码为ERROR_ALREADY_EXISTS,则表示该命名互斥对象存在,即程序重复运行。否则,认为程序是首次运行。

2.1.3 编码实现

代码语言:javascript复制
// 判断是否重复运行

BOOL IsAlreadyRun()

{

    HANDLE hMutex = NULL;

    hMutex = ::CreateMutex(NULL, FALSE, "TEST");

    if (hMutex)

    {

        if (ERROR_ALREADY_EXISTS == ::GetLastError())

        {

            return TRUE;

        }

    }

    return FALSE;

}

2.1.4 测试

直接运行上面的程序。第一次运行的时候,程序提示“NOT Already Run!”,如图2-1所示,意思是系统中没有运行该实例。继续双击执行程序,这次程序提示“Already Run!!!!”,如图2-2所示,意思是系统上已经存在该实例且正在运行。所以,程序成功地判断出程序是否重复运行。

2.1.5 小结

这个程序实现起来并不难,关键是熟悉CreateMutex函数的调用。在调用CreateMutex函数来创建命名的互斥对象时,注意互斥对象的名称不要与现有事件、信号量或者文件映射对象等名称相同,否则创建互斥对象会失败。

在实现过程中,特别要注意,程序一定不要调用CloseHandle函数来关闭由CreateMutex函数创建出来的互斥对象的句柄,否则会导致互斥对象判断失败。因为CloseHandle函数会关闭互斥对象的句柄,释放资源。这样,系统上便不会存在对应的命名互斥对象了,通过CreateMutex创建的命名互斥对象都是不会重复的。

安全小贴士

使用CreateMutex函数创建的互斥对象,可以通过调用CloseHandle函数来关闭互斥对象的句柄,从属于它的所有句柄都关闭后,就会删除该对象。

在线程同步操作中, ReleaseMutex函数可以释放线程对互斥对象的控制权。

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

0 人点赞