【文章标题】: 一次简单的算法分析
【文章作者】: 请哥慢捂
【作者邮箱】: none
【软件名称】: File Tree Printer V3.1.6.317
【软件大小】: 398 KB
【下载地址】: http://www.skycn.com/soft/17993.html
【加壳方式】: 无
【编写语言】: Microsoft Visual C++ 7.0
【使用工具】: OD110
【操作平台】: Win9x/NT/2000/XP/2003
【软件介绍】: 将文件目录结构或CD/DVD节目列表显示、输出为TXT文
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
用OD载入,运行则出现提示注册的窗口,随便输入用户名qgmw和注册码12345678,立刻提示注册码错误的消息框。
是一个标准的windows消息框,于是在USER32.MessageBoxA处下断,再次验证时中断了,返回到程序代码空间:
004073B3 . 8B46 70 MOV EAX, DWORD PTR [ESI+70] ; 用户名qgmw,下面以n代替这个字符串
004073B6 . 8B68 F4 MOV EBP, DWORD PTR [EAX-C]
004073B9 . 83FD 02 CMP EBP, 2
004073BC . 7D 15 JGE SHORT 004073D3 ; 长度必须大于等于2
004073BE . 6A 00 PUSH 0 ; 否则提示错误
004073C0 . 6A 00 PUSH 0
004073C2 . 68 2CFF4200 PUSH 0042FF2C ; ASCII "Please input correct User Name!"
004073C7 . E8 17130200 CALL 004286E3
。。。。。。
004073D3 > 8B4E 74 MOV ECX, DWORD PTR [ESI+74] ; 假注册码12345678,下面以k代替
004073D6 . 8379 F4 08 CMP DWORD PTR [ECX-C], 8
004073DA . 7D 15 JGE SHORT 004073F1 ; 长度必须大于等于8
004073DC . 6A 00 PUSH 0 ; 否则提示错误
004073DE . 6A 00 PUSH 0
004073E0 . 68 04FF4200 PUSH 0042FF04 ; ASCII "Please input correct Registration Code!"
004073E5 . E8 F9120200 CALL 004286E3
。。。。。。
004073F1 > 8B46 70 MOV EAX, DWORD PTR [ESI+70]
004073F4 . 8B48 F4 MOV ECX, DWORD PTR [EAX-C]
004073F7 . 85C9 TEST ECX, ECX
004073F9 . 7D 0A JGE SHORT 00407405 ; 可能是对数组溢出的保护处理
004073FB . 68 57000780 PUSH 80070057 ; 只是增强程序的稳定,可以不管
00407400 . E8 0B9CFFFF CALL 00401010
00407405 > 8A10 MOV DL, BYTE PTR [EAX] ; 取n[1]=0x71,即用户名第一位
00407407 . 8B46 70 MOV EAX, DWORD PTR [ESI+70]
0040740A . 3978 F4 CMP DWORD PTR [EAX-C], EDI
0040740D . 7D 0A JGE SHORT 00407419
0040740F . 68 57000780 PUSH 80070057
00407414 . E8 F79BFFFF CALL 00401010
00407419 > 8A40 01 MOV AL, BYTE PTR [EAX+1] ; 取n[2]=0x67
0040741C . 884424 0E MOV BYTE PTR [ESP+E], AL
00407420 . 8B46 70 MOV EAX, DWORD PTR [ESI+70]
00407423 . 8B48 F4 MOV ECX, DWORD PTR [EAX-C]
00407426 . 85C9 TEST ECX, ECX
00407428 . 7D 0A JGE SHORT 00407434
0040742A . 68 57000780 PUSH 80070057
0040742F . E8 DC9BFFFF CALL 00401010
00407434 > 8B4E 70 MOV ECX, DWORD PTR [ESI+70]
00407437 . 53 PUSH EBX
00407438 . 8A18 MOV BL, BYTE PTR [EAX] ; n[1]=0x71
0040743A . 3979 F4 CMP DWORD PTR [ECX-C], EDI
0040743D . 7D 0A JGE SHORT 00407449
0040743F . 68 57000780 PUSH 80070057
00407444 . E8 C79BFFFF CALL 00401010
00407449 > 0FB6C2 MOVZX EAX, DL
0040744C . 83C8 45 OR EAX, 45 ; n[1]|0x45=0x75
0040744F . 99 CDQ
00407450 . BF 0A000000 MOV EDI, 0A
00407455 . F7FF IDIV EDI ; 上面的结果对10求余数,保存在DL
00407457 . 0FB64424 12 MOVZX EAX, BYTE PTR [ESP+12]
0040745C . 83C8 42 OR EAX, 42 ; n[2]|0x42=0x67
0040745F . 885424 16 MOV BYTE PTR [ESP+16], DL ; 保存上面的余数[esp+16]=0x07,r1
00407463 . 99 CDQ
00407464 . F7FF IDIV EDI ; 上面的结果对10求余数,保存在DL
00407466 . 0FB6C3 MOVZX EAX, BL
00407469 . 83C8 43 OR EAX, 43 ; n[1]|0x43=0x73
0040746C . 885424 12 MOV BYTE PTR [ESP+12], DL ; 保存上面的余数[esp+12]=0x03,r2
00407470 . 99 CDQ
00407471 . F7FF IDIV EDI ; 上面的结果对10求余数,保存在DL
00407473 . 0FB641 01 MOVZX EAX, BYTE PTR [ECX+1]
00407477 . 83C8 44 OR EAX, 44 ; n[2]|0x44=0x67
0040747A . 8BCF MOV ECX, EDI
0040747C . 885424 17 MOV BYTE PTR [ESP+17], DL ; 保存上面的余数[esp+17]=0x05,r3
00407480 . 99 CDQ
00407481 . F7F9 IDIV ECX ; 上面的结果对10求余数,保存在DL
00407483 . 33C0 XOR EAX, EAX
00407485 . 33C9 XOR ECX, ECX
00407487 . 85ED TEST EBP, EBP
00407489 . 885424 18 MOV BYTE PTR [ESP+18], DL ; 保存上面的余数[esp+18]=0x03,r4
0040748D . 7E 20 JLE SHORT 004074AF
0040748F . 90 NOP
00407490 > 85C9 TEST ECX, ECX
00407492 . 0F8C D2000000 JL 0040756A
00407498 . 8B7E 70 MOV EDI, DWORD PTR [ESI+70]
0040749B . 3B4F F4 CMP ECX, DWORD PTR [EDI-C]
0040749E . 0F8F C6000000 JG 0040756A
004074A4 . 0FB6140F MOVZX EDX, BYTE PTR [EDI+ECX]
004074A8 . 03C2 ADD EAX, EDX
004074AA . 41 INC ECX
004074AB . 3BCD CMP ECX, EBP
004074AD .^ 7C E1 JL SHORT 00407490 ; 循环将用户名的每一位相加,我的结果EAX=0x1BC
天知道这4个字母加起来居然是0x01BC,还真不是什么好数字呢
004074AF > 8B4E 74 MOV ECX, DWORD PTR [ESI+74] ; 下面开始处理假注册码了
004074B2 . 8B51 F4 MOV EDX, DWORD PTR [ECX-C]
004074B5 . 85D2 TEST EDX, EDX
004074B7 . 7D 0A JGE SHORT 004074C3
004074B9 . 68 57000780 PUSH 80070057
004074BE . E8 4D9BFFFF CALL 00401010
004074C3 > 8A11 MOV DL, BYTE PTR [ECX]
004074C5 . 8B4E 74 MOV ECX, DWORD PTR [ESI+74] ; 取k[1]=0x31,即注册码的第一位
004074C8 . 8379 F4 01 CMP DWORD PTR [ECX-C], 1
004074CC . 885424 19 MOV BYTE PTR [ESP+19], DL ; k[1] -> [esp+19]以及DL
004074D0 . 7D 0A JGE SHORT 004074DC
004074D2 . 68 57000780 PUSH 80070057
004074D7 . E8 349BFFFF CALL 00401010
004074DC > 8A49 01 MOV CL, BYTE PTR [ECX+1]
004074DF . 8B7E 74 MOV EDI, DWORD PTR [ESI+74]
004074E2 . 884C24 13 MOV BYTE PTR [ESP+13], CL ; k[2] -> [esp+13]
004074E6 . 837F F4 02 CMP DWORD PTR [EDI-C], 2
004074EA . 7D 0A JGE SHORT 004074F6
004074EC . 68 57000780 PUSH 80070057
004074F1 . E8 1A9BFFFF CALL 00401010
004074F6 > 8A4F 02 MOV CL, BYTE PTR [EDI+2]
004074F9 . 8B7E 74 MOV EDI, DWORD PTR [ESI+74]
004074FC . 884C24 14 MOV BYTE PTR [ESP+14], CL ; k[3] -> [esp+14]
00407500 . 837F F4 03 CMP DWORD PTR [EDI-C], 3
00407504 . 7D 0A JGE SHORT 00407510
00407506 . 68 57000780 PUSH 80070057
0040750B . E8 009BFFFF CALL 00401010
00407510 > 8A4F 03 MOV CL, BYTE PTR [EDI+3]
00407513 . 8B7E 74 MOV EDI, DWORD PTR [ESI+74]
00407516 . 884C24 15 MOV BYTE PTR [ESP+15], CL ; k[4] -> [esp+15]
0040751A . 837F F4 04 CMP DWORD PTR [EDI-C], 4
0040751E . 7D 0A JGE SHORT 0040752A
00407520 . 68 57000780 PUSH 80070057
00407525 . E8 E69AFFFF CALL 00401010
0040752A > 8A4F 04 MOV CL, BYTE PTR [EDI+4] ; k[5] -> cl
0040752D . 8B7E 74 MOV EDI, DWORD PTR [ESI+74]
00407530 . 837F F4 05 CMP DWORD PTR [EDI-C], 5
00407534 . 7D 0A JGE SHORT 00407540
00407536 . 68 57000780 PUSH 80070057
0040753B . E8 D09AFFFF CALL 00401010
00407540 > 8A5F 05 MOV BL, BYTE PTR [EDI+5]
00407543 . 8B7E 74 MOV EDI, DWORD PTR [ESI+74]
00407546 . 885C24 1A MOV BYTE PTR [ESP+1A], BL ; k[6] -> [esp+1A]
0040754A . 837F F4 06 CMP DWORD PTR [EDI-C], 6
0040754E . 7D 0A JGE SHORT 0040755A
00407550 . 68 57000780 PUSH 80070057
00407555 . E8 B69AFFFF CALL 00401010
0040755A > 8A5F 06 MOV BL, BYTE PTR [EDI+6]
0040755D . 8B7E 74 MOV EDI, DWORD PTR [ESI+74]
00407560 . 885C24 1B MOV BYTE PTR [ESP+1B], BL ; k[7] -> [esp+1B]
00407564 . 837F F4 07 CMP DWORD PTR [EDI-C], 7
00407568 . 7D 0A JGE SHORT 00407574
0040756A > 68 57000780 PUSH 80070057
0040756F . E8 9C9AFFFF CALL 00401010
00407574 > 8A5F 07 MOV BL, BYTE PTR [EDI+7] ; k[8] -> bl
到这里用户名和注册码的预处理基本完毕,可以在内存中看一下,熟悉一下各自的位置,下面就要逐一计算比较了。
00407577 . 0FB67C24 16 MOVZX EDI, BYTE PTR [ESP+16] ; r1
0040757C . 0FB6D2 MOVZX EDX, DL ; k[1]
0040757F . 83EA 30 SUB EDX, 30
00407582 . 3BFA CMP EDI, EDX ; 比较1:k[1]-0x30 == r1
00407584 . 75 48 JNZ SHORT 004075CE ; 如果不相等,似乎也没有一下跳到出错处哦
00407586 . 0FB65424 13 MOVZX EDX, BYTE PTR [ESP+13] ; k[2]
0040758B . 0FB67C24 12 MOVZX EDI, BYTE PTR [ESP+12] ; r2
00407590 . 83EA 30 SUB EDX, 30
00407593 . 3BFA CMP EDI, EDX ; 比较2:k[2]-0x30 == r2
00407595 . 75 37 JNZ SHORT 004075CE
00407597 . 0FB65424 14 MOVZX EDX, BYTE PTR [ESP+14] ; k[3]
0040759C . 0FB67C24 17 MOVZX EDI, BYTE PTR [ESP+17] ; r3
004075A1 . 83EA 30 SUB EDX, 30
004075A4 . 3BFA CMP EDI, EDX ; 比较3:k[3]-0x30 == r3
004075A6 . 75 26 JNZ SHORT 004075CE
004075A8 . 0FB65424 15 MOVZX EDX, BYTE PTR [ESP+15] ; k[4]
004075AD . 0FB67C24 18 MOVZX EDI, BYTE PTR [ESP+18] ; r4
004075B2 . 83EA 30 SUB EDX, 30
004075B5 . 3BFA CMP EDI, EDX ; 比较4:k[4]-0x30 == r4
004075B7 . 75 15 JNZ SHORT 004075CE
004075B9 . 99 CDQ
004075BA . BF 0A000000 MOV EDI, 0A
004075BF . F7FF IDIV EDI ; EAX % 0x0A = 4,即上面求的和
004075C1 . 0FB6C2 MOVZX EAX, DL ; 上面的余数
004075C4 . 0FB6D1 MOVZX EDX, CL ; 比较5:k[5]-0x30 = 4
004075C7 . 83EA 30 SUB EDX, 30
004075CA . 3BC2 CMP EAX, EDX
004075CC . 74 3A JE SHORT 00407608 ; 完成最后一个比较,就成功了!
如果上面的条件没有满足,会跳到这里再经过一次判断:
004075CE > 807C24 19 38 CMP BYTE PTR [ESP+19], 38 ; k[1] == 0x38
004075D3 . 0F85 85000000 JNZ 0040765E ; 这次可是真的跳到失败处了
004075D9 . 807C24 13 33 CMP BYTE PTR [ESP+13], 33 ; k[2] == 0x33
004075DE . 75 7E JNZ SHORT 0040765E
004075E0 . 807C24 14 39 CMP BYTE PTR [ESP+14], 39 ; k[3] == 0x39
004075E5 . 75 77 JNZ SHORT 0040765E
004075E7 . 8A5424 15 MOV DL, BYTE PTR [ESP+15] ; k[4] == 0x31
004075EB . B0 31 MOV AL, 31
004075ED . 3AD0 CMP DL, AL
004075EF . 75 6D JNZ SHORT 0040765E
004075F1 . 80F9 33 CMP CL, 33 ; k[5] == 0x33
004075F4 . 75 68 JNZ SHORT 0040765E
004075F6 . 384424 1A CMP BYTE PTR [ESP+1A], AL ; k[6] == 0x31
004075FA . 75 62 JNZ SHORT 0040765E
004075FC . 807C24 1B 34 CMP BYTE PTR [ESP+1B], 34 ; k[7] == 0x34
00407601 . 75 5B JNZ SHORT 0040765E
00407603 . 80FB 36 CMP BL, 36 ; k[8] == 0x36
00407606 . 75 56 JNZ SHORT 0040765E ; 天啊,居然有万能注册码'83913146'
00407608 > 6A 00 PUSH 0 ; 下面不用说了,提示注册成功并且保存注册信息
0040760A . 6A 00 PUSH 0
0040760C . 68 E8FE4200 PUSH 0042FEE8 ; ASCII "Registration has succeeded!"
00407611 . E8 CD100200 CALL 004286E3
00407616 . 8B7E 70 MOV EDI, DWORD PTR [ESI+70]
00407619 . E8 8A1E0200 CALL 004294A8
0040761E . 8B40 04 MOV EAX, DWORD PTR [EAX+4]
00407621 . 57 PUSH EDI ; /Arg3
00407622 . 68 F4FD4200 PUSH 0042FDF4 ; |Arg2 = 0042FDF4 ASCII "username"
00407627 . 68 ECFD4200 PUSH 0042FDEC ; |Arg1 = 0042FDEC ASCII "Option"
0040762C . 8BC8 MOV ECX, EAX ; |
0040762E . E8 100E0200 CALL 00428443 ; \FileTree.00428443
00407633 . 8B7E 74 MOV EDI, DWORD PTR [ESI+74]
00407636 . E8 6D1E0200 CALL 004294A8
0040763B . 8B40 04 MOV EAX, DWORD PTR [EAX+4]
0040763E . 57 PUSH EDI ; /Arg3
0040763F . 68 D8FD4200 PUSH 0042FDD8 ; |Arg2 = 0042FDD8 ASCII "registration_code"
00407644 . 68 ECFD4200 PUSH 0042FDEC ; |Arg1 = 0042FDEC ASCII "Option"
00407649 . 8BC8 MOV ECX, EAX ; |
0040764B . E8 F30D0200 CALL 00428443 ; \FileTree.00428443
00407650 . 5B POP EBX
00407651 . 5F POP EDI
00407652 . 8BCE MOV ECX, ESI
00407654 . 5E POP ESI
00407655 . 5D POP EBP
00407656 . 83C4 0C ADD ESP, 0C
00407659 . E9 9B8F0100 JMP 004205F9
注册码出错的地方:
0040765E > 6A 00 PUSH 0
00407660 . 6A 00 PUSH 0
00407662 . 68 D0FE4200 PUSH 0042FED0 ; ASCII "Registration failed!"
00407667 . E8 77100200 CALL 004286E3
经过上面的分析,算法大致可以描述出来了,伪代码如下:
string username;
string regcode;
int r[4];
r[1] = (username[1] or 0x45) mod 10;
r[2] = (username[2] or 0x42) mod 10;
r[3] = (username[1] or 0x43) mod 10;
r[4] = (username[2] or 0x44) mod 10;
int sum = username逐位求和;
regcode[1] = r[1] + 0x30;
regcode[2] = r[2] + 0x30;
regcode[3] = r[3] + 0x30;
regcode[4] = r[4] + 0x30;
regcode[5] = (sum mod 10) + 0x30;
regcode[6..8]任意,当然也可以多于8位。
算法不复杂,但是如果还想偷懒一下的话就直接这样:
printf("RegCode: 83913146\n");
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2006年07月27日 11:11:11