180501 逆向-RedHat(Reverse)

AK了(:з」∠)题目难度相对不太大,不过识别算法的思路还是学到了

Reverse

icm

反编译main函数,校验了长度42以后在函数中进行判断
发现每8个字节进行一次处理,最后异或119-i后和数组比较
将其dump出来备用,查看处理函数

发现在其中把指定种子的随机数作为密钥,然后把输入的8个比特编码成4个int,再变换,最后解码还原,顺便异或了8-i

那么关键就是这个变换是什么了
比赛的时候是没找到什么算法,头铁,硬着逆出来了
后来询问了一下师傅知道是IDEA算法
实际上key和密文dump出来解密即可得到明文

下面简述一下头铁解法

查看发现密钥扩展以后循环了8轮,每轮使用了子密钥的12个字节
完成后对四个字节再次进行了一堆处理,最后组合成一个int
每轮中的计算函数如下

cal_2中也是mul_low_sub_high和add和子密钥的组合,就不截图了

图上从函数命名中即可看出功能,值得一题的是mul_low_sub_high这个函数有点复杂
它return的是a * b - 0x10001 * (0xFFFF0000FFFF0001LL * (a * b) >> 64) >> 16)
简化加动调可知实际上结果是a*b的低16位减去高16位

对于add和xor函数只要得到结果和一个操作数就能还原出另一个操作数,这个函数该怎么处理呢?
位运算学的不好,没有想到它代表的意义,只好从头铁角度来操作

爆破
当然,由于两个操作数各16位,穷举空间高达0xffff*0xffff,不太现实
观察发现
这个函数的操作数是有限的–它的第二个操作数总是子密钥中的某个定值。由于密钥是给定的,因此第二个操作数只有有限的十几个
这样穷举空间就限制到0xffff*10左右了

完成以上操作以后可以通过结果和一个操作数逆出另一个操作数
但是cal函数中最后v3是通过中间数和v8、v9异或得来的,而这几个数我们都没有

绕了一下,注意到cal_2生成v8和v9的过程中只用到了v6、v7和子密钥,这其中v6和v7是中间数异或出来的,注意到v3[0]和v3[2]的异或数一样,因此可以逐个还原
说人话:
v3[0]^v3[2] = v10^v12 = v6
同理得v3[1]^v3[3] = v7,然后正向复制cal_2生成v8、v9,从而得到中间数
继续往上逆即可得到输入数了

将子密钥完全dump出来,同样循环九轮即可得到明文

