2024 极客大挑战reverse部分题解
风瞬息 发表于 江西 CTF 345浏览 · 2024-11-21 13:12

Hello_re

提示010,点击查看,发现加了一层upx的壳,并且特征位UPX0被修改成SYC0

修改后进行脱壳,然后拖进IDA

可以推出加密函数就是

sub_140001408(v6, &v5, v4);

v6为输入的flag,v5为密钥,v4为输出并且后续会与已知的v7进行对比

得脚本

v7 = [
    0, 1, 2, 52, 3, 96, 47, 28,
    107, 15, 9, 24, 45, 62, 60, 2,
    17, 123, 39, 58, 41, 48, 96, 26,
    8, 52, 63, 100, 33, 106, 122, 48
]

# 密钥v5,转换为字节数组形式
v5 = 0x5245564F4C435953
v5_bytes = v5.to_bytes(8, 'little')
# 注意是小端序

v4 = [0] * 32

# XOR
for j in range(32):
    v4[j] = v7[j] ^ (j ^ v5_bytes[j % 8])

# 将每个字符转换为字符串
flag = ''.join(chr(c) for c in v4)

print("The flag is:", flag)

# The flag is: SYC{H3lI0_@_new_R3vers3_Ctf3r!!}

先来一道签到题

拿到sssssssss.s文件,先拖进IDA看看是什么意思

这种未转成可读的exe有两种选择,要么是选中按a,把他转换成字符类型来阅读看看有没有什么信息,第二种是选中按c,转换成代码

这里我们按a转换成字符串

输入flag,判断长度

进行加密操作

脚本

temp = "TTDv^jrZu`Gg6tXfi+pZojpZSjXmbqbmt.&x"
flag = ""
times = 0
for i in temp:
    if times % 2 == 0:
        flag += chr(ord(i) ^ 7)
    else:
        flag += chr(ord(i) + 5)
    times += 1

print(flag)

# SYC{You_re@l1y_kn0w_how_To_revers3!}

也许你也听jay

这个题给了一个c文件

#include <stdio.h>

int main() {

    char URL[46];
    char o00O0OO000OO0oooo0o0oo0O0oo000000O0O0OO0O0O00OO0OO0O[46];
    strcpy(o00O0OO000OO0oooo0o0oo0O0oo000000O0O0OO0O0O00OO0OO0O, URL);
    char o00O0OO000OO0oooo0o0oo0O0oo000000O0O0OO0O00000O0OO0O[] = {0x96, 0xa1, 0xa0, 0x9b, 0x9b, 0x5f, 0x49, 0x46, 0x85, 0x82, 0x53, 0x95, 0x7d, 0x36, 0x8d, 0x74, 0x82, 0x88, 0x46, 0x7a, 0x81, 0x65, 0x80, 0x6c, 0x78, 0x2f, 0x6b, 0x6a, 0x27, 0x50, 0x61, 0x38, 0x3f, 0x37, 0x33, 0xf1, 0x27, 0x32, 0x34, 0x1f, 0x39, 0x23, 0xde, 0x1c, 0x17, 0xd4};
    int  o00O0OO000OO0oooo0o0oo0O0000oooooooO0O0OO0O0O00OO0OO0O[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D};
    int  o00O0OO000OO0oooo0o0oo0O000O0OO0O0O00OO0OO0O00000[] = {0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58, 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01};
    int o00O0OO000OO0oooo0o0oo0O000000O00O0O0OO0O0O00OO0OO0O[]={0x65, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5F, 0x5E, 0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58, 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x00, 0x31, 0x30, 0x2F};
    int len = strlen(URL);
    for(int i = 0; i < len; i++) {
        o00O0OO000OO0oooo0o0oo0O000000O00O0O0OO0O0O00OO0OO0O[i] ^=  o00O0OO000OO0oooo0o0oo0O000O0OO0O0O00OO0OO0O00000[i+1];  

    }
    for(int i = 0; i < len; i++) {
        o00O0OO000OO0oooo0o0oo0O0oo000000O0O0OO0O0O00OO0OO0O[i] ^=  o00O0OO000OO0oooo0o0oo0O0000oooooooO0O0OO0O0O00OO0OO0O[i];  

    }
     for(int i = 0; i < len; i++) {
        o00O0OO000OO0oooo0o0oo0O000000O00O0O0OO0O0O00OO0OO0O[i] -=  o00O0OO000OO0oooo0o0oo0O0000oooooooO0O0OO0O0O00OO0OO0O[i];  

    }
    for(int i = 0; i < len; i++) {
            o00O0OO000OO0oooo0o0oo0O0oo000000O0O0OO0O0O00OO0OO0O[i] -=  o00O0OO000OO0oooo0o0oo0O0000oooooooO0O0OO0O0O00OO0OO0O[47 + i];  
             o00O0OO000OO0oooo0o0oo0O0000oooooooO0O0OO0O0O00OO0OO0O[i]^=o00O0OO000OO0oooo0o0oo0O000000O00O0O0OO0O0O00OO0OO0O[51];

}
    for(int i = 0; i < len; i++) {
        o00O0OO000OO0oooo0o0oo0O0oo000000O0O0OO0O0O00OO0OO0O[i] +=  o00O0OO000OO0oooo0o0oo0O000O0OO0O0O00OO0OO0O00000[i];  
    }
    for(int i=0;i<len;i++){
        if(o00O0OO000OO0oooo0o0oo0O0oo000000O0O0OO0O0O00OO0OO0O[i] != o00O0OO000OO0oooo0o0oo0O0oo000000O0O0OO0O00000O0OO0O[i]){
            printf("Error");
        }
    }



    return 0;

}

