CrackMe爆破与算法分析(二)
[wocy.1]
程序功能:输入username和id,判断是否注册。
爆破
IDA发现关键字符串“Registed. Good job.”,根据字符串定位到代码段。
关键跳是jnz这条指令。要想“Registed. Good job.”正常输出,把jnz这条指令替换为空指令即可。
运行后输入长度比较短的字符串,发现注册失败。IDA查看前面还有一跳。再把jl指令nop掉。
成功爆破
算法分析
判断username长度不小于4后,在0x40164D处调用库函数(MakeReverse)翻转username字符串,再用翻转后的字符串与id比较,相等则表示注册成功。
[ArturDents-CrackMe#2]
程序功能:输入Name和Serial,检查是否正确。输入错误没有提示。
爆破
根据字串“Yeah, you did it!”定位关键代码段。
关键跳是位于地址40111A处的:jge short loc_401134和位于地址40115A处的:jnz short locret_401174。
其中jge这条指令判断输入的字符数是否大于5,大于5则跳转执行401134处的指令。利用这一跳绕过字符串长度的检查。
把jge指令改成jmp、jnz指令改成nop,成功爆破。
算法分析
GetDlgItemTextA函数获取输入Name的长度,如果长度小于5,则发出警告,并退出程序。
执行下面一段循环,循环次数取决于Name的长度。每次循环取出Name字符串第一个字符,ascii码减去当前Name字符串长度后与Serial第一个字符比较,相等则继续执行循环。Name和Serial都删掉第一个字符后作为新的Name和Serial。
写成python,获取每个Name的正确Serial
#!/usr/bin/env python3
name = list(input("input you name[length >= 5]:"))
for i in range(len(name)):
arry = name[i:]
name[i] = chr(ord(arry[0]) - len(arry))
print(f'your serial is:{"".join(name)}')
[Acid burn]
程序有两个功能。一个功能是输入Serial,判断Serial是否正确;另一个功能是输入Username和Serial,判断Username对应的Serial是否正确。
去掉Nag窗口
nag是指一种弹出窗口,用于提醒用户购买正版软件或者注册软件。
每次启动都弹出窗口,目的是不让程序弹出这个窗口。
静态分析
IDA首先找到弹出这个窗口的函数入口地址0042F784,现在要找出调用这个函数的指令。
Ctrl+x查看交叉引用,并没有显示引用该函数的地址。说明主调函数在动态执行过程中才获取到这个函数的地址。
动态分析
OD在函数入口0042F784下断点,F9执行到此处。查看栈的情况如下,ESP所指的数据就是函数的返回地址。
00425643处的调用指令,就是这一条指令调用弹出Nag窗口函数。
低地址的JE指令可以让程序跳过call指令,把JE改成JMP就行了。
爆破
爆破的方式与前面的类似,找到关键字符串的所在代码的关键跳转,nop掉即可。
算法分析
功能一:只输入Serial
两个局部变量,分别赋值为"Hello"和"Dude!",合并后"Hello Dude!"与输入进行比较
功能二:输入Username和Serial
#代码段前面有很多对程序没有作用的指令,但是为了往下分析,也不得不把这一部分分析出来。起到了一定的保护作用。
#这一大段指令做了如下工作,其中ESI、EAX为寄存器,但是它们并没有被赋值给程序的变量或参数
ESI = h << 3 - h
ESI = u << 4 + ESI
ESI = 0x6E * 0x0B
EAX = 0x61 * 0x0E
ESI = EAX + ESI
真正起到作用的部分,转为python
key_bk = "CW-"
key_fd = "-CRACKED"
name = input("name:")
number = ord(name[0]) * 0x29 * 2
print("your serial:" + key_bk + str(number) + key_fd)