本栏目主要讲解如何解除禁止双开方面的各种方案.docx

上传人:b****5 文档编号:11858123 上传时间:2023-04-06 格式:DOCX 页数:43 大小:330.85KB
下载 相关 举报
本栏目主要讲解如何解除禁止双开方面的各种方案.docx_第1页
第1页 / 共43页
本栏目主要讲解如何解除禁止双开方面的各种方案.docx_第2页
第2页 / 共43页
本栏目主要讲解如何解除禁止双开方面的各种方案.docx_第3页
第3页 / 共43页
本栏目主要讲解如何解除禁止双开方面的各种方案.docx_第4页
第4页 / 共43页
本栏目主要讲解如何解除禁止双开方面的各种方案.docx_第5页
第5页 / 共43页
点击查看更多>>
下载资源
资源描述

本栏目主要讲解如何解除禁止双开方面的各种方案.docx

《本栏目主要讲解如何解除禁止双开方面的各种方案.docx》由会员分享,可在线阅读,更多相关《本栏目主要讲解如何解除禁止双开方面的各种方案.docx(43页珍藏版)》请在冰豆网上搜索。

本栏目主要讲解如何解除禁止双开方面的各种方案.docx

本栏目主要讲解如何解除禁止双开方面的各种方案

本栏目主要讲解如何解除禁止双开方面的各种方案.为什么要禁止双开或多开呢?

原因很多.但我们的软件中若能有解开多开的功能,可以有很多的好处.比如一台机子可以同时登陆多个帐号上去玩.

 

要想解除中禁止双开的功能,就得先了解禁止双开方面的原理.其实想要禁止双开并不难.禁止双开的方法也有很多.但其基本的方式,本栏目会都给介绍一下.

 

在操作系统中每个在运行的进程都是独立的.禁双开的程序在运行时,需要留下一些专有的特征供第二次运行时检测用,当第二次运行时,会去尝试检测有没有某个专有的特征.若该特征已存在则结束自身进程.若不存在则继续运行.通过这种方式,就能简单的达到禁止双开的目的.

 

本文介绍第一种,是比较常用的.通过窗口标题与窗口类名的特征来达到禁止双开的功能.

 

如果我们的程序的主要窗口类名与窗口标题是唯一的,一般不会与他人的程序出现相同的情况时,可以用如下API来实现禁止双开功能.

 

查找窗口的API

 

在程序运行载入主窗口之前,先通过该API检测一下是否已有存在相应标题的窗口了,若已存在时,自结束自身进程的运行.反之继续运行.

 

利用窗口标题与类名来防止程序被多开

 

上面的这段代码,简单的示例了如何使用这个API来达到禁止双开的方式.

 

根据这种禁止双开的方式.只要我们在运行第二个进程之前,先把第一个进程的标题修改成别的后,就能正常运行第二个进程,也就能达到解除双开的功能了..呵呵,简单吧!

 

见下面的代码,就能说明这个方法的使用了.

 

通过修改窗口的标题达到破解利用标题禁多开的程序方式与效果

 

上面的代码,就是一种极简单的解除窗口标题方式的禁止双开的功能了...

 

但有些时候,事情可能并不是这么容易能解决的,我们修改了其窗口标题,虽然能使其正常运行了,但该进程若在后期运行过程中,若取自已标题进行一次判断有没有被改变的话,马脚自然就露出来了.

 

对于这种情况,需要在创建第二个进程之前,修改已存在的进程的窗口标题后,新进程创建出来后马上把其窗口标题改回去.但是,这很难操作.所以并不推荐.

 

所以若不想通过修改其原窗口标题来达到多开,必需得HOOK其用来检测窗口禁止多开时的那些API.如这里使用的FindWindowA 这个API.只要在创建进程时,注入个DLL,对该API进行HOOK.在HOOK到的参数时,判断窗口标题.进行返回0即可.

 

下面贴上EXE的代码

 

采用安装线程DLL()的方式注入mydll.dll文件

 

在注入EXE的代码中,采用2.0版模块中新增的安装线程DLL()方式进行注入.

 

下面再贴上DLL的代码.

 

采用APIHOOK来拦截FindWindowA例子程序运行效果

 

工具、源码可在网站首页公布的网盘中下载

 

