新手破解练习Crackme160之012 - attackiko (非PE)

引用大佬文章

160个CrackMe练手之012

Pnmker

当当当,期待已久的012破文终于面世了。这个CM技术上的难点不多,只因其程序格式不是主流PE之类的格式,看似破之颇有难度,其实非也。尽管如此,这篇破文中不会给出详细的跟踪步骤,而代替的是反汇编的静态分析。

主要讲述静态分析,并不意味着动态跟踪就不重要。之所以把跟踪忽略掉,一方面是跟踪调试技术大家都很熟练,另一方面这个CM对调试技术的要求也不高(前面已有朋友提及),最重要的我认为对于想要成为大牛的新手来说,要精通掌握破解逆向唯耐心不破。相对动态跟踪来说,静态分析更加考验个人的耐心与耐力,尤其是对于新手,在其学习的道路上考验更加之多。
所以此文仍然仅献给那些奔走在成为大牛之路上的新手们。大牛们如果认为写得不好可以无视。
对于这个CM的前期工作这里简单带过一下,只因它是比较古老的16位NE格式,我可是废了不少的周折。尽管之前已经有朋友提起过,在我拿到这个程序的时候没有想起。直到把它拖到PEiD上提示“不是有效的PE文件”才模糊记起来,于是拿资源工具ResScope检测一下果然是16位 NE。不多想了,直接上W32DAsm找程序中可能使用到的Windows API中有关的弹窗函数调用,确实找到了MessageBox,立即TRW2000上bpx MessageBox下断跑起来。咦,竟然没断下来!嗯,好吧,再试一下其它的bpxdialogbox, bpx dialogboxparam,bpx createwindow,这么奇怪一个都没断下来!这时突然想起来这个程序是TPascal的,跟Delphi同出一家,估计这些函数都是不能断下来的。(不要告诉我使用万能断点 bpxhmemcpy,我在学习如果使用了它很多经验就没法获得了。)而且看W32DAsm的反汇编是不太可能的了,很多代码的段偏移地址跟TRW2000都对应不上。于是返回去看我已经发过的关于16位的帖子,记得是有朋友提过使用IDA的。好吧,IDA隆重上场了,果然是神器!整个的反汇编连函数名都给出了,如果不确定的函数/过程,则使用sub_前缀顺序编号,反汇编中的函数调用关系也十分详细。大概浏览了一遍发现有几个重要的函数MessageDlg,MessageDlgPos, CreateMessageDialog可能跟弹窗有关,bpx这几个函数名是断不下来的(当时估计可能不是导出函数的原因吧)。细看CreateMessageDialog里面有调用USER模块的DRAWTEXT,果断bpx DRAWTEXT!啊哈,断下来了,Delphi果然可以不用调用Windows的经典弹窗API,但谁让你运行在Windows系统上呢,某些底层实现始终不能绕开Windows啊,这不DRAWTEXT不就是一个可以断下来的吗。循着这个断点层层追踪,不费吹灰之力就找到了“CheckIt"按钮的点击处理事件的处理过程,在IDA里面的地址是cseg01:01F4。由于TRW2000每次载入程序的时候,代码段寄存器的基址可能都不一样,所以只需每次载入断在程序入口的时候bpx cs:01F4就行了。查了下看雪论坛的TRW2000操作手册,使用u cs:01F4 >aa.txt导出了反汇编代码。下面的工作主要是静态分析反汇编了,不确定的地方在针对性下断确认。
这段反汇编代码490行左右,不像之前朋友说的只有十几行。我逐部分按代码在做什么讲下就OK了,至于细节有兴趣的朋友个人去分析和跟踪吧。

220F:01F4 PUSH BP[/align][align=left]220F:01F5 MOV BP,SP
220F:01F7 MOV AX,050E
220F:01FA CALL 270B       ;__StackCheck(Word)
220F:01FF SUB SP,050E       
 
220F:0203 LEA DI,[BP-40E]
220F:0207 PUSH SS
220F:0208 PUSH DI ;
220F:0209 LES DI,[BP+06]
220F:020C LES DI,[ES:DI+0188]
220F:0211 PUSH ES       ;
220F:0212 PUSH DI       
220F:0213 CALL 1D53 ;TControl::GetText(void)
220F:0218 ADD SP,BYTE +04 ;
220F:021B CMP BYTE [BP-40E],00 ;输入的Password的长度
220F:0220 JNZ 0225 ;长度不为0获取成功
220F:0222 JMP 0781 ;长度为0直接退出,0781是函数结尾

上面这段主要是做了堆栈检查和判断输入文本的长度,非常简单不多说。

220F:0225  MOV      BYTE [BP-30D],01  ;
220F:022A  MOV      BYTE [BP-100],00  ;
220F:022F  XOR      AX,AX
220F:0231  MOV      [BP-104],AX       ;
220F:0235  MOV      BYTE [BP-204],00  ;
220F:023A  XOR      AX,AX
220F:023C  MOV      [BP-306],AX       ;
220F:0240  MOV      WORD [BP-30C],00  ;
220F:0246  MOV      WORD [BP-30A],00  ;
220F:024C  MOV      WORD [BP-308],00  ;以上几行都是对局部变量的初始化
 
220F:0252  LEA      DI,[BP-40E]                  ; 获取输入的Password存入[BP-40E]
220F:0256  PUSH     SS
220F:0257  PUSH     DI
220F:0258  LES      DI,[BP+06]
220F:025B  LES      DI,[ES:DI+0188]
220F:0260  PUSH     ES
220F:0261  PUSH     DI
220F:0262  CALL     1D53               ;TControl:GetText(void)
                                                                                ;