先ctrl + r把易混淆的这几个变量换成a1,a2....

然后看一下逻辑,就是明文a1经过多轮加密,得到密文a2

a1 = [0] * 46
a2 = [0x96, 0xa1, 0xa0, 0x9b, 0x9b, 0x5f, 0x49, 0x46, 0x85, 0x82,
      0x53, 0x95, 0x7d, 0x36, 0x8d, 0x74, 0x82, 0x88, 0x46, 0x7a,
      0x81, 0x65, 0x80, 0x6c, 0x78, 0x2f, 0x6b, 0x6a, 0x27, 0x50,
      0x61, 0x38, 0x3f, 0x37, 0x33, 0xf1, 0x27, 0x32, 0x34, 0x1f,
      0x39, 0x23, 0xde, 0x1c, 0x17, 0xd4]
a3 = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
      0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14,
      0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E,
      0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
      0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32,
      0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C,
      0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
      0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
      0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A,
      0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64,
      0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E,
      0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
      0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82,
      0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C,
      0x8D]
a4 = [0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58, 0x57, 0x56, 0x55, 0x54, 0x53,
      0x52, 0x51, 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48,
      0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, 0x3E, 0x3D,
      0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32,
      0x31, 0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27,
      0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1C,
      0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11,
      0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06,
      0x05, 0x04, 0x03, 0x02, 0x01]
a5 = [0x65, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5F, 0x5E, 0x5D, 0x5C,
      0x5B, 0x5A, 0x59, 0x58, 0x57, 0x56, 0x55, 0x54, 0x53, 0x52,
      0x51, 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48,
      0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, 0x3E,
      0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34,
      0x33, 0x00, 0x31, 0x30, 0x2F]

for i in range(32):
    a5[i] ^= a4[i + 1]

for i in range(32):
    a1[i] ^= a3[i]

for i in range(32):
    a5[i] -= a3[i]

for i in range(32):
    a1[i] -= a3[47 + i]
    a3[i] ^= a5[51]

for i in range(32):
    a1[i] += a4[i]

for i in range(32):
    if a1[i] != a2[i]:
        print("Error")
    else:
        print("yes")

写成python代码,主要看一下这几轮加密

for i in range(32):
    a5[i] ^= a4[i + 1]

for i in range(32):
    a1[i] ^= a3[i]

for i in range(32):
    a5[i] -= a3[i]

for i in range(32):
    a1[i] -= a3[47 + i]
    a3[i] ^= a5[51]

