飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 3099|回复: 1

[原创] QQPlay1.5多开分析

[复制链接]

该用户从未签到

发表于 2010-1-25 10:39:51 | 显示全部楼层 |阅读模式
【标题】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 [esp+4]
00587594   |8848 14         mov     byte ptr [eax+14], cl
00587597   |8B4C24 08       mov     ecx, dword ptr [esp+8]
0058759B   |8948 44         mov     dword ptr [eax+44], 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 [eax+4]
7831D26D    E8 4F2CFFFF     call    7830FEC1
7831D272    FF7424 1C       push    dword ptr [esp+1C]
7831D276    8B78 04         mov     edi, dword ptr [eax+4]
7831D279    FF7424 1C       push    dword ptr [esp+1C]
7831D27D    FF7424 1C       push    dword ptr [esp+1C]
7831D281    FF7424 1C       push    dword ptr [esp+1C]
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 [edi]
7831D294    8BCF            mov     ecx, edi
7831D296    FF90 98000000   call    dword ptr [eax+98]
7831D29C    85C0            test    eax, eax
7831D29E    74 2A           je      short 7831D2CA
7831D2A0    8B06            mov     eax, dword ptr [esi]
7831D2A2    8BCE            mov     ecx, esi
7831D2A4    FF50 58         call    dword ptr [eax+58]             此处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 00000000  mov     eax, dword ptr fs:[0]
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 [esi+A4], 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 [esi+A4]
004CDD14    52              push    edx
004CDD15    8D8D 00FFFFFF   lea     ecx, dword ptr [ebp-100]
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 [esi+1C], 8
0042F5DC    57              push    edi
0042F5DD    8975 FC         mov     dword ptr [ebp-4], esi
0042F5E0    C706 00000000   mov     dword ptr [esi], 0
0042F5E6    74 2B           je      short 0042F613
0042F5E8    8B45 08         mov     eax, dword ptr [ebp+8]
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 [esi], 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 [ebp+8], 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 编辑 ]
PYG19周年生日快乐!
  • TA的每日心情
    开心
    2015-8-3 23:07
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    发表于 2010-1-25 11:37:13 | 显示全部楼层
    不错,学习下
    PYG19周年生日快乐!
    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表