Back

dfjk 2021 RE

  • RE1:迷宫
  • RE2:so层

最后一个好像是php?告辞

RE1

程序逻辑很简单,就是一个迷宫,迷宫的每一个位置写成了一个函数,一开始想手动推一下试试,结果发现有的格子可能有多条路径,然后想反着推,然后发现有相同的问题…

考虑写自动化脚本,一开始想试试angr,同样有很多问题,想用idaapi又只能现查各种api

后来在手动执行的时候,发现错误输入和正确输入之间的区别是反馈不同,而且走错路径的话不需要退出,直接原路返回就行,于是考虑直接用pwntools模拟手动执行

直接简单回溯

import sys

sys.setrecursionlimit(20000)

from pwn import *

success = [
    b'Just do it\n',
    b'GOGOGO\n',
    b'Wuhu~!\n',
    b'Wuhu\n',
    b'You are so good\n',
    b'Nice.\n',
    b'Yeah~~\n',
    b'Yeah~~~\n',
    b'Let\'s go.\n',
    b'Never stop\n',
    b'So smart\n',
]

p = process('./maze')
# solvepath = "SSSSSSSSSDDDDDDWWWWAAWWAASSSSD"
# context(os='linux', arch='amd64', log_level='debug')

# solveend = "AASSDDSSSSDDS"

# solvepath = 'S' * 8
solvepath = 'S' * 8

direct = ['W', 'A', 'D', 'S']

p.recvuntil(b'You can only go south.\n')
for i in solvepath:
    p.send(i)
    print (p.recvline(), i)

def dfs():
    global solvepath
    for cur in direct:
        if direct.index(solvepath[-1]) + direct.index(cur) != 3:
            p.send(cur)
            rev = p.recvline()
            # print (rev, cur)
            if rev in success:
                solvepath += cur
                # print (solvepath)
                dfs()
                # print (direct[3 - direct.index(solvepath[-1])])
                p.send(direct[3 - direct.index(solvepath[-1])])
                solvepath = solvepath[:-1]
                p.recvline()
            elif b'Good Job.' in rev:
                print (solvepath + cur)
                exit(0)

dfs()

运行结果拿去算个md5就行

RE2

这题才是传统的逆向啊,为什么做的人反而比第一题少…

看一下jeb,发现加密在so层,直接ida看so层

发现先进行了一个RC4,然后是一个XXTEA

直接解密

解密代码来自 NewBieReer 师傅

先上XXTEA模板

#include <stdio.h>  
#include <stdint.h>  
#define DELTA 0x9e3779b9  
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))  

void btea(uint32_t *v, int n, uint32_t const key[4]) { 
        uint32_t y, z, sum;  
    unsigned p, rounds, e;  
        rounds = 6 + 52/n;  //12        52/6 = 8    n
        sum = rounds*DELTA;  
        y = v[0];  
        do {  
            e = (sum >> 2) & 3;  
            for (p=n-1; p>0; p--) {  
                z = v[p-1];  
                y = v[p] -= MX;  
            }  
            z = v[n-1];  
            y = v[0] -= MX;  
            sum -= DELTA;  
        }  
        while (--rounds);  
}

int main(){
    uint32_t v[9] = {0x68E5973E, 0x0C20C7367,
    0x98AFD41B, 0xFE4B9DE2,
    0x1A5B60B, 0x3D36D646,
    0xDBCC7BAF, 0xA0414F00,
    0x762CE71A
    };
    uint32_t const k[4] = {0x1,0x10,0x100,0x1000};
    int n = 9;
    btea(v,n,k);
    printf("解密后的数据:0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x %08x\n",v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8]); 
}

然后再接一个RC4

def __rc4_init(key):
    keylength = len(key)
    S = list(range(256))
    j = 0
    for i in range(256):
        j = (j + S[i] + int(key[i % keylength])) % 256
        S[i], S[j] = S[j], S[i]
    return S

def rc4_crypt(key, data):
    S = __rc4_init(key)
    i = j = 0
    result = b''
    for a in data:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        k = (a ^ S[(S[i] + S[j]) % 256]).to_bytes(1, 'big')
        print (hex(S[(S[i] + S[j]) % 256]))
        result += k
    return result

if __name__ == "__main__":
    from libnum import n2s, s2n
    key = b'\x01\x00\x00\x00\x10\x00\x00\x00\x00\x01\x00\x00\x00\x10\x00\x00'
    data = n2s(0x5604b0d49c634d3096cec00593be3b82524b16b28a33b74d6d7b9950c2b10c12e1840a93)
    def convert(k):
        ret = []
        while k > 0:    
            ret.append(k & 0xff)
            k >>= 8
        return ret[::-1]
    result_rc4 = rc4_crypt(key,data)
    print(result_rc4)

注意一下大小端就行

Built with Hugo
Theme Stack designed by Jimmy