for i in range(32):
    a1[i] += a4[i]

for i in range(32):
    if a1[i] != a2[i]:

逆向从尾向头,那么先让

  1. a1 = a2
  2. 原本是a1每一位都加a4[i],现在就是a1[i] - a4[i]
  3. 原本是a1先减去a3[47+i],然后a3每一位(in range 32)和a5[51]进行异或,现在就是a1先加上a3[47+i],然后a3每一位(in range 32)和a5[51]进行异或
  4. 后面就是两个异或

得脚本

a1 = [0] * 46
a2 = [0x96, 0xa1, 0xa0, 0x9b, 0x9b, 0x5f, 0x49, 0x46, 0x85, 0x82,
      0x53, 0x95, 0x7d, 0x36, 0x8d, 0x74, 0x82, 0x88, 0x46, 0x7a,
      0x81, 0x65, 0x80, 0x6c, 0x78, 0x2f, 0x6b, 0x6a, 0x27, 0x50,
      0x61, 0x38, 0x3f, 0x37, 0x33, 0xf1, 0x27, 0x32, 0x34, 0x1f,
      0x39, 0x23, 0xde, 0x1c, 0x17, 0xd4]
a3 = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
      0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14,
      0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E,
      0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
      0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32,
      0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C,
      0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
      0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
      0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A,
      0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64,
      0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E,
      0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
      0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82,
      0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C,
      0x8D]
a4 = [0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58, 0x57, 0x56, 0x55, 0x54, 0x53,
      0x52, 0x51, 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48,
      0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, 0x3E, 0x3D,
      0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32,
      0x31, 0x30, 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27,
      0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E, 0x1D, 0x1C,
      0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11,
      0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06,
      0x05, 0x04, 0x03, 0x02, 0x01]
a5 = [0x65, 0x64, 0x63, 0x62, 0x61, 0x60, 0x5F, 0x5E, 0x5D, 0x5C,
      0x5B, 0x5A, 0x59, 0x58, 0x57, 0x56, 0x55, 0x54, 0x53, 0x52,
      0x51, 0x50, 0x4F, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, 0x49, 0x48,
      0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x3F, 0x3E,
      0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34,
      0x33, 0x00, 0x31, 0x30, 0x2F]


for i in range(46):
    a1[i] = a2[i]

for i in range(46):
    a1[i] -= a4[i]

for i in range(46):
    a1[i] += a3[47 + i]
    a3[i] ^= a5[51]


for i in range(46):
    a5[i] += a3[i]

for i in range(46):
    a1[i] ^= a3[i]

for i in range(46):
    a5[i] ^= a4[i + 1]

for i in range(46):
    print(chr(a1[i]),end="")

这里写的都是range(46),因为32解密不完全

得到https://am1re-sudo.github.io/CoisniĮgithubĮioį

后面几位解密稍微有些问题,但是可读字符串github和io还在,į其实是/

或者直接搜

点进可能你也听jay(声音好大)

这里还有一个RC4加密


)

找个在线网站即可解出

SYC{ILIKELISTENJAYSONG}

我勒个z3啊

打开IDA查看主函数

先输入key,再输入flag

我们先去看一下key检验处的逻辑

逻辑就是对输入的key中的每一个字符串在给定的字典中遍历,如果相匹配则那个字符被替换成被匹配的字符在字典中的相对序号,最后与已知的数列数组相比对

写个脚本

temp = [42, 14, 14, 20, 63, 63, 63, 38, 17, 10,
        21, 21, 14, 23, 16, 14]
key = ""
dic = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ?_"

for i in temp:
    key += dic[i]
print(key)

得到key是Geek___Challenge

继续往下看flag的逻辑

sub_401AAC(v6, v4);
  if ( !sub_40179A(v6) )
  {
    puts("[~]NO,Something_gets_wrong. TT.TT");
    exit(0);
  }

第一个函数传进去的是flag和key,第二个函数检测的是加密后的flag。

我们先看第二个函数

写一个z3脚本解一下

from z3 import *

