支付宝com组件分析

2014-11-15 17:06:33 41 18227
所需基础请阅读<<COM本质论>>
如果你此前从未玩过COM.

那么首先运行  Install.bat 安装COM

然后运行 HtmlCom.htm  (如果不能打开程序,尝试使用IE浏览器)

每次运行都会加载COM组件,浏览器都会有个提示


打开后,你就能看到CM程序了
工具: ie 6.0  od1.0 支付宝
环境:xp sp3

在Ddv群里面有个朋友问我怎样给淘宝的密码框发送诸如wm_settext之类的消息. 心想现在也没工作了,反正闲着也是闲着,就看看.首先直接打开www.支付宝.com 可以看到,密码框处会提示 请先安装控件. 然后浏览器上方会显示 需要下载的文件.

我们只要点击下载文件然后安装,安装后,直接刷新或者重新打开浏览器即可.
印象中,安装控件有的时候下载是exe文件,有的时候是直接下载com组件(非exe)

安装好了之后,我们就可以正常的登录了.我们来写一个发消息的,看看是否如那位朋友所说.

代码:
Private Sub Command1_Click()
    SendMessage &H10B90, WM_SETTEXT, 0, "bjbl"
End Sub
点了按钮之后果真没有反映.
我们首先要确定消息是否有到达.
可以打开spy来看看.

通过spy回显,我们可以知道消息是已经到达了.
但是 fSucceeded:False 的提示.我们现在知道消息是到达的.
只是支付宝处理(过滤掉)了.

那么我们就来看看支付宝做了哪些”手脚”.

我们大家都知道支付宝是b/s框架的.(好像也有c/s的,本文只讲b/s).
我们来打开一个browser 然后看一下他用了哪些模块.
这里browser我用的ie 6.0  模块查看工具用的 xuetr(它支持直接显示非系统模块)

我们可以直观的看出目录为 3.6.0.0 的模块是可疑的.
既然是b/s那这些模块肯定就是com程序.
下面我们直接用od 加载 ie . 看看它的导出函数.
我们随便找个aliedit.dll 模块看看.

通过那四个 DLLxxxxx 的导出函数名,我们就能基本判定这个是com了.
Com的程序怎么分析? 看雪有一篇贴子有详细的介绍如何分析.

链接:跟踪调试COM组件的接口

文中的方法大致就是对oleaut32.dispcallfunc 下断点.然后com里面调用了哪些函数就都会断下来.

