Pnmker 发表于 2015-5-27 23:10

160个CrackMe练手之012

本帖最后由 Pnmker 于 2015-5-27 23:12 编辑

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 BP220F:01F5 MOV BP,SP
220F:01F7 MOV AX,050E
220F:01FA CALL 270B      ;__StackCheck(Word)
220F:01FF SUB SP,050E      

220F:0203 LEA DI,
220F:0207 PUSH SS
220F:0208 PUSH DI ;
220F:0209 LES DI,
220F:020C LES DI,
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 ,00 ;输入的Password的长度
220F:0220 JNZ 0225 ;长度不为0获取成功
220F:0222 JMP 0781 ;长度为0直接退出,0781是函数结尾

上面这段主要是做了堆栈检查和判断输入文本的长度,非常简单不多说。
220F:0225MOV      BYTE ,01   ;
220F:022AMOV      BYTE ,00   ;
220F:022FXOR      AX,AX
220F:0231MOV      ,AX      ;
220F:0235MOV      BYTE ,00   ;
220F:023AXOR      AX,AX
220F:023CMOV      ,AX      ;
220F:0240MOV      WORD ,00   ;
220F:0246MOV      WORD ,00   ;
220F:024CMOV      WORD ,00   ;以上几行都是对局部变量的初始化

220F:0252LEA      DI,                   ; 获取输入的Password存入
220F:0256PUSH   SS
220F:0257PUSH   DI
220F:0258LES      DI,
220F:025BLES      DI,
220F:0260PUSH   ES
220F:0261PUSH   DI
220F:0262CALL   1D53                ;TControl:GetText(void)
                                                                              ;
220F:0267LEA      DI,         ;将的Password复制到
220F:026BPUSH   SS
220F:026CPUSH   DI
220F:026DPUSH   WORD FF
220F:0270CALL   34C7                ; In IDA : operator=(String &,String &,Byte),

220F:0275LEA      DI,         ;将再复制到
220F:0279PUSH   SS                                        ;因此程序一开头,,存放都是Password
220F:027APUSH   DI                                        ;当然后面 ,有发生变化
220F:027BLEA      DI,
220F:027FPUSH   SS
220F:0280PUSH   DI
220F:0281PUSH   WORD FF
220F:0284CALL   34C7                            ; operator=(String &,String &,Byte)

220F:0289MOV      AL,                  ; 为输入文本的长度,注意Pascal/Delphi存放字符串的方式是
220F:028DXOR      AH,AH                              ;首地址第一个字节给出文本长度,后面紧接着就是文本(超过0xFF(255d)咋办呢?)
220F:028FMOV      ,AX         ;
220F:0293MOV      WORD ,00    ;置为0,其实这三个连续双字是存放浮点数的
220F:0299MOV      WORD ,00    ;
220F:029FMOV      WORD ,00    ;
220F:02A5MOV      AX,         ;
220F:02A9MOV      ,AX         ; 文本长度
220F:02ADMOV      AX,01
220F:02B0CMP      AX,         ;
220F:02B4JG       0308                ; 如果文本长度<1,直接跳转;长度大于0不跳转的,从220F:02B6
                                                                              ;到220F:0306是在求所有的字符ASCII码之和
220F:02B6MOV      ,AX                  ;为求和的循环变量
220F:02BAJMP      SHORT 02C0
220F:02BCINC      WORD        ;
220F:02C0MOV      AX,                  ;正如上面所说,这三个连续双字为浮点数,程序中存放的是字符ASCII码之和
220F:02C4MOV      BX,         ;
220F:02C8MOV      DX,         ;
220F:02CCCALL   2CEE                  ;Extended(Real),将通用寄存器中的浮点数(IEE?)转换为
                                                                              ;浮点数寄存器FPU运算支持的扩展实数