solver = Solver()
cal_flag = [Int(f'cal_flag{i}') for i in range(32)]
calculate = [0x19B, 0x113, 0x189, 0x1C9, 0x250, 0x536, 0x4DE, 0x1BC, 0x41B,
             0x724, 0x6D0, 0x4A1, 0x645, 0x475, 0x4CA, 0x68C, 0x3E5, 0x1C7,
             0x33D, 0x5B7, 0x28D, 0x244, 0x30E, 0x291, 0x271, 0x301, 0x45F,
             0x46F, 0x517, 0x41E, 0x426, 0x4B5]
enc_flag = [0] * 32
for i in range(0, 32, 4):
    solver.add(
        cal_flag[i] + 8 * cal_flag[i + 1] + 6 * cal_flag[i + 2] + cal_flag[i + 3] == calculate[i],
        cal_flag[i + 1] + 8 * cal_flag[i + 2] + 6 * cal_flag[i + 3] + cal_flag[i] == calculate[i + 1],
        cal_flag[i + 2] + 8 * cal_flag[i + 3] + 6 * cal_flag[i] + cal_flag[i + 1] == calculate[i + 2],
        cal_flag[i + 3] + 8 * cal_flag[i] + 6 * cal_flag[i + 1] + cal_flag[i + 2] == calculate[i + 3]
    )

if solver.check() == sat:
    model = solver.model()
    enc_flag = [model[cal_flag[i]].as_long() for i in range(32)]
    print(enc_flag)
    # print("strlen =", len(enc_flag))

解出来加密的flag后,我们再来看一下第一个加密函数

这个函数对每个字符进行了两次异或加密

其中还有个函数,是对输入的flag进行重新排序

既然现在拿到的是加密后的数据,那么我们先要进行解密xor,然后再把顺序恢复

这里最主要的点就是对xor逻辑的理解

for ( i = 0; i <= 31; ++i )
  {
    a1[i] ^= a1[(v3 + i - 1) % v3];
    a1[i] ^= a2[(47 - i) % 16] ^ i;
  }

从第一位到最后一位,数据先与自己的前一位进行异或(第一位取模后实际上是与最后一位异或),然后再与key和i异或;

从逆向的角度来看,每一个数据与自己前一位异或后还要在key,i异或,那么就先和key与i异或,再与前一位异或;

并且,与前一位异或时,前一位已经是异或加密之后的状态了,所以循环要从后往前进行,同理,还原顺序时也要注意是同样的逻辑

写个脚本

flag = [0] * 32
for i in range(31, -1, -1):
    enc_flag[i] ^= ord(key[(47 - i) % 16]) ^ i
    enc_flag[i] ^= enc_flag[(32 + i - 1) % 32]
    flag[i] = enc_flag[i]


for i in range(7, -1, -1):
    for j in range(i - 1, -1, -1):
        v2 = flag[4 * i + 3]
        for k in range(2, -1, -1):
            flag[4 * i + k + 1] = flag[4 * i + k]
        flag[4 * i] = v2


for i in range(32):
    print(chr(flag[i]), end="")

完整脚本

temp = [42, 14, 14, 20, 63, 63, 63, 38, 17, 10,
        21, 21, 14, 23, 16, 14]
key = ""
dic = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ?_"

for i in temp:
    key += dic[i]
print(key)
# print("strlen =", len(key))

from z3 import *

solver = Solver()
cal_flag = [Int(f'cal_flag{i}') for i in range(32)]
calculate = [0x19B, 0x113, 0x189, 0x1C9, 0x250, 0x536, 0x4DE, 0x1BC, 0x41B,
             0x724, 0x6D0, 0x4A1, 0x645, 0x475, 0x4CA, 0x68C, 0x3E5, 0x1C7,
             0x33D, 0x5B7, 0x28D, 0x244, 0x30E, 0x291, 0x271, 0x301, 0x45F,
             0x46F, 0x517, 0x41E, 0x426, 0x4B5]
