逆向qqspy,实现qq2010聊天信息获取

评: QQ中的util函数暴露了很多信息啊~~

 

*******************************************************
*标题:【原创】逆向qqspy,实现qq2010聊天信息获取 *
*作者:踏雪流云                                        *
*日期:2010年9月1号                                   *
*声明:本文章的目的仅为技术交流讨论                    *
*******************************************************
小弟第一次发帖,写的不好或者错误的地方还望指正~~~
前些日子,偶然看到这个qqspy的程序可以获取qq的聊天记录,本人比较好奇,于是决定分析分析它是如何实现的;终于皇天不负有心人,被小弟看出了端倪,特来与大家分享。。。
程序下载地址为:http://www.myqqspy.cn/
程序说明如下:
家庭上网侦察员6.3家庭上网侦察员 V6.3 又名:QQ间谍、QQ聊天记录工具、QQ聊天监视工具、QQ2010聊天记录工具、QQ2009聊天记录工具、QQ聊天记录器、MSN聊天记录器 是目前唯一一款兼容 WINDOWS XP、VISTA、WINDOWS7,又支持QQ、MSN聊天软件的一款聊天监控软件,完美兼容QQ2010、MSN最新版,欢迎免费试用,试用满意后付款!
我下载的是试用版进行分析,共有5个文件,分别是:qqspy.exe、db.dll、im32.dll、msimg32.dll、base.ini。下面先简单介绍下各个文件的作用:
qqspy.exe主程序,负责聊天记录的显示与功能的设置。
db.dll数据模块,封装了SQLite功能,把聊天记录存储为SQLite数据库格式文件;并使用ADVAPI32对此SQLite数据库进行SHA加密保护。
im32.dll聊天记录获取模块,负责聊天记录的获取并保存在聊天记录文件中。
msimg32貌似是QQ录音机软件模块的dll,QQ在启动的时候会加载msimg32.dll文件;而此文件已被修改,负责加载im32.dll模块,这样im32.dll模块就可被QQ加载了。
base.ini数据记录文件,记录QQ聊天记录,记录密码、配置、注册等信息,SQLite数据库格式,并用SHA算法加密。
将上述5个文件都放入QQ的bin目录下,开始进行分析:
首先,im32.dll被加了壳,先脱壳;然后,用OD加载im32.dll文件,ctrl+N打开当前模块中的名称:
名称:  1.JPG
查看次数: 1822
文件大小:  63.7 KB
发现kernel32.WriteProcessMemory和kernel32.VirtualProtect两个API比较可以,这让我想到了APIHook技术,在kernel32.WriteProcessMemory行回车,来到函数参考:

