防止程序多开方法

告别手动输入!用Burp插件+ddddocr,5分钟搞定图片验证码自动识别 本文详细介绍了如何利用Burp插件和ddddocr源库快速构建图片验证码自动识别系统,实现高效、零成本的验证码自动化解决方案。通过环境搭建、性能调优和Burp Suite深度集成,显著提升安全测试效率,特别适用于金融和电商系统的批量测试场景。 阅读详情
 

最近,一个公司项目要求防止程序多开,采用了几种方法,效果还行。

一、使用Mutex

      1、原理

       创建一个互斥体,并检查它是否已经有拥有者,如果有,表明互斥体已经建立(程序已经启动),否则表明程序未启动。

       2、实现

       (1)首先创建一个互斥体,CreateMutex函数,第一个参数可以设置为NULL,第二个参数必须设置为false,第三个参数表示互斥体的名称,这个名称最好有一些特殊标识以防止与其他应用程序冲突,比如程序名+时间。

       (2)使用GetLastError()函数判断错误信息是否为ERROR_ALREADY_EXISTS,如果是,则表示程序已经启动。

       示例代码如下:

  1. HANDLE hObject = ::CreateMutex(NULL,FALSE, _T("Mutex20100731")); 
  2. if(GetLastError() == ERROR_ALREADY_EXISTS) 
  3.    
  4.         CloseHandle(hObject); 
  5.         MessageBox(NULL, _T("应用程序已经在运行!"), _T("提示"), MB_ICONERROR|MB_OK); 
  6.         return FALSE; 
  7.    

       3、效果

       这个是非常简单的应用程序多开检测,一般的程序多开器均能破解此限制。

二、使用窗口属性

      1、原理

      在程序启动时,枚举桌面所有窗口,并检查其属性列表中是否存在特殊的属性值,如果有则表明程序已经启动,否则程序未启动。

      2、实现

      (1)程序启动时首先枚举所有窗口查找是否存在特定属性值,使用EnumWindows函数遍历所有窗口。此函数需要一个回调函数,对于每一个窗口,都会调用此函数,并把遍历到的窗口句柄(HWND)传递给该函数,该回调函数原型如下:

      BOOL CALLBACK EnumWndProc(HWND hwnd,LPARAM lParam);

lParam可由EnumWindows的第二个参数传递。

      (2)在EnumWndProc回调函数中,我们需要获取窗口的属性值,然后检查是否和我们预定的属性值相同,如果相同,则表示程序已经启动。

      (3)如果没有找到,我们需要将此特殊属性值设置到本程序的主窗口。

      示例代码如下:

   

  1. CString g_propName = _T("Prop20100731"); 
  2. HANDLE g_hValue = (HANDLE)1; 
  3. BOOL CALLBACK EnumWndProc(HWND hwnd,LPARAM lParam) 
  4.      HANDLE h = GetProp(hwnd, g_propName); 
  5. if(h == g_hValue) 
  6.    
  7.         *(HWND*)lParam = hwnd; 
  8.         return FALSE; 
  9.    
  10.     return TRUE; 
  11. BOOL CXxxxDlg::OnInitDialog() 
  12.     CDialog::OnInitDialog(); 
  13.     //枚举窗口
  14.     HWND hOldWnd = NULL; 
  15.     EnumWindows(EnumWndProc, (LPARAM)&hOldWnd);//枚举所有运行的窗口
  16.     if(IsWindow(hOldWnd)) 
  17.    
  18.            MessageBox(NULL, _T("应用程序已经在运行!"), _T(""), MB_ICONERROR|MB_OK); 
  19.            DestroyWindow(); 
  20.            return FALSE; 
  21.    
  22.     SetProp(m_hWnd, g_propName, g_hValue); 

      3、效果

      没有做过多的测试,手头有两个多开器均不能多开。

