这个软件是bithaha给我们新手出的题,现在把分析过程尽可能完整的写出来。希望能帮助到大家。
软件名称:Speed DVD Creator
下载地址:http://www.newhua.com/soft/47230.htm
任 务:需要找出来注册码。
首先,用OD加载这个软件,shift+f9,先让他运行起来,注册一下看看,输入pediy,55555555
当然这些是自己乱输的,肯定不对,我们就是让他弹出错误的提示。"Invalid username or registration code"看到这个
Sorry对话框了没?
接下来,就要使用OD的字符串查找功能,右键-->超级字符串参考-->查找 ASCII,弹出超级字符串参考窗体,在点右键-->查找"Invalid username or"
这里就找到了我们要找的字符串,双点找到串我们就来到程序中用到这个串的地方。F2下断。从新输入pediy,55555555,呵呵能断到说明我们找的是正确的
程序是走这里的。
00423C66 . 50 push eax
00423C67 . 51 push ecx
00423C68 . C64424 1C 01 mov byte ptr [esp+1C], 1
00423C6D . E8 3EFDFFFF call 004239B0
00423C72 . 83C4 08 add esp, 8
00423C75 . 85C0 test eax, eax ; 检测eax是否为0,eax=1进入正确流程,那我们就要关注一下EAX怎么来的,EAX是上边函数的返回值.关注上边的函数.跟进看看
00423C77 75 18 jnz short 00423C91 ; 如果程序在这里不跳转将进入正确流程,否则就进入下边弹错误框的地方.
00423C79 . 6A 40 push 40
00423C7B . 68 38FE4900 push 0049FE38 ; sorry
00423C80 . 68 0CFE4900 push 0049FE0C ; invalid username or registration code
00423C85 . 8BCE mov ecx, esi
00423C87 . E8 EF7E0400 call 0046BB7B
00423C8C . E9 A0000000 jmp 00423D31
00423C91 > 8B4E 5C mov ecx, dword ptr [esi+5C]
00423C94 . 8D5424 04 lea edx, dword ptr [esp+4]
00423C98 . 51 push ecx
00423C99 . 68 F0FD4900 push 0049FDF0 ; license to:%s
00423C9E . 52 push edx
00423C9F . E8 201E0400 call 00465AC4
00423CA4 . 8B4424 10 mov eax, dword ptr [esp+10]
00423CA8 . 83C4 0C add esp, 0C
00423CAB . 8BCE mov ecx, esi
进入 00423C6D . E8 3EFDFFFF call 004239B0 看看。当然要先在这里下断才能跟进去看了。。。呵呵
004239B0 /$ 56 push esi
004239B1 |. 8B7424 0C mov esi, dword ptr [esp+C]
004239B5 |. 57 push edi
004239B6 |. 8B7C24 0C mov edi, dword ptr [esp+C]
004239BA |. 56 push esi
004239BB |. 57 push edi
004239BC |. E8 0FFCFFFF call 004235D0
004239C1 |. 83C4 08 add esp, 8
004239C4 |. 85C0 test eax, eax
004239C6 |. 75 11 jnz short 004239D9 ; 注1
004239C8 |. 56 push esi
004239C9 |. 57 push edi
004239CA |. E8 E1F6FFFF call 004230B0
004239CF |. 83C4 08 add esp, 8
004239D2 |. 85C0 test eax, eax
004239D4 |. 75 03 jnz short 004239D9 ; 注1
004239D6 |. 5F pop edi
004239D7 |. 5E pop esi
004239D8 |. C3 retn
004239D9 |> 5F pop edi
004239DA |. B8 01000000 mov eax, 1
004239DF |. 5E pop esi
004239E0 \. C3 retn
在这个函数里边有2个地方跳转能跳到4239DA处,mov eax,1才是正确流程。
那我们就要看看这两个函数了,第一个函数大概走了一下没有发现什么特别的操作。跟这个函数需要耐心。。。当时看的时候也有点犯晕。
进入这个4230b0函数以后,前边对用户名和密码进行了长度的验证。
0042314D |. F7D1 not ecx
0042314F |. 49 dec ecx
00423150 |. 3BCD cmp ecx, ebp
00423152 |. 0F87 52010000 ja 004232AA ;比较用户名和密码的长度,名称不能比密码长。
00423158 |. 8BFB mov edi, ebx
0042315A |. 8BCE mov ecx, esi
0042315C |. F2:AE repne scas byte ptr es:[edi]
0042315E |. F7D1 not ecx
00423160 |. 49 dec ecx
00423161 |. 0F84 43010000 je 004232AA ;又是比较,如果让他跳走,那就失败了。
00423167 |. 8BFA mov edi, edx
00423169 |. 8BCE mov ecx, esi
0042316B |. F2:AE repne scas byte ptr es:[edi]
0042316D |. F7D1 not ecx
0042316F |. 49 dec ecx
00423170 |. 0F84 34010000 je 004232AA ;又是比较,如果让他跳走,那就失败了。
00423176 |. 894424 38 mov dword ptr [esp+38], eax
0042317A |> 8B5424 38 /mov edx, dword ptr [esp+38]
0042317E |. 8A82 E0FC4900 |mov al, byte ptr [edx+49FCE0]
00423184 |. 8B15 D4424A00 |mov edx, dword ptr [4A42D4] ; Speed_DV.004A42E8
这个地方有3个跳转,如果跳转出去就是说你输入的用户名或者密码的长度不符合软件要求。(看完后你就知道用户名和密码是一一对应的。)
继续下走。~~~~
004230B0 /$ 6A FF push -1
004230B2 |. 68 A01C4800 push 00481CA0 ; 柑7i; SE 处理程序安装
004230B7 |. 64:A1 0000000>mov eax, dword ptr fs:[0] ; 在这里就是关于异常处理的安装有兴趣的可以看看关于SEH的介绍
004230BD |. 50 push eax
004230BE |. 64:8925 00000>mov dword ptr fs:[0], esp
004230C5 |. 83EC 14 sub esp, 14
004230C8 |. 8B4424 24 mov eax, dword ptr [esp+24]
004230CC |. 53 push ebx
004230CD |. 55 push ebp
004230CE |. 56 push esi
004230CF |. 57 push edi
004230D0 |. 50 push eax ; ASCII "pediy"----参数用户名
004230D1 |. 8D4C24 18 lea ecx, dword ptr [esp+18]
004230D5 |. E8 D9520400 call 004683B3 ; 在IDA里边看他只有一个参数.那就是上边的EAX
004230DA |. 8D4C24 14 lea ecx, dword ptr [esp+14]
004230DE |. C74424 2C 000>mov dword ptr [esp+2C], 0
004230E6 |. E8 382A0400 call 00465B23
004230EB |. 8D4C24 14 lea ecx, dword ptr [esp+14]
004230EF |. E8 E3290400 call 00465AD7
004230F4 |. 6A 20 push 20
004230F6 |. 8D4C24 18 lea ecx, dword ptr [esp+18] ; 名
004230FA |. E8 76560400 call 00468775
004230FF |. 8B4C24 38 mov ecx, dword ptr [esp+38] ; 密码
00423103 |. 8BD8 mov ebx, eax
00423105 |. 51 push ecx
00423106 |. 8D4C24 14 lea ecx, dword ptr [esp+14]
0042310A |. E8 A4520400 call 004683B3
0042310F |. 8D4C24 10 lea ecx, dword ptr [esp+10]
00423113 |. C64424 2C 01 mov byte ptr [esp+2C], 1
00423118 |. E8 062A0400 call 00465B23
0042311D |. 8D4C24 10 lea ecx, dword ptr [esp+10]
00423121 |. E8 B1290400 call 00465AD7
00423126 |. 6A 20 push 20
00423128 |. 8D4C24 14 lea ecx, dword ptr [esp+14]
0042312C |. E8 44560400 call 00468775
00423131 |. 8BD0 mov edx, eax
00423133 |. 83CE FF or esi, FFFFFFFF
00423136 |. 8BFA mov edi, edx ; edi 密码
00423138 |. 8BCE mov ecx, esi
0042313A |. 33C0 xor eax, eax
0042313C |. 895424 20 mov dword ptr [esp+20], edx
00423140 |. F2:AE repne scas byte ptr es:[edi]
00423142 |. F7D1 not ecx
00423144 |. 49 dec ecx
00423145 |. 8BFB mov edi, ebx
00423147 |. 8BE9 mov ebp, ecx
00423149 |. 8BCE mov ecx, esi
0042314B |. F2:AE repne scas byte ptr es:[edi]
0042314D |. F7D1 not ecx
0042314F |. 49 dec ecx
00423150 |. 3BCD cmp ecx, ebp
00423152 |. 0F87 52010000 ja 004232AA ; 比较用户名和密码的长度
00423158 |. 8BFB mov edi, ebx
0042315A |. 8BCE mov ecx, esi
0042315C |. F2:AE repne scas byte ptr es:[edi]
0042315E |. F7D1 not ecx
00423160 |. 49 dec ecx
00423161 |. 0F84 43010000 je 004232AA
00423167 |. 8BFA mov edi, edx
00423169 |. 8BCE mov ecx, esi
0042316B |. F2:AE repne scas byte ptr es:[edi]
0042316D |. F7D1 not ecx
0042316F |. 49 dec ecx
00423170 |. 0F84 34010000 je 004232AA
00423176 |. 894424 38 mov dword ptr [esp+38], eax ; 循环变量,对应42325c inc eax
0042317A |> 8B5424 38 /mov edx, dword ptr [esp+38]
0042317E |. 8A82 E0FC4900 |mov al, byte ptr [edx+49FCE0] ; 从49fce0取值,ebx在哪加的呢?找找看,看上边一句,ESP+38,谁改变了ESP+38
00423184 |. 8B15 D4424A00 |mov edx, dword ptr [4A42D4] ; Speed_DV.004A42E8
0042318A |. 884424 18 |mov byte ptr [esp+18], al
0042318E |. 895424 34 |mov dword ptr [esp+34], edx
00423192 |. 8BFB |mov edi, ebx ; 开始计算用户名称的长度
00423194 |. 83C9 FF |or ecx, FFFFFFFF
00423197 |. 33C0 |xor eax, eax
00423199 |. 33ED |xor ebp, ebp
0042319B |. F2:AE |repne scas byte ptr es:[edi]
0042319D |. F7D1 |not ecx
0042319F |. 49 |dec ecx ; 得到用户名称的长度
004231A0 |. C64424 2C 02 |mov byte ptr [esp+2C], 2
004231A5 |. 74 4F |je short 004231F6
004231A7 |> 8A042B |/mov al, byte ptr [ebx+ebp] ; ebx是字符串"pediy"基地址,ebp在后边有+1
004231AA |. 33F6 ||xor esi, esi ; 这里给esi置0,就是循环里边的i=0啊.
004231AC |> 3A0475 78FC49>||/cmp al, byte ptr [esi*2+49FC78] ; 依次比较p e d i y
004231B3 |. 74 08 |||je short 004231BD ; 如果取得的字符和里边的字符相等--跳出
004231B5 |. 46 |||inc esi ; 不相等i++;
004231B6 |. 83FE 34 |||cmp esi, 34 ; i<0x34
004231B9 |.^ 7C F1 ||\jl short 004231AC ; 小于的话继续下一次.
004231BB |. EB 11 ||jmp short 004231CE ; 如果在这里边找不到的话,跳转
004231BD |> 8A0C75 79FC49>||mov cl, byte ptr [esi*2+49FC79] ; 这里是49fc79和49fc78查一个字节,说明如果找到和pediy中一个字符相等的,取他下一个字符.
004231C4 |. 51 ||push ecx ; 参数压栈,把得到的数放到结果里边
004231C5 |. 8D4C24 38 ||lea ecx, dword ptr [esp+38] ; 存放结果的地址
004231C9 |. E8 7A550400 ||call 00468748
004231CE |> 83FE 34 ||cmp esi, 34 ; 0x34是什么呢?大小写字母一共26*2=0x34啊.所以输入用户名的时候应该有判定是否输入的是字符,否则这里算法怎么过啊?
004231D1 |. 75 0E ||jnz short 004231E1
004231D3 |. 8B5424 18 ||mov edx, dword ptr [esp+18]
004231D7 |. 8D4C24 34 ||lea ecx, dword ptr [esp+34]
004231DB |. 52 ||push edx
004231DC |. E8 67550400 ||call 00468748 ; 填充,关注一下参数就知道函数大概意思了。
004231E1 |> 8BFB ||mov edi, ebx
004231E3 |. 83C9 FF ||or ecx, FFFFFFFF
004231E6 |. 33C0 ||xor eax, eax
004231E8 |. 45 ||inc ebp ; 这里不是EBP+1吗?以取得pediy下一个字符
004231E9 |. F2:AE ||repne scas byte ptr es:[edi]
004231EB |. F7D1 ||not ecx
004231ED |. 49 ||dec ecx ; 计算长度啊,我们做练习的时候用过吧.
004231EE |. 3BE9 ||cmp ebp, ecx ; 比较用户名称长度和循环次数
004231F0 |.^ 72 B5 |\jb short 004231A7
004231F2 |. 8B5424 34 |mov edx, dword ptr [esp+34] ; 到这里算法我想都清楚了吧
004231F6 |> 8B42 F8 |mov eax, dword ptr [edx-8]
004231F9 |. 83F8 10 |cmp eax, 10 ; 比较0x10注册码要满足0x10?继续跟~~
004231FC |. 7D 34 |jge short 00423232
004231FE |. B9 10000000 |mov ecx, 10
00423203 |. 8D5424 1C |lea edx, dword ptr [esp+1C]
00423207 |. 2BC8 |sub ecx, eax
00423209 |. 51 |push ecx
0042320A |. 52 |push edx
0042320B |. B9 54894A00 |mov ecx, 004A8954 ; GkesVcnrTpAQsXwK
00423210 |. E8 8F240400 |call 004656A4
00423215 |. 50 |push eax
00423216 |. 8D4C24 38 |lea ecx, dword ptr [esp+38]
0042321A |. C64424 30 03 |mov byte ptr [esp+30], 3
0042321F |. E8 39550400 |call 0046875D ; 用上边的串填充剩下不满0x10以后的数.到这已经是注册码了
00423224 |. 8D4C24 1C |lea ecx, dword ptr [esp+1C] ; eax=12ada4 看eax里边存放地址里边的值,.
00423228 |. C64424 2C 02 |mov byte ptr [esp+2C], 2
0042322D |. E8 13510400 |call 00468345
00423232 |> 8B4424 20 |mov eax, dword ptr [esp+20]
00423236 |. 8B4C24 34 |mov ecx, dword ptr [esp+34]
0042323A |. 50 |push eax ; /Arg2
0042323B |. 51 |push ecx ; |(initial cpu selection)
0042323C |. E8 B4F90200 |call 00452BF5 ; \Speed_DV.00452BF5
00423241 |. 83C4 08 |add esp, 8
00423244 |. 8D4C24 34 |lea ecx, dword ptr [esp+34]
00423248 |. 85C0 |test eax, eax
0042324A |. C64424 2C 01 |mov byte ptr [esp+2C], 1
0042324F 74 1B je short 0042326C
00423251 |. 33F6 |xor esi, esi
00423253 |. E8 ED500400 |call 00468345
00423258 |. 8B4424 38 |mov eax, dword ptr [esp+38]
0042325C |. 40 |inc eax
0042325D |. 83F8 03 |cmp eax, 3
00423260 |. 894424 38 |mov dword ptr [esp+38], eax
00423264 |.^ 0F8C 10FFFFFF \jl 0042317A ; 外部大循环(在还原代码的时候,没有包括这部分)
0042326A |. EB 0A jmp short 00423276
0042326C |> BE 01000000 mov esi, 1
00423271 |. E8 CF500400 call 00468345
00423276 |> 8D4C24 10 lea ecx, dword ptr [esp+10]
还有一种情况就是用户名大于0x10的时候他要继续循环,数字也可以。
对于我来说还原全部代码还有点困难。耐心的考验啊~~主要还是掌握技巧。
以后我会继续努力的。时间有点仓促暂时只能做这么多了。
感谢Aker 大菜 bithaha还有组员对我的支持。:)感动ing
/***************************************************************************************************************************************
部分还原代码如下:
/*************************************************************/
/* username字符串输入的时候只能是大小写字母,长度小于16个字符。
o_out字符数组里边是存放最后的注册码。
*/
/*************************************************************/
char username[]="Second";
int nameLength=sizeof(username)-1;
if(nameLength>0x10)
{
AfxMessageBox("名称过长");
return;
}
//用到的一个全局数据区域。
BYTE b_49fc78[0x80]={
0x61, 0x43, 0x62, 0x78, 0x63, 0x69, 0x64, 0x49, 0x65, 0x41,
0x66, 0x58, 0x67, 0x4D, 0x68, 0x6B, 0x69, 0x45, 0x6A, 0x56,
0x6B, 0x5A, 0x6C, 0x65, 0x6D, 0x52, 0x6E, 0x79, 0x6F, 0x42,
0x70, 0x4B, 0x71, 0x64, 0x72, 0x54, 0x73, 0x53, 0x74, 0x50,
0x75, 0x57, 0x76, 0x6C, 0x77, 0x6A, 0x78, 0x44, 0x79, 0x48,
0x7A, 0x46, 0x41, 0x7A, 0x42, 0x71, 0x43, 0x70, 0x44, 0x4F,
0x45, 0x6B, 0x46, 0x67, 0x47, 0x59, 0x48, 0x6D, 0x49, 0x74,
0x4A, 0x61, 0x4B, 0x72, 0x4C, 0x51, 0x4D, 0x6E, 0x4E, 0x73,
0x4F, 0x75, 0x50, 0x55, 0x51, 0x47, 0x52, 0x4A, 0x53, 0x4C,
0x54, 0x4E, 0x55, 0x62, 0x56, 0x63, 0x57, 0x66, 0x58, 0x68,
0x59, 0x6F, 0x5A, 0x77, 0x41, 0x4D, 0x42, 0x00, 0x47, 0x6B,
0x65, 0x73, 0x56, 0x63, 0x6E, 0x72, 0x54, 0x70, 0x41, 0x51,
0x73, 0x58, 0x77, 0x4B, 0x00, 0x00, 0x00, 0x00
};
char o_out[100]={0};
int j=0;
do
{
for(int i=0;i<0x34;i++)
{
if(username[j]==b_49fc78[i*2])
{
o_out[j]=b_49fc78[i*2+1];
j++;
break;
}
}
}while(j<nameLength);
int otherLen=0x10-nameLength;
for(int x=0;x<otherLen;x++)
{
o_out[nameLength+x]=b_49fc78[x+0x6c];
}
AfxMessageBox(_T(o_out));