025
无壳

暴力破解
发现主要跳转语句,将其改成直接跳转,即可实现爆破


算法分析
跟进主要函数,发现先是对用户名进行获取长度,循环生成用户名长度的字符串,每一位都是0x32,检验获取的字符串是否为0,获取一个系统自带值a1,就继续乡下分析发现这些都是用来混淆的,下面没有用到

同理也对序列号进行了这样的一系列操作,也是混淆

真正实现算法的部分是,先在用户名的前面拼接一个字符串,再将拼接后的字符串进行标准CRC检验,得到的结果存在esi内

之后将获得的序列号前拼接一个“0”将该数字字符串转换成整数再转换成十六进制与之前获得esi内的CRC检验数进行比对,相等则判断成功

函数crc32crackme.404224内的函数源代码大致为:
temp1 = 0
for ch in serial:
temp1 = temp1 * 10 + (ord(ch) – 0x30)

可以生成keygen:
import zlib
def calculate_crc32(data):
crc = zlib.crc32(data.encode('utf-8')) & 0xFFFFFFFF
return crc
def decimal_to_serial(decimal_num):
if decimal_num == 0:
return "0"
serial_chars = []
remaining = decimal_num
while remaining > 0:
remainder = remaining % 10
serial_chars.append(chr(remainder + 0x30))
remaining = remaining // 10
serial = ''.join(reversed(serial_chars))
return serial
def generate_serial(username):
combined = "DiKeN" + username
print(f"[*] Combined string: {combined}")
crc_value = calculate_crc32(combined)
print(f"[*] CRC-32 (hex): 0x{crc_value:08X}")
decimal_value = crc_value
print(f"[*] Decimal value: {decimal_value}")
serial = decimal_to_serial(decimal_value)
print(f"[*] Generated serial: {serial}")
return serial
def verify_serial(username, serial):
temp1 = 0
for ch in serial:
temp1 = temp1 * 10 + (ord(ch) – 0x30)
combined = "DiKeN" + username
crc_value = calculate_crc32(combined)
print(f"\\n[Verify] Serial calculated: {temp1}")
print(f"[Verify] CRC decimal: {crc_value}")
return temp1 == crc_value
def main():
print("=" * 50)
print("KeyGen for DiKeN CrackMe")
print("=" * 50)
while True:
print("\\nEnter username (or 'quit' to exit):")
username = input("> ").strip()
if username.lower() == 'quit':
break
if not username:
print("[!] Username cannot be empty!")
continue
serial = generate_serial(username)
print("\\n" + "-" * 50)
if verify_serial(username, serial):
print("[OK] Serial is correct!")
print(f"\\n[*] Final serial: {serial}")
else:
print("[FAIL] Verification failed")
print("-" * 50)
if __name__ == "__main__":
main()
028
有壳


脱壳
使用ESP定律,在x32dbg、Ollydbg中脱壳之后的程序都没办法直接运行,也没有找到相关脱壳软件的安装包,所以本题不脱壳,直接分析。
先运行找到真正程序所在设置断点,方便以后直接运行到关键函数位置


暴力破解
找到关键跳转,将其给nop掉即可获取破解版本,但是破解版本的软件因为没有脱壳,所以不能直接运行,这里只在x32dbg中进行分析学习

算法分析
先是检验序列号和用户名是否为空

步过发现输入的用户名先是经过一个循环对每个字符进行除法,获得商转换成十六进制的两位数,然后将每次获得的新的两位数拼到旧两位数之前,循环结束后将获得的字符串前拼接一个固定的字符串“ADCM3-”,将其作为序列号与用户输入的序列号进行对比,如果相等则成功

可以生成keygen:
username=input("Input username:").strip()
result=""
for ch in username:
temp=ord(ch)//3
result+=str(temp)
serial="ADCM3-"+result
print(f"Serial:{serial}")
030
UPX壳

脱壳

退出时有neg

暴力破击
找到弹窗函数,将其给nop掉即可获取无neg版本
再分析别的,发现要求用输入的用户名长度必须大于等于6

还有一个检验输入的序列号是否正确的跳转,将第一个改成直接跳转第二个给nop掉,即可获取破解版本

发现检验序列号是否正确的跳转是唯一的,但是给检验长度的跳转改变之后会产生错误,可能是在下面程序中还会用到用户名长度这一变量


“Range check error”通常指程序运行时变量的值超出了其允许的范围,导致越界错误。,所以目前只有必须输入用户名长度大于等于6的破解版本
算法分析
先是堆栈平衡,再检验用户名长度必须大于6,序列号长度必须大于0,继续向下分析发现分别对用户名的前六位分别进行ASCII码值乘2,再累加到esi中

处理完前六个字符之后,再对字符串的长度乘2加到esi中,最后将esi中的值转换为字符串,与输入的序列号进行对比,相等的成功

可以生成keygen:
username=input("Input username:").strip()
temp=0
for ch in username:
temp+=ord(ch)*2
temp+=(2*len(username))
print(f"temp{temp}")