代码如下:

     # r = [167, 150, 222, 232, 190, 10, 42, 36, 82, 138, 135, 95, 58, 46, 4, 84, 41, 168, 186, 209, 34, 98, 125, 140, 188, 69, 158, 208, 202, 127, 38, 67, 55, 168, 96, 200, 185, 86, 29, 215, 194, 217, 222, 16, 243, 208, 57, 61]
    # for i in range(len(r)//8):
    #     p = r[i*8:i*8+8]
    #     for j in range(8):
    #         print(p[j]^(8-j), end=', ')
    from string import printable
    r = [175, 145, 216, 237, 186, 9, 40, 37, 90, 141, 129, 90, 62, 45, 6, 85, 33, 175, 188, 212, 38, 97, 127, 141, 180, 66, 152, 213, 206, 124, 36, 66, 63, 175, 102, 205, 189, 85, 31, 214, 202, 222, 216, 21, 247, 211, 59, 60]
    mul_table = {}
    rand_table = [6398, 40087, 2674, 38645, 49917, 61102, 5237, 37546, 11796, 58669, 60293, 64477, 23592, 60197, 21553, 64825, 23511, 3063, 47800, 20950, 19112, 25594, 29276, 10698, 61301, 28835, 44181, 20679, 62692, 47187, 38071, 44567, 18265, 10913, 36841, 51568, 42793, 28508, 12254, 60129, 17183, 54162, 57678, 21214, 47199, 48597, 49806, 45653]
    mul_table_value = [0x25c2, 0xbf7b]
    for i in range(8):
        mul_table_value.append(rand_table[6*i+0])
        mul_table_value.append(rand_table[6*i+3])


    def mul(a, b):
        p = (((a*b)&0xffff) - (a*b>>16))
        return p&0xffff if p>0 else (p&0xffff)+1

    def find_mul_table(x, v):
        # print(hex(x))
        for i in range(len(mul_table[v])):
            if(mul_table[v][i]==x):
                return i
        else:
            print("error")

    for v in mul_table_value:
        mul_table[v] = []
        for m in range(0x100):
            for n in range(0x100):
                q = (m<<8) + n
                # print(hex(q))
                mul_table[v].append(mul(q, v)&0xffff)
        # print("%x has added"% v)
    print(len(r))
    rn = []
    for i in range(24):
        # for j in range(4):

            p = (r[i*2]<<8) + r[i*2+1]
            rn.append(p)
        # print(hex(p))
    print(rn)

    # rn = [44945, 55533, 47625, 10277, 23181, 33114, 15917, 1621, 8623, 48340, 9825, 32653, 46146, 39125, 52860, 9282, 16303, 26317, 48469, 8150, 51934]

    def re_cal(r, j):
        # result = []
        # for i in range(6):
        #     print(hex(rand_table[6*j+i]), end=' ')
        # print()
        r[1], r[2] = r[2], r[1]
        v6 = r[0]^r[2]
        # print(hex(v6))
        v7 = r[1]^r[3]
        rand0 = rand_table[6*j+4]
        rand1 = rand_table[6*j+5]

        v4 = mul(v6, rand0)
        v5 = (v7+v4)&0xffff
        v9 = mul(v5, rand1)
        v8 = (v4+v9)&0xffff
        # print(r[0], v9)
        r0 = r[0]^v9
        r1 = r[1]^v8
        r2 = r[2]^v9
        r3 = r[3]^v8
        # print(r0)
        r0 = find_mul_table(r0, rand_table[6*j+0])
        r1 = (r1 - rand_table[6*j+1])&0xffff
        r2 = (r2 - rand_table[6*j+2])&0xffff
        r3 = find_mul_table(r3, rand_table[6*j+3])
        return [r0, r1, r2, r3]





    def re(r):
        a0 = find_mul_table(r[0],0x25c2)
        a1 = (r[1]-0x9ca5)&0xffff
        a2 = (r[2]-0xbd70)&0xffff
        a3 = find_mul_table(r[3],0xbf7b)
        a1, a2 = a2, a1
        k = [a0, a1, a2, a3]
        # for i in k:
        #     print(hex(i), end=' ')
        # print()
        for j in range(7, -1, -1):
            k = re_cal(k, j)
            # print(k, j)
            # for i in k:
            #     print(hex(i), end=' ')
            # print(j)
        # print(k)
        return k
    for i in range(6):
        p = re(rn[i*4+0:i*4+4])
        for i in p:
            print(chr(i>>8), end='')
            print(chr(i&0xff), end='')

用IDEA的源码可以秒解=。=

wcm

ida插件识别到SMS4算法的box,比对发现一致
找到源码,key同样由指定种子的随机数生成,dump下来后通过源码解密即可

(本来icm也是可以这么简洁的qaq羡慕师傅们的识别能力)

ccm

查壳发现nSPack,脱壳机搞定
逆向发现对输入的hex进行了转换

在这个函数中将字母通过一系列很复杂的方法进行了处理,而其他字符则直接变为了一个Table中的大写字母

最后decode逐字节对比,值得一提的是第(7+16*i)个字节的数据被跳过对比,而是最后通过CRC32来校验

原样dump出来,反解码,发现数字都正常还原了,几个字母由于懒得逆而空着

