欢迎光临
我们一直在努力

新160个CrackMe025-CRC-32crackme、028-ArturDents-CrackMe#3、030-Acid Bytes.4逆向分析

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}")

赞(0)
未经允许不得转载:171主机测评 » 新160个CrackMe025-CRC-32crackme、028-ArturDents-CrackMe#3、030-Acid Bytes.4逆向分析
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址