windows黑客编程系列(一):运行单一实例

windows黑客编程系列(一)

由于课题需要,不得不转行windows PE文件的研究,需要接触windows黑客编程

本文为《windows黑客编程技术详解》读书笔记。

新建windows编程系列笔记,待课题结束,回归ELF。

使用codeblocks新建一个win32 GUI程序

打开codeblocks -> create a new project -> 选择win32 GUI project -> Go -> 选择frame based -> 输入工程名字即可

windows黑客编程系列(一):运行单一实例_第1张图片

新建win32 GUI工程的主程序

windows黑客编程系列(一):运行单一实例_第2张图片

  • 红框圈出部分为该程序的入口函数

运行单一实例

大多数的病毒木马在成功植入用户计算机之后,在执行核心恶意代码之前,都会先进行初始化操作。在初始化操作中有一个很重要的点,运行单一实例

如果病毒木马被多次运行,系统中会存在多份病毒木马的进程,那么,这就有可能增加暴露的风险。所以要想解决上述问题,就要确保系统中只运行一个病毒木马的进程。

要确保只运行一个进程实例的实现方法有很多,它可以通过扫描进程列表来实现,可以通过枚举程序窗口来实现,也可以通过共享全局变量来实现。

下面介绍一种使用广泛且应用简单的方法,即通过创建系统命名互斥对象的方式来实现。

函数介绍

CreateMutex函数

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

HANDLE WINAPI CreateMutex
(
    LPSECURITY_ATTRIBUTES ipMutexAttributes, 
    BOOL bInitialOwner, 
    LPCTSTR lpName
)
  • 第一个参数:指向SECURITY_ATTRIBUTES结构的指针,如果此参数为NULL,则该举兵不能由子进程继承
  • 第二个参数:如果此值为TRUE并且调用者创建了互斥锁,否则线程不会获得互斥锁的所有权
  • 第三个参数:互斥对象的名称,该名称仅限于MAX_PATH字符,名称区分大小写。如果为NULL,则会创建不带名称的互斥对象
返回值
  • 如果函数成功,则返回值为新创建的互斥对象的句柄
  • 如果函数失败,则返回值为NULL。要获得扩展的错误信息,需要调用GetLastError函数
  • 如果互斥锁是一个已命名的互斥锁,并且该对象在此函数调用之前就存在,则返回值是现有对象的句柄,GetLastError哈桑农户返回ERROE_ALREADY_EISTS。

实现原理

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

CreateMutex函数一共三个参数:

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

如何判断是否重复运行

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

函数实现

BOOL IsAlreadyRun()
{
    HANDLE hmutex = NULL;
    hmutex = ::CreateMutex(NULL, FALSE, "TEST");
    if (hmutex)
    {
        if (ERROR_ALREADY_EXISTS == ::GetLastError())
            return TRUE;
    }
    return FALSE;
}

函数效果

  • 转到存放源程序的目录
  • 在该目录下的bin\Debug目录下
  • 双击运行编译生成的exe文件

第一次运行效果图:
windows黑客编程系列(一):运行单一实例_第3张图片

第一次运行的窗口不关闭,进行第二次运行

windows黑客编程系列(一):运行单一实例_第4张图片

可以发现程序按照我们想要的逻辑往下走,给出了已经重复运行的提示

完整源代码

#if defined(UNICODE) && !defined(_UNICODE)
    #define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
    #define UNICODE
#endif

#include 
#include 
#include 

BOOL IsAlreadyRun()
{
    HANDLE hmutex = NULL;
    hmutex = ::CreateMutex(NULL, FALSE, "TEST");
    if (hmutex)
    {
        if (ERROR_ALREADY_EXISTS == ::GetLastError())
            return TRUE;
    }
    return FALSE;
}


int WINAPI WinMain (HINSTANCE hThisInstance,HINSTANCE hPrevInstance,LPSTR lpszArgument,int nCmdShow)
{
    BOOL flag = IsAlreadyRun();
    if (flag == TRUE)
        printf("Already Run\n");
    else
        printf("Not Already Run\n");
    system("pause");

    return 0;
}

安全提示

  • 使用该函数进行创建的互斥对象,可以通过调用CloseHandle函数来关闭互斥对象的句柄,从属于他的所有句柄都关闭后,就会删除该对象。
  • 在本程序中不要使用CloseHandle函数来关闭CreateMutex函数创建的互斥对象的句柄,关闭句柄的同时会释放资源,系统上也就不会存在对应的命名互斥对象了,我们的程序逻辑也会出现问题,因为已经没办法判断了该互斥对象是否在内存中运行了。
  • 在线程同步操作中,ReleaseMutex函数可以释放线程对互斥对象的控制权。

你可能感兴趣的:(windows编程)