• 标 题:文字处理LemmyV4.0算法浅析!
  • 作 者:ShenGe
  • 时 间:2003/07/03 10:56am
  • 链 接:http://bbs.pediy.com

软件大小:  851 KB
软件语言:  英文
软件类别:  国外软件 / 共享版 / 文字处理
应用平台:  Win9x/NT/2000/XP
界面预览:  无
加入时间:  2003-07-02 17:09:04
推荐等级:  ★★★★
软件下载:  http://count.skycn.com/softdown.php?id=12742&url=http://on165-http.skycn.net:8080/down/lemmy40.exe

软件介绍:
   是一套文字编辑软件。是Unix上的文件编辑器(vi)的Windows版本。它提供了vi的所有功能。以下列出几个unix下的vi所没有的功能:1、分割视窗模式,允许向上移四个分割视窗。2、支持Windows的剪贴簿。3、可以直接拖拉文件到Lemmy中。4、可以设定字型与颜色,并且支持语法高亮度显示。5、状态列显示资讯。6、可从文件选单中,选取最近使用过的文件。7、支持印表机打印,也可以把语法高亮度印出来喔。虽然它是个文字编辑器,但对Windows的使用者来说,是一套很不好用的编辑器。


破解工具:OllyDby1.09,TRW1.22
作者声明:初学破解,仅作学习交流之用,失误之处敬请大侠赐教!

无壳,VC编写,这个软件的注册部分是在安装文件夹下的lemreg.exe文件中!
先在TRW中用bpx getwindowtexta下断找断点,再用OD载入lemreg.exe分析!

【简要过程】:
用户名:ShenGe[BCG]
试验码:1234567887654321

.............(略)
0040179B  PUSH    EAX  
                 <---EAX="1234567887654321",假码                      
0040179C  PUSH    ECX
                 <---ECX="ShenGe[BCG]",用户名
0040179D  LEA     ECX, DWORD PTR DS:[ESI+68]
004017A0  CALL    LEMREG.004019F0
                 <---这个是关键的Call,跟进!①
004017A5  TEST    EAX, EAX                        
004017A7  JE      SHORT LEMREG.004017FF
                 <---关键跳转!不跳就完了!
004017A9  PUSH    0
004017AB  PUSH    30
004017AD  PUSH    LEMREG.0042E0B0                  
                 <---"Check the values supplied"入栈!
004017B2  CALL    LEMREG.0041EE0E
                 <---注册码错误!