三、使用公共文件

      1、原理

      程序启动时,在一个公共目录(比如C:\或者Temp目录)中创建一个公共文件,并将此文件设置为不共享读写。第二个程序启动时,也打开此文件,如果打开成功,则表示程序未启动过,否则表示程序已经启动。

      2、实现

      此方法实现较为简单,不做详细说明了,请自行查阅CFile等相关文件操作。

      3、效果

      多开器肯定是不能够多开了,但是可以手动设置多开。比如:设定文件访问权限,不允许此程序在公共目录创建文件等。应对方法就是,如果不能创建文件则程序不允许运行。

四、mac地址验证

      1、原理

      必须是网络应用程序,如果单机运行,此方法无效。

      登陆服务器时,获取本机mac地址,发送至服务器端,服务端进行mac地址验证,如果mac地址重复登陆,则不允许同服务器进行消息传递。

      2、实现

      客户端主要是mac地址获取,这个问题我至今没有找到太好的解决方案,效果较好的方法是读取注册表获取。

      首先使用GetAdaptersInfo函数获取所有网卡信息,然后,对于每一个网卡信息查找注册表HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\网卡名称\\Connection位置,如果MediaSubType的值为0x01并且PnpInstanceID中含有PCI字串则表示是物理网卡。

     3、效果

     差强人意,多开器倒是不能用了,但是可以使用超级兔子等软件修改mac地址实现。

五、查看网络连接

     1、原理

     必须是网络应用程序,如果是单机运行,则此方法无效。

     获取本机所有网络连接,检查是否有连接到服务器IP和端口号的连接,如果有,表示程序已经启动,否则程序未启动。

    2、实现

    使用GetTcpTable获取TCP连接,使用GetUdpTable获取UDP连接。需要注意的是,其获取的ip和端口号都是一个DWORD值,并且高低位相反。IP地址可以通过inet_addr函数将字符串形式的IP地址(如"127.0.0.1")转换为DWORD型的,端口号可以使用以下公式转换:DWORD dwPort = ((nPort & 0xff) << 8) + ((nPort & 0xff00) >> 8);

    示例代码如下:

  1. PMIB_TCPTABLE pTcpTable = new MIB_TCPTABLE[1]; 
  2. DWORD dwSize = 0; 
  3. if(GetTcpTable(pTcpTable, &dwSize, TRUE) == ERROR_INSUFFICIENT_BUFFER) 
  4.     delete pTcpTable; 
  5.     pTcpTable = new MIB_TCPTABLE[dwSize / sizeof(MIB_TCPTABLE)]; 
  6. if(GetTcpTable(pTcpTable, &dwSize, FALSE) == NO_ERROR) 
  7.     char cServerAddr[100];//服务器IP
  8.     int nPort;//服务器端口
  9.     DWORD dwIP = inet_addr(cServerAddr); 
  10.     DWORD dwPort = ((nPort & 0xff) << 8) + ((nPort & 0xff00) >> 8); 
  11.     for (int i = 0; i < (int) pTcpTable->dwNumEntries; i++) 
  12.    
  13.         if(pTcpTable->table[i].dwRemoteAddr == dwIP 
  14.             && pTcpTable->table[i].dwRemotePort == dwPort) 
  15.        
  16.             MessageBox(gDataCenter.GetMainWnd(), _T("应用程序已经在运行!"), _T("提示"), MB_ICONERROR|MB_OK); 
  17.             return FALSE; 
  18.        
  19.    
  20. delete []pTcpTable; 

    3、效果

    多开器肯定不能用,但有其他方式导致GetTcpTable函数失败(比如挂系统钩子等)。

    总结了以上几种方法,具体哪种适合,还需要根据实际应用情况来判断,也可以几种方法混合使用,加强效果。

 

 

补充

 

windows系统下,程序防止多开的几种常见方法:
1)使用FindWindow API函数。
通过查找窗口标题(或/和类名)来判断程序是否正在运行。如果找到了,表明程序正在运行,这时可退出程序,达到不重复运行的效果;反之表明程序是第一次运行。
这种方法不适用于以下情况,程序的标题是动态变化的、系统中运行了相同标题(或/和类名)的程序

