【软件大小】:  2216 KB
【软件语言】:  英文
【软件类别】:  国外软件 / 共享版 / 音频处理
【应用平台】:  Win9x/NT/2000/XP
【加入时间】:  2005-02-15 15:27:50
【下载次数】:  9691
【推荐等级】:  ★★★★
【软件下载】:  天空软件站
【作者声明】:初学破解,仅作学习交流之用,失误之处敬请大侠赐教!

【破解工具】:Ollydbg1.10、PEid
   用PEid检测无壳,为VC编写,用OD中载入,输入用户名:sharpair及假码:SMRPR000B07807128712"下断getwindowtexta,你一定会来到如下代码(多用几次Ctrl+F9):
程序调试后会有异常,用Shift+F9可跳过!但是调试时F9、F8键无效,但可用菜单项调试,看
输入表中有SetUnhandledExceptionFilter函数,懒得跟了,得过且过吧!^_^

【算法的第一部分】
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
..........

004207E0   push -1
004207E2   push smrpro.004D2BC0           ;  SE handler installation
004207E7   mov eax,dword ptr fs:[0]
004207ED   push eax
004207EE   mov dword ptr fs:[0],esp
004207F5   sub esp,40
004207F8   push ebx
004207F9   push ebp
004207FA   push esi
004207FB   push edi
004207FC   mov esi,ecx
004207FE   push 1
00420800   mov dword ptr ss:[esp+14],esi
00420804   call smrpro.004A5162
00420809   push 7F02                      ; /RsrcName = IDC_WAIT
0042080E   push 0                         ; |hInst = NULL
00420810   call dword ptr ds:[<&USER32.Lo>; \LoadCursorA
00420816   push eax                       ; /hCursor
00420817   call dword ptr ds:[<&USER32.Se>; \SetCursor
0042081D   push 1388                      ; /Timeout = 5000. ms
00420822   call dword ptr ds:[<&KERNEL32.>; \我们点注册后出现的停顿由此函数产生
00420828   mov ebp,dword ptr ds:[esi+5C]  ;  ebp="65148455",假码
0042082B   mov esi,smrpro.004F8B54        ;  esi="4L14A67H9P72Z569WY90",真码已产生了?
00420830   mov eax,ebp                    ;  后面一般的老套路,按位比较
00420832   mov dl,byte ptr ds:[eax]
00420834   mov bl,byte ptr ds:[esi]
00420836   mov cl,dl
00420838   cmp dl,bl
0042083A   jnz short smrpro.0042085A
0042083C   test cl,cl
0042083E   je short smrpro.00420856
00420840   mov dl,byte ptr ds:[eax+1]
00420843   mov bl,byte ptr ds:[esi+1]
00420846   mov cl,dl
00420848   cmp dl,bl
0042084A   jnz short smrpro.0042085A
0042084C   add eax,2
0042084F   add esi,2
00420852   test cl,cl
00420854   jnz short smrpro.00420832
00420856   xor ebx,ebx
00420858   jmp short smrpro.0042085F
0042085A   sbb ebx,ebx               ;注意这两句,会使ebx=-1
0042085C   sbb ebx,-1                ;注意这后面出现了一段和上面类同的比较,莫非有两个注册码?
0042085F   mov esi,smrpro.004F8B38   ;ASCII "#j14NeRo111143000059"
00420864   mov eax,ebp
00420866   mov dl,byte ptr ds:[eax]
00420868   mov cl,dl
0042086A   cmp dl,byte ptr ds:[esi]
0042086C   jnz short smrpro.0042088A
0042086E   test cl,cl
00420870   je short smrpro.00420886
00420872   mov dl,byte ptr ds:[eax+1]
00420875   mov cl,dl
00420877   cmp dl,byte ptr ds:[esi+1]
0042087A   jnz short smrpro.0042088A
0042087C   add eax,2
0042087F   add esi,2
00420882   test cl,cl
00420884   jnz short smrpro.00420866
00420886   xor edx,edx
00420888   jmp short smrpro.0042088F
0042088A   sbb edx,edx                 ;  edx清0
0042088C   sbb edx,-1                  ;  edx=1
0042088F   mov edi,ebp
00420891   or ecx,FFFFFFFF
00420894   xor eax,eax
00420896   repne scas byte ptr es:[edi]
00420898   not ecx
0042089A   dec ecx                            ;  上面一小段经典的取字串位数代码
0042089B   cmp ecx,14                         ;  正确码应该为20位
0042089E   jnz smrpro.00420B89
004208A4   test ebx,ebx                       ;  ebx的值还记得吗,上面比较通过后被置为0
004208A6   je smrpro.00420B89                 ;  这个跳转很远,凭感觉不大对
004208AC   test edx,edx                       ;  呵呵,又来一个判断
004208AE   je smrpro.00420B89                 ;  呵呵,原来上面为内置的两个黑名单注册码   
004208B4   cmp byte ptr ss:[ebp+5],30         ;  这里才是真正的正假码比较开始,从假码第6位开始
004208B8   jnz short smrpro.004208D0
004208BA   cmp byte ptr ss:[ebp+6],30         ;  真码第7位,同第6位,也应该为0
004208BE   jnz short smrpro.004208D0
004208C0   cmp byte ptr ss:[ebp+7],30         ;  真码第8位为0
004208C4   jnz short smrpro.004208D0
004208C6   cmp byte ptr ss:[ebp+8],30         ;  真码第9位不能为0(上面的判断也是跳向这里)
004208CA   je smrpro.00420B89
004208D0   xor ecx,ecx                        ;  ecx清0
004208D2   mov edx,ebp                        ;  再取假码
004208D4   mov al,byte ptr ds:[edx]           ;  从第1位开始取
-------------------------------------------------------------------------
004208D6   cmp al,61                          
004208D8   jl short smrpro.004208E0
004208DA   cmp al,66
004208DC   jg short smrpro.004208E0
004208DE   sub al,7
-------------------------------------------------------------------------
这一小段代码很简单,若字符为(a,f)之间的则sub al,7
004208E0   shl al,4                           ; 结果再shl al,4,注意为al,高位会自动舍去
004208E3   mov byte ptr ss:[esp+ecx+44],al    ; 再存入ss:[esp+ecx+44]中,ecx作指针用
004208E7   mov al,byte ptr ds:[edx+1]         ; 取假码第2位
004208EA   cmp al,61                          ; 以下的判断同上,不过后面的处理方法不同
004208EC   jl short smrpro.004208F6           
004208EE   cmp al,66
004208F0   jg short smrpro.004208F6
004208F2   sub al,57                       ; 若字符在(a,f)之间则sub al,57,否则sub al,30
004208F4   jmp short smrpro.004208F8
004208F6   sub al,30
004208F8   mov bl,byte ptr ss:[esp+ecx+44]    ; 第1位计算后的值取到bl中
004208FC   add edx,2                          ; add edx,2,调整指针取下一组字符
004208FF   add bl,al                          ; 1、2位转换后的值累加到bl中
00420901   mov byte ptr ss:[esp+ecx+44],bl    ; 累加和再存到ss:[esp+ecx+44]中
00420905   inc ecx                            ; ecx步进1
00420906   cmp ecx,0A                         ; 循环10次,取完假码
00420909   jl short smrpro.004208D4
0042090B   push 0                    ;结束后我的累加值在内存中为4D 40 20 00 B0 78 07 12 87 12
0042090D   push smrpro.004F8428               ; 固定串压入堆栈"SMRPRO0000"
00420912   lea eax,dword ptr ss:[esp+34]      ; 这个地址可能用来传出结果
00420916   push 0A                            ; 0A压入堆栈
00420918   lea ecx,dword ptr ss:[esp+50]      ; 不用说,指向注册码前10位的计算值
0042091C   push eax
0042091D   push ecx
0042091E   call smrpro.00401DC0               ; 这个Call干什么呢?我们要跟进去看一下
00420923   mov al,byte ptr ss:[esp+40] ;注意这里ss:[esp+40]指向"55 14 37 7B 1C 45 41 72 B2 A6"
00420927   add esp,14                         ; 调整一下堆栈,迷惑cracker一下^_^
0042092A   cmp al,72                          ; 往下看可知要满足条件我们Call之后的ss:[esp+40]中
0042092C   jnz smrpro.00420B3F                ; 指向的值应为"72 67 37 7B 1C 45 41 72 63 78"
00420932   cmp byte ptr ss:[esp+2D],67        ; 我们强行改变Z标志,使其能通过校验继续往下看
00420937   jnz smrpro.00420B3F
0042093D   cmp byte ptr ss:[esp+34],63
00420942   jnz smrpro.00420B3F
00420948   cmp byte ptr ss:[esp+35],78
0042094D   jnz smrpro.00420B3F
00420953   mov al,byte ptr ss:[esp+2F]  ;al=7B,第4位
00420957   mov dl,byte ptr ss:[esp+2E]  ;dl=37,第3位
0042095B   mov cl,byte ptr ss:[esp+30]  ;cl=1C,第5位
0042095F   mov byte ptr ss:[esp+39],al  ;下面将al,dl保存起来
00420963   mov byte ptr ss:[esp+38],dl
00420967   mov dl,byte ptr ss:[esp+31]  ;dl=45,第6位
0042096B   lea eax,dword ptr ss:[esp+38]
0042096F   mov byte ptr ss:[esp+3A],cl  ;cl值也保存起来
00420973   push eax
00420974   mov byte ptr ss:[esp+3F],dl  ;dl值保存起来,此时观察内存区eax所指向的为"37 7B 1C 45"
00420978   mov byte ptr ss:[esp+40],0   ;ss:[esp+40]赋0,用来表示字符结束
0042097D   call smrpro.0046B58C      
   
这个Call干什么呢,先不要跟(我们的原则是能偷懒就偷懒),我们看压入栈的为37 7B 1C 45,
而此Call后在eax中的返回值为7,莫非是ASCII字符值转换成字符?但后面的数值到哪儿去呢?
我们可以手工把压入栈的值改为别的值如"37 32 36 69"我们发现调用后ecx中为字符形式"7269",
而eax中为1C64(7269值的Hex进制形式)!多换几组值试一下我们可猜测出此Call将压入栈的值
转换成Dec形式(而如果其中任一位值<30 or >39则条件不满足跳出,如若压入的堆栈处
为37 33 1C 45,则返回49(73的Hex进制形式),而若为7B 37 1C 45,则返回0)这样描述感觉
有些不妥,没办法了,自己看代码吧!有兴趣的也可自己跟一下!

00420982   mov cl,byte ptr ss:[esp+36] ;cl=41,第7位
00420986   mov dl,byte ptr ss:[esp+37] ;dl=72,第8位
0042098A   mov esi,eax
0042098C   lea eax,dword ptr ss:[esp+3C]
00420990   push eax                    ;注意这个地址中的内容
00420991   mov byte ptr ss:[esp+40],cl ;cl值传给堆栈
00420995   mov byte ptr ss:[esp+41],dl ;dl值传给堆栈
00420999   mov byte ptr ss:[esp+42],0  ;格式同上相同,此时看eax指向的内容为"41 72 00 45"
0042099E   call smrpro.0046B58C
004209A3   mov ecx,eax                 
004209A5   mov eax,esi                 ;eax=07
004209A7   cdq
004209A8   mov esi,59                  ;esi=59
004209AD   add esp,8                   
004209B0   idiv esi
004209B2   mov esi,0D                  ;esi赋值0D
004209B7   mov eax,edx                 ;上面运算的余数存入eax中,eax=7
004209B9   cdq
004209BA   idiv esi                    ;再除以esi,此时esi=0D了              
004209BC   cmp edx,ecx                        ; 最后一次判断了
----------------------------------------------------------
这里小结一下,上面对"55 14 37 7B 1C 45 41 72 B2 A6"的中间6位进行校验
要求3~6位经Call 0046B58C后的返回值a与7~8位经Call 0046B58C后的返回值b满足以下关系
即(a%59)%0D=b,则最后的校验通过!可以偷着乐了!^_^

004209BE   jnz smrpro.00420B3F         ; 照例是不能跳的,后面应该是把住息写到文件和注册表中
004209C4   push smrpro.004F8444               ;  ASCII "HotKeyString"
004209C9   lea ecx,dword ptr ss:[esp+24]
004209CD   call smrpro.004A1EF1
004209D2   xor ebx,ebx
004209D4   push smrpro.004F8438               ;  ASCII "UserName"
004209D9   lea ecx,dword ptr ss:[esp+20]
004209DD   mov dword ptr ss:[esp+5C],ebx
004209E1   call smrpro.004A1EF1
004209E6   mov edi,dword ptr ss:[esp+10]
004209EA   mov byte ptr ss:[esp+58],1
004209EF   mov esi,dword ptr ds:[edi+5C]
004209F2   call smrpro.004BF645
004209F7   mov ecx,dword ptr ss:[esp+20]
004209FB   mov eax,dword ptr ds:[eax+4]
004209FE   push esi                           ; /Arg3
004209FF   push ecx                           ; |Arg2
00420A00   push smrpro.004F806C               ; |Arg1 = 004F806C ASCII "smr"
00420A05   mov ecx,eax                        ; |
00420A07   call smrpro.004B227F               ; \smrpro.004B227F
00420A0C   mov esi,dword ptr ds:[edi+60]
00420A0F   call smrpro.004BF645
00420A14   mov edx,dword ptr ss:[esp+1C]
00420A18   mov eax,dword ptr ds:[eax+4]
00420A1B   push esi                           ; /Arg3
00420A1C   push edx                           ; |Arg2
00420A1D   push smrpro.004F806C               ; |Arg1 = 004F806C ASCII "smr"
00420A22   mov ecx,eax                        ; |
00420A24   call smrpro.004B227F               ; \smrpro.004B227F
00420A29   push smrpro.004F8294
00420A2E   push smrpro.004FDB78        ;ASCII "D:\Program Files\Admiresoft\Super Mp3 Recorder Professional\scheme.dat"
00420A33   mov dword ptr ds:[4FDA60],ebx
00420A39   call smrpro.0046B137
00420A3E   mov esi,eax
00420A40   add esp,8
00420A43   cmp esi,ebx
00420A45   je short smrpro.00420A5F
00420A47   mov eax,dword ptr ds:[edi+5C]
00420A4A   push eax
00420A4B   push smrpro.004F8B28               ;  ASCII "as341%sghn33
"
00420A50   push esi
00420A51   call smrpro.0046B4C5
00420A56   push esi
00420A57   call smrpro.0046B14A
00420A5C   add esp,10
00420A5F   mov ecx,dword ptr ds:[4F97C8]      ;  smrpro.004F97DC
.......
此处后面略去一些写信息到注册表的操作!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★


【算法的第二部分】
我们跟进0042091E   call smrpro.00401DC0,看看这个Call里都干些什么:
☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0040A090   sub esp,104
0040A096   push ebx
0040A097   mov ebx,dword ptr ss:[esp+118]
0040A09E   push ebp
0040A09F   push esi
0040A0A0   push edi
0040A0A1   mov edi,ebx
0040A0A3   or ecx,FFFFFFFF
0040A0A6   xor eax,eax
0040A0A8   repne scas byte ptr es:[edi]   ;[edi]中为"SMRPRO0000"
0040A0AA   not ecx                         
0040A0AC   dec ecx                        ;取得上面串的位数为0A
-------------------------------------------------------
0040A0AD   mov byte ptr ss:[esp+1C],3
0040A0B2   mov edi,ecx
0040A0B4   mov byte ptr ss:[esp+1D],5
0040A0B9   mov byte ptr ss:[esp+1E],7
0040A0BE   mov byte ptr ss:[esp+1F],0B
0040A0C3   mov byte ptr ss:[esp+20],0D
0040A0C8   mov byte ptr ss:[esp+21],11
0040A0CD   mov byte ptr ss:[esp+22],13
0040A0D2   mov byte ptr ss:[esp+23],17
0040A0D7   mov byte ptr ss:[esp+24],1D
0040A0DC   mov byte ptr ss:[esp+25],1F
0040A0E1   mov byte ptr ss:[esp+26],25
0040A0E6   mov byte ptr ss:[esp+27],29
0040A0EB   mov byte ptr ss:[esp+28],2B
0040A0F0   mov byte ptr ss:[esp+29],2F
0040A0F5   mov byte ptr ss:[esp+2A],35
0040A0FA   mov byte ptr ss:[esp+2B],3B
0040A0FF   mov byte ptr ss:[esp+2C],3D
0040A104   mov byte ptr ss:[esp+2D],43
0040A109   mov byte ptr ss:[esp+2E],47
0040A10E   mov byte ptr ss:[esp+2F],49
0040A113   mov byte ptr ss:[esp+30],4F
0040A118   mov byte ptr ss:[esp+31],53
0040A11D   mov byte ptr ss:[esp+32],59
0040A122   mov byte ptr ss:[esp+33],61
0040A127   mov byte ptr ss:[esp+34],65
0040A12C   mov byte ptr ss:[esp+35],67
0040A131   mov byte ptr ss:[esp+36],6B
0040A136   mov byte ptr ss:[esp+37],6D
0040A13B   mov byte ptr ss:[esp+38],71
0040A140   mov byte ptr ss:[esp+39],7F
0040A145   mov byte ptr ss:[esp+3A],83
0040A14A   mov byte ptr ss:[esp+3B],89
0040A14F   mov byte ptr ss:[esp+3C],8B
0040A154   mov byte ptr ss:[esp+3D],0E
0040A159   mov byte ptr ss:[esp+3E],97
0040A15E   mov byte ptr ss:[esp+3F],9D
0040A163   mov byte ptr ss:[esp+40],0A3
0040A168   mov byte ptr ss:[esp+41],0A7
0040A16D   mov byte ptr ss:[esp+42],0AD
0040A172   mov byte ptr ss:[esp+43],0B3
0040A177   mov byte ptr ss:[esp+44],0B5
0040A17C   mov byte ptr ss:[esp+45],0BF
0040A181   mov byte ptr ss:[esp+46],0C1
0040A186   mov byte ptr ss:[esp+47],0C5
0040A18B   mov byte ptr ss:[esp+48],0C7
0040A190   mov byte ptr ss:[esp+49],0D3
0040A195   mov byte ptr ss:[esp+4A],0DF
0040A19A   mov byte ptr ss:[esp+4B],0E3
0040A19F   mov byte ptr ss:[esp+4C],0E5
0040A1A4   mov byte ptr ss:[esp+4D],0E9
0040A1A9   mov byte ptr ss:[esp+4E],0EF
0040A1AE   mov byte ptr ss:[esp+4F],0F1
0040A1B3   mov byte ptr ss:[esp+50],0FB
-----------------------------------------------
这一段建立一张大表格,和很明显,后面会有查表运算

0040A1B8   mov dword ptr ss:[esp+64],edi
0040A1BC   js short smrpro.0040A1DE
---------------------------------------
0040A1BE   lea edx,dword ptr ss:[esp+DC]
0040A1C5   lea esi,dword ptr ss:[esp+6C]
0040A1C9   sub edx,ebx
0040A1CB   mov eax,ebx
0040A1CD   sub esi,ebx
0040A1CF   lea ebx,dword ptr ds:[edi+1]   ;ebx=0b
0040A1D2   mov cl,byte ptr ds:[eax]       ;ds:[eax]中为"SMRPRO0000"
0040A1D4   mov byte ptr ds:[edx+eax],cl
0040A1D7   mov byte ptr ds:[esi+eax],cl
0040A1DA   inc eax
0040A1DB   dec ebx
0040A1DC   jnz short smrpro.0040A1D2
---------------------------------------
这一小段把字串"SMRPRO0000"复制了两份在地址ss:[esp+DC]和ss:[esp+6C]中
0040A1DE   xor ebx,ebx
0040A1E0   xor ecx,ecx
0040A1E2   xor eax,eax
0040A1E4   cmp edi,ebx
0040A1E6   jle short smrpro.0040A1FA
0040A1E8   xor edx,edx
0040A1EA   mov dl,byte ptr ss:[esp+eax+DC] ;取上面复制的字串,dl=53("S")
0040A1F1   add edx,eax                     ;和累加到edx中
0040A1F3   xor ecx,edx                     ;再与ecx或
0040A1F5   inc eax                         ;指针
0040A1F6   cmp eax,edi                     ;比较是否取完字串
0040A1F8   jl short smrpro.0040A1E8
-----------------------------------------
这一小段可简单描述为
for(i=0;i<11;i++) 
{
 a=name[i]+i; 
 d=d^a; 
 j++;} 
}结果为0x18h 
-----------------------------------------
0040A1FA   xor eax,eax                     
0040A1FC   cmp edi,ebx
0040A1FE   jle short smrpro.0040A210
0040A200   mov dl,byte ptr ss:[esp+eax+6C] ;取复制的另一份字串,dl=53("S")
0040A204   xor dl,cl                       ;与上面运算后的结果或
0040A206   inc ecx
0040A207   mov byte ptr ss:[esp+eax+6C],dl ;结果存回原位置
0040A20B   inc eax
0040A20C   cmp eax,edi                     ;比较是否取完字串
0040A20E   jl short smrpro.0040A200
-----------------------------------------
上面这一小段更简单了,把上面计算得到的值0x18h再与字串"SMRPRO0000"的每位或存回
原处,在内存中其Hex值显示为4B 54 48 4B 4E 52 2E 2F 10 11
★★★★★★★★★★★★★★★★★★★★★★★
0040A210   xor esi,esi
0040A212   cmp edi,ebx
0040A214   jle short smrpro.0040A230
0040A216   xor eax,eax
0040A218   mov ebp,35                     ;ebp赋值35,后面将参与运算
0040A21D   mov al,byte ptr ss:[esp+esi+6C];上面运算后的结果再按位取:4B 54 48 4B 4E 52 2E 2F 10 11
0040A221   cdq                            ;扩展成双字
0040A222   idiv ebp
0040A224   inc esi
0040A225   cmp esi,edi
0040A227   mov byte ptr ss:[esp+esi+A3],dl;余数存入堆栈中"16 1F 13 16 19 1D 2E 2F 10 11"
0040A22E   jl short smrpro.0040A216
★★★★★★★★★★★★★★★★★★★★★★★
这上面一小段可描述为将上面或运算后得到的值每位再分别除以35将余数存入一地址

0040A230   mov eax,ecx                    ;eax=ecx=22,即(0A+1)*2,往上看应该不难理解
0040A232   mov ecx,35                      
0040A237   cdq
0040A238   idiv ecx                       ;余数为22
0040A23A   mov eax,dword ptr ss:[esp+11C] ;ss:[esp+11c],可能作buffer用
0040A241   xor esi,esi
0040A243   xor cl,cl
------------------------------------------
0040A245   mov byte ptr ss:[esp+13],bl
0040A249   mov byte ptr ss:[esp+18],cl
0040A24D   mov byte ptr ss:[esp+14],bl
0040A251   mov dword ptr ss:[esp+54],ebx
0040A255   mov dword ptr ss:[esp+58],eax
0040A259   mov dword ptr ss:[esp+5C],edx ;余数存入ss:[esp+5C]
------------------------------------------
这一段给特定临时变量赋值0,后面会以用到
0040A25D   mov edx,dword ptr ss:[esp+118]
0040A264   sub edx,eax                   ;edx=18
0040A266   mov dword ptr ss:[esp+60],edx
下面开始一个大循环
☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
0040A26A   mov edx,dword ptr ss:[esp+60]    
0040A26E   mov eax,dword ptr ss:[esp+58]
0040A272   mov edi,dword ptr ss:[esp+120] ;edi=0A
0040A279   movsx eax,byte ptr ds:[edx+eax]
-----------------------------------------------
ds:[edx+eax]指向我们的假码转换后的值4D 40 20 00 B0 78 07 12 87 12

0040A27D   mov edx,dword ptr ss:[esp+54] ;还记得上面的一小段赋值吗?现在用到了,后面还会用到
0040A281   cmp edx,edi                   ;循环判断,edi中为0A
0040A283   jnb smrpro.0040A3AF           
0040A289   mov edx,dword ptr ss:[esp+128]
0040A290   test edx,edx
0040A292   je short smrpro.0040A2D3      ;第1次此处会跳
下面的这一段看起来有点乱,我的描述能力有限,只好在每行后加注释,看不明白的话最好自己跟一下
就清楚了

0040A294   mov bl,byte ptr ss:[esp+esi+6C] bl=4B ,"
0040A298   mov dl,byte ptr ss:[esp+esi+DC] dl=53 ,"
0040A29F   mov edi,ebx
0040A2A1   mov ebp,edx
0040A2A3   and edi,0FF
0040A2A9   and ebp,0FF
0040A2AF   xor edi,ebp
0040A2B1   mov ebp,dword ptr ss:[esp+14]
0040A2B5   and ebp,0FF
0040A2BB   mov byte ptr ss:[esp+14],cl
0040A2BF   xor edi,ebp
0040A2C1   mov ebp,dword ptr ss:[esp+18]
0040A2C5   and ebp,0FF
0040A2CB   xor edi,ebp
0040A2CD   xor eax,edi
0040A2CF   mov cl,al
0040A2D1   jmp short smrpro.0040A316
0040A2D3   mov bl,byte ptr ss:[esp+esi+6C];接上跳转,bl=4B,"4B 54 48 4B 4E 52 2E 2F 10 11"
0040A2D7   mov dl,byte ptr ss:[esp+esi+DC];dl=53,"53 4D 52 50 52 4F 30 30 30 30"
0040A2DE   mov edi,ebx                    
0040A2E0   mov ebp,edx
0040A2E2   and edi,0FF                    ;取低位,edi=4B
0040A2E8   and ebp,0FF                    ;取低位,edi=53
0040A2EE   xor edi,ebp                    ;edi=4B^53=18
0040A2F0   mov ebp,dword ptr ss:[esp+14]  ;ss:[esp+14]前面赋过值
0040A2F4   and ebp,0FF                    ;取低位,ebp=0
0040A2FA   mov dword ptr ss:[esp+68],eax  ;eax=4D,往前看,假码转换后的
0040A2FE   xor edi,ebp                    ;edi=18^0=18
0040A300   mov ebp,dword ptr ss:[esp+18]  
0040A304   and ebp,0FF                    ;ebp=0
0040A30A   mov byte ptr ss:[esp+14],cl    ;cl的值先保存在ss:[esp+14]下一轮循环用
0040A30E   mov cl,byte ptr ss:[esp+68]    ;cl=4D
0040A312   xor edi,ebp                    ;edi=18^0=18
0040A314   xor eax,edi                    ;eax=4D^18=55
0040A316   mov edi,dword ptr ss:[esp+58]  ;ss:[esp+58]可能作为一个缓冲地址
0040A31A   mov ebp,dword ptr ss:[esp+64]
0040A31E   mov byte ptr ss:[esp+18],cl    ;cl=4D存入ss:[esp+18],下一轮循环用
0040A322   mov byte ptr ds:[edi],al       ;果然,al的值存入
0040A324   mov eax,dword ptr ss:[esp+54]  ;ss:[esp+54]初始为0,保存控制循环
0040A328   inc eax                         ;步进,调整指针
0040A329   inc edi                         ;同上
0040A32A   mov dword ptr ss:[esp+54],eax   ;果然,再存入
0040A32E   xor eax,eax
0040A330   mov al,byte ptr ss:[esp+esi+A4] ;这里存着什么呢,al=16,"16 1F 13 16 19 1D 2E 2F 10 11"
0040A337   mov dword ptr ss:[esp+58],edi   ;保存edi
0040A33B   mov edi,dword ptr ss:[esp+5C]   ;ss:[esp+5C]中存放着余数22
0040A33F   mov al,byte ptr ss:[esp+eax+1C] ;还记得刚开始建的一张大表吗,这里就是由eax值查表,al=59
0040A343   add al,dl                       ;al=59+53=AC
0040A345   mov dl,byte ptr ss:[esp+edi+1C] ;由edi值查表,dl=97
0040A349   add dl,bl                       ;dl=97+4B=E2
0040A34B   mov byte ptr ss:[esp+esi+DC],al ;结果存回原处
0040A352   mov byte ptr ss:[esp+esi+6C],dl ;结果存回原处
0040A356   inc esi
0040A357   cmp esi,ebp
0040A359   jnz smrpro.0040A26A
☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆
这一段看起来不少,我们尽量简单描述成如下:(40A2D3~40A322段代码为以下运算)
4B 54 48 4B 4E 52 2E 2F 10 11                看上面的解释吧
53 4D 52 50 52 4F 30 30 30 30               对应字串"SMRPRO0000"
00 00 4D 40 20 00 20 78 07 12  
00 4D 40 20 00 20 78 07 12 87  
4D 40 20 00 20 78 07 12 87 12 
---------------------------------按位或运算
55 14 37 7B 1C 45 41 72 B2 A6

而40A330至40A359处代码实现由余数值"16 1F 13 16 19 1D 2E 2F 10 11"
查表与"53 4D 52 50 52 4F 30 30 30 30"的每位加运算,结果为
ss:[esp+esi+DC]中:AC D6 9B A9 B9 CE 0F 13 6D 73
以及用余数值22查表与"4B 54 48 4B 4E 52 2E 2F 10 11 "的每位加
运算(即每位加上97舍去高位),结果
在ss:[esp+esi+6C]中为E2 EB DF E2 E5 E9 C5 C6 A7 A8(为定值)

0040A35F   mov al,byte ptr ss:[esp+13]
0040A363   inc al
0040A365   mov byte ptr ss:[esp+13],al
0040A369   jnz short smrpro.0040A3A8
0040A36B   xor edx,edx
0040A36D   xor eax,eax
0040A36F   cmp ebp,edx
0040A371   jle short smrpro.0040A3A8
0040A373   mov bl,byte ptr ss:[esp+eax+A4]
0040A37A   inc bl
0040A37C   cmp bl,35
0040A37F   mov byte ptr ss:[esp+eax+A4],bl
0040A386   jnz short smrpro.0040A38F
0040A388   mov byte ptr ss:[esp+eax+A4],dl
0040A38F   mov bl,byte ptr ss:[esp+eax+1C]
0040A393   add byte ptr ss:[esp+eax+6C],bl
0040A397   inc edi
0040A398   cmp edi,35
0040A39B   jnz short smrpro.0040A39F
0040A39D   xor edi,edi
0040A39F   inc eax
0040A3A0   cmp eax,ebp
0040A3A2   jl short smrpro.0040A373
0040A3A4   mov dword ptr ss:[esp+5C],edi
0040A3A8   xor esi,esi
0040A3AA   jmp smrpro.0040A26A
0040A3AF   mov eax,dword ptr ss:[esp+11C]
0040A3B6   pop edi
0040A3B7   pop esi
0040A3B8   pop ebp
0040A3B9   mov byte ptr ds:[edx+eax],0
0040A3BD   xor eax,eax
0040A3BF   pop ebx
0040A3C0   add esp,104
0040A3C6   retn
这个函数的返回值为或运算后的结果55 14 37 7B 1C 45 41 72 B2 A6,其余两个查表后得到的值
在注册码的校验中没有用到,在后面的写注册信息时用到!对此我不感兴趣,有兴趣的自己跟一下!


【算法总结】:
 说实话,写到这有点头晕眼花了,死老外,弄个这么麻烦的算法!还是稍微梳理一下吧!
 注册码与用户名无关,注册码须为20位,其中第6、7、8位须为0,第9位不得为0,假设我们的
 注册码为 abcde000fghijklmnopq,经004208D4~00420909处的代码转换为n1n2n3n4n5n6n7n8n9n10
     a  b  c  d  e  0  0  0  f  g  h  i  j  k  l  m  n  o  p  q
     ┕┘ ┕┘  ┕┘  ┕┘  ┕┘  ┕┘  ┕┘  ┕┘  ┕┘  ┕┘
           n1    n2    n3    n4    n5    n6    n7    n8    n9    n10
然后后将此值与几组程序内定值按位或运算后得到一个值
4B 54 48 4B 4E 52 2E 2F 10 11               固定值 
53 4D 52 50 52 4F 30 30 30 30               固定值
00 00 n1 n2 n3 n4 n5 n6 n7 n8  
00 n1 n2 n3 n4 n5 n6 n7 n8 n9
n1 n2 n3 n4 n5 n6 n7 n8 n9 n10 
---------------------------------按位或运算
j1 j2 j3 j4 j5 j6 j7 j8 j9 j10

要求j1、j2、j9、j10须为r、g、c、x
而j3~j6位经call smrpro.0046B58C后的返回值a与j7~j8经call smrpro.0046B58C后的
返回值b须满足(a%59)%0Dh=b,满足以上条件的即为正确注册码!


【注册机】:
  呵呵,不要指望我了,还是请高手出招了,我只想要一个能用的注册码,让我们看看有没有
偷懒的办法!由于程序涉及到的校验太多,而且会把信息写到注册表和文件中,所以要爆破的
话得工作量可能不小,而且是非明码比较,用程序自身作注册机太麻烦,但我们注意到程序开
始进行了校验黑名单操作,我们不凡用黑名单中的注册码试一下!运行程序,再输入
假码4L14A0009P72Z569WY90(注意把把6~8位改为0),注册试试,失败!别灰心,再
换#j14N000111143000059(同上,6~8位改为0)试试,呵呵.....笑开花了吧!注册成功了!^_^

用户名随意,一个可用注册码#j14N000111143000059!

欢迎e-mail到sharpair@163.com交流!