很多的或一些共享软件,都在采用窗口标题方式来进行禁止多开.大家可以试试修改前个已创建进程的窗口标题一段时间,那个进程会不会出错.若不会出错说明修改标题无影响.然后再运行第二个进程看看能不能运行起来.

 

需要注意的是,并不定都会采用FindWindowA 该API来检测窗口,事实上,可用来查窗口的API有很多.只是FindWindowA 相对比较常用罢了.对于其它的API检测窗口,可就得调试分析了. 另外有些是用文件名来判断的,只要复制一份EXE重新命令后就能双开了

 

前文讲解了有些使用窗口的标题类名特征来禁止程序双开.本文接着讲解使用进程名来禁止双开与解除的方式.

 

采用程序名来限制双开的情况很多.这类程序进程被创建时,会枚举系统里现有的所有进程,进行名称对照,发现与已相同存在时,就结束自身进程.

 

见下面的简单例子

 

使用枚举进程来禁止程序被多开

 

上述的代码在进程创建后,会枚举所有进程,然后进行程序名称的判断,发现有存在同名时就结束.

 

对于这类的,可以做个简单的解禁功能,只要把要运行的程序文件复制一份为别的文件名,然后运行之即可.见下面代码.

 

先复制为临时文件再用创建进程并指定原程序目录来运行

 

上述代码把目标程序复制一份临时文件,运行之,就可能达解除双开的目的了.

 

但有些时候,情况并没有这么简单,比如,有些程序进程被运行后,自已再检测自身的进程文件名是不是被改成别的了,禁止被改名的情况下,上述的方式就行不通了.

 

下面再贴一段APIHOOK枚举进程时的一个API.

 

Process32Next

 

只需要APIHOOK Process32Next进行程序名的判断,发现同名时,就再调用一次Process32Next取下个进程结构去即可.

 

EXE的代码与上文的一致,下面为DLL的代码.

 

mydll.dll代码.采用APIHOOK拦截Process32Next实现解除多开限制

 

工具、源码可在网站首页公布的网盘中下载

 

很显然,这一切并不太难..可以通过APIHOOK实现一些简单的进程隐藏,DLL隐藏等.文章中介绍得简单,只能给大家开扩一下思路.不过需要注意的是,可以用来枚举出进程和DLL模块等的API还是蛮多的,例如作坊2.5模块里的枚举进程线程模块等功能不使用R3层的API实现的,无法被APIHOOK给拦截到.

本文再介绍一种常用的禁双开的方式,英文名叫Mutex 中文名叫突变体或互斥体 等.作坊教程里称它为互斥体.

 

相同名称的互斥体对象在系统里也是唯一的.也就是说,若有一个进程已经创建了某个名称的互斥体对象后,其它的进程再去创建该名称的互斥体对象时.不会新建,而且把之前已创建的互斥体对象打开,返回该互斥体对象句柄.如果是打开的话另外会设置API错误码183.

 

所以在很多程序中就会使用这个方式来实现禁止多开.例如QQ遊戲大厅就是这种方式.

 

下面为使用互斥体进行禁止多开的简单例子.

 

先贴上本例用到的几个API

 

下面是如何使用互斥体来实现禁止双开的代码.

 

使用互斥体实现禁止程序多开

 

采用互斥体的程序可以用procexp.exe这个程序查看到.

 

要解除这类的双开,只要在运行新进程前,先尝试着把所有进程中的该名称的互斥体句柄全关掉即可.

 

下面贴上如何枚举所有进程中的句柄,并且取出这些互斥体句柄对象的名称.判断是否是\BaseNamedObjects\禁止双开示例”如果是的话,则使用一个远线程在目标进程里执行CloseHandle这个API来关掉句柄.

 

注意,枚举出来的其它进程里的句柄,只属于那个进程才能用的,在我们的进程里是不能直接使用的,需要把那个句柄拷贝一份过来,才能在我们的进程中使用.

 

枚举出所有的句柄,找到目标进程里的某种对象句柄使用远线程进行关闭

 

上面的代码有些技术性和技巧性.大家慢慢的试着理解吧!

 

同样的,本文也给出了一个APIHOOK的方案,DLL中的代码见下面.

 