更新:
就是维吉尼亚, 详细分析过程见后一天的blog
对比一下发现只有flag{中的“l”和”{“,和后面几个位置的’-‘存在字母,因此直接对应还原即可

缺失字母只能通过爆破CRC32来还原了,反正Table很小,五个字母几秒就出

全部还原后解得flag
代码如下:

    tt = "GHIJKLMNOPQRSTUV"

    # 原始dump数组
    r = [77, 77, 77, 117, 77, 72, 77, 211, 78, 121, 74, 76, 74, 75, 77, 77, 74, 80, 74, 75, 74, 77, 77, 227, 74, 76, 73, 102, 77, 77, 74, 80, 74, 76, 77, 72, 73, 120, 74, 243, 77, 72, 74, 71, 77, 72, 73, 113, 77, 73, 77, 72, 74, 74, 74, 3, 73, 118, 74, 78, 77, 73, 74, 72, 74, 78, 74, 72, 77, 72, 74, 19, 77, 76, 77, 74, 77, 72, 74, 79, 74, 73, 78, 101]
    # 填充过CRC爆破后的数组
    r = "MMMuMHMNNyJLJKMMJPJKJMMMJLIfMMJPJLMHIxJKMHJGMHIqMIMHJJJHIvJNMIJHJNJHMHJNMLMJMHJOJINe"


    # from zlib import crc32
    # table = b"GHIJKLMNOPQRSTUV"
    # def brute():
    #     for a1 in table:
    #         for a2 in table:
    #             for a3 in table:
    #                 for a4 in table:
    #                     for a5 in table:
    #                         b = (bytes((a1,a2,a3,a4,a5)))
    #                         if(crc32(b)==0x9D945A6E):
    #                             print(b)
    #                             return
    # brute()
    # b'NMKHN'
    # 第7 18 23等缺失的部分,通过CRC爆破得到,补回原数列中



    flag = ""
    k = 7
    for i in range(len(r)):
        # 用原始dump数组计算的时候需要跳过这些错误的字符
        # if(i==k):
        #     k += 16
        #     # i += 1
        #     flag += ' '
        #     continue
        p = (r[i])
        # print(p, end='')#, i, t[i%len(t)])
        if(p in tt):
            p = str(int(tt.index(p)))
        else:
            # 含有字母的几个HEX大部分是'-',转出的值为2d
            # 头部的flag{的l和{也含有字母,分别为6c和7b
            # 还原后即可
            p = 'd'
        flag += p
    print()
    print(flag)

    # 666c61677b35346639343666352d663935612d346130612d626133312d3762313731613765636138327d
    print(bytes.fromhex("666c61677b35346639343666352d663935612d346130612d626133312d3762313731613765636138327d"))
    # b'flag{54f946f5-f95a-4a0a-ba31-7b171a7eca82}'

Explain

很明显是个虚拟机,将code dump下来然后对应写函数运行打log即可
对照log发现接收输入以后将input[i]异或了i,然后与数组比较
求解很简单
没啥好说的(望天

    code = [0x2b, 0x0, 0x30, 0x92, 0x2b, 0x0, 0x31, 0x96, 0x2b, 0x0, 0x32, 0x0, 0x2b, 0x0, 0x40, 0x93, 0x2b, 0x0, 0x41, 0x92, 0x2b, 0x0, 0x42, 0x0, 0x2b, 0x0, 0xa0, 0x66, 0x2b, 0x0, 0xa1, 0x6d, 0x2b, 0x0, 0xa2, 0x63, 0x2b, 0x0, 0xa3, 0x64, 0x2b, 0x0, 0xa4, 0x7f, 0x2b, 0x0, 0xa5, 0x51, 0x2b, 0x0, 0xa6, 0x6e, 0x2b, 0x0, 0xa7, 0x36, 0x2b, 0x0, 0xa8, 0x7b, 0x2b, 0x0, 0xa9, 0x56, 0x2b, 0x0, 0xaa, 0x3b, 0x2b, 0x0, 0xab, 0x78, 0x2b, 0x0, 0xac, 0x53, 0x2b, 0x0, 0xad, 0x59, 0x2b, 0x0, 0xae, 0x67, 0x2b, 0x0, 0xaf, 0x41, 0x2b, 0x0, 0xb0, 0x69, 0x2b, 0x0, 0xb1, 0x4e, 0x2b, 0x0, 0xb2, 0x44, 0x2b, 0x0, 0xb3, 0x7a, 0x2b, 0x0, 0xb4, 0x66, 0x2b, 0x0, 0xb5, 0x61, 0x2b, 0x0, 0xb6, 0x43, 0x2b, 0x0, 0xb7, 0x56, 0x2b, 0x0, 0xb8, 0x29, 0x2b, 0x0, 0xb9, 0x46, 0x2b, 0x0, 0xba, 0x57, 0x2b, 0x0, 0xbb, 0x7a, 0x2b, 0x0, 0xbc, 0x7f, 0x2b, 0x0, 0xbd, 0x55, 0x2b, 0x0, 0xbe, 0x77, 0x2b, 0x0, 0xbf, 0x71, 0x2b, 0x0, 0xc0, 0x45, 0x2b, 0x0, 0xc1, 0x0, 0x2b, 0x0, 0xc2, 0x5f, 0x29, 0x0, 0x0, 0x60, 0x29, 0x1, 0x0, 0x0, 0x24, 0x0, 0x31, 0x0, 0x0, 0x1, 0x31, 0x1, 0x0, 0x1, 0x2d, 0x1, 0x0, 0x23, 0x3c, 0x0, 0xac, 0x29, 0x0, 0x0, 0x60, 0x29, 0x1, 0x0, 0x0, 0x39, 0x0, 0x1, 0x31, 0x0, 0x0, 0x1, 0x31, 0x1, 0x0, 0x1, 0x2d, 0x1, 0x0, 0x23, 0x3c, 0x0, 0xc5, 0x29, 0x0, 0x0, 0x60, 0x29, 0x1, 0x0, 0xa0, 0x29, 0x2, 0x0, 0x0, 0x2f, 0x0, 0x1, 0x3c, 0x1, 0x1a, 0x31, 0x0, 0x0, 0x1, 0x31, 0x1, 0x0, 0x1, 0x31, 0x2, 0x0, 0x1, 0x2d, 0x2, 0x0, 0x23, 0x3c, 0x0, 0xe3, 0x29, 0x0, 0x0, 0x30, 0x29, 0x1, 0x0, 0x0, 0x38, 0x0, 0x0, 0xdd, 0x27, 0x0, 0x31, 0x0, 0x0, 0x1, 0x31, 0x1, 0x0, 0x1, 0x2d, 0x1, 0x0, 0x2, 0x3c, 0x1, 0x4, 0x3d, 0x29, 0x0, 0x0, 0x40, 0x29, 0x1, 0x0, 0x0, 0x38, 0x0, 0x0, 0xdd, 0x27, 0x0, 0x31, 0x0, 0x0, 0x1, 0x31, 0x1, 0x0, 0x1, 0x2d, 0x1, 0x0, 0x2, 0x3c, 0x1, 0x22, 0x3d, 0x48, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x30, 0x40, 0x0, 0x10, 0x23, 0x40, 0x0, 0x1, 0x0, 0x0, 0x0, 0x52, 0x53, 0x44, 0x53, 0x66, 0x25, 0x2d, 0xa3, 0xeb, 0x8f, 0x4d, 0x40, 0xba, 0xaa, 0x2d, 0x3e, 0x10, 0xd3, 0xe6, 0xdd, 0x1, 0x0, 0x0, 0x0, 0x44, 0x3a, 0x5c, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x5c, 0x45, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x5c, 0x45, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x5c, 0x52, 0x65, 0x6c, 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值