enc_flag = [0] * 32
for i in range(0, 32, 4):
    solver.add(
        cal_flag[i] + 8 * cal_flag[i + 1] + 6 * cal_flag[i + 2] + cal_flag[i + 3] == calculate[i],
        cal_flag[i + 1] + 8 * cal_flag[i + 2] + 6 * cal_flag[i + 3] + cal_flag[i] == calculate[i + 1],
        cal_flag[i + 2] + 8 * cal_flag[i + 3] + 6 * cal_flag[i] + cal_flag[i + 1] == calculate[i + 2],
        cal_flag[i + 3] + 8 * cal_flag[i] + 6 * cal_flag[i + 1] + cal_flag[i + 2] == calculate[i + 3]
    )

if solver.check() == sat:
    model = solver.model()
    enc_flag = [model[cal_flag[i]].as_long() for i in range(32)]
    print(enc_flag)
    # print("strlen =", len(enc_flag))


flag = [0] * 32
for i in range(31, -1, -1):
    enc_flag[i] ^= ord(key[(47 - i) % 16]) ^ i
    enc_flag[i] ^= enc_flag[(32 + i - 1) % 32]
    flag[i] = enc_flag[i]


for i in range(7, -1, -1):
    for j in range(i - 1, -1, -1):
        v2 = flag[4 * i + 3]
        for k in range(2, -1, -1):
            flag[4 * i + k + 1] = flag[4 * i + k]
        flag[4 * i] = v2


for i in range(32):
    print(chr(flag[i]), end="")

得到flag:SYC{Wow!!_Y0u_4r3_9o0d_At_r3$!!}

好像是python?

先根据给的汇编,写一个python代码

def test2(s2):
    key = 'SYC'
    length = 18
    cipher = []
    for i in range(length):
        cipher.append(ord(s2[i]) ^ i + ~ord(key[i % 3]) + 1)
    return cipher

def test(s, R):
    result = []
    for i in s:
        if ord('A') <= i <= ord('Z'):
            result.append(chr((ord(i) - ord('A') + R) % 26 + ord('A')))
        elif ord('a') <= i <= ord('z'):
            result.append(chr((ord(i) - ord('a') + R) % 26 + ord('a')))
        elif ord('0') <= i <= ord('9'):
            result.append(chr((ord(i) - ord('0') + R) % 10 + ord('0')))
        else:
            result.append(i)
        return result

input0 = input("plz input")
a = 13
b = 14

c = (a + b) ^ a
d = b * 100
e = a ^ b
m = (4 * c) - d + e - 1
r = m % 26

cipher1 = test(input0, r)
cipher2 = test2(cipher1)

num = [-1, -36, 26, -5, 14, 41, 6, -9, 60, 29, -28, 17, 21, 7, 35, 38, 26, 48]

for i in range(18):
    if cipher2[i] != num[i]:
        print("wrong!")

让我康康你的调试

观察main函数,能看出逻辑大概是

key = syclover
s2[0] = 0xA67A02C9047D5B94
s2[1] = 0x7EF9680DBC980739
s2[2] = 0x7104F81698BFBD08
s2[3] = 0x61DB8498B686155F

flag = input()
for i in flag:
    xor_flag += i ^ 0x14
enc_flag = RC4(xor_flag, 33, key, 8)
if enc_flag == s2:
    print("yes")

查看RC4函数逻辑

能看到先调用sub_55B7E1B161C9(v9, a3, a4)对key进行处理

然后进行RC4加密运算

题目提示使用动调,我们可以利用动调获得数据,更加方便我们进行逆向脚本的编写

我们在key加密后的地方设置断点,在输入flag之后程序会运行到断点处,这时我们查看key的数据

使用选项Debugger中的Locals查看数据

点击v9展开

选中v9的全部数据之后,使用shift+e获取

得到key

得到key之后,我们把下面的加密逻辑复现出来

for i in range(32):
    v6 = (v6 + 1) % 256
    v7 = (v7 + key[v6]) % 256
    v5 = key[v6]
    key[v6] = key[v7]
    key[v7] = v5
    flag[i] ^= key[(key[v6] + key[v7]) % 256]