2)Mutex/Event/Semaphore
通过互斥对象/信号量/事件等线程同步对象来确定程序是否已经运行。最常用的函数如:CreateMutexA(注意:QQ堂、QQ游戏大厅就是采用这样方法来限制程序多开的)

3)内存映射文件(File Mapping)
通过把程序实例信息放到跨进程的内存映射文件中,也可以控制程序多开。

4)DLL全局共享区
DLL全局共享区在映射到各个进程的地址空间时仅被初始化一次,且是在第一次被windows加载时,所以利用该区数据就能对程序进行多开限制。

5)全局Atom
将某个特定字符串通过GlobalAddAtom加入全局原子表(Global Atom Table),程序运行时检查该串是否存在来限制程序多开。(该Atom不会自动释放,程序退出前必须调用GlobalDeleteAtom来释放Atom)

6)检查窗口属性
将某些数据通过SetProp加入到指定窗口的property list,程序运行时枚举窗口并检查这些数据是否存在来限制多开。

以上只列举了最常见的几种方法,具体应用中可以有n种选择,或综合运用多种方法来限制。 

 

波动性GARCH模型与波动率预测(代码+结果分析) 本文介绍的ARCH、GARCH模型可以刻画出随时间变化的条件异方差。 阅读详情

相关推荐

语言API创建互斥禁止程序重复运行.7z

语言API创建互斥禁止程序重复运行.7z

C语言防止程序多创建互斥

我的一个程序可能被多次启动,但是我希望程序启动时一旦发现本程序当前有另一个已经在运行的进程后就弹出提示信息并自行退出,达到防止程序多的目的。 我们可以利用创建互斥(Mutex)的方法,第一个被启动的进程发现当前没有创建过某个名字的互斥(比如我们给互斥起名叫MyTestMutex)之后,就会创建这个互斥,等到这个程序再被启动的时候发现当前存在一个指定名字的互斥,就可以自己退出了。 #include <windows.h> #include <stdio.h> #inc

Rabbit_Gray的博客 1775

语言API创建互斥禁止程序重复运行

语言API创建互斥禁止程序重复运行源码,API创建互斥禁止程序重复运行,禁止重复运行,WaitForSingleObject,CreateMutex,ReleaseMutex,CloseHandle

Windows程序设计学习笔记——线程(二)同步

同步问题是由于多个线程对cpu资源抢占造成的,是多线程中的常见问题,本节从用户模式和内核同步对象两个方面来介绍解决同步问题的方法,在用户模式中主要通过原子操作和关键段(临界区)来解决,此外还可以使用互斥量,事件和信号量这些内核同步对象来解决...

weixin_48088263的博客 357

多线程问题

线程与进程: 一个应用程序会有多个进程,一个进程中会有多个线程。 进程是线程的容器,进程不执行具操作 每个进程至少有一个线程,来执行地址空间中的代码 当创建一个进程时操作系统会自动创建这个进程的第一个线程也就是主线程,也就是执行mian函数和winmain函数的线程。此后主线程可以创建其它的线程。 每个进程有独立的内存空间,而进程与进程之间共享内存空间。     创建进程函数:C

鑫鑫天堂 740

【Qt专栏】实现单例程序,禁止程序多的几种方式

实现单例程序,禁止程序多的几种方式

weixin_43729127的博客 4127

防止程序多方法

 最近,一个公司项目要求防止程序多,采用了几种方法,效果还行。一、使用Mutex      1、原理       创建一个互斥,并检查它是否已经有拥有者,如果有,表明互斥已经建立(程序已经启动),否则表明程序未启动。       2、实现       (1)首先创建一个互斥,CreateMutex函数,第一个参数可以设置为NULL,第二个参数必须设置为false,第三个参数表示互斥的名称,这个名称最好有一些特殊标识以防止与其他应用程序冲突,比如程序名+时间。       (2)使用GetLastE