004017B7  PUSH    3E8
004017BC  MOV     ECX, ESI
004017BE  CALL    LEMREG.0041B8AA
004017C3  MOV     ECX, EAX                        
004017C5  CALL    LEMREG.0041BB07
004017CA  PUSH    3E8
004017CF  MOV     ECX, ESI
004017D1  CALL    LEMREG.0041B8AA
004017D6  MOV     EDI, DWORD PTR DS:[<&USER32.Send>
004017DC  MOV     ESI, EAX                        
004017DE  PUSH    -1                               ; /lParam = FFFFFFFF
004017E0  PUSH    0                                ; |wParam = 0
004017E2  MOV     ECX, DWORD PTR DS:[ESI+1C]       ; |
004017E5  PUSH    0B1                              ; |Message = EM_SETSEL
004017EA  PUSH    ECX                              ; |hWnd = 81637000
004017EB  CALL    EDI                              ; \SendMessageA
004017ED  MOV     EDX, DWORD PTR DS:[ESI+1C]
004017F0  PUSH    0                                ; /lParam = 0
004017F2  PUSH    0                                ; |wParam = 0
004017F4  PUSH    0B7                              ; |Message = EM_SCROLLCARET
004017F9  PUSH    EDX                              ; |hWnd = 81637040
004017FA  CALL    EDI                              ; \SendMessageA
004017FC  POP     EDI    
004017FD  POP     ESI                          
004017FE  RETN
004017FF  MOV     ECX, ESI
00401801  CALL    LEMREG.00418656
00401806  POP     EDI                              
00401807  POP     ESI                              
00401808  RETN

★★★★★★★★★
①跟进那个关键的Call,来到以下代码:
004019F0  PUSH    EBX
004019F1  PUSH    EBP
004019F2  PUSH    ESI
004019F3  PUSH    EDI
004019F4  MOV     EDI, ECX
004019F6  PUSH    8
004019F8  OR      EBP, FFFFFFFF
004019FB  CALL    LEMREG.00417E88
00401A00  MOV     ESI, DWORD PTR SS:[ESP+1C]
00401A04  ADD     ESP, 4
00401A07  MOV     EBX, EAX
00401A09  XOR     EDX, EDX

☆☆☆☆☆☆☆☆☆☆
00401A0B  MOVSX   EAX, BYTE PTR DS:[ESI]
                 <---取假码第1位
00401A0E  MOVSX   ECX, BYTE PTR DS:[ESI+1]
                 <---取假码第2位

下面这1段对取得的字符进行判断,并进行不同的处理:
对于字符在[0,9]的,Hex值减0x30
对于字符在[A,F]的,Hex值减0x37
其余字符为不合法字符
≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈
00401A12  CMP     EAX, 30
00401A15  JL      SHORT LEMREG.00401A21
00401A17  CMP     EAX, 39
00401A1A  JG      SHORT LEMREG.00401A21
00401A1C  SUB     EAX, 30
00401A1F  JMP     SHORT LEMREG.00401A32
00401A21  CMP     EAX, 41
00401A24  JL      SHORT LEMREG.00401A30
00401A26  CMP     EAX, 46
00401A29  JG      SHORT LEMREG.00401A30
00401A2B  SUB     EAX, 37
00401A2E  JMP     SHORT LEMREG.00401A32
00401A30  XOR     EAX, EAX
00401A32  CMP     ECX, 30
00401A35  JL      SHORT LEMREG.00401A41
00401A37  CMP     ECX, 39
00401A3A  JG      SHORT LEMREG.00401A41
00401A3C  SUB     ECX, 30
00401A3F  JMP     SHORT LEMREG.00401A52
00401A41  CMP     ECX, 41
00401A44  JL      SHORT LEMREG.00401A50
00401A46  CMP     ECX, 46
00401A49  JG      SHORT LEMREG.00401A50
00401A4B  SUB     ECX, 37
00401A4E  JMP     SHORT LEMREG.00401A52
≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈≈

00401A50  XOR     ECX, ECX
-------------------------
00401A52  SHL     AL, 4
00401A55  ADD     AL, CL
-------------------------
☆☆☆☆☆☆☆☆☆☆
这1段实现如下功能:Char(如"12")--->Hex(转换成0x12)

00401A57  ADD     ESI, 2
                 <---指针指向下一组
00401A5A  MOV     BYTE PTR DS:[EBX+EDX], AL
                 <---结果存入DS:[EBX+EDX]中
                 我的结果在内存中表示为:
                 12 34 56 78 87 65 43 21
00401A5D  INC     EDX
00401A5E  CMP     EDX, 8
                 <---循环控制,循环8次
00401A61  JL      SHORT LEMREG.00401A0B
00401A63  PUSH    EBX
                 <---EBX的值为上面运算后的结果
                 在内存中为12 34 56 78 87 65 43 21  
00401A64  MOV     ECX, EDI                          
00401A66  CALL    LEMREG.00401060  
                 <---跟进此Call看看②,此Call后的返回
                 值在EBX中为:B6 7C EE 16 84 13 91 EE
00401A6B  MOV     EDX, DWORD PTR SS:[ESP+14]
                 <---EDX="ShenGe[BCG]"      
00401A6F  OR      ECX, FFFFFFFF
00401A72  MOV     EDI, EDX
00401A74  XOR     EAX, EAX
00401A76  REPNE   SCAS BYTE PTR ES:[EDI]
                 <---取用户名位数
00401A78  NOT     ECX
00401A7A  DEC     ECX
00401A7B  CMP     ECX, 8
                 <---判断用户名位数是否大于等于8
00401A7E  JBE     SHORT LEMREG.00401A87
00401A80  MOV     ECX, 8
                 <---ECX=8,估计只取用户名8位运算
00401A85  JMP     SHORT LEMREG.00401A93
00401A87  MOV     EDI, EDX
00401A89  OR      ECX, FFFFFFFF
00401A8C  XOR     EAX, EAX
00401A8E  REPNE   SCAS BYTE PTR ES:[EDI]
00401A90  NOT     ECX
00401A92  DEC     ECX
00401A93  TEST    ECX, ECX
00401A95  JLE     SHORT LEMREG.00401AA8
00401A97  PUSH    ECX
                 <---ECX=8
00401A98  PUSH    EBX
                 <---EBX指向B6 7C EE 16 84 13 91 EE
00401A99  PUSH    EDX
                 <---EDX="ShenGe[BCG]"
00401A9A  CALL    LEMREG.004079F0
                 <---比对的Call,这个代码我就不列出来了
                 这个Call将用户名的前8位字符的Hex与
                 B6 7C EE 16 84 13 91 EE分别进行比较是否相等,
                 即要求注册码经过转换后的值要与用户名
                 的Hex值相等。
00401A9F  ADD     ESP, 0C
00401AA2  TEST    EAX, EAX
00401AA4  JNZ     SHORT LEMREG.00401AA8
                 <---比较不相等此处会跳!
00401AA6  XOR     EBP, EBP
                 <---EBP=0
00401AA8  PUSH    EBX
00401AA9  CALL    LEMREG.00417EC4
00401AAE  ADD     ESP, 4
00401AB1  MOV     EAX, EBP
                 <---EAX=EBP,标志位!
00401AB3  POP     EDI                              
00401AB4  POP     ESI                              
00401AB5  POP     EBP                              
00401AB6  POP     EBX                            
00401AB7  RETN    8


★★★★★★★★★
②跟进这个Call:
00401060  SUB     ESP, 8
00401063  MOV     EDX, DWORD PTR SS:[ESP+C]
                 <---EDX指向内存中
                 12 34 56 78 87 65 43 21
00401067  PUSH    EBX
00401068  PUSH    ESI
00401069  PUSH    EDI
☆☆☆☆☆☆☆☆☆☆
0040106A  MOV     AL, BYTE PTR DS:[EDX+4]
                 <---AL=87,取第5位
0040106D  MOV     EDI, ECX
0040106F  MOV     CL, BYTE PTR DS:[EDX+2]
                 <---CL=56,取第3位
00401072  MOV     BYTE PTR SS:[ESP+C], AL
                 <---AL的值存入SS:[ESP+C]
00401076  MOV     AL, BYTE PTR DS:[EDX+7]
                 <---AL=21,取第8位
00401079  MOV     BYTE PTR SS:[ESP+D], CL
                 <---CL的值存入SS:[ESP+D]中
0040107D  MOV     CL, BYTE PTR DS:[EDX]
                 <---CL=12,取第1位,唉!后面懒得写了!
0040107F  MOV     BYTE PTR SS:[ESP+E], AL
00401083  MOV     AL, BYTE PTR DS:[EDX+6]
00401086  MOV     BYTE PTR SS:[ESP+F], CL
0040108A  MOV     CL, BYTE PTR DS:[EDX+3]
0040108D  MOV     BYTE PTR SS:[ESP+10], AL
00401091  MOV     AL, BYTE PTR DS:[EDX+5]
00401094  MOV     BYTE PTR SS:[ESP+11], CL
00401098  MOV     CL, BYTE PTR DS:[EDX+1]
0040109B  MOV     BYTE PTR SS:[ESP+12], AL
☆☆☆☆☆☆☆☆☆☆
上面这一小段是将内存中的值重新排序,对应关系如下:

原值:                12 34 56 78 87 65 43 21
                     ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
对应于在原值中的位置:5  3  8  1  7  4  6  2
----------------------------------------------
排序后:              87 56 21 12 43 78 65 34
                 
0040109F  LEA     ESI, DWORD PTR SS:[ESP+C]
004010A3  XOR     EAX, EAX
004010A5  MOV     BYTE PTR SS:[ESP+13], CL
004010A9  SUB     ESI, EDX
004010AB  MOV     CL, BYTE PTR DS:[EAX+EDI+14]
                 <---[EDI+14]中指向的内存中为
                定值31 2A CF 04 C7 6B F4 DA
                 CL=0x31
                 CL=0x2A
                 .....(略)
004010AF  MOV     BL, BYTE PTR DS:[ESI+EDX]
                 <---[ESI]中为重新排序后的值
                 87 56 21 12 43 78 65 34
                 BL=0x87
                 BL=0x56
                 ....(略)
004010B2  XOR     CL, BL
                 <---CL=CL^BL=0x31^0x87=0xB6
                     CL=0x2A^0x56=0x7C
                     ....(略)
004010B4  INC     EAX
004010B5  MOV     BYTE PTR DS:[EDX], CL
                 <---作或运算后的结果存入DS:[EDX]中
                 我最后得到的为:B6 7C EE 16 84 13 91 EE
004010B7  INC     EDX
004010B8  CMP     EAX, 8
004010BB  JL      SHORT LEMREG.004010AB
004010BD  POP     EDI                              
004010BE  POP     ESI                              
004010BF  POP     EBX                              
004010C0  ADD     ESP, 8
004010C3  RETN    4

【总结】:用户名长度必须大于或等于8,注册码与用户名前8位有关。具体算法见我下
面逆推我的注册码过程:
程序中置定值31 2A CF 04 C7 6B F4 DA与注册码作运算!

 S--->53---->53^31=62
 h--->68---->68^2A=42
 e--->65====>65^CF=AA
 n--->6E====>6E^04=6A
 G--->47====>47^C7=80
 e--->65====>65^6B=0E
 [--->5B====>5B^F4=AF
 B--->42====>42^DA=98

原值:               6A 98 42 0E 62 AF 80 AA
--------------------------------------------
对应于在原值的位置: 5  3  8  1  7  4  6  2
                    ↑ ↑ ↑ ↑ ↑ ↑ ↑ ↑
排序后:             62 42 AA 6A 80 0E AF 98

由此得到我的注册码为:6A98420E62AF80AA
软件注册成功后将注册信息保存在注册表的:
"HKEY_LOCAL_MACHINE\Software\Lemmy\Lemmy\Registration"下。
                 
给出一个可用注册码:
用户名:ShenGe[BCG]
注册码:6A98420E62AF80AA

                                             Cracked By ShenGe[BCG]  2003.07.03