在加密完成之后,还要和s2的值进行比对,我们在memcmp处下断点,提取s2的值

双击并选中s2,同样的办法提取,这里有大小端序的问题存在

由于输入的flag在加密前与0x14异或过,要注意这一步

写个脚本

key = [0x31, 0x50, 0x52, 0xC1, 0xCD, 0xA7, 0x07, 0x39, 0x3D, 0x04,
       0xFD, 0xC4, 0x2A, 0x72, 0xDF, 0x60, 0xE3, 0xBD, 0xE2, 0x61,
       0xE4, 0x63, 0xEA, 0xFF, 0xFE, 0x09, 0xF9, 0xC3, 0xCE, 0x9E,
       0x25, 0x6A, 0x4C, 0xDC, 0x13, 0xF0, 0x83, 0x3B, 0x24, 0xDB,
       0xDD, 0x7F, 0xEF, 0x8C, 0x3E, 0xE1, 0x26, 0x6F, 0x92, 0x06,
       0xF7, 0x96, 0xD0, 0xB4, 0xE7, 0xF8, 0x5F, 0x78, 0xF2, 0xAA,
       0x44, 0x32, 0x36, 0x5A, 0xEC, 0xA6, 0x7B, 0x08, 0xC0, 0x2E,
       0x9B, 0x84, 0x55, 0x9C, 0xAE, 0x65, 0x0A, 0x10, 0x53, 0x88,
       0x49, 0x46, 0xAB, 0x0C, 0x1F, 0x59, 0x7E, 0xE5, 0xB3, 0xF6,
       0x48, 0x1A, 0xD1, 0xA4, 0x67, 0x6B, 0xBA, 0x87, 0x73, 0x4B,
       0xA2, 0xCF, 0x1D, 0x18, 0xD4, 0xBB, 0x2C, 0x70, 0x93, 0xAC,
       0x0F, 0x7A, 0x51, 0xB5, 0x21, 0x85, 0x45, 0x02, 0x1C, 0x9F,
       0x81, 0x5C, 0x4A, 0x95, 0x1B, 0x16, 0xD2, 0xC7, 0xE0, 0xDA,
       0x58, 0xA9, 0x1E, 0xD7, 0xC2, 0x69, 0x71, 0xD6, 0x2D, 0x75,
       0xBC, 0x66, 0xFA, 0x30, 0xAD, 0x99, 0x8B, 0x77, 0x41, 0x97,
       0x22, 0xB8, 0xB2, 0xD3, 0x47, 0xC6, 0x79, 0x14, 0x0B, 0xF4,
       0x3F, 0x11, 0x2B, 0xDE, 0xEE, 0xF3, 0xF5, 0xAF, 0xA5, 0x86,
       0x91, 0xBE, 0x8E, 0x8F, 0xE8, 0xE6, 0xB1, 0x4E, 0x37, 0xD5,
       0xFC, 0x4D, 0x5E, 0x42, 0xCA, 0x35, 0xC8, 0x6E, 0xA3, 0x89,
       0x15, 0x6D, 0x03, 0x8A, 0x8D, 0xD8, 0x76, 0xCB, 0xC5, 0xF1,
       0x6C, 0xB9, 0x17, 0x64, 0x68, 0xE9, 0x56, 0x29, 0x90, 0xED,
       0x74, 0x0D, 0xEB, 0xB0, 0xA1, 0x94, 0x80, 0xC9, 0x7C, 0xB7,
       0x28, 0x05, 0x5B, 0x23, 0x9D, 0xA0, 0x27, 0x98, 0x43, 0x7D,
       0xBF, 0x4F, 0x12, 0x34, 0xA8, 0xD9, 0x57, 0x33, 0x9A, 0x01,
       0x54, 0x2F, 0x3C, 0x62, 0x38, 0xFB, 0x82, 0x0E, 0x3A, 0x19,
       0x5D, 0xB6, 0x40, 0x20, 0xCC]


