本栏目主要讲解如何解除禁止双开方面的各种方案.doc_第1页
本栏目主要讲解如何解除禁止双开方面的各种方案.doc_第2页
本栏目主要讲解如何解除禁止双开方面的各种方案.doc_第3页
本栏目主要讲解如何解除禁止双开方面的各种方案.doc_第4页
本栏目主要讲解如何解除禁止双开方面的各种方案.doc_第5页
已阅读5页,还剩37页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

本栏目主要讲解如何解除禁止双开方面的各种方案.为什么要禁止双开或多开呢?原因很多.但我们的软件中若能有解开多开的功能,可以有很多的好处.比如一台机子可以同时登陆多个帐号上去玩.要想解除中禁止双开的功能,就得先了解禁止双开方面的原理.其实想要禁止双开并不难. 禁止双开的方法也有很多.但其基本的方式,本栏目会都给介绍一下.在操作系统中每个在运行的进程都是独立的.禁双开的程序在运行时,需要留下一些专有的特征供第二次运行时检测用,当第二次运行时,会去尝试检测有没有某个专有的特征.若该特征已存在则结束自身进程.若不存在则继续运行.通过这种方式,就能简单的达到禁止双开的目的.本文介绍第一种,是比较常用的.通过 窗口标题 与 窗口类名 的特征来达到禁止双开的功能.如果我们的程序的主要窗口类名与窗口标题是唯一的,一般不会与他人的程序出现相同的情况时,可以用如下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只需要APIHOOKProcess32Next 进行程序名的判断,发现同名时,就再调用一次 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上.目的在于断在双开判断后将要终止进程时.ExitProcessTerminateProcess按F9运行OD.会中断在 ExitProcess .见堆栈窗口内容0012FE541002A273/CALL 到 ExitProcess 来自 krnln.1002A26D0012FE5800000000ExitCode = 0然后在汇编里转到 1002A26D 处 这里krnln是易语言的核心支持库.1002A25855pushebp; 核库某入口1002A2598BECmovebp, esp1002A25B8B45 08moveax, dword ptr ebp+81002A25E50pusheax1002A25FB9 E8B91310movecx, 1013B9E81002A264E8 D7270300call1005CA401002A2698B4D 08movecx, dword ptr ebp+81002A26C51pushecx1002A26DFF15 E8830D10calldword ptr ; ExitProcess1002A2735Dpopebp1002A274C3retn; 函数尾为了能追查到是什么地方CALL这个核心库.在该核库函数入口处1002A258下断点,然后OD重载 禁止双开示例.exe .我的的目的需要是一直的往向走,直到在EXE的领空里为止,因为禁止双开的判断函数都是在EXE里的,不太可能会在别的地方.按F9运行,会中断在该核库函数入口1002A258处.见堆栈窗口内容0012FE60 00403367 返回到 禁止双开.00403367 来自 禁止双开.004033E1回到在汇编里转到 00403367 处. 这里的00403367已经是禁止双开示例.exe领空了.可以见到如下汇编代码段0040332155pushebp; 子程序入口004033228BECmovebp, esp0040332481EC 10000000subesp, 100040332A8965 FCmovdword ptr ebp-4, esp0040332D68 D3304000push004030D3; 入栈窗口标题0040333268 E0304000push004030E0; ASCII Afx:10000000:b:10011:1900015:000403337B8 00000000moveax, 0; 设置EAX=00040333CE8 BE000000call004033FF; 第一个CALL 调用 FindWindowA004033413965 FCcmpdword ptr ebp-4, esp0040334474 0Djeshort 00403353; 跳转指令0040334668 06000000push60040334BE8 A9000000call004033F9; 第二个CALL0040335083C4 04addesp, 4004033538945 F4movdword ptr ebp-C, eax; EAX值入栈00403356837D F4 00cmpdword ptr ebp-C, 0; 比较 值00040335A0F84 0A000000je0040336A; 跳转指令004033606A 00push000403362E8 7A000000call004033E1; 调用易核库函数 结束()0040336783C4 04addesp, 4; 核库函数调用返回到这里0040336A68 02000080push800000020040336F6A 00push00040337168 01000000push1004033766A 00push0004033786A 00push00040337A6A 00push00040337C68 01000100push100010040338168 00000106push60100000040338668 01000152push520100010040338B68 03000000push300403390BB 20030000movebx, 32000403395E8 59000000call004033F30040339A83C4 28addesp, 280040339DB8 00000000moveax, 0004033A2E9 00000000jmp004033A7004033A78BE5movesp, ebp004033A95Dpopebp004033AAC3retn; 子程序结尾见上面的这段汇编代码,这段汇编子程序正是禁止双开的关健段.从核心库返回到的 00403367 上一个CALL 是调用核心库最终会调用 ExitProcess API来终止进程的.再上面的就是一个比较跳转指令,可以跳过这个核心库的结束()命令004033538945 F4movdword ptr ebp-C, eax; EAX值入栈00403356837D F4 00cmpdword ptr ebp-C, 0; 比较 值00040335A0F84 0A000000je0040336A; 跳转指令这个跳转指令,比较了一个EAX值与0的大小.一般情况下,EAX寄存器中的值都是来自某CALL执行后的返回值.所以我们得再看看,距离这个EAX最近的CALL里会不会有禁止双开的检测.最近的CALL是0040334BE8 A9000000call004033F9; 第二个CALL我们在这第二个CALL下断点,然后进行OD重载,准备分析这个CALL,但很奇怪,居然没有断在这个断点的第二个CALL上.那么就得继续往上分析了.以第二个CALL之前,有个比较跳转命令,该命令会跳过第二个CALL.004033413965 FCcmpdword ptr ebp-4, esp0040334474 0Djeshort 00403353; 跳转指令此时可以决定第二个CALL与禁止双开无关,那么,再往上找,还有个CALL.看来这个CALL一定会是了,因为再之上已经没有其它的CALL指令了.下面是第一个CALL的指令,可以在第一个CALL处下断点,0040332D68 D3304000push004030D3; 入栈窗口标题0040333268 E0304000push004030E0; ASCII Afx:10000000:b:10011:1900015:000403337B8 00000000moveax, 0; 设置EAX=00040333CE8 BE000000call004033FF; 第一个CALL 调用 FindWindowA然后OD重载EXE进行调试,断在了第一个CALL处.在这个CALL之前入栈了两次,可以在查看被入栈了两个参数正好分别是 禁止双开示例 与 Afx:10000000:b:10011:1900015:0.现在我们跟进这个CALL,需要去更详细的了解它出来如下指令.004033FF - FF25 95324000jmpdword ptr 403295; krnln.1002996F一个JMP指令,无条件继续跟进.这回跟到了 krnln 里了,核心库.已经离开了EXE的领空.1002996F50pusheax; 核心库函数体入口10029970E8 E7FFFFFFcall1002995C; 返回 FindWindowA 入口1002997583C4 04addesp, 410029978FFE0jmpeax; 跳向API这段汇编指令不多,一个CALL与一个JMP.需要一步步仔细的调试他的变化了.记得注意EAX的变化,因为EAX中的值最终会被用来比较而跳向API函数 ExitProcess 去第一条指令 1002996F 不重要.第二条指令 是一个CALL,很显然很有必要跟进去了解其详情.但是第三条指令 平衡一下堆栈用.第四条指令 jmp eax 说明了,第二条指令的CALL会返回EAX里的值会是某个函数地址.如果不是地址的话,不该出现 JMP EAX 进行跳转的.现在我想,先不急着跟进第二条指令CALL.打算先分析第四条指令的JMP会搞些什么.于是,按F8单步步过 10029970E8 E7FFFFFFcall1002995C 这条指令结果奇迹发生了,见右边的寄存器中的EAX值状态.EAX 77D2DE87 USER32.FindWindowAECX 0012FFE0EDX 1013C4F4 krnln.1013C4F4EBX 0012FEC0 ASCII krnln.fneESP 0012FE58EBP 0012FE78ESI FFFFFFFFEDI 7C930738 ntdll.7C930738EIP 10029975 krnln.10029975EAX中的值是一个 user32.dll 里的API FindWindowA .下面的JMP指令就是跳向该API的.10029978FFE0jmpeax下面的进入了 FindWindowA 函数体77D2DE87 8BFFmovedi, edi; ntdll.7C93073877D2DE8955pushebp77D2DE8A8BECmovebp, esp77D2DE8C33C0xoreax, eax77D2DE8E50pusheax77D2DE8FFF75 0Cpushdword ptr ebp+C77D2DE92FF75 08pushdword ptr ebp+877D2DE9550pusheax77D2DE9650pusheax77D2DE97E8 4CFFFFFFcall77D2DDE877D2DE9C5Dpopebp77D2DE9DC2 0800retn8堆栈状态0012FE5C 00403341 /CALL 到 FindWindowA 来自 禁止双开.0040333C0012FE60 004030E0 |Class = Afx:10000000:b:10011:1900015:00012FE64 004030D3 Title = BD,顾,AB,开示例执行完该API后就回到了EXE领空0040333CE8 BE000000call004033FF; 第一个CALL 调用 FindWindowA004033413965 FCcmpdword ptr ebp-4, esp0040334474 0Djeshort 00403353; 跳转指令现在可以总结,造成禁止双开的祸根就是在执行了 FindWindowA 这个API之后.会比较它的返回值是不是0?不为0时就会跳向 ExitProcess 终止进程的运行.清楚了禁止双开的原因后,接着就可以对症下药了.可以HOOK掉该API就行了.正所谓,光说不练假把式.本篇内容是以QQ游戏大厅程序为例子,本来我是很不情愿再写这篇的,因为此时写的这篇文章,很可能会在一段时间后,游戏更新了,未来本文就会失效.但还是写了,为了大家,也给前面的第四文做个佐证与一点补充.先创建一个游戏进程,然后去创建第二个进程时,会创建失败,并且第一个进程的大厅窗口会被激活置为前台,另外任务栏下的QQ游戏按钮也会被闪烁几下.会闪烁可是好事啊,可以给我们找关键的禁止双开的CALL提供很多的帮助.QQ游戏闪烁时的效果,是蓝色的,连着闪好几次下面我们在开着第一个大厅的情况下,用OD载入第二个QQ游戏大厅程序,然后下断点在以下两个会终止进程的API上ExitProcessTerminateProcess在OD里按F9运行,会中断在 ExitProcess 上.见堆栈情况0012FF04 77C09D45 /CALL 到 ExitProcess 来自 MSVCRT.77C09D3F0012FF08 00000000 ExitCode = 0看堆栈提示,是 MSVCRT 领空的 77C09D3F 处指令 MSVCRT 是VC+的运行时库,与易语言的核心库一样的概念.另外就是易语言与易核心库是用VC+编的,所以我们编写的易程序在运行时,也会加载这个 MSVCRT 运行库的现在我们在反汇编代码处转到 77C09D3F .77C09D138BFFmovedi, edi; VC运行时库某函数77C09D1555pushebp77C09D168BECmovebp, esp77C09D1868 A440BE77push77BE40A4; ASCII mscoree.dll77C09D1DFF15 E810BE77 calldword ptr ; kernel32.GetModuleHandleA77C09D2385C0testeax, eax77C09D2574 15jeshort 77C09D3C77C09D2768 9440BE77push77BE4094; ASCII CorExitProcess77C09D2C50pusheax77C09D2DFF15 D010BE77 calldword ptr ; kernel32.GetProcAddress77C09D3385C0testeax, eax77C09D3574 05jeshort 77C09D3C77C09D37FF75 08pushdword ptr ebp+877C09D3AFFD0calleax77C09D3CFF75 08pushdword ptr ebp+877C09D3FFF15 1C12BE77 calldword ptr ; kernel32.ExitProcess77C09D45CCint377C09D46CCint3我们当前要做的事就是一级一级的往上找,直到EXE领空为止,所以这次接着在这段汇编段入口处下断,然后用OD重载,按F9,运行到 77C09D13 处.可以在堆栈中看到如下情况0012FF10 77C09E78 返回到 MSVCRT.77C09E78 来自 MSVCRT.77C09D13再在汇编里转到 77C09E78 处.77C09DDACCint377C09DDB8BFFmovedi, edi; VC+运行库中的某个函数入口处77C09DDD55pushebp77C09DDE8BECmovebp, esp77C09DE056pushesi77C09DE16A 08push877C09DE3E8 D3070000call_lock77C09DE833F6xoresi, esi77C09DEA46incesi77C09DEB3935 541AC377 cmpdword ptr 77C31A54, esi77C09DF159popecx77C09DF274 67jeshort 77C09E5B77C09DF4837D 0C 00cmpdword ptr ebp+C, 077C09DF88935 501AC377 movdword ptr 77C31A50, esi77C09DFE881D 4C1AC377 movbyte ptr 77C31A4C, bl77C09E0475 44jnzshort 77C09E4A77C09E068B0D A027C377 movecx, dword ptr 77C327A077C09E0C85C9testecx, ecx77C09E0E74 29jeshort 77C09E3977C09E10A1 9C27C377moveax, dword ptr 77C3279C77C09E1583E8 04subeax, 477C09E183BC1cmpeax, ecx77C09E1AEB 16jmpshort 77C09E3277C09E1C8B00moveax, dword ptr eax77C09E1E85C0testeax, eax77C09E2074 02jeshort 77C09E2477C09E22FFD0calleax77C09E24A1 9C27C377moveax, dword ptr 77C3279C77C09E2983E8 04subeax, 477C09E2C3B05 A027C377 cmpeax, dword ptr 77C327A077C09E32A3 9C27C377movdword ptr 77C3279C, eax77C09E37 73 E3jnbshort 77C09E1C77C09E3968 B012BE77push77BE12B077C09E3E68 A012BE77push77BE12A077C09E43E8 1FFFFFFFcall_initterm77C09E4859popecx77C09E4959popecx77C09E4A68 BC12BE77push77BE12BC77C09E4F68 B412BE77push77BE12B477C09E54E8 0EFFFFFFcall_initterm77C09E5959popecx77C09E5A59popecx77C09E5B85DBtestebx, ebx77C09E5D74 0Bjeshort 77C09E6A77C09E5F6A 08push877C09E61E8 B3060000call_unlock77C09E6659popecx77C09E675Epopesi77C09E685Dpopebp77C09E69C3retn77C09E6AFF75 08pushdword ptr ebp+877C09E6D8935 541AC377 movdword ptr 77C31A54, esi77C09E73E8 9BFEFFFFcall77C09D1377C09E78CCint3该段代码依然不是EXE领空里的 继续在其入口处 77C09DDB 下断点.后重载EXE按F9到该断点处.可以看到如下的堆栈情况.0012FF20 77C09E90 返回到 MSVCRT.77C09E90 来自 MSVCRT.77C09DDB再转到汇编 77C09E90 处77C09E7E 8BFFmovedi, edi; vc运行时库中的 exit 函数入口77C09E8055pushebp77C09E818BECmovebp, esp77C09E8353pushebx77C09E846A 00push077C09E86FF75 08pushdword ptr ebp+877C09E8933DBxorebx, ebx77C09E8BE8 4BFFFFFFcall77C09DDB77C09E9059popecx77C09E9159popecx77C09E925Bpopebx77C09E935Dpopebp77C09E94C3retn继续在 77C09E7E 下断,重载OD,F9运行,出现如下堆栈数据0012FF34 0040228E /CALL 到 exit 来自 QQGame.004022880012FF38 00000000 status = 0OD已经提示我们,该CALL的名称就是 vc+ 里的 exit 函数,等同于易语言核心库里的 结束() 函数一样.QQGame.00402288 看到这个,是多么振奋人心的一件事哇,终于可以到 EXE领空了.在汇编窗口转到 00402288 处,正是QQGame领空.下面这段汇编子程序的代码可长了,哎!00402150 /$ 55pushebp; 子程序入口处,也是EXE程序的入口点00402151 |. 8BECmovebp, esp00402153 |. 6A FFpush-100402155 |. 68 38314000push004031380040215A |. 68 D6224000push; SE 处理程序安装0040215F |. 64:A1 00000000 moveax, dword ptr fs:000402165 |. 50pusheax00402166 |. 64:8925 0000000 movdword ptr fs:0, esp0040216D |. 83EC 68subesp, 6800402170 |. 53pushebx00402171 |. 56pushesi00402172 |. 57pushedi00402173 |. 8965 E8movdword ptr ebp-18, esp00402176 |. 33DBxorebx, ebx00402178 |. 895D FCmovdword ptr ebp-4, ebx0040217B |. 6A 02push20040217D |. FF15 A8304000 calldword ptr ; MSVCRT._set_app_type00402183 |. 59popecx00402184 |. 830D 28454000 F ordword ptr 404528, FFFFFFFF0040218B |. 830D 2C454000 F ordword ptr 40452C, FFFFFFFF00402192 |. FF15 A4304000 calldword ptr ; MSVCRT._p_fmode00402198 |. 8B0D 1C444000 movecx, dword ptr 40441C0040219E |. 8908movdword ptr eax, ecx004021A0 |. FF15 E8304000 calldword ptr ; MSVCRT._p_commode004021A6 |. 8B0D 18444000 movecx, dword ptr 404418004021AC |. 8908movdword ptr eax, ecx004021AE |. A1 9C304000moveax, dword ptr 004021B3 |. 8B00moveax, dword ptr eax004021B5 |. A3 24454000movdword ptr 404524, eax004021BA |. E8 16010000call004022D5004021BF |. 391D 70424000 cmpdword ptr 404270, ebx004021C5 |. 75 0Cjnzshort 004021D3004021C7 |. 68 D2224000push004022D2004021CC |. FF15 98304000 calldword ptr ; MSVCRT._setusermatherr004021D2 |. 59popecx004021D3 | E8 E8000000call004022C0004021D8 |. 68 0C404000push0040400C004021DD |. 68 08404000push00404008004021E2 |. E8 D3000000call004021E7 |. A1 14444000moveax, dword ptr 404414004021EC |. 8945 94movdword ptr ebp-6C, eax004021EF |. 8D45 94leaeax, dword ptr ebp-6C004021F2 |. 50pusheax004021F3 |. FF35 10444000 pushdword ptr 404410004021F9 |. 8D45 9Cleaeax, dword ptr ebp-64004021FC |. 50pusheax004021FD |. 8D45 90leaeax, dword ptr ebp-7000402200 |. 50pusheax00402201 |. 8D45 A0leaeax, dword ptr ebp-6000402204 |. 50pusheax00402205 |. FF15 90304000 calldword ptr ; MSVCRT._getmainargs0040220B |. 68 04404000push0040400400402210 |. 68 00404000push0040400000402215 |. E8 A0000000call0040221A |. 83C4 24addesp, 240040221D |. A1 8C304000moveax, dword ptr 00402222 |. 8B30movesi, dword ptr eax00402224 |. 8975 8Cmovdword ptr ebp-74, esi00402227 |. 803E 22cmpbyte ptr esi, 220040222A |. 75 3Ajnzshort 004022660040222C | 46/incesi0040222D |. 8975 8C|movdword ptr ebp-74, esi00402230 |. 8A06|moval, byte ptr esi00402232 |. 3AC3|cmpal, bl00402234 |. 74 04|jeshort 0040223A00402236 |. 3C 22|cmpal, 2200402238 |. 75 F2jnzshort 0040222C0040223A | 803E 22cmpbyte ptr esi, 220040223D |. 75 04jnzshort 004022430040223F | 46incesi00402240 |. 8975 8Cmovdword ptr ebp-74, esi00402243 | 8A06moval, byte ptr esi00402245 |. 3AC3cmpal, bl00402247 |. 74 04jeshort 0040224D00402249 |. 3C 20cmpal, 200040224B |. 76 F2jbeshort 0040223F0040224D | 895D D0movdword ptr ebp-30, ebx00402250 |. 8D45 A4leaeax, dword ptr ebp-5C00402253 |. 50pusheax; /pStartupinfo00402254 |. FF15 48304000 calldword ptr ; GetStartupInfoA0040225A |. F645 D0 01testbyte ptr ebp-30, 10040225E |. 74 11jeshort 0040227100402260 |. 0FB745 D4movzx eax, word ptr ebp-2C00402264 |. EB 0Ejmpshort 0040227400402266 | 803E 20/cmpbyte ptr esi, 2000402269 |. 76 D8|jbeshort 004022430040226B |. 46|incesi0040226C |. 8975 8C|movdword ptr ebp-74, esi0040226F |. EB F5jmpshort 0040226600402271 | 6A 0Apush0A00402273 |. 58popeax00402274 | 50pusheax00402275 |. 56pushesi00402276 |. 53pushebx00402277 |. 53pushebx; /pModule00402278 |. FF15 28304000 calldword ptr ; GetModuleHandleA0040227E |. 50pusheax0040227F |. E8 F1FDFFFFcall00402075; 禁止双开的关健CALL100402284 |. 8945 98movdword ptr ebp-68, eax00402287 |. 50pusheax; /status00402288 |. FF15 88304000 calldword ptr ; exit0040228E |. 8B45 ECmoveax, dword ptr ebp-1400402291 |. 8B08movecx, dword ptr eax00402293 |. 8B09movecx, dword ptr ecx00402295 |. 894D 88movdword ptr ebp-78, ecx00402298 |. 50pusheax00402299 |. 51pushecx0040229A |. E8 15000000call0040229F |. 59popecx004022A0 |. 59popecx004022A1 . C3retn; 子程序尾注意这段汇编代码上红色的代码.首先说最上面的那个,00402150 是这个子程序的入口处,同时也是这个EXE的入口点.当OD载入QQ游戏大厅时正是停留在00402150 这个入口点上.靠,得来全不费功夫,跑了那么大的一个圈,搞来搞去的原来就是最初的入口点上.为什么会这样呢?因为禁止双开的功能,一般都是在进程刚起动的不远处进行,没必要让一个程序运行了一大堆的功能后,再去判断有没有双进程存在,然后再关闭.但对于加壳的程序,一般EXE的入口被被改了,改成了壳的入口点.所以禁止双开的功能就未必在OD载入时停留的入口点上了.当然即可以从 ExitProcess 进行逆推,也可以从最初的入口点一个一个的CALL往下调试直到发现禁止双开的功能,这就得视个人的爱好了.现在回到正题上.上文也有说过,禁止双开的功能,一般都在终止进程的附近.这个汇编函数体挺大的,里面的CALL也不少.现在我们用F8单步步过的方式,一个个CALL调试过去.每调试步过一

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论