【文章标题】: 一次简单的算法分析
【文章作者】: 请哥慢捂
【作者邮箱】: 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