因为创建互斥体时,若互斥体已存在时,会设置API错误码为185.所以我们只需要HOOK创建互斥体时的那个API,判断其参数三的互斥体名称.然后把API错误码置为0即可.

 

采用APIHOOK拦截 CreateMutexA达到解除双开限制功能

 

工具、源码可在网站首页公布的网盘中下载

 

本文介绍完毕,采用互斥体进行禁止双开的使用率是很高的.除了这三文所介绍的这些方式禁双开外,还有其它如独占方式打开文件 或共享内存 或注册表等等都可以做到禁止双开的目的.

本节教程采用解除双开限制-01里的禁止双开示例.exe进行.

先运行一个禁止双开示例.exe进程 

再用OD载入第二个 禁止双开示例.exe进程.

 

分别下断点在以下两个API上.目的在于断在双开判断后将要终止进程时.

 

ExitProcess

TerminateProcess

 

按F9运行OD.会中断在 ExitProcess .

见堆栈窗口内容

0012FE54 1002A273 /CALL 到ExitProcess来自krnln.1002A26D

0012FE58 00000000 \ExitCode=0

 

然后在汇编里转到 1002A26D处这里krnln是易语言的核心支持库.

 

1002A258 55 push ebp ;核库某入口

1002A259 8BEC mov ebp,esp

1002A25B 8B45 08 mov eax,dwordptr[ebp+8]

1002A25E 50 push eax

1002A25F B9E8B91310 mov ecx,1013B9E8

1002A264 E8 D7270300 call 1005CA40

1002A269 8B4D08 mov ecx,dword ptr [ebp+8]

1002A26C 51 push ecx

1002A26D FF15 E8830D10 call dword ptr[<&KERNEL32.ExitProcess>] ;ExitProcess

1002A273 5D pop ebp

1002A274 C3 retn ;函数尾

 

为了能追查到是什么地方CALL这个核心库.

在该核库函数入口处1002A258下断点,然后OD重载禁止双开示例.exe.

我的的目的需要是一直的往向走,直到在EXE的领空里为止,因为禁止双开的判断函数都是在EXE里的,不太可能会在别的地方.

 

按F9运行,会中断在该核库函数入口1002A258处.

见堆栈窗口内容

0012FE6000403367返回到禁止双开.00403367 来自禁止双开.004033E1

 

回到在汇编里转到00403367处.这里的00403367已经是禁止双开示例.exe领空了.

可以见到如下汇编代码段

 

00403321 55 push ebp ;子程序入口

00403322 8BEC mov ebp,esp

00403324 81EC10000000 sub esp,10

0040332A 8965FC mov dword ptr[ebp-4],esp

0040332D 68D3304000 push 004030D3 ;入栈窗口标题

00403332 68E0304000 push 004030E0 ;ASCII"Afx:

10000000:

b:

10011:

1900015:

0"

00403337 B8 00000000 mov eax,0 ;设置EAX=0

0040333C E8 BE000000 call 004033FF ; 第一个CALL调用FindWindowA

00403341 3965FC cmp dwordptr [ebp-4],esp

00403344 740D je short00403353 ;跳转指令

00403346 6806000000 push 6

0040334B E8A9000000 call 004033F9 ;第二个CALL

00403350 83C404 add esp,4

00403353 8945F4 mov dwordptr[ebp-C], eax ; EAX值入栈

00403356 837DF400 cmp dword ptr[ebp-C], 0 ; 比较值<>0

0040335A 0F84 0A000000 je 0040336A ;跳转指令

00403360 6A00 push 0

00403362 E87A000000 call 004033E1 ; 调用易核库函数结束()

00403367 83C404 add esp, 4 ;核库函数调用返回到这里

0040336A 6802000080 push 80000002

0040336F 6A 00 push 0

00403371 6801000000 push 1

00403376 6A00 push 0

00403378 6A00 push 0

0040337A 6A00 push 0

0040337C 6801000100 push 10001

00403381 6800000106 push 6010000

00403386 68 01000152 push 52010001

0040338B 6803000000 push 3

00403390 BB 20030000 mov ebx,320

00403395 E8 59000000 call 004033F3

0040339A 83C428 add esp, 28

0040339D B800000000 mov eax,0