v6 = 0
v7 = 0
s2 = [0x94, 0x5B, 0x7D, 0x04, 0xC9, 0x02, 0x7A, 0xA6, 0x39, 0x07,
      0x98, 0xBC, 0x0D, 0x68, 0xF9, 0x7E, 0x08, 0xBD, 0xBF, 0x98,
      0x16, 0xF8, 0x04, 0x71, 0x5F, 0x15, 0x86, 0xB6, 0x98, 0x84,
      0xDB, 0x61]
flag = [0] * 33

for i in range(32):
    v6 = (v6 + 1) % 256
    v7 = (v7 + key[v6]) % 256
    v5 = key[v6]
    key[v6] = key[v7]
    key[v7] = v5
    flag[i] = key[(key[v6] + key[v7]) % 256] ^ s2[i] ^ 0x14

    print(chr(flag[i]),end="")

奇怪的RC4

先从exe反编译为pyc,再反编译为py文件

from Rc4 import *


def xor1(plaintext, xor_list):
    try:
        xor_list = (lambda .0: [ord(i) for i in .0])(xor_list)
    finally:
        pass

    try:
        plaintext = (lambda .0: [ord(i) for i in .0])(plaintext)
    finally:
        pass
    for i in range(len(plaintext)):
        plaintext[i] ^= xor_list[i]
    return plaintext


def xor2(plaintext):
    try:
        plaintext = (lambda .0: [ord(i) for i in .0])(plaintext)
    finally:
        pass
    for i in range(len(plaintext) - 1):
        plaintext[i + 1] = plaintext[i] ^ plaintext[i + 1]
    return plaintext


def enc(plaintext, key, xor_list):
    plaintext = rc4(plaintext, key)
    plaintext = xor1(plaintext, xor_list)
    plaintext = xor2(plaintext)
    return plaintext


plaintext = input('please give your input:')
key = 'SYCFOREVER'
xor_list = list(range(len(plaintext)))
cipher = [
    158, 31, 205, 434, 354, 15, 383, 298, 304, 351,
    465, 312, 261, 442, 397, 474, 310, 397, 31, 21,
    78, 67, 47, 133, 168, 48, 153, 99, 103, 204,
    137, 29, 22, 13, 228, 3, 136, 141, 248, 124,
    26, 26, 65, 200, 7
]
plaintext = enc(plaintext, key, xor_list)
for i in range(len(cipher)):
    if cipher[i] != plaintext[i]:
        print('Wrong')
        exit(1)
        continue
        print('You know the flag!!')
        return None

看逻辑

cipher = [
    158, 31, 205, 434, 354, 15, 383, 298, 304, 351,
    465, 312, 261, 442, 397, 474, 310, 397, 31, 21,
    78, 67, 47, 133, 168, 48, 153, 99, 103, 204,
    137, 29, 22, 13, 228, 3, 136, 141, 248, 124,
    26, 26, 65, 200, 7
]
xor_list = list(range(len(cipher)))

xor_plaintext = [0] * 45
xor_plaintext[0] = 158
for i in range(len(xor_plaintext) - 1):
    xor_plaintext[i + 1] = cipher[i] ^ cipher[i + 1]

rc4_plaintext = [0] * 45
for i in range(len(rc4_plaintext)):
    rc4_plaintext[i] = xor_list[i] ^ xor_plaintext[i]

def rc4_key_schedule(key1):
    key_len = len(key1)
    S = list(range(256))

    j = 0
    for i in range(256):
        j = (j + S[i] + key1[i % key_len]) % 256
        S[i], S[j] = S[j], S[i]  # 交换S[i]与S[j]
    return S

key = [ord(c) for c in "SYCFOREVER"]
key = rc4_key_schedule(key)

def rc4(S, plaintext):
    keystream = []
    i = j = 0
    for char in plaintext:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]  # 交换
        keystream.append(S[(S[i] + S[j]) % 256])
    return [c ^ k for c, k in zip(plaintext, keystream)]

rc4_decrypted = rc4(key, rc4_plaintext)

for i in range(45):
    print(chr(rc4_decrypted[i] % 128), end="")
