1625-5 王子昂 总结《2017年6月20日》 【连续第261天总结】
A.CrackMe(34)
B.从没见过的KeyFile形式验证,拖到PEiD中查看,幸好是MASM汇编写的
拖到OD里运行,比昨天还恐怖,没有任何输入、选择和确认信息
猜测应该是开始运行的时候检测根目录下是否存在KeyFile,但是失败了也没有弹窗,连查MessageBox的机会都不给
那么有两个办法:
一,因为这是汇编写的程序。而汇编写的程序有一个特点,非常短。上下拖动就可以看出来整个程序的指令极其少,因此可以从一开始就单步跟踪
二,查找参考字符串
第二步是可以的,不过我干脆单步跟好了,反正也不长,从头开始更便于逻辑的理解
跟了几步,发现有一个OD加上了CreateFile的注释的call:
00401028 |. 68 D7204000 push Cruehead.004020D7 ; |FileName = "CRACKME3.KEY"
0040102D |. E8 76040000 call <jmp.&KERNEL32.CreateFileA> ; \CreateFileA
00401032 |. 83F8 FF cmp eax,-0x1 ; 文件判断
00401035 |. 75 0C jnz short Cruehead.00401043 ; 失败跳
再下面是判断和跳转,当直接运行的时候将会不跳转,然后看到一行字符串被添加了“Uncracked”的字样,再然后就直接跳转显示窗口了
很明显, eax=-1是出错的返回值,也就是说利用了CreateFile时判断文件是否已存在的特性
再往上一行就是FileName,因此很明显,所需的KeyFile的文件名就是这个
在同目录下创建一个CRACKME3.KEY,用记事本向其中随便写入,再次运行
发现能够跳转了,再往下跟:
00401061 |. E8 30040000 call <jmp.&KERNEL32.ReadFile> ; \ReadFile
00401066 |. 833D A0214000>cmp dword ptr ds:[0x4021A0],0x12 ; 判断长度,非18失败
0040106D |.^ 75 C8 jnz short Cruehead.00401037 ; 失败跳
0040106F |. 68 08204000 push Cruehead.00402008
00401074 |. E8 98020000 call Cruehead.00401311 ; 每个字符与0x40+N异或,并累加
是一个ReadFile的API,下面是一个判断和跳转
这种判断不是长度就是内容的整型值,第一次随便写入的是123456,此时0x4021A0的值是6
那八成就是长度了,可以再改变一下KEY的内容,再看看该内存的值是否跟随变化
既然长度要求是0x12即18个字符的话,那么我们就乖乖在KEY里面写18个字符
通过跳转,下面一个call的参数00102008是上一个ReadFile的buffer参数,因此这个call就是对数据处理的了
跟进去,是一个循环:
00401319 |. B3 41 mov bl,0x41
0040131B |> 8A06 /mov al,byte ptr ds:[esi]
0040131D |. 32C3 |xor al,bl ; 第n个字符ASCII与(0x40+n)异或
0040131F |. 8806 |mov byte ptr ds:[esi],al
00401321 |. 46 |inc esi ; Cruehead.<ModuleEntryPoint>
00401322 |. FEC3 |inc bl
00401324 |. 0105 F9204000 |add dword ptr ds:[0x4020F9],eax ; 异或结果累加
0040132A |. 3C 00 |cmp al,0x0 ; 异或结果为0时结束处理
0040132C |. 74 07 |je short Cruehead.00401335
0040132E |. FEC1 |inc cl
00401330 |. 80FB 4F |cmp bl,0x4F ; 最多处理16个字符
00401333 |.^ 75 E6 \jnz short Cruehead.0040131B
00401335 |> 890D 49214000 mov dword ptr ds:[0x402149],ecx ; 处理次数-1
0040133B \. C3 retn
很好理解,其中有一个0判断值得注意一下,当异或结果为0时结束处理,作用后面再说
注意累加和和处理次数保存在内存中
出了这个call以后:
00401079 |. 8135 F9204000>xor dword ptr ds:[0x4020F9],0x12345678 ; 累加和与0x12345678异或
00401083 |. 83C4 04 add esp,0x4
00401086 |. 68 08204000 push Cruehead.00402008 ; ASCII "night"
0040108B |. E8 AC020000 call Cruehead.0040133C ; 最后四位ASCII送入EAX
00401090 |. 83C4 04 add esp,0x4
00401093 |. 3B05 F9204000 cmp eax,dword ptr ds:[0x4020F9] ; 最后四位的ASCII与之前的异或结果比较,不等则失败
00401099 |. 0f94c0 sete al
0040109C |. 50 push eax
0040109D |. 84C0 test al,al
0040109F |.^ 74 96 je short Cruehead.00401037 ; 失败跳
004010A1 |. 68 0E214000 push Cruehead.0040210E ; ASCII "CrackMe v3.0 "
004010A6 |. E8 9B020000 call Cruehead.00401346 ; 成功提示
累加和与0x12345678异或,然后与KEY的最后4位字符的ASCII进行比较,相等则通过
通过的call是对字符串添加“Cracked"的字样
这里是通过sete al和test来判断的,当相等时令al=1,否则令al=0
00401188 |. 3C 01 cmp al,0x1 ; 重复验证
0040118A |. 75 17 jnz short Cruehead.004011A3
0040118C |. 68 86214000 push Cruehead.00402186 ; ASCII "Now try the next crackme!"
00401191 |. 68 6A214000 push Cruehead.0040216A ; ASCII "Cracked by: Now try the next crackme!"
00401196 |. 68 08204000 push Cruehead.00402008 ; ASCII "night"
0040119B |. E8 C2010000 call Cruehead.00401362 ; 成功弹窗
在后面又对al进行了一次验证,成功的话会弹窗
值得一提的是,有一个Cracked by: !的内容,中间的地方填的是之前字符串异或后的结果
还记得之前那个异或后结果为0则判断结束的地方吗,那里就是用来设置字符串结束的
总结一下:
对输入的字符串逐个字符异或,遇到0则停止。将异或后的字符串累加求和,与字符串最后四个字符校验,相等则成功。
那么脚本就很简单了,输入一个名字,先求和,然后如果不满14个字符就以0填充,再对名字与0x40+n逐个异或,最后4个字符为之前求和的结果与0x12345678异或,每2位转换一个字符而成。
这里就有一个问题了:如果累加和与0x12345678异或后出的结果,超出了ASCII表怎么办。ASCII表只有128个,到0x7F就结束了。在转换字符的时候就会因为没有对应的字符而出问题。
事实上我自己的ID转换出来就无法输出,因此没办法看到Cracked by:我 的弹窗TAT
异或的运算对大小没什么规律,跟名字长短也没啥关系,因此也没办法提前判断
脚本:
n="0"*17 name="" while(len(n)>14): n=input("请输入你的名字(小于15个字符的英文)") if(len(n)>14): print("你输入的名字超出长度啦,请重试") bx=0x41 s=0 for i in range(len(n)): s=s+ord(n[i]) name=name+chr(ord(n[i]) ^ bx) bx=bx+1 if(bx<0x4e): name=name+chr(0^bx)*(0x4e-bx+1) s=s^0x12345678 for i in range(4): #print(hex(s)) if(s%0x100>126): print("很抱歉由于CM的BUG,无法输出该Name对应的Serial") break name=name+chr(s%0x100) s=s//0x100 else: f=open("CRACKME3.KEY","w") f.write(name) f.close print("生成KeyFile成功:\n"+name)
总体来说,虽然KeyFile的形式是第一次见,但是由于汇编比较友好,再加上OD能即使识别API的名称,再加上整个算法不怎么复杂,所以还是挺简单的(吧
看了一眼52破解的前辈留下的集合,好像没做出来,有点成就感www
C.明日计划
CrackMe(27)