-
-
[旧帖] [原创]菜鸟分析aheaddvd注册算法 0.00雪花
-
发表于: 2010-3-19 12:13 2582
-
上学期学校其他系信息安全课后的一个小题目http://tech.cuit.edu.cn/forum/thread-4719-1-1.html
今天逛论坛看到下下来分析分析,希望能对和我一样菜的新手有所帮助。
Ahead DVD Ripper是一款能将DVD备份为VCD2.0, SVCD1.0或AVI(divx...)的小工具。它制作高质量AVI , MPEG1/2格式的影片只有原始大小的1/10。
首先运行软件,随意输入111,fafageeeg
当然是试试搜索字串的方法,OD载入,搜索字符串 Invalid username or registration code 来到00412F20
---------------------------------------------------------------华丽的分割线
00412F03 . 8B4E 60 mov ecx, dword ptr [esi+60]
00412F06 . 50 push eax
00412F07 . 51 push ecx
00412F08 . C64424 18 01 mov byte ptr [esp+18], 1
00412F0D . E8 DEFCFFFF call 00412BF0
00412F12 . 83C4 08 add esp, 8
00412F15 . 85C0 test eax, eax
00412F17 . 75 15 jnz short 00412F2E ; eax不为0就成功
00412F19 . 6A 40 push 40
00412F1B . 68 982D4D00 push 004D2D98 ; ASCII "Sorry"
00412F20 . 68 6C2D4D00 push 004D2D6C ; ASCII "Invalid username or registration code "
00412F25 . 8BCE mov ecx, esi
00412F27 . E8 1C6B0800 call <jmp.&MFC42.#4224_CWnd::MessageBoxA>
00412F2C . EB 54 jmp short 00412F82
00412F2E > 8B46 60 mov eax, dword ptr [esi+60]
00412F31 . 8D4C24 04 lea ecx, dword ptr [esp+4]
00412F35 . 50 push eax
00412F36 . 68 502D4D00 push 004D2D50 ; ASCII "License To:%s "
00412F3B . 51 push ecx
00412F3C . E8 D76A0800 call <jmp.&MFC42.#2818_CString::Format>
00412F41 . 8B5424 10 mov edx, dword ptr [esp+10]
00412F45 . 83C4 0C add esp, 0C
00412F48 . 8BCE mov ecx, esi
00412F4A . 6A 40 push 40
00412F4C . 68 442D4D00 push 004D2D44 ; ASCII "Thank you"
----------------------------------------------------------------华丽的分割线
看看附近,显示License To:%s ;"Thank you"就应该是成功了,我们看到只要00412F17处的跳转实现,就表示注册成功,倒推回去,影响eax的应该是00412F0D处的CALL,所以这里非常重要,F2设个断点,重新载入程序,单步走,到00412F0D处的CALL再F7进去:
----------------------------------------------------------------华丽的分割线
00412BF0 /$ 53 push ebx
00412BF1 |. 55 push ebp
00412BF2 |. 8B6C24 0C mov ebp, dword ptr [esp+C]
00412BF6 |. 56 push esi
00412BF7 |. 57 push edi
00412BF8 |. BE 9C404F00 mov esi, 004F409C
00412BFD |. 8BC5 mov eax, ebp
00412BFF |> 8A10 /mov dl, byte ptr [eax]
00412C01 |. 8A1E |mov bl, byte ptr [esi]
00412C03 |. 8ACA |mov cl, dl
00412C05 |. 3AD3 |cmp dl, bl
00412C07 |. 75 1E |jnz short 00412C27
00412C09 |. 84C9 |test cl, cl ; cl不能为0
00412C0B |. 74 16 |je short 00412C23
00412C0D |. 8A50 01 |mov dl, byte ptr [eax+1]
00412C10 |. 8A5E 01 |mov bl, byte ptr [esi+1]
00412C13 |. 8ACA |mov cl, dl
00412C15 |. 3AD3 |cmp dl, bl
00412C17 |. 75 0E |jnz short 00412C27
00412C19 |. 83C0 02 |add eax, 2
00412C1C |. 83C6 02 |add esi, 2
00412C1F |. 84C9 |test cl, cl
00412C21 |.^ 75 DC \jnz short 00412BFF
00412C23 |> 33C0 xor eax, eax ; 不能让这里实现
00412C25 |. EB 05 jmp short 00412C2C
00412C27 |> 1BC0 sbb eax, eax
00412C29 |. 83D8 FF sbb eax, -1
00412C2C |> 85C0 test eax, eax ; eax不能为0
00412C2E |. 74 62 je short 00412C92 ; 不能让这里实现
00412C30 |. 8B7C24 18 mov edi, dword ptr [esp+18]
00412C34 |. BE 9C404F00 mov esi, 004F409C
00412C39 |. 8BC7 mov eax, edi
00412C3B |> 8A10 /mov dl, byte ptr [eax]
00412C3D |. 8A1E |mov bl, byte ptr [esi]
00412C3F |. 8ACA |mov cl, dl
00412C41 |. 3AD3 |cmp dl, bl
00412C43 |. 75 1E |jnz short 00412C63
00412C45 |. 84C9 |test cl, cl
00412C47 |. 74 16 |je short 00412C5F
00412C49 |. 8A50 01 |mov dl, byte ptr [eax+1]
00412C4C |. 8A5E 01 |mov bl, byte ptr [esi+1]
00412C4F |. 8ACA |mov cl, dl
00412C51 |. 3AD3 |cmp dl, bl
00412C53 |. 75 0E |jnz short 00412C63
00412C55 |. 83C0 02 |add eax, 2
00412C58 |. 83C6 02 |add esi, 2
00412C5B |. 84C9 |test cl, cl
00412C5D |.^ 75 DC \jnz short 00412C3B
00412C5F |> 33C0 xor eax, eax
00412C61 |. EB 05 jmp short 00412C68
00412C63 |> 1BC0 sbb eax, eax
00412C65 |. 83D8 FF sbb eax, -1
00412C68 |> 85C0 test eax, eax
00412C6A |. 74 26 je short 00412C92 ; 这里实现就失败
00412C6C |. 57 push edi
00412C6D |. 55 push ebp
00412C6E |. E8 6DF9FFFF call 004125E0 ; 这个函数使我们失败
00412C73 |. 83C4 08 add esp, 8
00412C76 |. 85C0 test eax, eax
00412C78 |. 75 0E jnz short 00412C88 ; eax不为0就成功
00412C7A |. 57 push edi
00412C7B |. 55 push ebp
00412C7C |. E8 8FFBFFFF call 00412810
00412C81 |. 83C4 08 add esp, 8
00412C84 |. 85C0 test eax, eax
00412C86 |. 74 0A je short 00412C92 ; 不能让这里实现
00412C88 |> 5F pop edi
00412C89 |. 5E pop esi
00412C8A |. 5D pop ebp
00412C8B |. B8 01000000 mov eax, 1
00412C90 |. 5B pop ebx
00412C91 |. C3 ret
00412C92 |> 5F pop edi
00412C93 |. 5E pop esi
00412C94 |. 5D pop ebp
00412C95 |. 33C0 xor eax, eax ; 不能让这里实现
00412C97 |. 5B pop ebx
00412C98 \. C3 ret
----------------------------------------------------------------华丽的分割线
我们看到这里有2个ret(00412C91,00412C98),而00412C98处的ret前面是xor eax清零,显然不能运行到这个ret,否则eax返回0回到主程序就如前面分析的会失败。。所以00412C91处的ret是关键,再倒推回去必须实现00412C78处的跳转,再倒推,00412C76处的eax就不能为0,而影响00412C76处的eax正是00412C6E处的CALL,而通过我们F8单步走,我们发现,正是因为00412C6E处的CALL使eax返回0的,所以这又是关键CALL。。F7进去:
----------------------------------------------------------------华丽的分割线
004125E0 /$ 6A FF push -1
004125E2 |. 68 40C84900 push 0049C840 ; SE 处理程序安装
004125E7 |. 64:A1 0000000>mov eax, dword ptr fs:[0]
004125ED |. 50 push eax
004125EE |. 64:8925 00000>mov dword ptr fs:[0], esp
004125F5 |. 83EC 14 sub esp, 14
004125F8 |. 8B4424 24 mov eax, dword ptr [esp+24]
004125FC |. 53 push ebx
004125FD |. 55 push ebp
004125FE |. 56 push esi
004125FF |. 57 push edi
00412600 |. 50 push eax
00412601 |. 8D4C24 18 lea ecx, dword ptr [esp+18] ; ecx 13EE80
00412605 |. E8 9E740800 call <jmp.&MFC42.#537_CString::CString>
0041260A |. 8D4C24 14 lea ecx, dword ptr [esp+14]
0041260E |. C74424 2C 000>mov dword ptr [esp+2C], 0
00412616 |. E8 57770800 call <jmp.&MFC42.#6282_CString::TrimLeft>
0041261B |. 8D4C24 14 lea ecx, dword ptr [esp+14]
0041261F |. E8 48770800 call <jmp.&MFC42.#6283_CString::TrimRight>
00412624 |. 6A 20 push 20
00412626 |. 8D4C24 18 lea ecx, dword ptr [esp+18]
0041262A |. E8 25740800 call <jmp.&MFC42.#2915_CString::GetBuffer>
0041262F |. 8B4C24 38 mov ecx, dword ptr [esp+38]
00412633 |. 8BD8 mov ebx, eax
00412635 |. 51 push ecx
00412636 |. 8D4C24 14 lea ecx, dword ptr [esp+14]
0041263A |. E8 69740800 call <jmp.&MFC42.#537_CString::CString>
0041263F |. 8D4C24 10 lea ecx, dword ptr [esp+10]
00412643 |. C64424 2C 01 mov byte ptr [esp+2C], 1
00412648 |. E8 25770800 call <jmp.&MFC42.#6282_CString::TrimLeft>
0041264D |. 8D4C24 10 lea ecx, dword ptr [esp+10]
00412651 |. E8 16770800 call <jmp.&MFC42.#6283_CString::TrimRight>
00412656 |. 6A 20 push 20
00412658 |. 8D4C24 14 lea ecx, dword ptr [esp+14]
0041265C |. E8 F3730800 call <jmp.&MFC42.#2915_CString::GetBuffer>
00412661 |. 8BD0 mov edx, eax
00412663 |. 83CE FF or esi, FFFFFFFF
00412666 |. 8BFA mov edi, edx
00412668 |. 8BCE mov ecx, esi
0041266A |. 33C0 xor eax, eax
0041266C |. 895424 20 mov dword ptr [esp+20], edx
00412670 |. F2:AE repne scas byte ptr es:[edi]
00412672 |. F7D1 not ecx
00412674 |. 49 dec ecx
00412675 |. 8BFB mov edi, ebx
00412677 |. 8BE9 mov ebp, ecx
00412679 |. 8BCE mov ecx, esi
0041267B |. F2:AE repne scas byte ptr es:[edi]
0041267D |. F7D1 not ecx
0041267F |. 49 dec ecx
00412680 |. 3BCD cmp ecx, ebp
00412682 |. 0F87 54010000 ja 004127DC ; 不能让这里实现
00412688 |. 8BFB mov edi, ebx
0041268A |. 8BCE mov ecx, esi
0041268C |. F2:AE repne scas byte ptr es:[edi]
0041268E |. F7D1 not ecx
00412690 |. 49 dec ecx
00412691 |. 0F84 45010000 je 004127DC ; 不能让这里实现
00412697 |. 8BFA mov edi, edx
00412699 |. 8BCE mov ecx, esi
0041269B |. F2:AE repne scas byte ptr es:[edi]
0041269D |. F7D1 not ecx
0041269F |. 49 dec ecx
004126A0 |. 0F84 36010000 je 004127DC ; 不能让这里实现
004126A6 |. 894424 38 mov dword ptr [esp+38], eax
004126AA |> 8B5424 38 /mov edx, dword ptr [esp+38]
004126AE |. 8D4C24 34 |lea ecx, dword ptr [esp+34]
004126B2 |. 8A82 B02C4D00 |mov al, byte ptr [edx+4D2CB0]
004126B8 |. 884424 18 |mov byte ptr [esp+18], al
004126BC |. E8 09730800 |call <jmp.&MFC42.#540_CString::CString>
004126C1 |. 8BFB |mov edi, ebx
004126C3 |. 83C9 FF |or ecx, FFFFFFFF
004126C6 |. 33C0 |xor eax, eax
004126C8 |. 33ED |xor ebp, ebp
004126CA |. F2:AE |repne scas byte ptr es:[edi]
004126CC |. F7D1 |not ecx
004126CE |. 49 |dec ecx
004126CF |. C64424 2C 02 |mov byte ptr [esp+2C], 2
004126D4 |. 74 4B |je short 00412721
004126D6 |> 8A042B |/mov al, byte ptr [ebx+ebp] ; 用户名
004126D9 |. 33F6 ||xor esi, esi ; esi清零
004126DB |> 3A0475 482C4D>||/cmp al, byte ptr [esi*2+4D2C48] ; 关键4D2C48
004126E2 |. 74 08 |||je short 004126EC
004126E4 |. 46 |||inc esi
004126E5 |. 83FE 34 |||cmp esi, 34
004126E8 |.^ 7C F1 ||\jl short 004126DB ; 小于
004126EA |. EB 11 ||jmp short 004126FD
004126EC |> 8A0C75 492C4D>||mov cl, byte ptr [esi*2+4D2C49]
004126F3 |. 51 ||push ecx
004126F4 |. 8D4C24 38 ||lea ecx, dword ptr [esp+38]
004126F8 |. E8 69760800 ||call <jmp.&MFC42.#940_CString::operator+=>
004126FD |> 83FE 34 ||cmp esi, 34
00412700 |. 75 0E ||jnz short 00412710
00412702 |. 8B5424 18 ||mov edx, dword ptr [esp+18]
00412706 |. 8D4C24 34 ||lea ecx, dword ptr [esp+34]
0041270A |. 52 ||push edx
0041270B |. E8 56760800 ||call <jmp.&MFC42.#940_CString::operator+=>
00412710 |> 8BFB ||mov edi, ebx
00412712 |. 83C9 FF ||or ecx, FFFFFFFF
00412715 |. 33C0 ||xor eax, eax
00412717 |. 45 ||inc ebp
00412718 |. F2:AE ||repne scas byte ptr es:[edi]
0041271A |. F7D1 ||not ecx
0041271C |. 49 ||dec ecx
0041271D |. 3BE9 ||cmp ebp, ecx
0041271F |.^ 72 B5 |\jb short 004126D6
00412721 |> 8B4424 34 |mov eax, dword ptr [esp+34]
00412725 |. 8B48 F8 |mov ecx, dword ptr [eax-8]
00412728 |. 83F9 10 |cmp ecx, 10
0041272B |. 7D 3A |jge short 00412767
0041272D |. 8BC1 |mov eax, ecx
0041272F |. B9 10000000 |mov ecx, 10
00412734 |. 2BC8 |sub ecx, eax
00412736 |. 8D5424 1C |lea edx, dword ptr [esp+1C]
0041273A |. 51 |push ecx
0041273B |. 52 |push edx ; EDX 13EE88
0041273C |. B9 8C155100 |mov ecx, 0051158C ; ASCII "`X<"
00412741 |. E8 1A760800 |call <jmp.&MFC42.#4129_CString::Left>
00412746 |. 50 |push eax
00412747 |. 8D4C24 38 |lea ecx, dword ptr [esp+38]
0041274B |. C64424 30 03 |mov byte ptr [esp+30], 3
00412750 |. E8 3B730800 |call <jmp.&MFC42.#939_CString::operator+=>
00412755 |. 8D4C24 1C |lea ecx, dword ptr [esp+1C]
00412759 |. C64424 2C 02 |mov byte ptr [esp+2C], 2
0041275E |. E8 5F710800 |call <jmp.&MFC42.#800_CString::~CString>
00412763 |. 8B4424 34 |mov eax, dword ptr [esp+34]
00412767 |> 8B4C24 20 |mov ecx, dword ptr [esp+20] ; 算法肯定在上面
0041276B |. 51 |push ecx ; /s2
0041276C |. 50 |push eax ; |s1
0041276D |. FF15 34F94900 |call dword ptr [<&MSVCRT._mbscmp>] ; \_mbscmp
00412773 |. 83C4 08 |add esp, 8
00412776 |. 8D4C24 34 |lea ecx, dword ptr [esp+34]
0041277A |. 85C0 |test eax, eax
0041277C |. C64424 2C 01 |mov byte ptr [esp+2C], 1
00412781 |. 74 1B |je short 0041279E
00412783 |. 33F6 |xor esi, esi
00412785 |. E8 38710800 |call <jmp.&MFC42.#800_CString::~CString>
0041278A |. 8B4424 38 |mov eax, dword ptr [esp+38]
0041278E |. 40 |inc eax
0041278F |. 83F8 03 |cmp eax, 3
00412792 |. 894424 38 |mov dword ptr [esp+38], eax
00412796 |.^ 0F8C 0EFFFFFF \jl 004126AA
0041279C |. EB 0A jmp short 004127A8
0041279E |> BE 01000000 mov esi, 1
004127A3 |. E8 1A710800 call <jmp.&MFC42.#800_CString::~CString>
004127A8 |> 8D4C24 10 lea ecx, dword ptr [esp+10]
004127AC |. C64424 2C 00 mov byte ptr [esp+2C], 0
004127B1 |. E8 0C710800 call <jmp.&MFC42.#800_CString::~CString>
004127B6 |. 8D4C24 14 lea ecx, dword ptr [esp+14]
004127BA |. C74424 2C FFF>mov dword ptr [esp+2C], -1
004127C2 |. E8 FB700800 call <jmp.&MFC42.#800_CString::~CString>
004127C7 |. 8BC6 mov eax, esi
004127C9 |. 5F pop edi
004127CA |. 5E pop esi
004127CB |. 5D pop ebp
004127CC |. 5B pop ebx
004127CD |. 8B4C24 14 mov ecx, dword ptr [esp+14]
004127D1 |. 64:890D 00000>mov dword ptr fs:[0], ecx
004127D8 |. 83C4 20 add esp, 20
004127DB |. C3 ret ; 这里返回就成功
004127DC |> 8D4C24 10 lea ecx, dword ptr [esp+10]
004127E0 |. C64424 2C 00 mov byte ptr [esp+2C], 0
004127E5 |. E8 D8700800 call <jmp.&MFC42.#800_CString::~CString>
004127EA |. 8D4C24 14 lea ecx, dword ptr [esp+14]
004127EE |. 897424 2C mov dword ptr [esp+2C], esi
004127F2 |. E8 CB700800 call <jmp.&MFC42.#800_CString::~CString>
004127F7 |. 8B4C24 24 mov ecx, dword ptr [esp+24]
004127FB |. 5F pop edi
004127FC |. 5E pop esi
004127FD |. 5D pop ebp
004127FE |. 33C0 xor eax, eax ; 失败
00412800 |. 5B pop ebx
00412801 |. 64:890D 00000>mov dword ptr fs:[0], ecx
00412808 |. 83C4 20 add esp, 20
0041280B \. C3 ret
----------------------------------------------------------------华丽的分割线
我们看到这里又是2个ret(004127DB,0041280B),同上面原理一样,eax返回0就失败,所以又根据要实现004127DB处的ret又倒推回去,看看哪些跳转要实现,哪些不能实现。。
我们刚进入这个CALL时,一路F8下来(眼睛紧盯右上方的寄存器框),会发现(我这里以111为用户名,F8到00412767时,EAX里会出现一串ZZZHLWsCbMErpAQO,这个估计就是密码了,试试,果然成功了)。。说明就是我们在这一路F8的时候产生的密码,算法就应该在这里了,我们再回头来分析汇编代码,00412682,00412691,004126A0这几处的跳转应该是对用户名和密码的检测,比如用户名和密码长度不为0等。。
我们重点来看看刚才F8时蹦出来的ZZZHLWsCbMErpAQO,在这之前可能会发现首先产生了个ZZZ,那这个ZZZ又是怎么来的?
重点来看从004126D6开始的这一段汇编:
004126D6 |> /8A042B |/mov al, byte ptr [ebx+ebp] ; 用户名
004126D9 |. |33F6 ||xor esi, esi ; esi清零
004126DB |> |3A0475 482C4D>||/cmp al, byte ptr [esi*2+4D2C48] ; 关键4D2C48
004126E2 |. |74 08 |||je short 004126EC
004126E4 |. |46 |||inc esi
004126E5 |. |83FE 34 |||cmp esi, 34
004126E8 |.^|7C F1 ||\jl short 004126DB ; 小于
这里是取用户名(比如我输入的用户名‘111’的‘1’)和byte ptr [esi*2+4D2C48]比较,那么4D2C48这个是什么东西?
我们来到OD左下方的数据窗口,查找4D2C48,是一串奇怪的字符aCbqcidHeSfXgMhkiEjVkZlemRnyoBpKqdrTsAtFuWvlwjxDyIzPAzBxCpDOEkFgGYHmItJaKrLQMnNsOuPUQGRJSLTNUbVcWfXhYoZwZQY
通过cmp al, byte ptr [esi*2+4D2C48]我们知道程序就是用我们输入的用户名和这一串奇怪的字符从'a'(4D2C48)开始隔一个字符依次比较(和abcdefghijk...ABCDEFG...比较,刚好52个字符,也就是为什么是cmp esi, 0x34)
如果找到相同的字符,就用这个字符的下一个字符作为密码(比如用户名为aaa,那么密码就是CCC)
但是如果我们的用户名不在这一串奇怪的字符里呢?看看汇编:
004126E5 |. 83FE 34 |||cmp esi, 34
004126E8 |.^ 7C F1 ||\jl short 004126DB ; 小于
004126EA |. /EB 11 ||jmp short 004126FD
只要循环超出0x34(也就是没在字符表里找到相应字符)就来到004126FD:
004126FD |> \83FE 34 ||cmp esi, 34
00412700 |. 75 0E ||jnz short 00412710
00412702 |. 8B5424 18 ||mov edx, dword ptr [esp+18]
这里向edx传入了dword ptr [esp+18],我们再往上看:
004126B2 |. 8A82 B02C4D00 |mov al, byte ptr [edx+4D2CB0]
004126B8 |. 884424 18 |mov byte ptr [esp+18], al
可以发现4D2CB0处正是字符‘Z’,也就是为什么用户名为111时,密码为ZZZ。。。
现在终于搞清楚算法了,别急,下面还有,如果用户名没达0x10,就用字符串‘HLWsCbMErpAQOXWK’补足。
所以最终的算法,以下用C写的:
#include<stdio.h>
#include<string.h>
void main()
{
char a=0;
char b='Z';
char len=0;
char user[100];
char psw[100]={0};
char lentmp=0;
char* str1="aCbqcidHeSfXgMhkiEjVkZlemRnyoBpKqdrTsAtFuWvlwjxDyIzPAzBxCpDOEkFgGYHmItJaKrLQMnNsOuPUQGRJSLTNUbVcWfXhYoZwZQY";
char* str2="HLWsCbMErpAQOXWK";
printf("请输入用户名:");
scanf("%s",user);
len=strlen(user);
for(int i=0;i<len;i++)
{
for(int j=0;j<=0x34;j++)
{
if(user[i]==str1[j*2])
{
psw[i]=str1[j*2+1];
break;
}
psw[i]=b;
}
}
if(len<=0x10)
{
lentmp=0x10-len;
for(int n=0;n<lentmp;n++)
{
psw[len+n]=str2[n];
}
printf("密码为:%s\n",psw);
getchar();
getchar();
return;
}
printf("用户名长度小于16:\n " );
}
总结:CALL,跳转等指令是关键,从这个程序来说还是比较容易的,像我这样的菜鸟没什么破解经验开始时一定要耐心慢慢跟。。另外碰到关键算法时,可以输入一些特别的值,比如111(3位长),1111(4位长),aaaaaaa等等,在关键地方单步走观察OD右上方寄存器的值变化,再结合汇编语句反复推敲,应该就能理解算法的原理。。。
aheaddvd.part1.rar
aheaddvd.part2.rar
aheaddvd.part3.rar
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!