我自己写了一个com程序,用了这个方法试了一下,并没有断下来 :(
而支付宝断是会断下来,但并不是响应我们想要他断下来的消息.当我们输入密码的时候.它并不会断下来. 所以这个贴子的方法,对于我们来说,是没有用的 :(

这里给出另一种可用的方法.
首先go到 user32.getwindowthreadprocessid 这个函数下.
77D18A80 user32.> $  8BFF          mov edi,edi
77D18A82          .  55            push ebp
77D18A83          .  8BEC          mov ebp,esp
77D18A85          .  56            push esi
77D18A86          .  FF75 08       push dword ptr ss:[ebp+8]
77D18A89          .  E8 38000000   call user32.77D18AC6
77D18A8E          .  8BF0          mov esi,eax
77D18A90          .  85F6          test esi,esi
77D18A92          .  74 28         je short user32.77D18ABC
77D18A94          .  E8 BCFBFFFF   call user32.77D18655
77D18A99          .  3BF0          cmp esi,eax
77D18A9B          .^ 0F85 49FCFFFF jnz user32.77D186EA
77D18AA1          .  8B4D 0C       mov ecx,dword ptr ss:[ebp+C]
77D18AA4          .  85C9          test ecx,ecx
77D18AA6          .  74 0B         je short user32.77D18AB3
77D18AA8          .  64:A1 1800000>mov eax,dword ptr fs:[18]
77D18AAE          .  8B40 20       mov eax,dword ptr ds:[eax+20]
77D18AB1          .  8901          mov dword ptr ds:[ecx],eax
77D18AB3          >  64:A1 1800000>mov eax,dword ptr fs:[18]
77D18AB9          .  8B40 24       mov eax,dword ptr ds:[eax+24]
77D18ABC          >  5E            pop esi
77D18ABD          .  5D            pop ebp
77D18ABE          .  C2 0800       retn 8
其中
77D18A9B          .^\0F85 49FCFFFF jnz user32.77D186EA
这里就是关键.

我们在go到 77D186EA 处
77D186EA          > /8B75 0C       mov esi,dword ptr ss:[ebp+C]
77D186ED          . |85F6          test esi,esi
77D186EF          . |74 0C         je short user32.77D186FD
77D186F1          . |6A 00         push 0
77D186F3          . |FF75 08       push dword ptr ss:[ebp+8]
77D186F6          . |E8 E0FFFFFF   call user32.77D186DB
77D186FB          . |8906          mov dword ptr ds:[esi],eax
77D186FD          > |6A 01         push 1
77D186FF          . |FF75 08       push dword ptr ss:[ebp+8]
77D18702          . |E8 D4FFFFFF   call user32.77D186DB
77D18707          . |E9 B0030000   jmp user32.77D18ABC
77D1870C          $ |55            push ebp
77D1870D          . |8BEC          mov ebp,esp
77D1870F          . |56            push esi
77D18710          . |57            push edi
77D18711          . |53            push ebx
77D18712          . |68 CDABBADC   push DCBAABCD
77D18717          . |56            push esi
77D18718          . |FF75 18       push dword ptr ss:[ebp+18]
77D1871B          . |FF75 14       push dword ptr ss:[ebp+14]
77D1871E          . |FF75 10       push dword ptr ss:[ebp+10]
77D18721          . |FF75 0C       push dword ptr ss:[ebp+C]
77D18724          . |64:A1 1800000>mov eax,dword ptr fs:[18]
77D1872A          . |8088 B40F0000>or byte ptr ds:[eax+FB4],1
77D18731          . |FF55 08       call near dword ptr ss:[ebp+8]
77D18734          . |64:8B0D 18000>mov ecx,dword ptr fs:[18]
77D1873B          . |80A1 B40F0000>and byte ptr ds:[ecx+FB4],0
77D18742          . |817C24 04 CDA>cmp dword ptr ss:[esp+4],DCBAABCD
77D1874A          . |0F85 607C0200 jnz user32.77D403B0
77D18750          > |83C4 08       add esp,8
77D18753          . |5B            pop ebx
77D18754          . |5F            pop edi
77D18755          . |5E            pop esi
77D18756          . |5D            pop ebp
77D18757          . |C2 1400       retn 14
其中下面这句就是com的毕竟桥梁.我们在这里下个f2断点即可.
77D18731          . |FF55 08       call near dword ptr ss:[ebp+8]
我们还可以用另外一个方法.直接搜索这个数值: 0xDCBAABCD.
References in user32:.text to constant DCBAABCD
Address    Disassembly  
77D186F3   push dword ptr ss:[ebp+8]
77D18712   push DCBAABCD
77D18742   cmp dword ptr ss:[esp+4],DCBAABCD
77D403B0   cmp dword ptr ss:[esp],DCBAABCD
会有上面四个结果, 双击 cmp dword ptr ss:[esp+4],DCBAABCD 这一句进去.
这样就会看到和上面一个方法一样的结果了.

我们在刚刚 77D18731  com必经桥梁下好断点后.现在就可以去输入密码.
我们会发现还没有等我们输入密码,od就已经断下来了.
断下来我们可以看信息窗口显示.
Stack ss:[0013EA90]=06740FB0
我们go到 06740FB0 处.

从图中我们可以看出,当前是主线程.
而在06740FB8 处 可以看到,将要跳向flash32 这个com.
那么我们就可以认为这个是和我们无关的,我们直接f9.

又断下来了,我们接着看信息窗口.
Stack ss:[0013E464]=75F4348B (BROWSEUI.75F4348B)
这下,我们直接从信息窗口中可以看出是 browseui 这个模块.
我们一直f9 会发现一直中断在这几个无关的模块下.
那么我们可以用条件断点过滤掉.

我们首先看一下我们判断的那几个模块的地址.
Executable modules
Base       Size        Entry       Name
07BF0000   00098000   07C852D0   Alidcp.dll
07A30000   000BC000   07AE90E0   aliedit.dll
07070000   0001D000   0707820C   itrusenroll.dll
10000000   000C5000   100C2640   npAliSecCtrl.dll
070A0000   00021000   070B19AB   pta.dll
00400000   00019000   00402451   IEXPLORE.EXE
知道地址后,我们可以对着必经桥梁按下shift+f2 写入下面的条件断点.

因为这几个模块地址的跨度比较大,为了省时间就不写复杂的条件语句了.
我们就一个一个的试过去.

aliedit.dll
[ebp+8]>=7a30000&[ebp+8]<=7AEC000
Alidcp.dll
[ebp+8]>=7bf0000&[ebp+8]<=7C88000
itrusenroll.dll
[ebp+8]>=7070000&[ebp+8]<=708D000
npAliSecCtrl.dll
[ebp+8]>=10000000&[ebp+8]<=100C5000
pta.dll
[ebp+8]>=70A0000&[ebp+8]<=70C1000
IEXPLORE.EXE
[ebp+8]>=400000&[ebp+8]<=419000
全部试下来,发现都没有中断.这是哪里的问题?
大家还记得刚刚中断的时候,是在主线程里面吧?所以我们这样写是不行的.
应该像下面这样.
[ebp+8]!=06740FB0&[ebp+8]<=7a30000
断下来了,看信息窗口.
Stack ss:[0013E77C]=06660F90
GO过去看反汇编.
06660F90           C74424 04 104BE>mov dword ptr ss:[esp+4],2E44B10
06660F98         - E9 D8529A09     jmp npAliSec.10006275
可以看到这时才是jmp 到 支付宝的模块里面了.
用此方法可以方便的定位到支付宝的com组件处理流程里面.
此方法我也测试过我写的com demo,也是可以轻松定位到的 :)

剩下的我们就是直接到 10006275分析即可.
之前的条件断点取消掉,在 10006275处下断点. F9运行.
10006275         /.  55            push ebp
10006276         |.  8BEC          mov ebp,esp
10006278         |.  83EC 24       sub esp,24
1000627B         |.  56            push esi
1000627C         |.  8B75 08       mov esi,[arg.1]
1000627F         |.  85F6          test esi,esi
10006281         |.  0F84 C1000000 je npAliSec.10006348
10006287         |.  8B06          mov eax,dword ptr ds:[esi]
10006289         |.  85C0          test eax,eax
1000628B         |.  0F84 B7000000 je npAliSec.10006348
10006291         |.  837E 1C 00    cmp dword ptr ds:[esi+1C],0
10006295         |.  0F84 AD000000 je npAliSec.10006348
1000629B         |.  57            push edi
1000629C         |.  6A 01         push 1
1000629E         |.  FF75 14       push [arg.4]
100062A1         |.  8D4D DC       lea ecx,[local.9]
100062A4         |.  FF75 10       push [arg.3]
100062A7         |.  FF75 0C       push [arg.2]
100062AA         |.  50            push eax
100062AB         |.  E8 B8F4FFFF   call npAliSec.10005768
100062B0         |.  FF76 20       push dword ptr ds:[esi+20]
100062B3         |.  8B7E 24       mov edi,dword ptr ds:[esi+24]
100062B6         |.  8B4E 1C       mov ecx,dword ptr ds:[esi+1C]
100062B9         |.  8D55 08       lea edx,[arg.1]
100062BC         |.  52            push edx
100062BD         |.  FF75 14       push [arg.4]
100062C0         |.  8D45 DC       lea eax,[local.9]
100062C3         |.  FF75 10       push [arg.3]
100062C6         |.  8946 24       mov dword ptr ds:[esi+24],eax
100062C9         |.  FF75 0C       push [arg.2]
100062CC         |.  8B01          mov eax,dword ptr ds:[ecx]
100062CE         |.  FF36          push dword ptr ds:[esi]
100062D0         |.  FF10          call near dword ptr ds:[eax]
100062D2         |.  897E 24       mov dword ptr ds:[esi+24],edi
100062D5         |.  85C0          test eax,eax
100062D7         |.  75 69         jnz short npAliSec.10006342
100062D9         |.  53            push ebx
100062DA         |.  BB 82000000   mov ebx,82
100062DF         |.  395D 0C       cmp [arg.2],ebx
100062E2         |.  74 15         je short npAliSec.100062F9
100062E4         |.  FF75 14       push [arg.4]
100062E7         |.  8BCE          mov ecx,esi
100062E9         |.  FF75 10       push [arg.3]
100062EC         |.  FF75 0C       push [arg.2]
100062EF         |.  E8 B5F3FFFF   call npAliSec.100056A9
100062F4         |.  8945 08       mov [arg.1],eax
100062F7         |.  EB 48         jmp short npAliSec.10006341
100062F9         |>  8B06          mov eax,dword ptr ds:[esi]
100062FB         |.  8B3D ECF20710 mov edi,dword ptr ds:[1007F2EC]
10006301         |.  6A FC         push -4
10006303         |.  50            push eax
10006304         |.  FFD7          call near edi
10006306         |.  FF75 14       push [arg.4]
10006309         |.  8BCE          mov ecx,esi
1000630B         |.  FF75 10       push [arg.3]
1000630E         |.  8945 0C       mov [arg.2],eax
10006311         |.  53            push ebx
10006312         |.  E8 92F3FFFF   call npAliSec.100056A9
10006317         |.  8945 08       mov [arg.1],eax
1000631A         |.  8B46 18       mov eax,dword ptr ds:[esi+18]
1000631D         |.  3B05 D4F20710 cmp eax,dword ptr ds:[1007F2D4]
10006323         |.  74 19         je short npAliSec.1000633E
10006325         |.  8B06          mov eax,dword ptr ds:[esi]
10006327         |.  6A FC         push -4
10006329         |.  50            push eax
1000632A         |.  FFD7          call near edi
1000632C         |.  3B45 0C       cmp eax,[arg.2]
1000632F         |.  75 0D         jnz short npAliSec.1000633E
10006331         |.  FF76 18       push dword ptr ds:[esi+18]
10006334         |.  6A FC         push -4
10006336         |.  FF36          push dword ptr ds:[esi]
10006338         |.  FF15 E8F20710 call near dword ptr ds:[1007F2E8]
1000633E         |>  8326 00       and dword ptr ds:[esi],0
10006341         |>  5B            pop ebx
10006342         |>  8B45 08       mov eax,[arg.1]
10006345         |.  5F            pop edi
10006346         |.  EB 02         jmp short npAliSec.1000634A
10006348         |>  33C0          xor eax,eax
1000634A         |>  5E            pop esi
1000634B         |.  C9            leave
1000634C         \.  C2 1000       retn 10
立马中断, 再F9运行,又中断, 如是重复, 再通过堆栈观察不难看出是下面四个参数.
BOOL IsDealMsg( 
                LPMSG lpMsg,        // message information
                HWND  hWnd,         // handle to window
                UINT  wMsgFilterMin,// first message
                UINT  wMsgFilterMax // last message);
我们把里面的msg都纪录一下.大概有如下一些消息.
#define WM_SETFOCUS                     0x0007
#define WM_KILLFOCUS                    0x0008
#define WM_SETTEXT                      0x000C
#define WM_GETTEXT                      0x000D
#define WM_PAINT                        0x000F
#define WM_ERASEBKGND                  0x0014
#define WM_CANCELMODE                  0x001F
#define WM_SETCURSOR                    0x0020
#define WM_MOUSEACTIVATE                0x0021
#define WM_WINDOWPOSCHANGING         0x0046
#define WM_WINDOWPOSCHANGED          0x0047
#define WM_NCCALCSIZE                   0x0083
#define WM_NCHITTEST                    0x0084
#define WM_NCPAINT                      0x0085
#define WM_NCMOUSEMOVE               0x00A0
#define WM_CTLCOLOREDIT                 0x0133
#define WM_MOUSEFIRST                  0x0200
#define WM_LBUTTONDOWN                0x0201
#define WM_LBUTTONUP                   0x0202
#define WM_CAPTURECHANGED              0x0215
#define WM_IME_SETCONTEXT               0x0281
#define WM_IME_NOTIFY                   0x0282

#define EM_GETSEL                        0x00B0
#define EM_SETSEL                        0x00B1
我们自己发的消息是wm_settext 对应的值是 0xc
那么我们直接在函数首下个条件断点 [esp+8]==0xc 即可

断下来后我们单步,走到这里的时候不该跳的,他却跳了.所以,我们只要把这句nop掉即可
100062D7         |. /75 69         jnz short npAliSec.10006342
Nop 后, 我们来用工具测试一下.

测试是okay的.我们的目的就达到了 :)

但是大家应该能看出好像哪里还有问题.
没错,问题就出现在密码是明文的了.我们点登录测试,
也是不成功的,会提示 “系统忙,请稍候再试” 的字样.

当我们再在 10006275 处下好wm_settext 条件断点.
然后直接运行, 在密码框处 输入 “b”
然后中断看 lparam 这个参数. 里面直接显示的是 “*”

同样用工具测试的时候,查看 lparam 而是显示 “bjbl”

说明在wm_settext 之前还做了些手脚.就okay了.
考虑到有些童鞋拿去做坏事,剩下的,就不写了.后面的分析方法和前面讲的都差不多.

那位朋友又问我, 如果不patch 可以实现吗?
方法还是有很多的. 比如 patch com文件 ,(当然也可能会有Crc 文件完整性效验)

甚至我们重写一份 edit 的 com 程序,也是可以的.

本文主要还是讲解com组件的调试分析方法、就讲到这里、谢谢支持!
请管理于本帖发表后的一个小时内升级阅读权限为20。谢谢。

关于作者

easycode篇文章篇回复

评论41次

要评论?请先  登录  或  注册