1. 基础知识
1.1 协议
网络验证协议分为UDP和TCP协议。
目前市面上流行的网络验证一半都是TCP协议的。
采用TCP协议程序发送数据所用API为:send,接收数据所用API为:recv
采用UDP协议程序发送数据所用API为:WSASend,接收数据所用API为:WSARecv
在分析封包时,了解程序使用的协议类型,采用相对应抓包工具。有的抓包工具只能抓到TCP协议发送的封包数据,比如用易语言网截所写的抓包工具,那种工具只能抓到TCP协议的封包。
1.2 网络验证类型
网络验证类型常见的为:Asp验证,PHP验证,云验证,exe程序互相通信验证。
判断验证类型的例子:
Asp验证 飘零网络验证
PHP验证 可可网络验证
云验证 注册宝网络验证
1.3 课程流程
利用新浪微博建立一个简单的未加密用户名密码验证,讲解起验证形成过程,讲解后破解(课件1)
利用新浪微博建立一个简单的加密用户名密码验证,讲解起验证形成过程,讲解后破解(课件2)
讲解易语言编译出客户端,服务端验证形成过程
未加密验证用户密码
BASE64加密验证用户密码到期时间
当程序无壳时,可以用查找字符串方法寻找敏感字符串;加壳时,可以用易语言的按钮事件:FF55FC5F5E(死码),前提是这个程序是用易语言编写的。下断运行,F7步入就是主程序代码。
2. 实例
这些程序都是用易语言编写的,所以也可以当作是易语言专栏吧。
2.1 网页未加密
破解简单说下:
程序运行一下知道大概流程,载入OD寻找敏感字符串。发现登录成功在很大的一个循环里,登录失败在循环外。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 004025D7 |. 895D C0 |mov [local.16],ebx 004025DA |. 8B5D C0 |mov ebx,[local.16] 004025DD |. FF33 |push dword ptr ds:[ebx] 004025DF |. 68 766C4800 |push 课件1_网.00486C76 ; 到期时间: 004025E4 |. B9 02000000 |mov ecx,0x2 004025E9 |. E8 BEF4FFFF |call 课件1_网.00401AAC 004025EE |. 83C4 08 |add esp,0x8 004025F1 |. 8945 BC |mov [local.17],eax 004025F4 |. 6A 00 |push 0x0 004025F6 |. 6A 00 |push 0x0 004025F8 |. 6A 00 |push 0x0 004025FA |. 68 04000080 |push 0x80000004 004025FF |. 6A 00 |push 0x0 00402601 |. 68 816C4800 |push 课件1_网.00486C81 ; 登录成功 00402606 |. 68 01030080 |push 0x80000301 0040260B |. 6A 00 |push 0x0 0040260D |. 68 00000000 |push 0x0 00402612 |. 68 04000080 |push 0x80000004 00402617 |. 6A 00 |push 0x0 00402619 |. 8B45 BC |mov eax,[local.17]
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 00402655 |> \83C4 0C add esp,0xC 00402658 |. 6A 00 push 0x0 0040265A |. 6A 00 push 0x0 0040265C |. 6A 00 push 0x0 0040265E |. 68 04000080 push 0x80000004 00402663 |. 6A 00 push 0x0 00402665 |. 68 8A6C4800 push 课件1_网.00486C8A ; 登录失败 0040266A |. 68 01030080 push 0x80000301 0040266F |. 6A 00 push 0x0 00402671 |. 68 00000000 push 0x0 00402676 |. 68 04000080 push 0x80000004 0040267B |. 6A 00 push 0x0 0040267D |. 68 936C4800 push 课件1_网.00486C93 ; 账号密码不正确 00402682 |. 68 04000000 push 0x4
|
猜测登录时,程序先比对输入的用户名和某网页的所有用户名,如果存在再比对这个用户名的密码。两个都比对成功则执行登录成功的代码。
输入假用户名和假密码进入循环。
1 2 3 4 5
| 00402485 |. 50 |push eax 00402486 |. 3BC8 |cmp ecx,eax 00402488 |. 0F8F C7010000 |jg 课件1_网.00402655 ; 判断输入是否为空 0040248E |. 8B5D D0 |mov ebx,[local.12] 00402491 |. E8 ADEBFFFF |call 课件1_网.00401043
|
1 2 3 4 5
| 0040250B |. 83C4 04 |add esp,0x4 0040250E |> 837D B8 00 |cmp [local.18],0x0 00402512 |. 0F84 35010000 |je 课件1_网.0040264D ; 这个跳转跳出循环外,不能跳转 00402518 |. 8B5D CC |mov ebx,[local.13] 0040251B |. E8 23EBFFFF |call 课件1_网.00401043
|
1 2 3 4 5
| 00402595 |. 83C4 04 |add esp,0x4 00402598 |> 837D B8 00 |cmp [local.18],0x0 0040259C |. 0F84 AB000000 |je 课件1_网.0040264D ; 这个跳转跳出循环外,不能跳转 004025A2 |. 8B5D C8 |mov ebx,[local.14] 004025A5 |. E8 99EAFFFF |call 课件1_网.00401043
|
将这两个je
指令都nop掉,实现破解。
但这节课的重点不是破解,而是算法流程。
载入OD,Ctrl+B输入二进制字串FF 55 FC 5F 5E
,这是易语言的按钮事件死码。
1 2 3
| 0041E18D |> \FF55 FC call [local.1] 0041E190 |. 5F pop edi ; kernel32.7C817077 0041E191 |. 5E pop esi ; kernel32.7C817077
|
F9运行至此处,再F9出现主程序,输入用户名和密码后点击注册,程序再次停在此处,现在F7进入call指令,就是作者编写的易语言代码处了。F8步过跟踪,到这里就是将要访问的网页压栈。
1
| 00401BD1 |. 68 FA6B4800 push 课件1_网.00486BFA ; http://blog.sina.com.cn/s/blog_151e522e60102vy1h.html
|
看着貌似写了一堆奇奇怪怪的东西,先不管它。回到OD继续往下,会发现信息窗口有类似于html的字符串,在信息窗口选中右键->数据窗口中跟随数值,发现这个程序的操作是把读取网页源码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| 00177CF0 00 00 00 00 DF 00 00 00 3C 68 74 6D 6C 3E 0D 0A ....?..<html>.. 00177D00 3C 68 65 61 64 3E 0D 0A 3C 73 63 72 69 70 74 20 <head>..<script 00177D10 6C 61 6E 67 75 61 67 65 3D 22 6A 61 76 61 73 63 language="javasc 00177D20 72 69 70 74 22 3E 73 65 74 54 69 6D 65 6F 75 74 ript">setTimeout 00177D30 28 22 6C 6F 63 61 74 69 6F 6E 2E 72 65 70 6C 61 ("location.repla 00177D40 63 65 28 6C 6F 63 61 74 69 6F 6E 2E 68 72 65 66 ce(location.href 00177D50 2E 73 70 6C 69 74 28 5C 22 23 5C 22 29 5B 30 5D .split(\"#\")[0] 00177D60 29 22 2C 31 30 30 30 29 3B 3C 2F 73 63 72 69 70 )",1000);</scrip 00177D70 74 3E 0D 0A 3C 2F 68 65 61 64 3E 0D 0A 3C 69 66 t>..</head>..<if 00177D80 72 61 6D 65 20 73 72 63 3D 22 68 74 74 70 3A 2F rame src="http:/ 00177D90 2F 32 32 32 2E 32 30 31 2E 35 34 2E 36 34 3A 38 /222.201.54.64:8 00177DA0 39 2F 66 6C 61 73 68 72 65 64 69 72 2E 68 74 6D 9/flashredir.htm 00177DB0 6C 22 20 66 72 61 6D 65 62 6F 72 64 65 72 3D 30 l" frameborder=0 00177DC0 3E 3C 2F 69 66 72 61 6D 65 3E 0D 0A 3C 2F 68 74 ></iframe>..</ht 00177DD0 6D 6C 3E 0D 0A 0D 0A 68 1D 00 1E 00 31 01 08 00 ml>....h..1. 00177DE0 3C 68 74 6D 6C 3E 0D 0A 3C 68 65 61 64 3E 0D 0A <html>..<head>.. 00177DF0 3C 73 63 72 69 70 74 20 6C 61 6E 67 75 61 67 65 <script language 00177E00 3D 22 6A 61 76 61 73 63 72 69 70 74 22 3E 73 65 ="javascript">se 00177E10 74 54 69 6D 65 6F 75 74 28 22 6C 6F 63 61 74 69 tTimeout("locati 00177E20 6F 6E 2E 72 65 70 6C 61 63 65 28 6C 6F 63 61 74 on.replace(locat 00177E30 69 6F 6E 2E 68 72 65 66 2E 73 70 6C 69 74 28 5C ion.href.split(\ 00177E40 22 23 5C 22 29 5B 30 5D 29 22 2C 31 30 30 30 29 "#\")[0])",1000) 00177E50 3B 3C 2F 73 63 72 69 70 74 3E 0D 0A 3C 2F 68 65 ;</script>..</he 00177E60 61 64 3E 0D 0A 3C 69 66 72 61 6D 65 20 73 72 63 ad>..<iframe src 00177E70 3D 22 68 74 74 70 3A 2F 2F 32 32 32 2E 32 30 31 ="http://222.201 00177E80 2E 35 34 2E 36 34 3A 38 39 2F 66 6C 61 73 68 72 .54.64:89/flashr 00177E90 65 64 69 72 2E 68 74 6D 6C 22 20 66 72 61 6D 65 edir.html" frame 00177EA0 62 6F 72 64 65 72 3D 30 3E 3C 2F 69 66 72 61 6D border=0></ifram 00177EB0 65 3E 0D 0A 3C 2F 68 74 6D 6C 3E 0D 0A 0D 0A 00 e>..</html>.....
|
再往下滑看到正文的一些字符串,应该是提取这些字符串之间的字符串,存进内存里。
1 2 3 4 5 6 7 8
| 00401E97 |. 68 536C4800 push 课件1_网.00486C53 ; <p>^^^ ... (进入第一个大循环) 00401F82 |. 68 5A6C4800 |push 课件1_网.00486C5A ; $$$ ... 00402003 |. 68 5E6C4800 |push 课件1_网.00486C5E ; ### ... 00402084 |. 68 626C4800 |push 课件1_网.00486C62 ; ***
|
1 2 3 4 5 6 7
| (进入第二个大循环) 00402485 |. 50 |push eax 00402486 |. 3BC8 |cmp ecx,eax 00402488 |. 0F8F C7010000 |jg 课件1_网.00402655 ; 判断输入是否为空 ... 004024D9 |. 83C4 10 |add esp,0x10 ; 输入的用户名 004024DC |. 8945 BC |mov [local.17],eax ; 存进local.17
|
此时发现寄存器窗口的eax也是我们输入的用户名,右键->数据窗口中跟随。
1 2 3
| 00169970 61 62 63 00 01 00 00 00 02 00 02 00 3C 01 0A 00 abc......<.. 00169980 61 62 63 39 39 00 37 00 02 00 02 00 22 01 0B 00 abc99.7...". 00169990 61 62 63 31 00 01 15 00 24 00 02 00 20 01 0C 00 abc1..$.. ..
|
发现上面是\^\^\^和$$$之间的内容“abc”,下面也是\^\^\^和$$$之间的内容“abc1”。
1
| 00402512 /0F84 35010000 je 课件1_网.0040264D ; 不能跳转
|
绕过这个跳转继续往下,到达这里后eax的值为111,是$$$和###之间的内容“111”,并且对应网页,前面的字符串是“abc”。数据窗口这一行的上面也是“abc”。
1 2
| 0040255E |. E8 5F100000 |call 课件1_网.004035C2 00402563 |. 83C4 10 |add esp,0x10
|
1 2 3
| 00169970 61 62 63 00 01 00 00 00 02 00 02 00 3C 01 0C 00 abc......<.. 00169980 31 31 31 00 39 00 37 00 02 00 02 00 22 01 0B 00 111.9.7...". 00169990 61 62 63 31 00 01 15 00 24 00 02 00 20 01 0C 00 abc1..$.. ..
|
继续往下
1
| 0040259C /0F84 AB000000 je 课件1_网.0040264D ; 不能跳转
|
绕过跳转
1
| 00402630 |. E8 870F0000 |call 课件1_网.004035BC
|
运行到这里时弹窗说登录成功,到期时间无法显示。但可以猜测^^^abc$$$111###30***
这一串中的“30”应该是到期时间。所以这一串奇怪的字符其实包含了用户名、密码和到期时间。
2.2 网页加密
破解同样是修改两个跳转指令。
算法分析:与2.1同样操作来到
1
| 004019C0 |. 68 CD9D4800 push 课件2_网.00489DCD ; http://blog.sina.com.cn/s/blog_151e522e60102vzdy.html
|
这时直接在程序按照分隔符输入字符串是不对的。看到字符串有等号很明显是Base64加密。拿去解码即可得真正的用户名、密码和到期时间。
但我们这个是分析流程,所以还是继续往下看看吧
1 2 3 4 5 6 7 8 9 10
| 00401F22 |. 83C4 1C |add esp,0x1C ; 加密后的用户名(第一次循环用户名为空,第二次才显示第一行的用户名) 00401F25 |. 8945 AC |mov [local.21],eax 00401F28 |. 8D45 AC |lea eax,[local.21] 00401F2B |. 50 |push eax 00401F2C |. 68 08FA4A00 |push 课件2_网.004AFA08 00401F31 |. 8B0424 |mov eax,dword ptr ss:[esp] 00401F34 |. 8B00 |mov eax,dword ptr ds:[eax] 00401F36 |. 8B00 |mov eax,dword ptr ds:[eax] 00401F38 |. FF50 0C |call dword ptr ds:[eax+0xC] ; base64解密出来的用户名 00401F3B |. 8945 A8 |mov [local.22],eax
|
执行完base64解密的函数后,eax右键->数据窗口中跟随,就可看到解密出来的“abc”。
1
| 001702A8 01 00 00 00 03 00 00 00 61 62 63 00 75 01 08 00 ......abc.u.
|
密码和到期时间一样的操作。
2.3 EXE验证
爆破:
开启服务端,再将客户端载入OD,查找敏感字符串或设置按钮事件,找到函数段首下断运行,点击“验证”,程序停在断点处。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 004012EB |. /0F85 99000000 jnz 课件3_易.0040138A ; 不能跳 004012F1 |. |8B5D F8 mov ebx,[local.2] 004012F4 |. |E8 0BFDFFFF call 课件3_易.00401004 004012F9 |. |B8 01000000 mov eax,0x1 004012FE |. |3BC1 cmp eax,ecx ; 课件3_易.00482C3B 00401300 |. |7C 0D jl short 课件3_易.0040130F 00401302 |. |68 01000000 push 0x1 00401307 |. |E8 4E030000 call 课件3_易.0040165A 0040130C |. |83C4 04 add esp,0x4 0040130F |> |C1E0 02 shl eax,0x2 00401312 |. |03D8 add ebx,eax 00401314 |. |895D F4 mov [local.3],ebx 00401317 |. |8B5D F4 mov ebx,[local.3] 0040131A |. |FF33 push dword ptr ds:[ebx] 0040131C |. |68 442C4800 push 课件3_易.00482C44 ; 到期时间: 00401321 |. |B9 02000000 mov ecx,0x2 00401326 |. |E8 01FEFFFF call 课件3_易.0040112C
|
分析算法:与2.4一样,只是没了加密过程。
2.4 EXE加密验证
爆破与2.3一样。
分析算法:
开头同2.1,F8一步步跟踪。
1
| 00401E6E |. E8 ED250000 call 课件4_易.00404460 ; 获取输入的用户名
|
1
| 00401EC2 |. FF50 08 call dword ptr ds:[eax+0x8] ; base64加密用户名:YWJj
|
1
| 00401EE6 |. E8 75250000 call 课件4_易.00404460 ; 获取输入的密码
|
1
| 00401F3A |. FF50 08 call dword ptr ds:[eax+0x8] ; 密码base64加密:MTIz
|
1
| 00401F68 |. 8945 E0 mov [local.8],eax ; 拼接:YWJj|MTIz
|
经过retn
后F9运行,程序又回到断点处。这次F7进去代码与之前不同。
1
| 00401B42 |. 83C4 10 add esp,0x10 ; 【登录失败】|账号密码错误
|
1
| 00401B6B |. 83C4 10 add esp,0x10 ; 【登录失败】|账号密码错误
|
1
| 00401C47 |. 68 CD6E4800 push 课件4_易.00486ECD ; 【登录成功】
|
1 2
| 00401C59 |. 83F8 00 cmp eax,0x0 ; 登录成功和登录失败相比较 00401C5C 0F85 99000000 jnz 课件4_易.00401CFB ; nop掉
|
2.5 EXE加密验证2.0
1
| 004013C4 /0F85 CC020000 jnz 课件5_易.00401696
|
1
| 0040147F |. /0F8C D0010000 jl 课件5_易.00401655
|
1
| 004014CE |. /0F8E 99000000 jle 课件5_易.0040156D
|
把这三处都nop掉即可。
2.6 可可 v9.5
程序无壳,放心食用。调试选项全选,StrongOD勾选忽略某些异常。下易语言按钮事件断点FF 55 FC 5F 5E
。运行,输入账号密码,点击登录。取消断点,F7跟进,一路F8,注意堆栈窗口。
1
| 00405776 . E8 D9460000 call 第七课作.00409E54 ; 获取输入的用户名
|
1
| 004057C8 . E8 87460000 call 第七课作.00409E54 ; 获取输入的密码
|
1 2 3 4
| 00405992 . /0F84 7F000000 je 第七课作.00405A17 ; 要跳 00405998 . |8D45 F8 lea eax,dword ptr ss:[ebp-0x8] 0040599B . |50 push eax 0040599C . |E8 A4BEFFFF call 第七课作.00401845 ; 账号未找到
|
1 2 3 4 5 6 7 8 9
| 00405AB9 . /0F84 FE000000 je 第七课作.00405BBD ; 要跳 ... 00405B63 . 68 04000080 push 0x80000004 00405B68 . 6A 00 push 0x0 00405B6A . 68 14C65500 push 第七课作.0055C614 ; err 00405B6F . 68 04000080 push 0x80000004 00405B74 . 6A 00 push 0x0 00405B76 . 68 18C65500 push 第七课作.0055C618 ; signdata 00405B7B . 68 04000080 push 0x80000004
|
改变两个跳转后,F8到这,卡住,暂停+运行,程序弹出不断弹出“用户身份未校验”,还弹出了一个“暗桩”。
1
| 00405F78 . E8 D13E0000 call 第七课作.00409E4E
|
救命啊我不会!!!
跟进继续F8,到这又回到按钮事件。重载,跟进这个函数。
1
| 004087E7 |. E8 8B030000 call 第七课作.00408B77
|
发现跟进这个函数里面的408C3F
的call指令又回到按钮事件。
1
| 00408C3F |. E8 D2D6FFFF call 第七课作.00406316
|
跟进这个函数里面的4063FF
的call指令又回到按钮事件。
1
| 004063FF |. E8 0DB3FFFF call 第七课作.00401711
|
1 2 3 4 5 6 7 8 9 10
| 004087CC |. 6A FF push -0x1 004087CE |. 6A 08 push 0x8 004087D0 |. 68 7A6B0116 push 0x16016B7A 004087D5 |. 68 2B010152 push 0x5201012B 004087DA |. E8 63160000 call 第七课作.00409E42 004087DF |. 83C4 18 add esp,0x18 004087E2 |. 68 00000000 push 0x0 004087E7 |. E8 8B030000 call 第七课作.00408B77 ; 暗桩call,跟进 004087EC |. 68 01000000 push 0x1 004087F1 |. E8 81030000 call 第七课作.00408B77
|