ps 以下代码均在win10 X64下实现,其他系统不兼容
反调试

#include <windows.h>
# include<stdio.h>
int main(int argc, char* argv[])
{//初始化临界区全局原子变量HANDLE MutexHandle = CreateMutex(NULL, FALSE, TEXT("AAA"));  //创建互斥体. 信号量为0. 有信号的状态.wait可以等待DWORD ErrorCode = 0;ErrorCode = GetLastError();if (ERROR_ALREADY_EXISTS == ErrorCode){printf("禁止多开\r\n");CloseHandle(MutexHandle);system("pause");}if (NULL == MutexHandle){return 0; //表示句柄获取失败}static int i = 0;while(1){Sleep(1000);printf("当前程序运行中. EIP 位置 等于 %d \r\n", i++);}system("pause");return 0;
}

反反调试
HandleCount清0
PointCount清0
Name替换
HandleTableEntry清0

用到的相关结构体

_HEADER_NAME_INFO
_EXHANDLE
_HANDLE_TABLE_ENTRY
_HANDLE_TABLE_FREE_LIST
_HANDLE_TABLE
_SYSTEM_INFORMATION_CLASS
_SYSTEM_THREADS
_SYSTEM_PROCESSES

详情

/// <summary>
/// 内核对象可变对象头之一,描述了一个内核对象的名称信息
/// </summary>
typedef struct _HEADER_NAME_INFO
{PVOID Directory;UNICODE_STRING Name;INT32 ReferenceCount;UINT32 Reserved;
} HEADER_NAME_INFO,* PHEADER_NAME_INFO;
/// <summary>
/// 句柄
/// </summary>
typedef struct _EXHANDLE
{//32位union{struct{ULONG TagBits : 2;ULONG Index : 30;};HANDLE GenericHandleOverlay;ULONG_PTR Value;};
} EXHANDLE, * PEXHANDLE;
/// <summary>
/// 句柄表项
/// </summary>
typedef struct _HANDLE_TABLE_ENTRY
{union{LONG_PTR VolatileLowValue;LONG_PTR LowValue;PVOID InfoTable;LONG_PTR RefCountField;struct{ULONG_PTR Unlocked : 1;ULONG_PTR RefCnt : 16;ULONG_PTR Attributes : 3;ULONG_PTR ObjectPointerBits : 44;//长度为 44 位的数据,指向一个内核对象};};union{LONG_PTR HighValue;struct _HANDLE_TABLE_ENTRY* NextFreeHandleEntry;EXHANDLE LeafHandleValue;struct{ULONG32 GrantedAccessBits : 25;//长度为 25 位的数据,表示对象权限ULONG32 NoRightsUpgrade : 1;ULONG32 Spare1 : 6;};ULONG32 Spare2;};
} HANDLE_TABLE_ENTRY, * PHANDLE_TABLE_ENTRY;
/// <summary>
/// _HANDLE_TABLE的成员之一
/// </summary>
typedef struct _HANDLE_TABLE_FREE_LIST
{ULONG_PTR FreeListLock;PHANDLE_TABLE_ENTRY FirstFreeHandleEntry;PHANDLE_TABLE_ENTRY lastFreeHandleEntry;LONG32 HandleCount;ULONG32 HighWaterMark;ULONG32 Reserved[8];
} HANDLE_TABLE_FREE_LIST, * PHANDLE_TABLE_FREE_LIST;
/// <summary>
/// EPROCESS的成员之一,描述了指向局部句柄表的相关信息,其中的TableCode指向局部句柄表
/// </summary>
typedef struct _HANDLE_TABLE
{ULONG32 NextHandleNeedingPool;LONG32 ExtraInfoPages;ULONG_PTR TableCode;PEPROCESS QuotaProcess;LIST_ENTRY HandleTableList;ULONG32 UniqueProcessId;union{ULONG32 Flags;struct{BOOLEAN StrictFIFO : 1;BOOLEAN EnableHandleExceptions : 1;BOOLEAN Rundown : 1;BOOLEAN Duplicated : 1;BOOLEAN RaiseUMExceptionOnInvalidHandleClose : 1;};};ULONG_PTR HandleContentionEvent;ULONG_PTR HandleTableLock;union{HANDLE_TABLE_FREE_LIST FreeLists[1];BOOLEAN ActualEntry[32];};PVOID DebugInfo;
} HANDLE_TABLE, * PHANDLE_TABLE;
/*
* 下面是一个枚举结构,每一个枚举值对应一类系统信息,
* 比如 SystemPerformanceInformation 代表所有的进程信息。
*/
typedef enum _SYSTEM_INFORMATION_CLASS
{SystemBasicInformation,                    //  0 Y N   SystemProcessorInformation,             //  1 Y N   SystemPerformanceInformation,           //  2 Y N   SystemTimeOfDayInformation,             //  3 Y N   SystemNotImplemented1,                  //  4 Y N   SystemProcessesAndThreadsInformation,   //  5 Y N   SystemCallCounts,                       //  6 Y N   SystemConfigurationInformation,         //  7 Y N   SystemProcessorTimes,                   //  8 Y N   SystemGlobalFlag,                       //  9 Y Y   SystemNotImplemented2,                  // 10 Y N   SystemModuleInformation,                // 11 Y N   SystemLockInformation,                  // 12 Y N   SystemNotImplemented3,                  // 13 Y N   SystemNotImplemented4,                  // 14 Y N   SystemNotImplemented5,                  // 15 Y N   SystemHandleInformation,                // 16 Y N   SystemObjectInformation,                // 17 Y N   SystemPagefileInformation,              // 18 Y N   SystemInstructionEmulationCounts,       // 19 Y N   SystemInvalidInfoClass1,                // 20   SystemCacheInformation,                 // 21 Y Y   SystemPoolTagInformation,               // 22 Y N   SystemProcessorStatistics,              // 23 Y N   SystemDpcInformation,                   // 24 Y Y   SystemNotImplemented6,                  // 25 Y N   SystemLoadImage,                        // 26 N Y   SystemUnloadImage,                      // 27 N Y   SystemTimeAdjustment,                   // 28 Y Y   SystemNotImplemented7,                  // 29 Y N   SystemNotImplemented8,                  // 30 Y N   SystemNotImplemented9,                  // 31 Y N   SystemCrashDumpInformation,             // 32 Y N   SystemExceptionInformation,             // 33 Y N   SystemCrashDumpStateInformation,        // 34 Y Y/N   SystemKernelDebuggerInformation,        // 35 Y N   SystemContextSwitchInformation,         // 36 Y N   SystemRegistryQuotaInformation,         // 37 Y Y   SystemLoadAndCallImage,                 // 38 N Y   SystemPrioritySeparation,               // 39 N Y   SystemNotImplemented10,                 // 40 Y N   SystemNotImplemented11,                 // 41 Y N   SystemInvalidInfoClass2,                // 42   SystemInvalidInfoClass3,                // 43   SystemTimeZoneInformation,              // 44 Y N   SystemLookasideInformation,             // 45 Y N   SystemSetTimeSlipEvent,                 // 46 N Y   SystemCreateSession,                    // 47 N Y   SystemDeleteSession,                    // 48 N Y   SystemInvalidInfoClass4,                // 49   SystemRangeStartInformation,            // 50 Y N   SystemVerifierInformation,              // 51 Y Y   SystemAddVerifier,                      // 52 N Y   SystemSessionProcessesInformation       // 53 Y N   } SYSTEM_INFORMATION_CLASS;
/// <summary>
/// 线程信息结构体,进程信息结构体的成员之一
/// </summary>
typedef struct _SYSTEM_THREADS
{LARGE_INTEGER           KernelTime;LARGE_INTEGER           UserTime;LARGE_INTEGER           CreateTime;ULONG                   WaitTime;PVOID                   StartAddress;CLIENT_ID               ClientIs;KPRIORITY               Priority;KPRIORITY               BasePriority;ULONG                   ContextSwitchCount;ULONG                   ThreadState;KWAIT_REASON            WaitReason;
#ifdef _WIN64ULONG    Reserved; //Add
#endif
}SYSTEM_THREADS, * PSYSTEM_THREADS;
/// <summary>
/// //进程信息结构体
/// </summary>
typedef struct _SYSTEM_PROCESSES
{ULONG                NextEntryDelta;    //链表下一个结构和上一个结构的偏移ULONG                ThreadCount;       //线程数目;ULONG                Reserved[6];LARGE_INTEGER        CreateTime;LARGE_INTEGER        UserTime;          //用户模式(Ring 3)的CPU时间;LARGE_INTEGER        KernelTime;       //内核模式(Ring 0)的CPU时间;UNICODE_STRING       ProcessName;     //进程名字KPRIORITY            BasePriority;HANDLE               ProcessId;      //进程的pid号HANDLE               InheritedFromProcessId;    //父进程的标识符;ULONG                HandleCount;ULONG                SessionId;ULONG_PTR            PageDirectoryBase;VM_COUNTERS          VmCounters;
#ifdef _WIN64SIZE_T               PrivatePageCount;
#endifIO_COUNTERS          IoCounters; //windows 2000 only  SYSTEM_THREADS       Threads[1];
}SYSTEM_PROCESSES, * PSYSTEM_PROCESSES;

用到的相关函数

/*
* --------------------------------函数声明
*/
typedef BOOLEAN (*PHANDLE_TABLE_ENTRY_FUNC)(PHANDLE_TABLE_ENTRY pHandleTableEntry, PVOID pObject, POBJECT_TYPE pObjectType);
PHANDLE_TABLE_ENTRY SearchHandleTableEntry(PHANDLE_TABLE pObjectTable, EXHANDLE HandleIndex);
NTKERNELAPI PVOID NTAPI ObGetObjectType(IN PVOID pObject);
BOOLEAN KillMutex(PHANDLE_TABLE_ENTRY pHandleTableEntry, PVOID pMutex, POBJECT_TYPE pObjectType);
NTKERNELAPI PVOID ObQueryNameInfo(IN PVOID Object);
void PrintPrivateTable(PEPROCESS pEprocess, PHANDLE_TABLE_ENTRY_FUNC func);
NTSTATUS ZwQuerySystemInformation(IN ULONG SystemInformationClass,  //处理进程线程信息,只需要处理类别为5的即可OUT PVOID SystemInformation,IN ULONG SystemInformationLength,OUT PULONG ReturnLength
);
NTSTATUS PsLookupProcessByProcessId(HANDLE    ProcessId,PEPROCESS* Process
);
CHAR GetRandomNumber();
/*
* --------------------------------函数声明
*/

详情

#pragma warning(disable:4100)
#pragma warning(disable:4214)
#pragma warning(disable:4201)
#pragma warning(disable:4189)
# define HANDLE_VALUE_INC 4
# define HANDLE_TABLE_OFFSET 0x418
//==================================================================
//函数名:GetEprocessByExeName
//功能:根据进程的名字,例如L"xxx.exe",获取进程的EPROCESS数组(进程名相同的进程不唯一)
//输入参数1:ExeName,IN,进程的名字字符串
//输入参数2:Process,OUT,获取到的进程的EPROCESS数组
//返回值:NTSTATUS ,返回PsLookupProcessByProcessId的返回值
//==================================================================
NTSTATUS  GetEprocessByExeName(wchar_t*ExeName, PEPROCESS* Process)
{NTSTATUS nStatus;ULONG retLength;  //缓冲区长度PVOID pProcInfo;//缓冲区指针PSYSTEM_PROCESSES pProcIndex;//调用函数,获取进程信息nStatus = ZwQuerySystemInformation(SystemProcessesAndThreadsInformation,   //获取进程信息,宏定义为5NULL,0,&retLength  //返回的长度,即为我们需要申请的缓冲区的长度);if (!retLength){DbgPrint("ZwQuerySystemInformation error!\n");return nStatus;}//DbgPrint("retLength =  %u\n", retLength);//申请空间pProcInfo = ExAllocatePool(NonPagedPool, retLength);if (!pProcInfo){DbgPrint("ExAllocatePool error!\n");return STATUS_UNSUCCESSFUL;}nStatus = ZwQuerySystemInformation(SystemProcessesAndThreadsInformation,   //宏定义为5pProcInfo,retLength,&retLength);if (NT_SUCCESS(nStatus)/*STATUS_INFO_LENGTH_MISMATCH == nStatus*/){pProcIndex = (PSYSTEM_PROCESSES)pProcInfo;//第一个进程应该是 pid 为 0 的进程/*    if (pProcIndex->ProcessId == 0)DbgPrint("ProcName: %-20ws pid:  %u\n", L"System Idle Process",0);*///循环打印所有进程信息,因为最后一天进程的NextEntryDelta值为0,所以先打印后判断do{pProcIndex = (PSYSTEM_PROCESSES)((char*)pProcIndex + pProcIndex->NextEntryDelta);//进程名字字符串处理,防止打印时,出错/*  if (pProcIndex->ProcessName.Buffer == NULL){pProcIndex->ProcessName.Buffer = L"NULL";}*/if (wcscmp(pProcIndex->ProcessName.Buffer, ExeName) == 0){DbgPrint("ProcName: %-20ws pid:  %u\n", pProcIndex->ProcessName.Buffer, pProcIndex->ProcessId);PsLookupProcessByProcessId(pProcIndex->ProcessId, Process);Process++;}          } while (pProcIndex->NextEntryDelta != 0);*Process = NULL;}else{DbgPrint("error code : %u!!!\n", nStatus);}ExFreePool(pProcInfo);return nStatus;
}
//==================================================================
//函数名:  PrintPrivateTable
//功能:   遍历一个进程所有的句柄表项,并执行自定义的回调函数
//输入参数1:IN,pEprocess 指定要遍历的局部句柄表的进程EPROCESS
//输入参数2:IN,func 自定义的回调函数
//返回值:null
//注意:根据句柄表项找到内核对象的步骤//Object = Entry->ObjectPointerBits;//Object <<= 4;//Object |= 0xFFFF000000000000;//Object += 0x30;
//==================================================================
void PrintPrivateTable(PEPROCESS pEprocess, PHANDLE_TABLE_ENTRY_FUNC func)
{POBJECT_TYPE pObjectType = NULL;PHANDLE_TABLE_ENTRY pHandleTableEntry = NULL;UINT64 pObject =0;ULONG_PTR Handle = 0;for (Handle = 0;; Handle += HANDLE_VALUE_INC){pHandleTableEntry = SearchHandleTableEntry(*(PHANDLE_TABLE*)((PUCHAR)pEprocess + HANDLE_TABLE_OFFSET), *(PEXHANDLE)&Handle);if ((PVOID)pHandleTableEntry == NULL){break;}pObject = pHandleTableEntry->ObjectPointerBits;pObject = pObject <<= 4;//DbgPrint("pObject=%p\n", pObject);if ((PVOID)pObject == NULL){continue;}pObject = pObject |= 0xFFFF000000000000;pObject  = pObject + 0x30;pObjectType = ObGetObjectType((PVOID)pObject);if (pObjectType == NULL){continue;}//DbgPrint("pObjectType=%p\n", pObjectType);//DbgPrint("pObjectType=%ws\n", *(PCWSTR*)((PUCHAR)pObjectType + 0x18));//do something ...if (func(pHandleTableEntry, (PVOID)pObject, pObjectType)){break;}/* if (Handle >= 0x20)break;*/}DbgPrint("PHANDLE_TABLE_ENTRY打印结束,Handle=%x\n", Handle);
}
//==================================================================
//函数名: SearchHandleTableEntry
//功能:   根据句柄索引搜索对应的句柄表项
//输入参数1:IN,pObjectTable ObjectTable表的地址
//输入参数2:IN,HandleIndex 句柄索引,13+9+10
//返回值:PHANDLE_TABLE_ENTRY,句柄表项
//==================================================================
PHANDLE_TABLE_ENTRY SearchHandleTableEntry(PHANDLE_TABLE pObjectTable, EXHANDLE HandleIndex)
{UINT64 var_TableBase;//TableCode表UINT64 var_TableLevel;//TableCode表的层数UINT64 var_HandleIndex;//清0属性位之后的HandleIndex的值UINT64 var_PageOffset;//表的偏移UINT64 temp;//临时指针//将HandleIndex的属性位清0HandleIndex.TagBits = 0;var_HandleIndex = (UINT32)HandleIndex.Value;//超出最大索引值,说明该索引无效,返回NULLif (HandleIndex.Value >= pObjectTable->NextHandleNeedingPool)return NULL;//判断私有句柄表的层数var_TableBase = pObjectTable->TableCode;//DbgPrint("var_TableBase=%p\n", var_TableBase);var_TableLevel = var_TableBase & 0x3;switch (var_TableLevel){//只有1层case 0:var_PageOffset = var_HandleIndex;// 先除以4知道返回第几个HandleTableEntry,再乘以10得到HandleTableEntry的索引temp = var_TableBase + (var_PageOffset / 0x4) * 0x10;return  (PHANDLE_TABLE_ENTRY)temp;//有两层case 1://获取前一层表的偏移var_PageOffset = (var_HandleIndex >> 10) ;//进入到后一层表temp =  *(PUINT64)((var_PageOffset * 8-1) + var_TableBase);             //需要-1//获取后一层表的偏移var_PageOffset = var_HandleIndex & 0x3FF ;return (PHANDLE_TABLE_ENTRY)(temp + (var_PageOffset / 0x4) * 0x10);//有三层case 2://获取前一层表的偏移var_PageOffset = (var_HandleIndex >> 19);//进入到中间那一层表temp = *(PUINT64)((var_PageOffset * 8-2) + var_TableBase);              //需要-2//获取中间那层表的偏移var_PageOffset = (var_HandleIndex >> 10) &0x1FF;//进入到后一层表temp = *(PUINT64)(var_PageOffset * 8 + temp);//获取后一层表的偏移var_PageOffset = var_HandleIndex & 0x3FF;return  (PHANDLE_TABLE_ENTRY)(temp + (var_PageOffset / 0x4) * 0x10);default:return NULL;}
}
//==================================================================
//函数名:  KillMutex
//功能:   杀死指定的互斥体,实现多开
//输入参数1:IN,pHandleTableEntry,句柄表项
//输入参数2:IN,pMutex,句柄表项指向的内核对象的body
//输入参数3:IN,pObjectType,句柄表项指向的内核对象所属的OBJECT_TYPE的首地址
//返回值:
//==================================================================
BOOLEAN KillMutex(PHANDLE_TABLE_ENTRY pHandleTableEntry,PVOID pMutex, POBJECT_TYPE pObjectType)
{if (wcscmp(*(PCWSTR*)((PUCHAR)pObjectType + 0x18), L"Mutant") != 0){return FALSE;}//ObQueryNameInfo是通过对象获得对象可变对象头之一的HEADER_NAME_INFO头PHEADER_NAME_INFO pHeaderNameInfo = ObQueryNameInfo(pMutex);if (pHeaderNameInfo==NULL){DbgPrint("ObQueryNameInfo调用失败\n");return FALSE;}//DbgPrint("MutexName=%ws", pHeaderNameInfo->Name.Buffer);if (0 == wcscmp(pHeaderNameInfo->Name.Buffer, L"AAA")){//找到对应名字的对象,将其关闭DbgPrint("MutexName=%ws", pHeaderNameInfo->Name.Buffer);//DbgPrint("PointCount=%d,pMutex-0x30", *(PINT64)((INT64)pMutex-0x30));//DbgPrint("HandleCount=%d,pMutex-0x28", *(PINT64)((INT64)pMutex-0x28));pHeaderNameInfo->Name.Buffer[0] = GetRandomNumber();DbgPrint("MutexName=%ws", pHeaderNameInfo->Name.Buffer);*(PINT64)((INT64)pMutex - 0x30) = 0;*(PINT64)((INT64)pMutex - 0x28) = 0;pHandleTableEntry->HighValue = 0;pHandleTableEntry->LowValue = 0;return TRUE; }return FALSE;
}
//==================================================================
//函数名:GetRandomNumber
//功能:   获取一个大小为8位的数字,使每次获取的数字不重复
//输入参数:void
//返回值:CHAR 返回获取到的数字
//==================================================================
CHAR GetRandomNumber()
{ULONG  inc;LARGE_INTEGER CurrentTime;inc = KeQueryTimeIncrement();KeQueryTickCount(&CurrentTime);CurrentTime.QuadPart *=inc;return (CHAR)CurrentTime.QuadPart;}

CreateMutex防多开相关推荐

  1. 关于防多开的几种方法

    关于防多开的几种方法 1)使用FindWindow API函数.  通过查找窗口标题(或/和类名)来判断程序是否正在运行.如果找到了,表明程序正在运行,这时可退出程序,达到不重复运行的效果:反之表明程 ...

  2. 人脸离线识别模块_人脸识别模块做到市场份额60%,这家AI公司如何用狼性在安防杀开一条血道?...

    导读 "我们是行业内的隐形冠军,只是很少对外说自己的成绩,但事实是我们从2014年就开始做人脸识别模组,市场上非常有名的门禁系统厂商基本都是我们的客户." 瑞为技术安防事业部总经理 ...

  3. 苹果开发者防关联开新号自查清单

    前言 关于开发者封号,防关联等话题之前已经讨论了不少.但是一直都没有做一个清单化的自查总结.所以在这里决定好好写一篇. 鉴于公众号文章没办法做更新和修改,如果我发现有比较重要的需要做补充的话题,很可能 ...

  4. C# 应用程序防多开方法

    Winform启动的时候,检测是否存在同样的进程名,防止程序多开: public static bool isShowMain;/// <summary>/// 应用程序的主入口点./// ...

  5. api接口 pc微信hook_API Hook PC微信防多开

    void HookApi() { //获取CreateMutexW函数地址 Addr = GetProcAddress(LoadLibraryA("Kernel32.dll"), ...

  6. hook createmutex openmutex 实现多开

    通过HOOK createmutex 来多开程序,比如微信. FARPROC addrOpenMutexW = NULL; FARPROC addrCreateMutexW = NULL;void h ...

  7. 我要玩石器多开的攻与防和外挂 ③

    本片博文准备介绍最新的驱动级防多开(20161012)是怎么一会事! 游戏加载后发现一个名为MMProtect的驱动被加载了 搜索后发现原来号称是专业反外挂的现成方案:http://mm-protec ...

  8. WIN32 使用 MUTEX 实现禁止多开

    WIN32 互斥体 MUTEX 可以跨进程获取,因此可以用它实现简易的防多开,进程启动时尝试获取 MUTEX,如果获取失败说明没有多开,如果获取成功,则提示错误信息. 下面是执行结果: 第一个程序已经 ...

  9. 单例模式 Windows下防止多开简介

    简单介绍 单例模式(Singleton Pattern)是一种常见的软件设计模式,在使用这个模式时,单例对象的类必须保证在全局中有且只有一个实例存在,并且提供了一个全局访问的接口,这样有利于我们协调系 ...

最新文章

  1. shell学习笔记 (2)
  2. Primality Test 素数,打表
  3. JDK8 SE安装步骤
  4. pc端实现 网页居中显示 且自适应
  5. SAS® Model Manager功能调研
  6. print to pdf in windows 7
  7. 计算机的病毒防治教案,小学信息技术《防治计算机病毒-计算机病毒》教案
  8. 配电网重构知识及matlab实现
  9. 红旗linux桌面版_瑞星ESM杀毒软件For Linux获红旗兼容性认证
  10. python读取grd数据_Matlab读取grd格式的文件
  11. Flutter TV应用的开发尝试
  12. java swing choice_Java-GUI基础(三)java.swing
  13. 一个类月光宝盒应用,把手机,电视,盒子变家庭游戏机(FBA,FBNEO,MAME)
  14. 移动应用开发技术选择六要素
  15. 力盟科技冲刺上市:主要通过力盟传媒展业,木瓜移动等亦在努力
  16. 10大好用的语音识别软件
  17. NET 页面生命周期
  18. 手机数据恢复的经历和过程
  19. ctfshow-命令执行-web38
  20. MATLAB中(:,1)是什么含义?/MATLAB中冒号的用法

热门文章

  1. 室内P2全彩LED高清显示屏做多大面积分辨率有2K(1920*1080)
  2. macbook只在外接显示器显示的方法
  3. cs-script和dotnet-script脚本
  4. (转)不要自称是程序员,我十多年的 IT 职场总结
  5. ncnn arm linux,ncnn 是一个为手机端极致优化的高性能神经网络前向计算框架
  6. php中的lt;?= ?gt;替换lt;?php echo ?gt;
  7. 概率与期望做题笔记1
  8. 提升你知识和技能的24个终极数据科学项目(分级+任务+数据+教程)
  9. 论文阅读笔记:BB-KBQA: BERT-Based Knowledge Base Question Answering
  10. 惨遭补刀!美链BEC爆合约漏洞后,美图公司宣布终止合作