004033A2 E900000000 jmp 004033A7

004033A7 8BE5 mov esp, ebp

004033A9 5D pop ebp

004033AA C3 retn ;子程序结尾

 

见上面的这段汇编代码,这段汇编子程序正是禁止双开的关健段.从核心库返回到的00403367上一个CALL 是调用核心库最终会调用ExitProcessAPI来终止进程的.

再上面的就是一个比较跳转指令,可以跳过这个核心库的结束()命令

 

00403353 8945 F4 mov dword ptr[ebp-C],eax ;EAX值入栈

00403356 837DF400 cmp dwordptr [ebp-C],0 ;比较值<>0

0040335A 0F840A000000 je 0040336A ;跳转指令

 

这个跳转指令,比较了一个EAX值与0的大小.一般情况下,EAX寄存器中的值都是来自某CALL执行后的返回值.所以我们得再看看,距离这个EAX最近的CALL里会不会有禁止双开的检测.

最近的CALL是

 

0040334B E8A9000000 call 004033F9 ;第二个CALL

 

我们在这第二个CALL下断点,然后进行OD重载,准备分析这个CALL,但很奇怪,居然没有断在这个断点的第二个CALL上..

那么就得继续往上分析了.

以第二个CALL之前,有个比较跳转命令,该命令会跳过第二个CALL.

 

00403341 3965FC cmp dwordptr[ebp-4],esp

00403344 74 0D je short 00403353 ; 跳转指令

 

此时可以决定第二个CALL与禁止双开无关,那么,再往上找,还有个CALL.看来这个CALL一定会是了,因为再之上已经没有其它的CALL指令了.

下面是第一个CALL的指令,可以在第一个CALL处下断点,

 

0040332D 68 D3304000 push 004030D3 ;入栈窗口标题

00403332 68E0304000 push 004030E0 ;ASCII"Afx:

10000000:

b:

10011:

1900015:

0"

00403337 B800000000 mov eax,0 ;设置EAX=0

0040333C E8BE000000 call 004033FF ;第一个CALL 调用FindWindowA

 

然后OD重载EXE进行调试,断在了第一个CALL处.在这个CALL之前入栈了两次,可以在查看被入栈了两个参数正好分别是 "禁止双开示例"与 "Afx:

10000000:

b:

10011:

1900015:

0".现在我们跟进这个CALL,需要去更详细的了解它

出来如下指令.

 

004033FF -FF25 95324000 jmp dwordptr[403295] ;krnln.1002996F

 

一个JMP指令,无条件继续跟进.

这回跟到了krnln里了,核心库.已经离开了EXE的领空.

 

1002996F 50 push eax ;核心库函数体入口

10029970 E8E7FFFFFF call 1002995C ;返回 FindWindowA入口

10029975 83C404 add esp,4

10029978 FFE0 jmp eax ;跳向API

 

这段汇编指令不多,一个CALL与一个JMP.需要一步步仔细的调试他的变化了.记得注意EAX的变化,因为EAX中的值最终会被用来比较而跳向API函数ExitProcess去

第一条指令1002996F不重要.

第二条指令是一个CALL,很显然很有必要跟进去了解其详情.但是

第三条指令平衡一下堆栈用.

第四条指令 jmpeax说明了,第二条指令的CALL会返回EAX里的值会是某个函数地址.如果不是地址的话,不该出现JMP EAX 进行跳转的.

 

现在我想,先不急着跟进第二条指令CALL.打算先分析第四条指令的JMP会搞些什么.

于是,按F8单步步过10029970 E8E7FFFFFF call 1002995C这条指令

结果奇迹发生了,见右边的寄存器中的EAX值状态.

 

EAX77D2DE87 USER32.FindWindowA

ECX0012FFE0

EDX 1013C4F4krnln.1013C4F4

EBX0012FEC0ASCII"\krnln.fne"

ESP0012FE58

EBP0012FE78

ESIFFFFFFFF

EDI7C930738ntdll.7C930738

EIP10029975 krnln.10029975

 

EAX中的值是一个 user32.dll里的APIFindWindowA.下面的JMP指令就是跳向该API的.

 

10029978 FFE0 jmp eax

 

下面的进入了FindWindowA 函数体