代码:
10001F73  |.  52            push    edx                              ; /ProcessId
10001F74  |.  6A 00         push    0                                ; |Inheritable = FALSE
10001F76  |.  6A 38         push    38                               ; |Access = VM_OPERATION|VM_READ|VM_WRITE
10001F78  |.  FF15 AC400210 call    dword ptr [<&KERNEL32.OpenProces>; /OpenProcess
10001F7E  |.  8B4E 04       mov     ecx, dword ptr [esi+4]
10001F81  |.  6A 00         push    0                                ; /pBytesWritten = NULL
10001F83  |.  8BF8          mov     edi, eax                         ; |
10001F85  |.  8B46 0C       mov     eax, dword ptr [esi+C]           ; |
10001F88  |.  50            push    eax                              ; |BytesToWrite
10001F89  |.  51            push    ecx                              ; |Buffer
10001F8A  |.  53            push    ebx                              ; |Address
10001F8B  |.  57            push    edi                              ; |hProcess
10001F8C  |.  FF15 C8400210 call    dword ptr [<&KERNEL32.WriteProce>; /WriteProcessMemory
10001F92  |.  8B0E          mov     ecx, dword ptr [esi]
10001F94  |.  6A 00         push    0                                ; /pOldProtect = NULL
10001F96  |.  8BE8          mov     ebp, eax                         ; |
10001F98  |.  8B4424 0C     mov     eax, dword ptr [esp+C]           ; |
10001F9C  |.  50            push    eax                              ; |NewProtect
10001F9D  |.  51            push    ecx                              ; |Size
10001F9E  |.  53            push    ebx                              ; |Address
10001F9F  |.  FF15 BC400210 call    dword ptr [<&KERNEL32.VirtualPro>; /VirtualProtect
10001FA5  |.  57            push    edi                              ; /hObject
10001FA6  |.  FF15 50400210 call    dword ptr [<&KERNEL32.CloseHandl>; /CloseHandle
下断后,运行QQ程序,很快命中断点,F8,发现WriteProcessMemory的BytesToWrite参数为5,应该是APIHook没错了;第一次Hook的函数为ole32.CoRegisterClassObject,不是我们要找到;F9,第二次Hook的函数为0149FE30   3182B3B0  KernelUt.Util::Msg::SaveMsg函数,它是QQ KernelUt模块的导出函数,这就是我们要找的函数了。
这时,我们来到KernelUt.Util::Msg::SaveMsg函数位置:
代码:
3182B3B0 >/$- E9 4B4CB6D0   jmp     02390000
3182B3B5  |.  68 88DB8531   push    3185DB88
3182B3BA  |.  64:A1 0000000>mov     eax, dword ptr fs:[0]
3182B3C0  |.  50            push    eax
3182B3C1  |.  83EC 38       sub     esp, 38
3182B3C4  |.  53            push    ebx
3182B3C5  |.  56            push    esi
3182B3C6  |.  57            push    edi
jmp     02390000就是Hook函数位置了。跳到02390000位置:
代码:
02390000    F0:FF05 C049FE0>lock inc dword ptr [FE49C0]
02390007    60              pushad
02390008    9C              pushfd
02390009    64:A1 18000000  mov     eax, dword ptr fs:[18]
0239000F    8B40 34         mov     eax, dword ptr [eax+34]
02390012    50              push    eax
02390013    8BD4            mov     edx, esp
02390015    68 00000000     push    0
0239001A    B9 8849FE00     mov     ecx, 0FE4988
0239001F    E8 0C2DC0FE     call    im32.00F92D30
02390024    5A              pop     edx
02390025    64:A1 18000000  mov     eax, dword ptr fs:[18]
0239002B    83C0 34         add     eax, 34
0239002E    8910            mov     dword ptr [eax], edx
02390030    9D              popfd
02390031    61              popad
02390032    F0:FF0D C049FE0>lock dec dword ptr [FE49C0]
02390039    C3              retn
在0239001F    E8 0C2DC0FE     call    im32.00F92D30行下断;然后F9,等QQ成功启动后,找个人发个QQ信息,就命中断点了。这时,F7跟进:
代码:
00F92D30  /.  55            push    ebp
00F92D31  |.  8BEC          mov     ebp, esp
00F92D33  |.  83E4 F8       and     esp, FFFFFFF8
00F92D36  |.  83EC 30       sub     esp, 30
00F92D39  |.  56            push    esi
00F92D3A  |.  8BF1          mov     esi, ecx
00F92D3C  |.  8B46 1C       mov     eax, dword ptr [esi+1C]
00F92D3F  |.  57            push    edi
00F92D40  |.  8BFA          mov     edi, edx
00F92D42  |.  894424 28     mov     dword ptr [esp+28], eax
00F92D46  |.  FF15 0C48FC00 call    dword ptr [FC480C]               ;  ntdll.NtCurrentTeb
00F92D4C  |.  8B57 14       mov     edx, dword ptr [edi+14]
00F92D4F  |.  894424 24     mov     dword ptr [esp+24], eax
00F92D53  |.  8B45 08       mov     eax, dword ptr [ebp+8]
00F92D56  |.  83C2 04       add     edx, 4
00F92D59  |.  837E 20 00    cmp     dword ptr [esi+20], 0
00F92D5D  |.  8D4C24 30     lea     ecx, dword ptr [esp+30]
00F92D61  |.  C74424 30 000>mov     dword ptr [esp+30], 0
00F92D69  |.  894C24 2C     mov     dword ptr [esp+2C], ecx
00F92D6D  |.  897424 34     mov     dword ptr [esp+34], esi
00F92D71  |.  895424 14     mov     dword ptr [esp+14], edx
00F92D75  |.  897C24 18     mov     dword ptr [esp+18], edi
00F92D79  |.  C74424 20 000>mov     dword ptr [esp+20], 0
00F92D81  |.  894424 1C     mov     dword ptr [esp+1C], eax
00F92D85  |.  75 22         jnz     short 00F92DA9
00F92D87  |.  833D F047FC00>cmp     dword ptr [FC47F0], 0
00F92D8E  |.  75 19         jnz     short 00F92DA9
00F92D90  |.  8B56 04       mov     edx, dword ptr [esi+4]
00F92D93  |.  8B02          mov     eax, dword ptr [edx]
00F92D95  |.  8D7E 04       lea     edi, dword ptr [esi+4]
00F92D98  |.  8BCF          mov     ecx, edi
00F92D9A  |.  FFD0          call    eax
00F92D9C  |.  84C0          test    al, al
00F92D9E  |.  74 09         je      short 00F92DA9
00F92DA0  |.  E8 3B010000   call    00F92EE0
00F92DA5  |.  85C0          test    eax, eax
00F92DA7  |.  74 16         je      short 00F92DBF
00F92DA9  |>  8B16          mov     edx, dword ptr [esi]
00F92DAB  |.  8B52 04       mov     edx, dword ptr [edx+4]
00F92DAE  |.  8D4424 14     lea     eax, dword ptr [esp+14]
00F92DB2  |.  50            push    eax
00F92DB3  |.  8BCE          mov     ecx, esi
00F92DB5  |.  FFD2          call    edx
00F92DB7  |.  5F            pop     edi
00F92DB8  |.  5E            pop     esi
00F92DB9  |.  8BE5          mov     esp, ebp
00F92DBB  |.  5D            pop     ebp
00F92DBC  |.  C2 0400       retn    4
00F92DBF  |>  8B46 18       mov     eax, dword ptr [esi+18]
00F92DC2  |.  83E0 03       and     eax, 3
00F92DC5  |.  74 1D         je      short 00F92DE4
00F92DC7  |.  8D4C24 0C     lea     ecx, dword ptr [esp+C]
00F92DCB  |.  51            push    ecx
00F92DCC  |.  8B4F 10       mov     ecx, dword ptr [edi+10]
00F92DCF  |.  894424 14     mov     dword ptr [esp+14], eax
00F92DD3  |.  8D4424 14     lea     eax, dword ptr [esp+14]
00F92DD7  |.  57            push    edi
00F92DD8  |.  894424 14     mov     dword ptr [esp+14], eax
00F92DDC  |.  E8 FFEDFFFF   call    00F91BE0
00F92DE1  |.  83C4 08       add     esp, 8
00F92DE4  |>  F646 18 01    test    byte ptr [esi+18], 1
00F92DE8  |.  75 15         jnz     short 00F92DFF
00F92DEA  |.  837C24 20 00  cmp     dword ptr [esp+20], 0
00F92DEF  |.  75 0E         jnz     short 00F92DFF
00F92DF1  |.  8B16          mov     edx, dword ptr [esi]
00F92DF3  |.  8B52 04       mov     edx, dword ptr [edx+4]
00F92DF6  |.  8D4424 14     lea     eax, dword ptr [esp+14]
00F92DFA  |.  50            push    eax
00F92DFB  |.  8BCE          mov     ecx, esi
00F92DFD  |.  FFD2          call    edx                              ;  im32.00F92E40
00F92DFF  |>  8B46 18       mov     eax, dword ptr [esi+18]
00F92E02  |.  A8 04         test    al, 4
00F92E04  |.  74 2C         je      short 00F92E32
00F92E06  |.  A8 01         test    al, 1
00F92E08  |.  75 28         jnz     short 00F92E32
00F92E0A  |.  F64424 20 01  test    byte ptr [esp+20], 1
00F92E0F  |.  74 21         je      short 00F92E32
00F92E11  |.  8D4C24 0C     lea     ecx, dword ptr [esp+C]
00F92E15  |.  51            push    ecx
00F92E16  |.  8B4F 10       mov     ecx, dword ptr [edi+10]
00F92E19  |.  8D4424 14     lea     eax, dword ptr [esp+14]
00F92E1D  |.  57            push    edi
00F92E1E  |.  C74424 18 040>mov     dword ptr [esp+18], 4
00F92E26  |.  894424 14     mov     dword ptr [esp+14], eax
00F92E2A  |.  E8 B1EDFFFF   call    00F91BE0
00F92E2F  |.  83C4 08       add     esp, 8
00F92E32  |>  5F            pop     edi
00F92E33  |.  5E            pop     esi
00F92E34  |.  8BE5          mov     esp, ebp
00F92E36  |.  5D            pop     ebp
00F92E37  /.  C2 0400       retn    4
00F92DFD  |.  FFD2          call    edx                              ;  im32.00F92E40,执行完这个call,栈里就出现了对方的QQ号码;这个call的作用大体是调用原来的KernelUt.Util::Msg::SaveMsg函数,有兴趣的同志可以跟进去看看。
执行之前:
代码:
0013F490   30021738  返回到 Common.30021738
0013F494   06C964CC  UNICODE "Addr-0x30016730"
执行之后:
代码:
0013F490   30021738  返回到 Common.30021738
0013F494   06C964CC  UNICODE "xxxxxxxx"     这个就是对方QQ号码的地址
即将宽字符串UNICODE "Addr-0x30016730"的地址填充了对方的QQ号码。
到此,已经成功的获取到了对方的QQ号码,方法是调用KernelUt.Util::Msg::SaveMsg函数后,出现在栈中。

下面分析如何找到获取聊天信息的部分:
首先,发现im32.dll里面,有多处调用kernel32.OutputDebugStringA API,于是想到使用Dbgview工具,来查看打印信息:

图中可以看出insert into chatlog (id,acc1,acc2,nickname,msg,time,issend,isgroup,chattype,sendover)打印出了聊天信息;因此,OD中查找上述字符串,找到insert into chatlog (id,acc1,acc2,nickname,msg,time,issend,isgroup,chattype,sendover) values(null,%d,%d,'%s','%s','%s',%d,%d,'%s',0)这组字符串就是了。回车,来到调用处,下断,运行QQ,聊天后,便命中断点;alt+K查看调用堆栈,发现第三行的函数有蹊跷,因为那个函数体里面调用了KernelUt.Util::Msg::GetMsgAbstract这个函数;于是在这里下断,聊天后,便命中断点;执行完这个函数就找到了我们的聊天信息了,哈哈~~~
至此,qqspy实现查看聊天记录的流程就水落石出了,总结如下:
1.利用msimg32.dll加载im32.dll。
2.在im32.dll中,Hook KernelUt.Util::Msg::SaveMsg 函数。
3.在Hook函数中,调用原KernelUt.Util::Msg::SaveMsg 函数,找到对方QQ号码。
4.在Hook函数中,调用KernelUt.Util::Msg::GetMsgAbstract函数,获取聊天信息。
是不是很简单,呵呵~~~小弟献丑了。。。利用此方法,可以将获取到的聊天信息实时发给对方或将聊天记录保存在文件中,每次启动发给对方等。
源代码很简单,就不发上来了~~~
测试环境:
名称:  4.JPG
查看次数: 1810
文件大小:  28.8 KB
效果如下图所示:
名称:  3.JPG
查看次数: 1811
文件大小:  42.4 KB

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值