RobertSoft 的专栏 8243

python大漠游戏多_防止程序多的两种方法

【程序篇】防止程序多的两种方法http://bbs.cskin.net/forum.php?mod=viewthread&tid=105&fromuid=2446(出处: CSkin论坛)互斥对象防止程序多private void Form1_Load(object sender, EventArgs e){bool Exist;//定义一个bool变量,用来表示是否已经运行/...

weixin_36297381的博客 997

防止程序多的两种方法

进程检查 private void Form1_Load(object sender, EventArgs e) { //获取当前活动进程的模块名称 string moduleName = Process.GetCurrentProcess().MainModule.ModuleName; //返回指定路径字符串的文件名 string process

分享智能财税相关技术探索 7924

PyQt防止程序多方法

方法: QSharedMemory # coding:utf-8 import sys from PyQt5.QtCore import QSharedMemory from PyQt5.QtWidgets import * def runWindow(): app = QApplication(sys.argv) share = QSharedMemory() share.setKey("main_window") if share.attach():

Jason的技术探索与分享 3471

C# 防止程序多的两种方法

互斥对象防止程序多 private void Form1_Load(object sender, EventArgs e) { bool Exist;//定义一个bool变量,用来表示是否已经运行 //创建Mutex互斥对象 System.Threading.Mutex newMutex = new System.Threading.Mutex(tr...

weixin_34233421的博客 511

C# Winform程序防止方法

【代码】C# Winform程序防止方法

qq_41184334的博客 915

创建互斥让程序只打一次

// CAudioPlayerApp initializationBOOL CAudioPlayerApp::InitInstance(){ // Standard initialization // If you are not using these features and wish to reduce the size //  of your final executable, you

hnhyliuzhiyuan的专栏 1269

CreateMutex(NULL, FALSE, strAppName); 配合GetLastError() == ERROR_ALREADY_EXISTS

正常情况下,一个进程的运行一般是不会影响到其他正在运行的进程的。但是对于某些有特殊要求的如以独占方式使用串行口等硬件设备的程序就要求在其进程运行期间不允许其他试图使用此端口设备的程序运行的,而且此类程序通常也不允许运行同一个程序的多个实例。这就引出了进程互斥的问题。   实现进程互斥的核心思想比较简单:进程在启动时首先检查当前系统是否已经存在有此进程的实例,如果没有,进程将成功创建并设置标识

yu_xiyan的专栏 3050

vc进程间互斥Mutex

参考MSDN例子 First Process #include <windows.h> #include <stdio.h> #include <conio.h> // This process creates the mutex object. int main(void) { HANDLE hMutex; hMutex = CreateMutex( NULL, // defau...

xiapang009的专栏 570

linux中qt防止程序二次运行,QT之防止程序重复运行方法

最近在做一个项目,添加了一个功能:防止一个程序能够重复启动。包括Windows平台和Linux平台,其中Q_OS_WIN32宏用来表示编译运行的目标平台是windows,Q_OS_LINUX则标示目标为linux。实现的思想是:对windows和linux分别采取了全局互斥变量和文件锁的方法。实现方法:#if defined Q_OS_WIN32 //for win#include bool ...

weixin_29607417的博客 884

只有一个实例运行

HANDLE hMutex=::CreateMutex(NULL,TRUE,_T("FirstName"));//FirstName可以随便取一个唯一的名字    if   (hMutex!=NULL)    {    if   (GetLastError()==ERROR_ALREADY_EXISTS)    {    AfxMessageBox(_T("已经有一个程序运行."));

zhoxier的专栏 660

SimpleBGC32- 源三轴无刷云台算法完全解说_电机_mpu6050三轴云台_云台源算法_云台电机_电机源_

使用STM32F103RC和MPU6050、无刷电机云台的三轴增稳

上一篇: VC获取当前时间
下一篇: C++中的虚拟继承机制探讨
Canvas
博客等级 码龄16年 4粉丝 1原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值