77D2DE87>8BFF mov edi, edi ;ntdll.7C930738

77D2DE89 55 push ebp

77D2DE8A 8BEC mov ebp, esp

77D2DE8C 33C0 xor eax,eax

77D2DE8E 50 push eax

77D2DE8F FF750C push dwordptr[ebp+C]

77D2DE92 FF75 08 push dwordptr[ebp+8]

77D2DE95 50 push eax

77D2DE96 50 push eax

77D2DE97 E84CFFFFFF call 77D2DDE8

77D2DE9C 5D pop ebp

77D2DE9D C20800 retn 8

 

堆栈状态

0012FE5C 00403341/CALL 到 FindWindowA来自禁止双开.0040333C

0012FE60004030E0|Class="Afx:

10000000:

b:

10011:

1900015:

0"

0012FE64004030D3\Title= ""BD,"顾",AB,"开示例"

 

执行完该API后就回到了EXE领空

0040333C E8BE000000 call 004033FF ;第一个CALL调用FindWindowA

00403341 3965 FC cmp dwordptr [ebp-4],esp

00403344 740D je short00403353 ;跳转指令

 

现在可以总结,造成禁止双开的祸根就是在执行了FindWindowA这个API之后.会比较它的返回值是不是0?

不为0时就会跳向ExitProcess终止进程的运行.

 

清楚了禁止双开的原因后,接着就可以对症下药了.可以HOOK掉该API就行了.

正所谓,光说不练假把式.本篇内容是以QQ游戏大厅程序为例子,本来我是很不情愿再写这篇的,因为此时写的这篇文章,很可能会在一段时间后,游戏更新了,未来本文就会失效.但还是写了,为了大家,也给前面的第四文做个佐证与一点补充.

 

先创建一个游戏进程,然后去创建第二个进程时,会创建失败,并且第一个进程的大厅窗口会被激活置为前台,另外任务栏下的QQ游戏按钮也会被闪烁几下.

 

会闪烁可是好事啊,可以给我们找关键的禁止双开的CALL提供很多的帮助.

 

QQ游戏闪烁时的效果,是蓝色的,连着闪好几次

 

下面我们在开着第一个大厅的情况下,用OD载入第二个QQ游戏大厅程序,然后下断点在以下两个会终止进程的API上

 

ExitProcess

TerminateProcess

 

在OD里按F9运行,会中断在 ExitProcess上.

见堆栈情况

 

0012FF0477C09D45/CALL 到ExitProcess 来自MSVCRT.77C09D3F

0012FF0800000000\ExitCode= 0

 

看堆栈提示,是MSVCRT领空的 77C09D3F处指令 MSVCRT 是VC++的运行时库,与易语言的核心库一样的概念.另外就是易语言与易核心库是用VC++编的,所以我们编写的易程序在运行时,也会加载这个MSVCRT运行库的

现在我们在反汇编代码处转到 77C09D3F .

 

77C09D13 8BFF mov edi,edi ;VC运行时库某函数

77C09D15 55 push ebp

77C09D16 8BEC mov ebp,esp

77C09D18 68 A440BE77 push 77BE40A4 ;ASCII"mscoree.dll"

77C09D1D FF15E810BE77 call dword ptr[<&KERNEL32.GetModuleHandleA>];kernel32.GetModuleHandleA

77C09D23 85C0 test eax,eax

77C09D25 7415 je short77C09D3C

77C09D27 68 9440BE77 push 77BE4094 ;ASCII "CorExitProcess"

77C09D2C 50 push eax

77C09D2D FF15D010BE77 call dwordptr [<&KERNEL32.GetProcAddress>] ; kernel32.GetProcAddress

77C09D33 85C0 test eax,eax

77C09D35 7405 je short77C09D3C

77C09D37 FF7508 push dwordptr[ebp+8]

77C09D3A FFD0 call eax

77C09D3C FF75 08 push dword ptr[ebp+8]

77C09D3F FF151C12BE77call dwordptr[<&KERNEL32.ExitProcess>] ;kernel32.ExitProcess

77C09D45 CC int3

77C09D46 CC int3

 

我们当前要做的事就是一级一级的往上找,直到EXE领空为止,所以这

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育 > 学科竞赛

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1