QQPlay1.5多开分析
【标题】QQPlay1.5多开分析【作者】fatwolf08
【邮箱】fatwolf2008#163.com(请修改#)
【主页】http://hi.baidu.com/fatwolf08
【工具】OD
【平台】WinXP
------------------------------------------------------------------------
【分析过程】
目标文件QQ影音1.5版。
PEID查壳,显示是UPX壳,ESP定律脱壳ImportREC修复。可以运行。我们可以假想程序在初始化开始时就要判断有没有程序打开过,所以我们就单步跟踪看看它是如何判断的。
OD载入后,F8单步跟踪,
到达下面时窗口出现:
0056C9DF E8 A2AB0100 call 00587586
我们F7跟进,
00587586 /E9 1F000000 jmp <jmp.&mfc80u.#1198>
0058758B |E8 AC47FEFF call <jmp.&mfc80u.#1079>
00587590 |8A4C24 04 mov cl, byte ptr
00587594 |8848 14 mov byte ptr , cl
00587597 |8B4C24 08 mov ecx, dword ptr
0058759B |8948 44 mov dword ptr , ecx
0058759E |33C0 xor eax, eax
005875A0 |40 inc eax
005875A1 |C2 0800 retn 8
005875A4-|FF25 200FAF00 jmp dword ptr [<&msvcr80.#882>]
005875AA-\FF25 080CAF00 jmp dword ptr [<&mfc80u.#1198>] 跳向MFC模块
来到下面代码:
7831D25F 53 push ebx
7831D260 56 push esi
7831D261 57 push edi
7831D262 83CB FF or ebx, FFFFFFFF
7831D265 E8 CA2CFFFF call 7830FF34
7831D26A 8B70 04 mov esi, dword ptr
7831D26D E8 4F2CFFFF call 7830FEC1
7831D272 FF7424 1C push dword ptr
7831D276 8B78 04 mov edi, dword ptr
7831D279 FF7424 1C push dword ptr
7831D27D FF7424 1C push dword ptr
7831D281 FF7424 1C push dword ptr
7831D285 E8 F3CA0200 call 78349D7D
7831D28A 85C0 test eax, eax
7831D28C 74 3C je short 7831D2CA
7831D28E 85FF test edi, edi
7831D290 74 0E je short 7831D2A0
7831D292 8B07 mov eax, dword ptr
7831D294 8BCF mov ecx, edi
7831D296 FF90 98000000 call dword ptr
7831D29C 85C0 test eax, eax
7831D29E 74 2A je short 7831D2CA
7831D2A0 8B06 mov eax, dword ptr
7831D2A2 8BCE mov ecx, esi
7831D2A4 FF50 58 call dword ptr 此处CALL将出现窗口
7831D2A7 85C0 test eax, eax
7831D2A9 75 16 jnz short 7831D2C1
F7跟进上面的CALL:
004CDB60 55 push ebp
004CDB61 8BEC mov ebp, esp
004CDB63 6A FF push -1
004CDB65 68 2F756300 push 0063752F
004CDB6A 64:A1 00000000mov eax, dword ptr fs:
004CDB70 50 push eax
。。。。。。。。。。。。。
。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。。。
。。。。。。。。。。。。。。。。。。。。。。。。。。
004CDCE3 68 64318900 push 00893164 ; UNICODE "QQPlayer Window"
004CDCE8 6A 01 push 1
004CDCEA 6A 00 push 0
004CDCEC FF15 5003AF00 call dword ptr [<&kernel32.#94>] ; kernel32.CreateMutexW
004CDCF2 8986 A4000000 mov dword ptr , eax
004CDCF8 FF15 A802AF00 call dword ptr [<&kernel32.#361>] ; ntdll.RtlGetLastWin32Error
004CDCFE 33C9 xor ecx, ecx
004CDD00 3D B7000000 cmp eax, 0B7 ; ERROR_ALREADY_EXISTS==0xB7
004CDD05 0F94C1 sete cl
004CDD08 8BC1 mov eax, ecx
004CDD0A 85C0 test eax, eax
004CDD0C 74 16 je short 004CDD24 ; 关键跳转,不跳则不能运行
004CDD0E 8B96 A4000000 mov edx, dword ptr
004CDD14 52 push edx
004CDD15 8D8D 00FFFFFF lea ecx, dword ptr
004CDD1B E8 B018F6FF call 0042F5D0 继续查找窗口类名
004CDD20 85C0 test eax, eax
004CDD22 75 22 jnz short 004CDD46
004CDD24 FF15 B002AF00 call dword ptr [<&kernel32.#317>] ; kernel32.GetCurrentProcessId
004CDD2A 50 push eax
004CDD2B 68 40358900 push 00893540 ; UNICODE "ProcessID"
004CDD30 E8 6B690100 call 004E46A0 ; 注册表保存进程ID
在004CDCE3处压入三个参数后调用CreateMutexW函数来创建一个命名的互斥对象,名称是“QQPlayer Window”, 接着调用
GetLastError来获得错误原因,如果互斥对象的名称已经存在的话,将返回ERROR_ALREADY_EXISTS,其定义正好为0xB7,
下面就判断是不是0xB7,如果是那么就不跳转,然后程序就是进入004CDD1B的CALL。
0042F5D0 55 push ebp
0042F5D1 8BEC mov ebp, esp
0042F5D3 51 push ecx
0042F5D4 53 push ebx
0042F5D5 56 push esi
0042F5D6 8BF1 mov esi, ecx
0042F5D8 F646 1C 08 test byte ptr , 8
0042F5DC 57 push edi
0042F5DD 8975 FC mov dword ptr , esi
0042F5E0 C706 00000000 mov dword ptr , 0
0042F5E6 74 2B je short 0042F613
0042F5E8 8B45 08 mov eax, dword ptr
0042F5EB 68 30750000 push 7530
0042F5F0 50 push eax
0042F5F1 FF15 8803AF00 call dword ptr [<&kernel32.#896>] ; kernel32.WaitForSingleObject
0042F5F7 85C0 test eax, eax
0042F5F9 0F84 E1000000 je 0042F6E0
0042F5FF 5F pop edi
0042F600 C706 01000000 mov dword ptr , 1
0042F606 5E pop esi
0042F607 B8 01000000 mov eax, 1
0042F60C 5B pop ebx
0042F60D 8BE5 mov esp, ebp
0042F60F 5D pop ebp
0042F610 C2 0400 retn 4
0042F613 8B1D 8C10AF00 mov ebx, dword ptr [<&user32.#231>] ; USER32.FindWindowW
0042F619 6A 00 push 0
0042F61B 68 30798600 push 00867930 ; UNICODE "QQPlayer Window"
0042F620 C745 08 0000000>mov dword ptr , 0
0042F627 BF D0070000 mov edi, 7D0 ; 设置查找窗口时间段
0042F62C FFD3 call ebx ; 查找是否存在类名为“QQPlayer Window”的窗口
0042F62E 8BF0 mov esi, eax
0042F630 85F6 test esi, esi
0042F632 75 24 jnz short 0042F658 ; 存在则跳转
0042F634 85FF test edi, edi
0042F636 7E 1C jle short 0042F654
0042F638 6A 64 push 64
0042F63A FF15 6C02AF00 call dword ptr [<&kernel32.#836>] ; 睡眠64ms
0042F640 6A 00 push 0
0042F642 68 30798600 push 00867930 ; UNICODE "QQPlayer Window"
0042F647 FFD3 call ebx ; 继续查找
0042F649 8BF0 mov esi, eax
0042F64B 83EF 64 sub edi, 64
0042F64E 85F6 test esi, esi
0042F650^ 74 E2 je short 0042F634 ; 循环查找
0042F652 EB 04 jmp short 0042F658
0042F654 85F6 test esi, esi
0042F656 74 51 je short 0042F6A9
这个CALL是循环查找是否存在窗口类名为“QQPlayer Window”的窗口,如果不存在,那么就运行播放器,如果存在就打开这个窗口,本进程退出。
------------------------------------------------------------------------
【总结】
这种判断多开的方法是很常用的,原理就是创建一个命名的互斥对象,如果名称已经存在就查找有没有规定的窗口类名称的窗口,如果有那么就退出。
------------------------------------------------------------------------
【版权声明】本文纯属技术交流, 转载请注明作者信息并保持文章的完整, 谢谢!
[ 本帖最后由 fatwolf08 于 2010-1-25 11:39 编辑 ] 不错,学习下
页:
[1]