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数学运算库的能告诉一下怎么使用吗?
这好像又是一枚大牛。 Hmily 发表于 2015-5-28 15:33
16位的程序太少见了,学习。
每次看你的头像都有种莫名的喜感,请原谅我笑点低~~~~~~ 大婶好像都喜欢大半夜发帖子?
前排广告位~
打死占广告位的~{:301_1000:} 16位的程序太少见了,学习。 感谢分享。。 不错啊,感谢分享了~ 谢谢大家支持一下
页:
[1]
2