220F:02D1MOV      DI,         ;
220F:02D5MOV      AL,      ;
220F:02D9XOR      AH,AH
220F:02DBXOR      DX,DX
220F:02DDMOV      ,AX         ;
220F:02E1MOV      ,DX         ;
220F:02E5NOP   
220F:02E6FILD   DWORD       ;以上为将Password的逐个字符作为浮点数载入FPU寄存器栈顶st(0)
220F:02EANOP                                                   ;此时st(1)就是上次循环所求的和
220F:02EBFADDP    ST1                                        ;相加,st(0)同时出战
220F:02EDCALL   2D18                ;Real(Extended),FPU扩展实数转换为通用寄存器实数(IEE)
220F:02F2MOV      ,AX                  ;
220F:02F6MOV      ,BX                        ;
220F:02FAMOV      ,DX         ;此次循环所求得的和数
220F:02FEMOV      AX,
220F:0302CMP      AX,         ;循环控制
220F:0306JNZ      02BC


上面这段主要工作有局部变量初始化、输入的Password拷贝三份和对输入文本进行ASCII码求和。
;接下来,这三个双字存储的浮点数为字符ASCII码的和
;以下因为涉及到比较复杂的数学运算,并且使用到了两个全局浮点数变量,所以在此规定记:
;1.输入Password的文本长度为len,
;2.字符ASCII码之和为sum(浮点数存储)
;3.存储的全局浮点数0.296439,记为d1
;4.存储的全局浮点数1294.39894,记为d2
;另对于FPU浮点数寄存器栈不熟的,请仔细查阅相关资料
220F:0308MOV      AX,   ;
220F:030CMOV      BX,            ;
220F:0310MOV      DX,   ;
220F:0314CALL   2CEE            ;Extended(Real),sum转FPU扩展实数
220F:0319NOP   
220F:031AFSTP   TWORD ;将sum转存到
220F:031EMOV      AX,
220F:0322MOV      BX,
220F:0326MOV      DX,
220F:032ACALL   2CEE            ;Extended(Real),sum转FPU扩展实数
220F:032FNOP   
220F:0330FLD      TWORD ; d1载入FPU寄存器栈顶st(0)
220F:0335NOP   
220F:0336FMULP    ST1                              ;求得乘积sum * d1,并将栈顶元素d1退栈
220F:0338CALL   2DC4            ;sqrt(double),求平方根 sqrt(sum*d1)
220F:033DNOP   
220F:033EFSTP   TWORD ;存储sqrt(sum*d1)
220F:0342MOV      AX,
220F:0346MOV      BX,
220F:034AMOV      DX,
220F:034ECALL   2CEE            ;Extended(Real),sum转FPU扩展实数
220F:0353NOP   
220F:0354FLD      TWORD       ;d2载入FPU寄存器栈顶st(0)
220F:0359CALL   2799            ;FSafeDivide(void),浮点数除法sum/d2
220F:035ECALL   2DD4                        ;Ln(Extended),求自然对数:ln(sum/d2)
220F:0363NOP   
220F:0364FLD      TWORD ; 载入220F:033E处存在的计算结果sqrt(sum*d1)到FPU栈顶st(0)
220F:0368NOP   
220F:0369FADDP    ST1             ; 求和sqrt(sum*d1)+ln(sum/d2)
220F:036BNOP   
220F:036CFLD      TWORD ; 将220F:031出存在的sum载入到FPU栈顶st(0)
220F:0370NOP   
220F:0371FMULP    ST1                            ; 求乘积sum * (sqrt(sum*d1)+ln(sum/d2)),栈顶元素退栈
220F:0373NOP   
220F:0374FSTP   TWORD ;存储sum * (sqrt(sum*d1)+ln(sum/d2))
220F:0378NOP   
220F:0379FILD   WORD    ;将220F:028F处存在的len载入到FPU栈顶st(0)
220F:037DCALL   2DC8                        ;Sin(Extended),求正弦, sin(len)
220F:0382NOP   
220F:0383FSTP   TWORD ; 存储sin(len)
220F:0387MOV      AX,
220F:038BMOV      BX,
220F:038FMOV      DX,
220F:0393CALL   2CEE            ;Extended(Real),sum转FPU扩展实数
220F:0398NOP   
220F:0399FILD   WORD    ; len
220F:039DNOP   
220F:039EFMULP    ST1             ;乘积, sum*len
220F:03A0CALL   2DCC                        ; Cos(Extended),求余弦cos(sum*len)
220F:03A5NOP   
220F:03A6FLD      TWORD ; 将220F:0383存储在的sin(len)载入到FPU栈顶st(0)
220F:03AANOP   
220F:03ABFMULP    ST1                              ; 求乘积sin(len)*cos(sum*len)
220F:03ADNOP   
220F:03AEFLD      TWORD ;将220F:0374存储在的计算结果sum * (sqrt(sum*d1)+ln(sum/d2))载入FPU栈顶st(0)
220F:03B2NOP   
220F:03B3FADDP    ST1                              ;求和得sum * (sqrt(sum*d1)+ln(sum/d2))+sin(len)*cos(sum*len
220F:03B5CALL   2DCC                        ;Cos(Extended)求余弦得 cos(sum * (sqrt(sum*d1)+ln(sum/d2))+sin(len)*cos(sum*len))
220F:03BACALL   2D18            ;Real(Extended),FPU扩展实数转换为通用寄存器实数(IEE)
220F:03BFMOV      ,AX
220F:03C3MOV      ,BX
220F:03C7MOV      ,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:03CBMOV      AX,
220F:03CFMOV      BX,
220F:03D3MOV      DX,
220F:03D7CALL   2CEE            ;Extended(Real),计算结果转FPU扩展实数
220F:03DCPUSH   BYTE +17      ;0x17,表示字符串的总长度吗???
220F:03DEPUSH   BYTE -01      ;难点是一个枚举值,表示转为科学计数法
220F:03E0LEA      DI,   ;科学计数法的字符串存储在此
220F:03E4PUSH   SS
220F:03E5PUSH   DI
220F:03E6PUSH   WORD FF
220F:03E9CALL   37A7            ; Str(Extended,Word,Word,String &,Word),转为字符串
220F:03EEMOV      WORD ,00
220F:03F4MOV      WORD ,00
220F:03FAMOV      WORD ,00 ;清零

上面这段个人认为比较复杂的一段,不过从IDA的反汇编上来看也不难,主要进行了一系列复杂的数学运算求得了结果cos(sum *(sqrt(sum*d1)+ln(sum/d2))+sin(len)*cos(sum*len)),并将其转换为了科学计数法的字符串
;从220F:0400到220F:06B8这段挺长,看似吓人,其实做得事情很简单
;叙述方便期间做以下规定:(以输入pnmker为例)
;1.记输入Password在处字符串首地址为P,则P为字符串长度,P='p',P='n',...,P='r'
;2.记存储在的科学计数法字符串首地址为Q,则Q为字符串长度,Q...Q[字符串长度]同1所述
;3.记存储的字符串首地址记为R
;4.记存储的字符串首地址记为S
;5.记程序开始存储在 的输入Password的首地址为K;
;那么最终的字符串即为所求,其计算公式如下:
;S=0x9,字符串长度
;S=Q+0xA;         S= Q+0x3C; S=Q+0x30
;S=Q+0x2A; S=Q+0x35;S=Q+0x2C
;S=Q+0x2F;S=Q-0x15;S=Q-0xD
220F:0400MOV      AL,                           ;Q字符串长度
220F:0404XOR      AH,AH
220F:0406CMP      AX,01
220F:0409JNL      040E            
220F:040BJMP      06BB                                    ;如果Q=1直接跳转到06BB

220F:040EMOV      ,AX                           ;存储Q字符串的逆序逐个字符遍历的循环变量
220F:0412JMP      SHORT 0418
220F:0414DEC      WORD                               ;逆序遍历字符

220F:0418CMP      WORD ,BYTE +12      ;
220F:041DJNZ      0465
220F:041FLEA      DI,               ;将字符串S赋给R
220F:0423PUSH   SS
220F:0424PUSH   DI
220F:0425LEA      DI,
220F:0429PUSH   SS
220F:042APUSH   DI
220F:042BCALL   34AD                                           ; operator=(String &,String &)
220F:0430LEA      DI,                                    ;K,曾经为输入Password,注意经过此次处理K变成了只有一个字符的字符串!
220F:0434PUSH   SS
220F:0435PUSH   DI
220F:0436MOV      AX,                                    ;AX=0x12,循环变量
220F:043ASUB      AX,0A                                                ;AX=0x12-0xA=0x8
220F:043DMOV      DI,AX                                          ;DI=0x8
220F:043FMOV      AL,                                 ;AL=Q
220F:0443XOR      AH,AH
220F:0445ADD      AX,                                    ;AX=Q+0x12
220F:0449ADD      AX,2A                                          ;AX=Q+0x12+0x2A=Q+0x3C
220F:044CPUSH   AX                                             ;
220F:044DCALL   35C9                                           ; operator=(String &,Char), K=1,K=AX,K只有一个字符了
220F:0452CALL   352C                                           ; Concat(String &,String &), R=R + K
220F:0457LEA      DI,               ;将字符串R赋给S
220F:045BPUSH   SS
220F:045CPUSH   DI
220F:045DPUSH   WORD FF
220F:0460CALL   34C7                                                   ; operator=(String &,String &,Byte) , S=R

220F:0465CMP      WORD ,BYTE +11
220F:046AJNZ      04A9
220F:046CLEA      DI,               ;将字符串S赋给R
220F:0470PUSH   SS
220F:0471PUSH   DI
220F:0472LEA      DI,
220F:0476PUSH   SS
220F:0477PUSH   DI
220F:0478CALL   34AD                                           ; operator=(String &,String &)
220F:047DLEA      DI,                                    ;K,此处K只有一个字符
220F:0481PUSH   SS
220F:0482PUSH   DI
220F:0483MOV      DI,                                    ;DI=0x11
220F:0487MOV      AL,                                 ;AL=Q
220F:048BXOR      AH,AH                        
220F:048DADD      AX,30                                                ;AX=Q+0x30
220F:0490PUSH   AX                                                      ;
220F:0491CALL   35C9                                           ; operator=(String &,Char), K=1,K=AX
220F:0496CALL   352C                                           ; Concat(String &,String &), R = R + K
220F:049BLEA      DI,               ;将字符串R赋给S
220F:049FPUSH   SS
220F:04A0PUSH   DI
220F:04A1PUSH   WORD FF
220F:04A4CALL   34C7                                                   ; operator=(String &,String &,Byte)

220F:04A9CMP      WORD ,BYTE +10
220F:04AEJNZ      04F1
220F:04B0LEA      DI,               ;将字符串S赋给R
220F:04B4PUSH   SS
220F:04B5PUSH   DI
220F:04B6LEA      DI,
220F:04BAPUSH   SS
220F:04BBPUSH   DI
220F:04BCCALL   34AD                                           ; operator=(String &,String &)
220F:04C1LEA      DI,                                        ; K只有一个字符了
220F:04C5PUSH   SS
220F:04C6PUSH   DI
220F:04C7MOV      DI,                                        ; DI=0x10
220F:04CBMOV      AL,                              ; AL=Q
220F:04CFXOR      AH,AH
220F:04D1ADD      AX,                                        ; AX = Q+0x10
220F:04D5ADD      AX,1A                                                ; AX = Q+0x10+0x1A=Q+0x2A
220F:04D8PUSH   AX
220F:04D9CALL   35C9                                           ; operator=(String &,Char), K=1, K=AX
220F:04DECALL   352C                                           ; Concat(String &,String &),R=R+K
220F:04E3LEA      DI,                                        ;将字符串R赋给S
220F:04E7PUSH   SS
220F:04E8PUSH   DI
220F:04E9PUSH   WORD FF
220F:04ECCALL   34C7                                                   ; operator=(String &,String &,Byte)

220F:04F1CMP      WORD ,BYTE +0F
220F:04F6JNZ      0541
220F:04F8LEA      DI,                                        ;将字符串S赋给R
220F:04FCPUSH   SS
220F:04FDPUSH   DI
220F:04FELEA      DI,
220F:0502PUSH   SS
220F:0503PUSH   DI
220F:0504CALL   34AD                                       ; operator=(String &,String &)
220F:0509LEA      DI,                                        ; K只有一个字符了
220F:050DPUSH   SS
220F:050EPUSH   DI
220F:050FMOV      AX,                                        ; AX=0xF
220F:0513MUL      WORD                               ; AX=0xF*0xF=0xE1
220F:0517MOV      DX,AX                                                ; DX=0xE1
220F:0519MOV      DI,                                        ; DI=0xF
220F:051DMOV      AL,                              ; AL=Q
220F:0521XOR      AH,AH
220F:0523ADD      AX,DX                                                ;AX = Q+0xE1
220F:0525SUB      AX,0ACh                                                ;AX = Q+0xE1-0xAC=Q+0x35
220F:0528PUSH   AX
220F:0529CALL   35C9                                           ; operator=(String &,Char), K=1,K=AX
220F:052ECALL   352C                                           ; Concat(String &,String &) ,R=R+K
220F:0533LEA      DI,                                        ;将字符串R赋给S
220F:0537PUSH   SS
220F:0538PUSH   DI
220F:0539PUSH   WORD FF
220F:053CCALL   34C7                                                   ; operator=(String &,String &,Byte)

220F:0541CMP      WORD ,BYTE +0E
220F:0546JNZ      0589
220F:0548LEA      DI,                                       ;将字符串S赋给R
220F:054CPUSH   SS
220F:054DPUSH   DI
220F:054ELEA      DI,
220F:0552PUSH   SS
220F:0553PUSH   DI
220F:0554CALL   34AD                                    ; operator=(String &,String &)
220F:0559LEA      DI,                                 ; K只有一个字符了
220F:055DPUSH   SS
220F:055EPUSH   DI
220F:055FMOV      DI,                ;DI=0xE
220F:0563MOV      AL,                           ;AL=Q
220F:0567XOR      AH,AH
220F:0569ADD      AX,                                 ;AX=Q+0xE
220F:056DADD      AX,1E                                           ;AX=Q+0xE+0x1E=Q+0x2C
220F:0570PUSH   AX
220F:0571CALL   35C9                                    ; operator=(String &,Char), K=1,K=AX
220F:0576CALL   352C                     ; Concat(String &,String &) ,R=R+K
220F:057BLEA      DI,                ;将字符串R赋给S
220F:057FPUSH   SS                        
220F:0580PUSH   DI                        
220F:0581PUSH   WORD FF                  
220F:0584CALL   34C7                                           ; operator=(String &,String &,Byte)

220F:0589CMP      WORD ,BYTE +0D
220F:058EJNZ      05DA
220F:0590LEA      DI,                                 ;将字符串S赋给R
220F:0594PUSH   SS
220F:0595PUSH   DI
220F:0596LEA      DI,
220F:059APUSH   SS
220F:059BPUSH   DI
220F:059CCALL   34AD                                    ; operator=(String &,String &)
220F:05A1LEA      DI,                                 ; K只有一个字符了
220F:05A5PUSH   SS
220F:05A6PUSH   DI
220F:05A7MOV      AX,                ; AX=0xD
220F:05ABCWD   
220F:05ACIDIV   WORD                            ; AX=0xD/0xD=0x1
220F:05B0MOV      DX,AX                                           ; DX=AX=0x1
220F:05B2MOV      DI,                                 ;
220F:05B6MOV      AL,                           ; AL=Q
220F:05BAXOR      AH,AH                                          
220F:05BCADD      AX,DX                                           ; AL=Q+0x1
220F:05BEADD      AX,2E                                           ; AX=Q+0x1+0x2E=Q+0x2F
220F:05C1PUSH   AX
220F:05C2CALL   35C9                                    ; operator=(String &,Char), K=1,K=AX
220F:05C7CALL   352C                                    ; Concat(String &,String &) ,R=R+K
220F:05CCLEA      DI,                ;将字符串R赋给S
220F:05D0PUSH   SS                        
220F:05D1PUSH   DI                        
220F:05D2PUSH   WORD FF                  
220F:05D5CALL   34C7                                 ; operator=(String &,String &,Byte)

220F:05DACMP      WORD ,BYTE +0C
220F:05DFJNZ      0622
220F:05E1LEA      DI,                                 ;将字符串S赋给R
220F:05E5PUSH   SS
220F:05E6PUSH   DI
220F:05E7LEA      DI,
220F:05EBPUSH   SS
220F:05ECPUSH   DI
220F:05EDCALL   34AD                                    ; operator=(String &,String &)
220F:05F2LEA      DI,                                 ; K只有一个字符了
220F:05F6PUSH   SS
220F:05F7PUSH   DI
220F:05F8MOV      DI,                                 ; DI=0xC
220F:05FCMOV      AL,                           ; AL=Q
220F:0600XOR      AH,AH
220F:0602ADD      AX,                                 ; AX=Q+0xC
220F:0606SUB      AX,21                                           ; AX=Q+0xC-0x21=Q-0x15
220F:0609PUSH   AX
220F:060ACALL   35C9                                    ; operator=(String &,Char), K=1,K=AX
220F:060FCALL   352C                                    ; Concat(String &,String &) ,R=R+K
220F:0614LEA      DI,                ;将字符串R赋给S
220F:0618PUSH   SS                        
220F:0619PUSH   DI                        
220F:061APUSH   WORD FF                  
220F:061DCALL   34C7                                           ; operator=(String &,String &,Byte)

220F:0622CMP      WORD ,BYTE +02
220F:0627JNZ      0667
220F:0629LEA      DI,                                 ; K只有一个字符了
220F:062DPUSH   SS
220F:062EPUSH   DI
220F:062FMOV      AX,                                 ; AX=0x2               
220F:0633MUL      WORD                            ; AX=0x2*0x2=0x4
220F:0637MOV      DX,AX                                           ; DX=0x4
220F:0639MOV      DI,
220F:063DMOV      AL,                           ; AL=Q
220F:0641XOR      AH,AH
220F:0643ADD      AX,DX                                           ; AX=Q+0x4
220F:0645ADD      AX,06                                           ; AX=Q+0x4+0x6=Q+0xA
220F:0648PUSH   AX
220F:0649CALL   35C9                     ; operator=(String &,Char), K=1,K=AX
220F:064ELEA      DI,                                 
220F:0652PUSH   SS
220F:0653PUSH   DI
220F:0654CALL   352C                                    ; Concat(String &,String &), K = K + S, K最后又发生变化
220F:0659LEA      DI,
220F:065DPUSH   SS
220F:065EPUSH   DI
220F:065FPUSH   WORD FF
220F:0662CALL   34C7                                           ; operator=(String &,String &,Byte), S=K

220F:0667CMP      WORD ,BYTE +0A
220F:066CJNZ      06B1
220F:066ELEA      DI,                                 ;将字符串S赋给R
220F:0672PUSH   SS
220F:0673PUSH   DI
220F:0674LEA      DI,
220F:0678PUSH   SS
220F:0679PUSH   DI
220F:067ACALL   34AD                                    ; operator=(String &,String &)
220F:067FLEA      DI,                                 ; K只有一个字符了
220F:0683PUSH   SS
220F:0684PUSH   DI
220F:0685MOV      AX,                ; AX=0xA
220F:0689SHL      AX,1                                           ; AX=0xA*2=0x14
220F:068BSUB      AX,07                                           ; AX=0x14-0x7=0xD
220F:068EMOV      DX,AX                                           ; DX=AX=0xD
220F:0690MOV      AL,                                 ; (BP-0xFD)-(BP-0x100)=0x3, AL=Q
220F:0694XOR      AH,AH
220F:0696SUB      AX,DX                                           ; AX=Q-0xD
220F:0698PUSH   AX
220F:0699CALL   35C9                                    ; operator=(String &,Char), K=1,K=AX
220F:069ECALL   352C                                    ; Concat(String &,String &) ,R=R+K
220F:06A3LEA      DI,                ;将字符串R赋给S
220F:06A7PUSH   SS                        
220F:06A8PUSH   DI                        
220F:06A9PUSH   WORD FF                  
220F:06ACCALL   34C7                                              ; operator=(String &,String &,Byte)
220F:06B1CMP      WORD ,BYTE +01
220F:06B6JZ       06BB
220F:06B8JMP      0414

上面这段完成了由科学计数法的字符串计算出一个新的9个字符的字符串,看似很长,相对来说还是简单的。
;正如我们程序一开始所说保存的是输入的Password,记其首地址为W,其长度W记为len
;字符串的首地址依然记为S,即其字符串长度S位ls
;字符串的首地址依然记为Q
220F:06BBMOV      AL,                   ;(BP-2FE)-(BP-304)=0x6, AL=W
220F:06BFXOR      AH,AH                         ;
220F:06C1MOV      DX,AX                                  ;DX=W
220F:06C3MOV      AL,                        ;(BP-0FA)-(BP-100)=0x6, AL=Q
220F:06C7XOR      AH,AH                                  ;00
220F:06C9ADD      AX,16                                  ;AX=Q+0x16
220F:06CCCMP      AX,DX                         ;W?? Q+0x16
220F:06CEJZ       06D5                              ;这里必然要跳,因为从下面的分析看要保证BYTE 为1,
220F:06D0MOV      BYTE ,00
220F:06D5MOV      AL,                  ;(BP-2FB)-(BP-304)=0x9, AL=W
220F:06D9XOR      AH,AH                              
220F:06DBMOV      DX,AX                              ; DX = W
220F:06DDMOV      AL,                   ;(BP-0F9)-(BP-100)=0x7, AL=Q
220F:06E1XOR      AH,AH
220F:06E3SHL      AX,1                              ;AX = Q*2
220F:06E5SUB      AX,09                              ;AX = Q*2-0x9
220F:06E8CMP      AX,DX                              ; W   ??Q*2-0x9
220F:06EAJZ       06F1                        ;这里必然要跳,因为从下面的分析看要保证BYTE 为1,
220F:06ECMOV      BYTE ,00
220F:06F1MOV      AL,                        ; S
220F:06F5XOR      AH,AH
220F:06F7MOV      ,AX         ;=S=ls
220F:06FBMOV      AX,01
220F:06FECMP      AX,
220F:0702JG       072A                ;>1=AX,一定不跳转
220F:0704MOV      ,AX         ;循环控制变量,初始为输入的Password长度,即len
220F:0708JMP      SHORT 070E
220F:070AINC      WORD        ;步进1
220F:070EMOV      DI,                        
220F:0712MOV      AL,      ;S
220F:0716XOR      AH,AH
220F:0718ADD      AX,         ;
220F:071CMOV      ,AX         ;
220F:0720MOV      AX,
220F:0724CMP      AX,                  ;
220F:0728JNZ      070A                              ;最终的值为 len + (S中所有字符之和)

220F:072AMOV      AL,                        ;S,即S的长度ls
220F:072EXOR      AH,AH
220F:0730INC      AX                                        ;ls+1                              
220F:0731SHL      AX,1                              ;(ls+1)*2
220F:0733MOV      CX,AX                                 ;(ls+1)*2
220F:0735MOV      AL,               ;(BP-0FB)-(BP-100)=5, AL=Q
220F:0739XOR      AH,AH
220F:073BSHL      AX,02                              ; Q*4
220F:073EMOV      DX,AX                              ;DX=Q*4
220F:0740MOV      AL,               ;(BP-0FC)-(BP-100)=4, AL=Q
220F:0744XOR      AH,AH
220F:0746IMUL   AX,AX,BYTE +09                ;AX=Q*9
220F:0749ADD      AX,DX                              ;AX=Q*9+Q*4
220F:074BADD      AX,CX                              ;AX=Q*9+Q*4+(ls+1)*2

;下面的判断是程序的前面所有跳转的必经之路,到这里已经完全明朗了,必须满足
;1.(Q*9+Q*4+(ls+1)*2)与len + (S中所有字符之和)相等
;2.BYTE 必须为01,而此值程序初始化时已经设为1
;3.W 等于 Q+0x16
;4.W 等于 Q*2-0x9
;其中W为输入的Password,len为其长度
;Q为cos(sum * (sqrt(sum*d1)+ln(sum/d2))+sin(len)*cos(sum*len))的17位科学计数法字符串
;S为由Q计算得来的字符串,方法为
;S=0x9,字符串长度, ls=9
;S=Q+0xA;         S= Q+0x3C; S=Q+0x30
;S=Q+0x2A; S=Q+0x35;S=Q+0x2C
;S=Q+0x2F;S=Q-0x15;S=Q-0xD
;
220F:074DCMP      AX,                  ; (Q*9+Q*4+(ls+1)*2) == len + (S中所有字符之和)
220F:0751JNZ      076F                              ;
220F:0753CMP      BYTE ,01      ;这个条件
220F:0758JNZ      076F
220F:075ALEA      DI,
220F:075EPUSH   SS
220F:075FPUSH   DI
220F:0760PUSH   BYTE +02
220F:0762PUSH   BYTE +04
220F:0764PUSH   BYTE +00
220F:0766PUSH   BYTE +01
220F:0768CALL   07BF                        ;MessageDlg
220F:076DJMP      SHORT 0781
220F:076FMOV      DI,01D7
220F:0772PUSH   CS
220F:0773PUSH   DI                           ;='Invalid password. Try again'
220F:0774PUSH   BYTE +02
220F:0776PUSH   BYTE +04
220F:0778PUSH   BYTE +00
220F:077APUSH   BYTE +01
220F:077CCALL   07BF                   ;MessageDlg
220F:0781LEAVE   
220F:0782RETF   08

到这里程序已经明朗了,输入的Password需要满足的条件为:1.(Q*9+Q*2+(ls+1)*2)与len + (S中所有字符之和)相等2.W 等于 Q+0x163.W 等于 Q*2-0x9其中W为输入的Passwod,len为其长度Q为cos(sum * (sqrt(sum*d1)+ln(sum/d2))+sin(len)*cos(sum*len))的17位科学计数法字符串S为由Q计算得来的字符串,方法为S=0x9,字符串长度, ls=9S=Q+0xA;       S= Q+0x3C;S=Q+0x30S=Q+0x2A; S=Q+0x35; S=Q+0x2CS=Q+0x2F; S=Q-0x15;S=Q-0xD整理的S中所有字符之和X=S+S+...+S=Q+0x0A+ Q+0x3C+Q+0x30+ Q+0x2A+ Q+0x35+ Q+0x2C+ Q+0x2F+Q-0x15+ Q-0x0D= Q+ Q+ Q+ Q+ Q+ Q+ Q+ Q+ Q+0x0A+0x3C+0x30+0x2A+0x35+0x2C+0x2F-0x15-0x0D=Q+Q+Q+Q+Q+Q+Q+Q+Q+ 10+60+48+42+53+44+47-21-13= Q+Q+Q+Q+Q+Q+Q+Q+Q+270
整理(Q*9+Q*4+(ls+1)*2)记为Y=9Q+4Q+20而X=Y,即Q+Q+Q+Q+Q+Q+Q+Q+Q+270=9Q+4Q+20分析可知这个方程有解,因而可程序求解。
但是我遇到了一个困难,这CM跟踪调试是输入“pnmker”求得的Q字符串为“7.87999800586476E-0001”, 而我用32位程序去求解得出来结果却是“ 7.879980058627672e-001” ,先不要看准不准确,他们的精度在小数点后的第5位就已经出现差距了,即便我的程序能求出来拿到他上面也可能会有问题。难道真的只能用16位去写这程序吗,而且数学运算库还必须得用Win87Em.dll?!!
有哪位大神使用过Win87Em.dll数学运算库的能告诉一下怎么使用吗?


cxj98 发表于 2015-5-29 14:52

这好像又是一枚大牛。

touyuan001 发表于 2015-5-29 14:29

Hmily 发表于 2015-5-28 15:33
16位的程序太少见了,学习。
每次看你的头像都有种莫名的喜感,请原谅我笑点低~~~~~~

asd9988 发表于 2015-5-27 23:36

大婶好像都喜欢大半夜发帖子?
前排广告位~

touyuan001 发表于 2015-5-28 13:26

打死占广告位的~{:301_1000:}

Hmily 发表于 2015-5-28 15:33

16位的程序太少见了,学习。

如果我徘徊 发表于 2015-5-28 15:41

感谢分享。。

hybmn 发表于 2015-5-29 00:55

brakefast 发表于 2015-5-29 23:58

不错啊,感谢分享了~

越峥嵘越从容 发表于 2015-5-31 08:07

谢谢大家支持一下
页: [1] 2
查看完整版本: 160个CrackMe练手之012