220F:0267  LEA      DI,[BP-100]        ;将[BP-40E]的Password复制到[BP-100]
220F:026B  PUSH     SS
220F:026C  PUSH     DI
220F:026D  PUSH     WORD FF
220F:0270  CALL     34C7               ; In IDA : operator=(String &,String &,Byte),
 
220F:0275  LEA      DI,[BP-100]        ;将[BP-100]再复制到[BP-304一份]
220F:0279  PUSH     SS                                       ;因此程序一开头[BP-40E],[BP-100],[BP-304]存放都是Password
220F:027A  PUSH     DI                                       ;当然后面[BP-40E] ,[BP-100]有发生变化
220F:027B  LEA      DI,[BP-304]
220F:027F  PUSH     SS
220F:0280  PUSH     DI
220F:0281  PUSH     WORD FF
220F:0284  CALL     34C7                           ; operator=(String &,String &,Byte)
 
220F:0289  MOV      AL,[BP-100]                   ; [BP-100]为输入文本的长度,注意Pascal/Delphi存放字符串的方式是
220F:028D  XOR      AH,AH                               ;首地址第一个字节给出文本长度,后面紧接着就是文本(超过0xFF(255d)咋办呢?)
220F:028F  MOV      [BP-306],AX        ;
220F:0293  MOV      WORD [BP-30C],00   ;置为0,其实这三个连续双字是存放浮点数的
220F:0299  MOV      WORD [BP-30A],00   ;
220F:029F  MOV      WORD [BP-308],00   ;
220F:02A5  MOV      AX,[BP-306]        ;
220F:02A9  MOV      [BP-310],AX        ; 文本长度
220F:02AD  MOV      AX,01
220F:02B0  CMP      AX,[BP-310]        ;
220F:02B4  JG       0308               ; 如果文本长度<1,直接跳转;长度大于0不跳转的,从220F:02B6
                                                                                ;到220F:0306是在求所有的字符ASCII码之和
220F:02B6  MOV      [BP-104],AX                   ;[BP-104]为求和的循环变量
220F:02BA  JMP      SHORT 02C0
220F:02BC  INC      WORD [BP-104]      ;
220F:02C0  MOV      AX,[BP-30C]                   ;正如上面所说,这三个连续双字为浮点数,程序中存放的是字符ASCII码之和
220F:02C4  MOV      BX,[BP-30A]        ;
220F:02C8  MOV      DX,[BP-308]        ;
220F:02CC  CALL     2CEE                   ;Extended(Real),将通用寄存器中的浮点数(IEE?)转换为
                                                                                ;浮点数寄存器FPU运算支持的扩展实数
220F:02D1  MOV      DI,[BP-104]        ;
220F:02D5  MOV      AL,[BP+DI-100]     ;
220F:02D9  XOR      AH,AH
220F:02DB  XOR      DX,DX
220F:02DD  MOV      [BP-314],AX        ;
220F:02E1  MOV      [BP-312],DX        ;
220F:02E5  NOP    
220F:02E6  FILD     DWORD [BP-314]     ;以上为将Password的逐个字符作为浮点数载入FPU寄存器栈顶st(0)
220F:02EA  NOP                                                    ;此时st(1)就是上次循环所求的和
220F:02EB  FADDP    ST1                                       ;相加,st(0)同时出战
220F:02ED  CALL     2D18               ;Real(Extended),FPU扩展实数转换为通用寄存器实数(IEE)
220F:02F2  MOV      [BP-30C],AX                   ;
220F:02F6  MOV      [BP-30A],BX                       ;
220F:02FA  MOV      [BP-308],DX        ;此次循环所求得的和数
220F:02FE  MOV      AX,[BP-104]
220F:0302  CMP      AX,[BP-310]        ;循环控制
220F:0306  JNZ      02BC

上面这段主要工作有局部变量初始化、输入的Password拷贝三份和对输入文本进行ASCII码求和。

