好友
阅读权限30
听众
最后登录1970-1-1
|
本帖最后由 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了,至于细节有兴趣的朋友个人去分析和跟踪吧。 [Asm] 纯文本查看 复制代码 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是函数结尾
上面这段主要是做了堆栈检查和判断输入文本的长度,非常简单不多说。
[Asm] 纯文本查看 复制代码 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码求和。
[Asm] 纯文本查看 复制代码 ;接下来,这三个双字存储的浮点数为字符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(sum*d1)+ln(sum/d2))+sin(len)*cos(sum*len)),并将其转换为了科学计数法的字符串
[Asm] 纯文本查看 复制代码 ;从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个字符的字符串,看似很长,相对来说还是简单的。
[Asm] 纯文本查看 复制代码 ;[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(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 整理的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数学运算库的能告诉一下怎么使用吗?
|
免费评分
-
查看全部评分
|