web选手入门reverse(2)——crackme_easy

admin 2025年5月14日22:56:45评论6 views字数 2915阅读9分43秒阅读模式
前言:代码审计累了就去做pwn,pwn做累了就去找反序列化链,反序列化链找累了就去写代码,写代码累了就去做逆向,逆向做累了就去代码审计。安全学习还是要劳逸结合啊。
老题,当然做的时候不知道。Windows上的注册机。
web选手入门reverse(2)——crackme_easy
ida看代码。
web选手入门reverse(2)——crackme_easy
跟进DialogFunc-> sub_401370
web选手入门reverse(2)——crackme_easy
先看sub_401258
web选手入门reverse(2)——crackme_easy

显然a2/v1是长度,限制了16,a1/&String是我们输入的字符串,看起来也有限制,但不知道也不影响做题。

那么修改一下参数名,来到核心方法4012A9

web选手入门reverse(2)——crackme_easy

显然最终对比的是v6和text,v6就是加密后的结果,v8看起来像种子,根据种子用sub_40110D生成key,再执行sub_4011A6(text, 16, key)进行加密。

我们断0040133E call sub_4011A6记录一下key。

web选手入门reverse(2)——crackme_easy

这个key是固定的68位,前64位作为密码表盘,65-67作为标志位指向表盘中的某个密码,刚开始为均为0x00。

接下来就是看sub_4011A6的算法了,这里要自己动调,对着汇编一行一行看,然后修改参数名和增加注释。

web选手入门reverse(2)——crackme_easy

加密算法比较简单,核心其实就是v7/v8/v10。

v7=&key[i]v8=&key[i2]v10=&key[i3]

所以就是搞清楚i/i2/i3是怎么来的。第一轮循环中i=flag_1自增也就是1,

i2=(key[i] + flag_2) & 0x3f

由于flag_2第一轮为0,所以其实就是

i2=key[i] & 0x3fi3=(i + key[i2]) & 0x3f

也就是说,i2跟key[i]有关,i3跟key[i2]有关,都是依次根据密码表盘上的某个位置的值算出来的。

还有这两处代码,它们实际上就是key[i]和key[i2]调换位置,key[i]和key[i3]调换位置,也就是说密码表盘是活动的。

web选手入门reverse(2)——crackme_easy

在v7/v8/v10的生成过程当中,全程没有text参与。生成之后,执行了如下代码。

text[0] = text[0] – ((v7 + v8 + v10) & 0x3F)

那么加密流程就出来了。

1,在key[i]/key[i2]/key[i3]三处获得v7/v8/v10,i为自增,i2根据i生成,i3根据i和i2生成。

2,交换key[i]/key[i2]/key[i3]三处的位置

3,用v7+v8+v10加密text[0]

4,重复16次。

虽然密码表盘在变动,但变动的规律实际上是固定的,不受我们输入的text影响,也就是这题可以简化成,用16个key对text[0]-text[15]进行加密。这样我们就可以用一个笨办法来获得正向加密。

那就是将16次循环中的v7/v8/v10都找出来,很容易找到断点处。(*v7 + *v8 + *v10)对应的汇编。

web选手入门reverse(2)——crackme_easy

可以看到第一次循环[edi]=0x19,[esi]=0x3e,  [eax]=0x1e,和ida注释中动调的结果一样。

web选手入门reverse(2)——crackme_easy

F9 16次,记录下每次的v7/v8/v10,写出正函数代码。

PS:这里更简单的做法是直接断dl寄存器里的值,也就是v7+v8+v10的结果。

def enc_k3(i, k1, k2, k3):    return hex(i - ((k1 + k2 + k3) & 0x3f))def enc(text):    str = enc_k3(text[0], 0x19,0x3e,0x1e)    str += enc_k3(text[1], 0x12,0x27,0x14)    str += enc_k3(text[2], 0x0f,0x3d,0x02)    str += enc_k3(text[3], 0x37,0x0d,0x36)    str += enc_k3(text[4], 0x1f,0x28,0x03)    str += enc_k3(text[5], 0x11,0x06,0x28)    str += enc_k3(text[6], 0x08,0x34,0x04)    str += enc_k3(text[7], 0x2e,0x1d,0x13)    str += enc_k3(text[8], 0x15,0x0a,0x3f)    str += enc_k3(text[9], 0x0a,0x00,0x12)    str += enc_k3(text[10], 0x33,0x31,0x3e)    str += enc_k3(text[11], 0x03,0x1c,0x08)    str += enc_k3(text[12], 0x31,0x24,0x33)    str += enc_k3(text[13], 0x3f,0x20,0x33)    str += enc_k3(text[14], 0x08,0x03,0x11)    str += enc_k3(text[15], 0x04,0x3b,0x0a)    return strtext = bytearray(b'A' * 16)print(enc(text))
web选手入门reverse(2)——crackme_easy

对比后发现结果一样,那么反函数就非常简单了,带入v6的值可以得到flag。

def dec_k3(i, k1, k2, k3):    return chr(i + ((k1 + k2 + k3) & 0x3f))def dec(text):    str = dec_k3(text[0], 0x19,0x3e,0x1e)    str += dec_k3(text[1], 0x12,0x27,0x14)    str += dec_k3(text[2], 0x0f,0x3d,0x02)    str += dec_k3(text[3], 0x37,0x0d,0x36)    str += dec_k3(text[4], 0x1f,0x28,0x03)    str += dec_k3(text[5], 0x11,0x06,0x28)    str += dec_k3(text[6], 0x08,0x34,0x04)    str += dec_k3(text[7], 0x2e,0x1d,0x13)    str += dec_k3(text[8], 0x15,0x0a,0x3f)    str += dec_k3(text[9], 0x0a,0x00,0x12)    str += dec_k3(text[10], 0x33,0x31,0x3e)    str += dec_k3(text[11], 0x03,0x1c,0x08)    str += dec_k3(text[12], 0x31,0x24,0x33)    str += dec_k3(text[13], 0x3f,0x20,0x33)    str += dec_k3(text[14], 0x08,0x03,0x11)    str += dec_k3(text[15], 0x04,0x3b,0x0a)    return strv6 = bytearray([    4610388411013710170,    2020151840362145])print(dec(v6))
web选手入门reverse(2)——crackme_easy

原文始发于微信公众号(珂技知识分享):web选手入门reverse(2)——crackme_easy

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年5月14日22:56:45
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   web选手入门reverse(2)——crackme_easyhttps://cn-sec.com/archives/4064884.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息