;接下来,这三个双字存储的浮点数为字符ASCII码的和
;以下因为涉及到比较复杂的数学运算,并且使用到了两个全局浮点数变量,所以在此规定记:
;1.输入Password的文本长度为len,
;2.字符ASCII码之和为sum(浮点数存储)
;3.[CS:01C3]存储的全局浮点数0.296439,记为d1
;4.[CS:01CD]存储的全局浮点数1294.39894,记为d2
;另对于FPU浮点数寄存器栈不熟的,请仔细查阅相关资料
220F:0308  MOV      AX,[BP-30C]    ;
220F:030C  MOV      BX,[BP-30A]           ;
220F:0310  MOV      DX,[BP-308]    ;
220F:0314  CALL     2CEE           ;Extended(Real),sum转FPU扩展实数
220F:0319  NOP    
220F:031A  FSTP     TWORD [BP-322] ;将sum转存到[BP-322]
220F:031E  MOV      AX,[BP-30C]
220F:0322  MOV      BX,[BP-30A]
220F:0326  MOV      DX,[BP-308]
220F:032A  CALL     2CEE           ;Extended(Real),sum转FPU扩展实数
220F:032F  NOP    
220F:0330  FLD      TWORD [CS:01C3] ; d1载入FPU寄存器栈顶st(0)
220F:0335  NOP    
220F:0336  FMULP    ST1                               ;求得乘积sum * d1,并将栈顶元素d1退栈
220F:0338  CALL     2DC4           ;sqrt(double),求平方根 sqrt(sum*d1)
220F:033D  NOP    
220F:033E  FSTP     TWORD [BP-318] ;存储sqrt(sum*d1)
220F:0342  MOV      AX,[BP-30C]
220F:0346  MOV      BX,[BP-30A]
220F:034A  MOV      DX,[BP-308]
220F:034E  CALL     2CEE           ;Extended(Real),sum转FPU扩展实数
220F:0353  NOP    
220F:0354  FLD      TWORD [CS:01CD]       ;d2载入FPU寄存器栈顶st(0)
220F:0359  CALL     2799           ;FSafeDivide(void),浮点数除法sum/d2
220F:035E  CALL     2DD4                       ;Ln(Extended),求自然对数:ln(sum/d2)
220F:0363  NOP    
220F:0364  FLD      TWORD [BP-318] ; 载入220F:033E处存在[BP-318]的计算结果sqrt(sum*d1)到FPU栈顶st(0)
220F:0368  NOP    
220F:0369  FADDP    ST1            ; 求和sqrt(sum*d1)+ln(sum/d2)
220F:036B  NOP    
220F:036C  FLD      TWORD [BP-322] ; 将220F:031出存在[BP-322]的sum载入到FPU栈顶st(0)
220F:0370  NOP    
220F:0371  FMULP    ST1                           ; 求乘积sum * (sqrt(sum*d1)+ln(sum/d2)),栈顶元素退栈
220F:0373  NOP    
220F:0374  FSTP     TWORD [BP-336] ;存储sum * (sqrt(sum*d1)+ln(sum/d2))
220F:0378  NOP    
220F:0379  FILD     WORD [BP-306]  ;将220F:028F处存在[BP-306]的len载入到FPU栈顶st(0)
220F:037D  CALL     2DC8                       ;Sin(Extended),求正弦, sin(len)
220F:0382  NOP    
220F:0383  FSTP     TWORD [BP-32C] ; 存储sin(len)
220F:0387  MOV      AX,[BP-30C]
220F:038B  MOV      BX,[BP-30A]
220F:038F  MOV      DX,[BP-308]
220F:0393  CALL     2CEE           ;Extended(Real),sum转FPU扩展实数
220F:0398  NOP    
220F:0399  FILD     WORD [BP-306]  ; len
220F:039D  NOP    
220F:039E  FMULP    ST1            ;乘积, sum*len
220F:03A0  CALL     2DCC                       ; Cos(Extended),求余弦cos(sum*len)
220F:03A5  NOP    
220F:03A6  FLD      TWORD [BP-32C] ; 将220F:0383存储在[BP-32C]的sin(len)载入到FPU栈顶st(0)
220F:03AA  NOP    
220F:03AB  FMULP    ST1                               ; 求乘积sin(len)*cos(sum*len)
220F:03AD  NOP    
220F:03AE  FLD      TWORD [BP-336] ;将220F:0374存储在[BP-336]的计算结果sum * (sqrt(sum*d1)+ln(sum/d2))载入FPU栈顶st(0)
220F:03B2  NOP    
220F:03B3  FADDP    ST1                               ;求和得sum * (sqrt(sum*d1)+ln(sum/d2))+sin(len)*cos(sum*len
220F:03B5  CALL     2DCC                       ;Cos(Extended)求余弦得 cos(sum * (sqrt(sum*d1)+ln(sum/d2))+sin(len)*cos(sum*len))
220F:03BA  CALL     2D18           ;Real(Extended),FPU扩展实数转换为通用寄存器实数(IEE)
220F:03BF  MOV      [BP-30C],AX
220F:03C3  MOV      [BP-30A],BX
220F:03C7  MOV      [BP-308],DX    ;将计算结果cos(sum * (sqrt(sum*d1)+ln(sum/d2))+sin(len)*cos(sum*len))存储在此三个双字
 
;下面这小段主要是将计算结果cos(sum * (sqrt(sum*d1)+ln(sum/d2))+sin(len)*cos(sum*len))
;转换为了使用科学计数法的字符串,总长度0x17,例如我输入Password为pnmker的时候转换为的字符串(注意正数有一个前导空格)
;为“ 7.87999800586476E-0001”
220F:03CB  MOV      AX,[BP-30C]
220F:03CF  MOV      BX,[BP-30A]
220F:03D3  MOV      DX,[BP-308]
220F:03D7  CALL     2CEE           ;Extended(Real),计算结果转FPU扩展实数
220F:03DC  PUSH     BYTE +17       ;0x17,表示字符串的总长度吗???
220F:03DE  PUSH     BYTE -01       ;难点是一个枚举值,表示转为科学计数法
220F:03E0  LEA      DI,[BP-100]    ;科学计数法的字符串存储在此
220F:03E4  PUSH     SS
220F:03E5  PUSH     DI
220F:03E6  PUSH     WORD FF
220F:03E9  CALL     37A7           ; Str(Extended,Word,Word,String &,Word),转为字符串
220F:03EE  MOV      WORD [BP-30C],00
220F:03F4  MOV      WORD [BP-30A],00
220F:03FA  MOV      WORD [BP-308],00 ;清零

上面这段个人认为比较复杂的一段,不过从IDA的反汇编上来看也不难,主要进行了一系列复杂的数学运算求得了结果cos(sum (sqrt(sumd1)+ln(sum/d2))+sin(len)cos(sumlen)),并将其转换为了科学计数法的字符串

;从220F:0400到220F:06B8这段挺长,看似吓人,其实做得事情很简单
;叙述方便期间做以下规定:(以输入pnmker为例)
;1.记输入Password在[BP-40E]处字符串首地址为P,则P[0]为字符串长度,P[1]='p',P[2]='n',...,P[6]='r'
;2.记存储在[BP-100]的科学计数法字符串首地址为Q,则Q[0]为字符串长度,Q[1]...Q[字符串长度]同1所述
;3.记[BP-50E]存储的字符串首地址记为R
;4.记[BP-204]存储的字符串首地址记为S
;5.记程序开始存储在[BP-40E] 的输入Password的首地址为K;
;那么最终[BP-204]的字符串即为所求,其计算公式如下:
;S[0]=0x9,字符串长度
;S[1]=Q[0x2]+0xA;         S[2]= Q[0x8]+0x3C; S[3]=Q[0x11]+0x30
;S[4]=Q[0x10]+0x2A; S[5]=Q[0xF]+0x35;  S[6]=Q[0xE]+0x2C
;S[7]=Q[0xD]+0x2F;  S[8]=Q[0xC]-0x15;  S[9]=Q[0x3]-0xD
220F:0400  MOV      AL,[BP-100]                            ;Q[0]字符串长度
220F:0404  XOR      AH,AH
220F:0406  CMP      AX,01
220F:0409  JNL      040E           
220F:040B  JMP      06BB                                   ;如果Q[0]=1直接跳转到06BB
 
220F:040E  MOV      [BP-104],AX                            ;[BP-104]存储Q字符串的逆序逐个字符遍历的循环变量
220F:0412  JMP      SHORT 0418
220F:0414  DEC      WORD [BP-104]                               ;逆序遍历字符
 
220F:0418  CMP      WORD [BP-104],BYTE +12     ;
220F:041D  JNZ      0465
220F:041F  LEA      DI,[BP-50E]                ;将字符串S赋给R
220F:0423  PUSH     SS
220F:0424  PUSH     DI
220F:0425  LEA      DI,[BP-204]
220F:0429  PUSH     SS
220F:042A  PUSH     DI
220F:042B  CALL     34AD                                          ; operator=(String &,String &)
220F:0430  LEA      DI,[BP-40E]                                   ;K,曾经为输入Password,注意经过此次处理K变成了只有一个字符的字符串!
220F:0434  PUSH     SS
220F:0435  PUSH     DI
220F:0436  MOV      AX,[BP-104]                                   ;AX=0x12,循环变量
220F:043A  SUB      AX,0A                                                 ;AX=0x12-0xA=0x8
220F:043D  MOV      DI,AX                                         ;DI=0x8
220F:043F  MOV      AL,[BP+DI-100]                                ;AL=Q[0x8]
220F:0443  XOR      AH,AH
220F:0445  ADD      AX,[BP-104]                                   ;AX=Q[0x8]+0x12
220F:0449  ADD      AX,2A                                         ;AX=Q[0x8]+0x12+0x2A=Q[0x8]+0x3C
220F:044C  PUSH     AX                                            ;
220F:044D  CALL     35C9                                          ; operator=(String &,Char), K[0]=1,K[1]=AX,K只有一个字符了
220F:0452  CALL     352C                                          ; Concat(String &,String &), R=R + K
220F:0457  LEA      DI,[BP-204]                ;将字符串R赋给S
220F:045B  PUSH     SS
220F:045C  PUSH     DI
220F:045D  PUSH     WORD FF
220F:0460  CALL     34C7                                                  ; operator=(String &,String &,Byte) , S=R
 
220F:0465  CMP      WORD [BP-104],BYTE +11
220F:046A  JNZ      04A9
220F:046C  LEA      DI,[BP-50E]                ;将字符串S赋给R
220F:0470  PUSH     SS
220F:0471  PUSH     DI
220F:0472  LEA      DI,[BP-204]
220F:0476  PUSH     SS
220F:0477  PUSH     DI
220F:0478  CALL     34AD                                          ; operator=(String &,String &)
220F:047D  LEA      DI,[BP-40E]                                   ;K,此处K只有一个字符
220F:0481  PUSH     SS
220F:0482  PUSH     DI
220F:0483  MOV      DI,[BP-104]                                   ;DI=0x11
220F:0487  MOV      AL,[BP+DI-100]                                ;AL=Q[0x11]
220F:048B  XOR      AH,AH                       
220F:048D  ADD      AX,30                                               ;AX=Q[0x11]+0x30
220F:0490  PUSH     AX                                                       ;
220F:0491  CALL     35C9                                          ; operator=(String &,Char), K[0]=1,K[1]=AX
220F:0496  CALL     352C                                          ; Concat(String &,String &), R = R + K
220F:049B  LEA      DI,[BP-204]                ;将字符串R赋给S
220F:049F  PUSH     SS
220F:04A0  PUSH     DI
220F:04A1  PUSH     WORD FF
220F:04A4  CALL     34C7                                                  ; operator=(String &,String &,Byte)
 
220F:04A9  CMP      WORD [BP-104],BYTE +10
220F:04AE  JNZ      04F1
220F:04B0  LEA      DI,[BP-50E]                ;将字符串S赋给R
220F:04B4  PUSH     SS
220F:04B5  PUSH     DI
220F:04B6  LEA      DI,[BP-204]
220F:04BA  PUSH     SS
220F:04BB  PUSH     DI
220F:04BC  CALL     34AD                                          ; operator=(String &,String &)
220F:04C1  LEA      DI,[BP-40E]                                       ; K只有一个字符了
220F:04C5  PUSH     SS
220F:04C6  PUSH     DI
220F:04C7  MOV      DI,[BP-104]                                       ; DI=0x10
220F:04CB  MOV      AL,[BP+DI-100]                               ; AL=Q[0x10]
220F:04CF  XOR      AH,AH
220F:04D1  ADD      AX,[BP-104]                                       ; AX = Q[0x10]+0x10
220F:04D5  ADD      AX,1A                                               ; AX = Q[0x10]+0x10+0x1A=Q[0x10]+0x2A
220F:04D8  PUSH     AX
220F:04D9  CALL     35C9                                          ; operator=(String &,Char), K[0]=1, K[1]=AX
220F:04DE  CALL     352C                                          ; Concat(String &,String &),R=R+K
220F:04E3  LEA      DI,[BP-204]                                       ;将字符串R赋给S
220F:04E7  PUSH     SS
220F:04E8  PUSH     DI
220F:04E9  PUSH     WORD FF
220F:04EC  CALL     34C7                                                  ; operator=(String &,String &,Byte)
 
220F:04F1  CMP      WORD [BP-104],BYTE +0F
220F:04F6  JNZ      0541
220F:04F8  LEA      DI,[BP-50E]                                       ;将字符串S赋给R
220F:04FC  PUSH     SS
220F:04FD  PUSH     DI
220F:04FE  LEA      DI,[BP-204]
220F:0502  PUSH     SS
220F:0503  PUSH     DI
220F:0504  CALL     34AD                                      ; operator=(String &,String &)
220F:0509  LEA      DI,[BP-40E]                                       ; K只有一个字符了
220F:050D  PUSH     SS
220F:050E  PUSH     DI
220F:050F  MOV      AX,[BP-104]                                       ; AX=0xF
220F:0513  MUL      WORD [BP-104]                               ; AX=0xF*0xF=0xE1
220F:0517  MOV      DX,AX                                               ; DX=0xE1
220F:0519  MOV      DI,[BP-104]                                       ; DI=0xF
220F:051D  MOV      AL,[BP+DI-100]                               ; AL=Q[0xF]
220F:0521  XOR      AH,AH
220F:0523  ADD      AX,DX                                               ;AX = Q[0xF]+0xE1
220F:0525  SUB      AX,0ACh                                               ;AX = Q[0xF]+0xE1-0xAC=Q[0xF]+0x35
220F:0528  PUSH     AX
220F:0529  CALL     35C9                                          ; operator=(String &,Char), K[0]=1,K[1]=AX
220F:052E  CALL     352C                                          ; Concat(String &,String &) ,R=R+K
220F:0533  LEA      DI,[BP-204]                                       ;将字符串R赋给S
220F:0537  PUSH     SS
220F:0538  PUSH     DI
220F:0539  PUSH     WORD FF
220F:053C  CALL     34C7                                                  ; operator=(String &,String &,Byte)
 
220F:0541  CMP      WORD [BP-104],BYTE +0E
220F:0546  JNZ      0589
220F:0548  LEA      DI,[BP-50E]                                        ;将字符串S赋给R
220F:054C  PUSH     SS
220F:054D  PUSH     DI
220F:054E  LEA      DI,[BP-204]
220F:0552  PUSH     SS
220F:0553  PUSH     DI
220F:0554  CALL     34AD                                     ; operator=(String &,String &)
220F:0559  LEA      DI,[BP-40E]                                  ; K只有一个字符了
220F:055D  PUSH     SS
220F:055E  PUSH     DI
220F:055F  MOV      DI,[BP-104]               ;DI=0xE
220F:0563  MOV      AL,[BP+DI-100]                          ;AL=Q[0xE]
220F:0567  XOR      AH,AH
220F:0569  ADD      AX,[BP-104]                                  ;AX=Q[0xE]+0xE
220F:056D  ADD      AX,1E                                          ;AX=Q[0xE]+0xE+0x1E=Q[0xE]+0x2C
220F:0570  PUSH     AX
220F:0571  CALL     35C9                                     ; operator=(String &,Char), K[0]=1,K[1]=AX
220F:0576  CALL     352C                      ; Concat(String &,String &) ,R=R+K
220F:057B  LEA      DI,[BP-204]               ;将字符串R赋给S
220F:057F  PUSH     SS                        
220F:0580  PUSH     DI                        
220F:0581  PUSH     WORD FF                   
220F:0584  CALL     34C7                                          ; operator=(String &,String &,Byte)
 
220F:0589  CMP      WORD [BP-104],BYTE +0D
220F:058E  JNZ      05DA
220F:0590  LEA      DI,[BP-50E]                                  ;将字符串S赋给R
220F:0594  PUSH     SS
220F:0595  PUSH     DI
220F:0596  LEA      DI,[BP-204]
220F:059A  PUSH     SS
220F:059B  PUSH     DI
220F:059C  CALL     34AD                                     ; operator=(String &,String &)
220F:05A1  LEA      DI,[BP-40E]                                  ; K只有一个字符了
220F:05A5  PUSH     SS
220F:05A6  PUSH     DI
220F:05A7  MOV      AX,[BP-104]               ; AX=0xD
220F:05AB  CWD    
220F:05AC  IDIV     WORD [BP-104]                          ; AX=0xD/0xD=0x1
220F:05B0  MOV      DX,AX                                          ; DX=AX=0x1
220F:05B2  MOV      DI,[BP-104]                                  ;
220F:05B6  MOV      AL,[BP+DI-100]                          ; AL=Q[0xD]
220F:05BA  XOR      AH,AH                                          
220F:05BC  ADD      AX,DX                                          ; AL=Q[0xD]+0x1
220F:05BE  ADD      AX,2E                                          ; AX=Q[0xD]+0x1+0x2E=Q[0xD]+0x2F
220F:05C1  PUSH     AX
220F:05C2  CALL     35C9                                     ; operator=(String &,Char), K[0]=1,K[1]=AX
220F:05C7  CALL     352C                                     ; Concat(String &,String &) ,R=R+K
220F:05CC  LEA      DI,[BP-204]               ;将字符串R赋给S
220F:05D0  PUSH     SS                        
220F:05D1  PUSH     DI                        
220F:05D2  PUSH     WORD FF                   
220F:05D5  CALL     34C7                                  ; operator=(String &,String &,Byte)
 
220F:05DA  CMP      WORD [BP-104],BYTE +0C
220F:05DF  JNZ      0622
220F:05E1  LEA      DI,[BP-50E]                                  ;将字符串S赋给R
220F:05E5  PUSH     SS
220F:05E6  PUSH     DI
220F:05E7  LEA      DI,[BP-204]
220F:05EB  PUSH     SS
220F:05EC  PUSH     DI
220F:05ED  CALL     34AD                                     ; operator=(String &,String &)
220F:05F2  LEA      DI,[BP-40E]                                  ; K只有一个字符了
220F:05F6  PUSH     SS
220F:05F7  PUSH     DI
220F:05F8  MOV      DI,[BP-104]                                  ; DI=0xC
220F:05FC  MOV      AL,[BP+DI-100]                          ; AL=Q[0xC]
220F:0600  XOR      AH,AH
220F:0602  ADD      AX,[BP-104]                                  ; AX=Q[0xC]+0xC
220F:0606  SUB      AX,21                                          ; AX=Q[0xC]+0xC-0x21=Q[0xC]-0x15
220F:0609  PUSH     AX
220F:060A  CALL     35C9                                     ; operator=(String &,Char), K[0]=1,K[1]=AX
220F:060F  CALL     352C                                     ; Concat(String &,String &) ,R=R+K
220F:0614  LEA      DI,[BP-204]               ;将字符串R赋给S
220F:0618  PUSH     SS                        
220F:0619  PUSH     DI                        
220F:061A  PUSH     WORD FF                   
220F:061D  CALL     34C7                                          ; operator=(String &,String &,Byte)
 
220F:0622  CMP      WORD [BP-104],BYTE +02
220F:0627  JNZ      0667
220F:0629  LEA      DI,[BP-40E]                                  ; K只有一个字符了
220F:062D  PUSH     SS
220F:062E  PUSH     DI
220F:062F  MOV      AX,[BP-104]                                  ; AX=0x2               
220F:0633  MUL      WORD [BP-104]                          ; AX=0x2*0x2=0x4
220F:0637  MOV      DX,AX                                          ; DX=0x4
220F:0639  MOV      DI,[BP-104]
220F:063D  MOV      AL,[BP+DI-100]                          ; AL=Q[0x2]
220F:0641  XOR      AH,AH
220F:0643  ADD      AX,DX                                          ; AX=Q[0x2]+0x4
220F:0645  ADD      AX,06                                          ; AX=Q[0x2]+0x4+0x6=Q[0x2]+0xA
220F:0648  PUSH     AX
220F:0649  CALL     35C9                      ; operator=(String &,Char), K[0]=1,K[1]=AX
220F:064E  LEA      DI,[BP-204]                                  
220F:0652  PUSH     SS
220F:0653  PUSH     DI
220F:0654  CALL     352C                                     ; Concat(String &,String &), K = K + S, K最后又发生变化
220F:0659  LEA      DI,[BP-204]
220F:065D  PUSH     SS
220F:065E  PUSH     DI
220F:065F  PUSH     WORD FF
220F:0662  CALL     34C7                                          ; operator=(String &,String &,Byte), S=K
 
220F:0667  CMP      WORD [BP-104],BYTE +0A
220F:066C  JNZ      06B1
220F:066E  LEA      DI,[BP-50E]                                  ;将字符串S赋给R
220F:0672  PUSH     SS
220F:0673  PUSH     DI
220F:0674  LEA      DI,[BP-204]
220F:0678  PUSH     SS
220F:0679  PUSH     DI
220F:067A  CALL     34AD                                     ; operator=(String &,String &)
220F:067F  LEA      DI,[BP-40E]                                  ; K只有一个字符了
220F:0683  PUSH     SS
220F:0684  PUSH     DI
220F:0685  MOV      AX,[BP-104]               ; AX=0xA
220F:0689  SHL      AX,1                                          ; AX=0xA*2=0x14
220F:068B  SUB      AX,07                                          ; AX=0x14-0x7=0xD
220F:068E  MOV      DX,AX                                          ; DX=AX=0xD
220F:0690  MOV      AL,[BP-0FD]                                  ; (BP-0xFD)-(BP-0x100)=0x3, AL=Q[0x3]
220F:0694  XOR      AH,AH
220F:0696  SUB      AX,DX                                          ; AX=Q[0x3]-0xD
220F:0698  PUSH     AX
220F:0699  CALL     35C9                                     ; operator=(String &,Char), K[0]=1,K[1]=AX
220F:069E  CALL     352C                                     ; Concat(String &,String &) ,R=R+K
220F:06A3  LEA      DI,[BP-204]               ;将字符串R赋给S
220F:06A7  PUSH     SS                        
220F:06A8  PUSH     DI                        
220F:06A9  PUSH     WORD FF                   
220F:06AC  CALL     34C7                                             ; operator=(String &,String &,Byte)
220F:06B1  CMP      WORD [BP-104],BYTE +01
220F:06B6  JZ       06BB
220F:06B8  JMP      0414

上面这段完成了由科学计数法的字符串计算出一个新的9个字符的字符串,看似很长,相对来说还是简单的。

;[BP-304]正如我们程序一开始所说保存的是输入的Password,记其首地址为W,其长度W[0]记为len
;[BP-204]字符串的首地址依然记为S,即其字符串长度S[0]位ls
;[BP-100]字符串的首地址依然记为Q
220F:06BB  MOV      AL,[BP-2FE]                  ;(BP-2FE)-(BP-304)=0x6, AL=W[0x6]
220F:06BF  XOR      AH,AH                        ;
220F:06C1  MOV      DX,AX                                 ;DX=W[6]
220F:06C3  MOV      AL,[BP-0FA]                         ;(BP-0FA)-(BP-100)=0x6, AL=Q[0x6]
220F:06C7  XOR      AH,AH                                 ;00
220F:06C9  ADD      AX,16                                 ;AX=Q[0x6]+0x16
220F:06CC  CMP      AX,DX                        ;W[6]  ?? Q[0x6]+0x16
220F:06CE  JZ       06D5                               ;这里必然要跳,因为从下面的分析看要保证BYTE [BP-30D]为1,
220F:06D0  MOV      BYTE [BP-30D],00
220F:06D5  MOV      AL,[BP-2FB]                   ;(BP-2FB)-(BP-304)=0x9, AL=W[0x9]
220F:06D9  XOR      AH,AH                               
220F:06DB  MOV      DX,AX                               ; DX = W[0x9]
220F:06DD  MOV      AL,[BP-0F9]                  ;(BP-0F9)-(BP-100)=0x7, AL=Q[0x7]
220F:06E1  XOR      AH,AH
220F:06E3  SHL      AX,1                               ;AX = Q[0x7]*2
220F:06E5  SUB      AX,09                               ;AX = Q[0x7]*2-0x9
220F:06E8  CMP      AX,DX                               ; W[0x9]   ??  Q[0x7]*2-0x9
220F:06EA  JZ       06F1                         ;这里必然要跳,因为从下面的分析看要保证BYTE [BP-30D]为1,
220F:06EC  MOV      BYTE [BP-30D],00
220F:06F1  MOV      AL,[BP-204]                       ; S[0]
220F:06F5  XOR      AH,AH
220F:06F7  MOV      [BP-310],AX        ;[BP-310]=S[0]=ls
220F:06FB  MOV      AX,01
220F:06FE  CMP      AX,[BP-310]
220F:0702  JG       072A               ;[BP-310]>1=AX,一定不跳转
220F:0704  MOV      [BP-104],AX        ;循环控制变量,初始[BP-306]为输入的Password长度,即len
220F:0708  JMP      SHORT 070E
220F:070A  INC      WORD [BP-104]      ;步进1
220F:070E  MOV      DI,[BP-104]                       
220F:0712  MOV      AL,[BP+DI-204]     ;S[DI]
220F:0716  XOR      AH,AH
220F:0718  ADD      AX,[BP-306]        ;
220F:071C  MOV      [BP-306],AX         ;
220F:0720  MOV      AX,[BP-104]
220F:0724  CMP      AX,[BP-310]                 ; 
220F:0728  JNZ      070A                               ;最终[BP-306]的值为 len + (S中所有字符之和)
 
220F:072A  MOV      AL,[BP-204]                       ;S[0],即S的长度ls
220F:072E  XOR      AH,AH
220F:0730  INC      AX                                       ;ls+1                               
220F:0731  SHL      AX,1                               ;(ls+1)*2
220F:0733  MOV      CX,AX                                ;(ls+1)*2
220F:0735  MOV      AL,[BP-0FB]                ;(BP-0FB)-(BP-100)=5, AL=Q[0x5]
220F:0739  XOR      AH,AH
220F:073B  SHL      AX,02                               ; Q[0x5]*4
220F:073E  MOV      DX,AX                               ;DX=Q[0x5]*4
220F:0740  MOV      AL,[BP-0FC]                ;(BP-0FC)-(BP-100)=4, AL=Q[0x4]
220F:0744  XOR      AH,AH
220F:0746  IMUL     AX,AX,BYTE +09               ;AX=Q[0x4]*9
220F:0749  ADD      AX,DX                               ;AX=Q[0x4]*9+Q[0x5]*4
220F:074B  ADD      AX,CX                               ;AX=Q[0x4]*9+Q[0x5]*4+(ls+1)*2
 
;下面的判断是程序的前面所有跳转的必经之路,到这里已经完全明朗了,必须满足
;1.(Q[0x4]*9+Q[0x5]*4+(ls+1)*2)与len + (S中所有字符之和)相等
;2.BYTE [BP-30D]必须为01,而此值程序初始化时已经设为1
;3.W[6] 等于 Q[0x6]+0x16
;4.W[0x9] 等于 Q[0x7]*2-0x9
;其中W为输入的Password,len为其长度
;Q为cos(sum * (sqrt(sum*d1)+ln(sum/d2))+sin(len)*cos(sum*len))的17位科学计数法字符串
;S为由Q计算得来的字符串,方法为
;S[0]=0x9,字符串长度, ls=9
;S[1]=Q[0x2]+0xA;         S[2]= Q[0x8]+0x3C; S[3]=Q[0x11]+0x30
;S[4]=Q[0x10]+0x2A; S[5]=Q[0xF]+0x35;  S[6]=Q[0xE]+0x2C
;S[7]=Q[0xD]+0x2F;  S[8]=Q[0xC]-0x15;  S[9]=Q[0x3]-0xD
;
220F:074D  CMP      AX,[BP-306]                 ; (Q[0x4]*9+Q[0x5]*4+(ls+1)*2) == len + (S中所有字符之和)
220F:0751  JNZ      076F                               ;
220F:0753  CMP      BYTE [BP-30D],01       ;这个条件
220F:0758  JNZ      076F
220F:075A  LEA      DI,[BP-204]
220F:075E  PUSH     SS
220F:075F  PUSH     DI
220F:0760  PUSH     BYTE +02
220F:0762  PUSH     BYTE +04
220F:0764  PUSH     BYTE +00
220F:0766  PUSH     BYTE +01
220F:0768  CALL     07BF                       ;MessageDlg
220F:076D  JMP      SHORT 0781
220F:076F  MOV      DI,01D7
220F:0772  PUSH     CS
220F:0773  PUSH     DI                          ;[CS:DI]='Invalid password. Try again'
220F:0774  PUSH     BYTE +02
220F:0776  PUSH     BYTE +04
220F:0778  PUSH     BYTE +00
220F:077A  PUSH     BYTE +01
220F:077C  CALL     07BF                  ;MessageDlg
220F:0781  LEAVE  
220F:0782  RETF     08

到这里程序已经明朗了,输入的Password需要满足的条件为:
1.(Q[0x4]9+Q[0x5]2+(ls+1)2)与len + (S中所有字符之和)相等
2.W[6] 等于 Q[0x6]+0x16
3.W[0x9] 等于 Q[0x7]
2-0x9
其中W为输入的Passwod,len为其长度
Q为cos(sum * (sqrt(sumd1)+ln(sum/d2))+sin(len)cos(sum*len))的17位科学计数法字符串
S为由Q计算得来的字符串,方法为
S[0]=0x9,字符串长度, ls=9
S[1]=Q[0x2]+0xA; S[2]= Q[0x8]+0x3C;S[3]=Q[0x11]+0x30
S[4]=Q[0x10]+0x2A; S[5]=Q[0xF]+0x35; S[6]=Q[0xE]+0x2C
S[7]=Q[0xD]+0x2F; S[8]=Q[0xC]-0x15; S[9]=Q[0x3]-0xD
整理的S中所有字符之和X=S[1]+S[2]+...+S[9]=
Q[0x02]+0x0A+ Q[0x08]+0x3C+Q[0x11]+0x30+ Q[0x10]+0x2A+ Q[0x0F]+0x35+
Q[0x0E]+0x2C+ Q[0x0D]+0x2F+Q[0x0C]-0x15+ Q[0x03]-0x0D
= Q[0x02]+ Q[0x03]+ Q[0x08]+ Q[0x0C]+ Q[0x0D]+ Q[0x0E]+ Q[0x0F]+ Q[0x10]+ Q[0x11]+
0x0A+0x3C+0x30+0x2A+0x35+0x2C+0x2F-0x15-0x0D
=Q[2]+Q[3]+Q[8]+Q[12]+Q[13]+Q[14]+Q[15]+Q[16]+Q[17]+
10+60+48+42+53+44+47-21-13
= Q[2]+Q[3]+Q[8]+Q[12]+Q[13]+Q[14]+Q[15]+Q[16]+Q[17]+270

整理(Q[0x4]9+Q[0x5]4+(ls+1)*2)记为Y=9Q[4]+4Q[5]+20
而X=Y,即
Q[2]+Q[3]+Q[8]+Q[12]+Q[13]+Q[14]+Q[15]+Q[16]+Q[17]+270=9Q[4]+4Q[5]+20
分析可知这个方程有解,因而可程序求解。

但是我遇到了一个困难,这CM跟踪调试是输入“pnmker”求得的Q字符串为
“7.87999800586476E-0001”, 而我用32位程序去求解得出来结果却是
“ 7.879980058627672e-001” ,先不要看准不准确,他们的精度在小数点后的第5位就已经出现差距了,即便我的程序能求出来拿到他上面也可能会有问题。
难道真的只能用16位去写这程序吗,而且数学运算库还必须得用Win87Em.dll?!!

有哪位大神使用过Win87Em.dll数学运算库的能告诉一下怎么使用吗?
图1
图2

 
 
 
这是160个软件part1
这是160个软件part2

1~160每个破解过程,在吾爱破解论坛都有高手破解过了,也有整理好现成的, 我这边主要就是自己动手操作的过程,与他们的不太一样
附上高手们的连接: 点击前往查看
使用的工具连接(工具有点多有点大,可以先下OD,其它的后面慢慢下) 点击前往下载

新人入门教程"玩玩破解,写给新人看" 点击前往查看
我就是从这里开始的,对我这样的小白感觉超级友好~

下面是我的OD的界面布局,我觉得这4个是最常用的界面,其它的我基本上没用到~
OD界面布局

posted @ 2024-08-30 11:31  hankerstudio  阅读(64)  评论(0)    收藏  举报