import hashlib
 def decrypt_test2(cipher):
    key = 'SYC'
    length = 18
    result = []
    for i in range(length):
    original = (cipher[i] - (~ord(key[i % 3]) + 1)) ^ i     
    result.append(chr(original))   
    return ''.join(result) 
    def decrypt_test(s, R):   
    result = []   
    for i in s:
    if 'A' <= i <= 'Z':
    result.append(         chr(((ord(i) - ord('A') + R) % 26) + ord('A'))       )
    elif 'a' <= i <= 'z':
    result.append(         chr(((ord(i) - ord('a') + R) % 26) + ord('a'))       )
    elif '0' <= i <= '9':       
    result.append(         chr(((ord(i) - ord('0') + R) % 10) + ord('0'))       )
    else:       
    result.append(i)   
    return ''.join(result) 
    num = [-1, -36, 26, -5, 14, 41, 6, -9, 60, 29, -28, 17, 21, 7, 35, 38, 26, 48] 
    str1 = decrypt_test2(num) 
    input_ = decrypt_test(str1, -14) 
    print(input_) print("SYC{" + hashlib.md5(input_.encode("UTF-8")).hexdigest()+"}")

得到D0_You_Iik3_python

玩就行了

得到一个黄金矿工程序,用CE改一下分数就通关了,或者010把"\玩就行了\玩就行了_Data\level0"最后末尾的666改成一个很小的数字

提示有些东西被遗漏了,根据提示发现文件夹中生成了一个文件data.txt,根据文件大小怀疑这是一个16进制的文件


)

导入到010中,保存得到了exe文件

IDA打开

根据逻辑写出代码

flag = ["0"] * 20
second = [0] * 20
for i in range(20):
    if ord(flag[i]) <= 96 or ord(flag[i]) > 122:
        if  ord(flag[i]) <= 64 or ord(flag[i]) > 90:
            if 47 < ord(flag[i]) <= 57:
                second[i] = (20 + ord(flag[i]) - 48) % 10 + 48
        else:
            second[i] = (ord(flag[i]) - 65 + 20) % 26 + 65
    else:
        second[i] = (ord(flag[i]) - 97 + 20) % 26 + 97

key = "GEEK"
v3 = len(key)
third = [0] * 20
for i in range(len(second)):
    third[i] = ord(key[i % v3]) ^ second[i]

final = "0A161230300C2D0A2B303D2428233005242C2D26182206233E097F133A"

# 把最后得到的字符串转成十六进制数组
# answer = ""
# for i in range(58):
#     if i % 2 == 0:
#         answer += ", 0x"
#         answer += final[i]
#     else:
#         answer += final[i]
# print(answer)

写个逆向脚本

final = "0A161230300C2D0A2B303D2428233005242C2D26182206233E097F133A"

flag = ["0"] * 29
second = [0] * 29

third = [0x0A, 0x16, 0x12, 0x30, 0x30, 0x0C, 0x2D, 0x0A, 0x2B, 0x30, 0x3D, 0x24, 0x28, 0x23, 0x30, 0x05, 0x24, 0x2C, 0x2D, 0x26, 0x18, 0x22, 0x06, 0x23, 0x3E, 0x09, 0x7F, 0x13, 0x3A]
key = "GEEK"
v3 = len(key)
for i in range(len(second)):
    second[i] = ord(key[i % v3]) ^ third[i]

decrypted_char = [0] * 29
for i in range(29):
    v3 = second[i]
    if 97 <= v3 <= 122:  # 小写字母
        decrypted_char[i] = (v3 - 97 - 20) % 26 + 97
    elif 65 <= v3 <= 90:  # 大写字母
        decrypted_char[i] = (v3 - 65 - 20) % 26 + 65
    elif 48 <= v3 <= 57:  # 数字
        decrypted_char[i] = (v3 - 48 - 20) % 10 + 48
    else:  # 其他字符保持不变
        decrypted_char[i] = v3
for i in range(29):
    print(chr(decrypted_char[i]), end="")

得到flag为SYC{cOnGraduulaTions_mIneR:D}

0 条评论
某人
表情
可输入 255

没有评论