第11届极客大挑战-Re WriteUp

2020-10-24
#ctf #re #wp

No RE no gain

文件: HelloRE.exe

IDA打开,有手就行。hellore

我真不会写驱动!

文件: SycDriver.sys

有手就行。

SycDriver

WhatsApk

文件: WhatsApk.apk

apktool解压,vscode搜索SYC{whatsapk

HelloAndroid

文件: HelloAndroid

同上。

HelloAndroid

re00

文件: re00

简单的异或。

re00_0

re00_1

maze

文件: maze.exe

通过字符串找到主函数为sub_401A10

maze_0

迷宫宽度为0x1Fo为墙,E为终点。起点是0xD9,换算一下坐标是(7,0),这道题有一个特殊之处,它的坐标是用一个量表示的,所以可以通过左右从边缘移动到上一行或下一行。

把地图提取出来,可以用正则替换来实现0x1F个字符换行。.{31}替换成$0\n

maze_1

地图不大,没有分叉,看看就行。

Hello .NET

文件: WpfAppCS.exe

dnSpy打开。简单的加密函数。

WpfAppCS

import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<Integer>();
        int[] array = new int[]{18,14,40,-14,-2,30,10,42,35,48,43,49,52,72,57,68,86,145,115,128,115,86};
        int num = 99;
        while (list.size() < array.length) {
            boolean flag = true;
            for (int i = 3; i < num; i += 2){
                boolean flag2 = num % i == 0;
                if (flag2){
                    flag = false;
                    break;
                }
            }
            if (flag){
                list.add(num);
            }
            num += 2;
        }
        for (int i = 0; i < array.length; i++) {
            System.out.print((char)(list.get(i)-array[i]));
        }
    }
}

刘壮的BaseXX

文件: baseXX.exe

经过简单分析,两次加密,第一次是异或下标和高低位交换,第二次是改版Base64

BaseXX

s='maj7TmztjquUN8Xm-hKplvaYfEAxrUnIc51qxlKOwCKN4XsdzBmjOd_-'
baseAlphabet='zyxwvutsrqponmlkjihgfedcbaABCDEFGHIJKLMNOPQRSTUVWXYZ9876543210-_'
out=[]
i=0
while i<=len(s)-3:
    a1=baseAlphabet.find(s[i])
    a2=baseAlphabet.find(s[i+1])
    a3=baseAlphabet.find(s[i+2])
    a4=baseAlphabet.find(s[i+3])
    out.append((a1<<2)+(a2>>4))
    out.append(((a2&0xf)<<4)+(a3>>2))
    out.append(((a3&3)<<6)+a4)
    i+=4
for i in range(len(out)):
    x=out[i]
    x^=i
    x=((x&0xf)<<4)+(x>>4)
    print(chr(x),end='')

un_snake

文件: un_snake.cpython-38.pyc

python逆向,直接上uncompyle6

uncompyle6 un_snake.cpython-38.pyc > un_snake.py

得到代码

from base64 import *

def pre(data):
    th1s = 'TBESCFSRSAEUITANAIIN'.encode()
    if (data_len := len(data)) > (th1s_len := len(th1s)):
        th1s = th1s * (data_len // th1s_len) + th1s[:data_len - th1s_len]
    return bytes(map(lambda x, y: x ^ y, data, th1s))

def enc(plain):
    plain = list(plain)
    plain = plain[::-1]
    for i in range(len(plain)):
        c = plain[i]
        plain[i] = (c << 3 | c >> 5) & 255
    for i in range(len(plain) - 1):
        plain[i] ^= plain[(i + 1)]
    return bytes(plain)

def check(a):
    return b64encode(a) == b'mEiQCAjJoXJy2NiZQGGQyRm6IgHYQZAICKgowHHo4Dg='

if __name__ == '__main__':
    print()
    while True:
        stuff = input('Now input you flag:')
        stuff_ready = pre(stuff.encode())
        result = check(enc(stuff_ready))
        if result:
            print('You get it! Python is so charming right?')
            break
        else:
            print('Failed, try again!')

    print('[🐍] Commit you flag, see you next time!')

可以看出,两次加密,都是可逆的,exp:

from base64 import *

a=b64decode(b'mEiQCAjJoXJy2NiZQGGQyRm6IgHYQZAICKgowHHo4Dg=')
a=list(a)
for i in range(len(a)-2,-1,-1):
    a[i]^=a[i+1]
for i in range(len(a)):
    b=a[i]
    b=((b>>3)|(b<<5)) & 0xFF
    a[i]=b
a=a[::-1]
th1s = 'TBESCFSRSAEUITANAIIN'.encode()
if (data_len := len(a)) > (th1s_len := len(th1s)):
    th1s = th1s * (data_len // th1s_len) + th1s[:data_len - th1s_len]
print(bytes(map(lambda x, y: x ^ y, a, th1s)))

Easy_virus

文件: Windows的DLL和PE好难.exe

提醒:

  1. 一定要关杀毒!!!
  2. 文件不要有中文名
  3. 要以管理员身份运行

上来就发现一个很可疑的函数sub_401200,8000行的mov指令,之后就是写文件的操作。动调一下发现文件在C:\SYC_DLL.dll

Easy_virus_0

以管理员身份运行得到那个文件。直接IDA打开发现只能以二进制文件打开。需要修复一下文件头。

Easy_virus_1

IDA打开,找到关键函数,只做了一个简单的字符串拼接,因为是在栈里直接拼接、传参,所以字符是倒序,用python简单拼接一下就行。

Easy_virus_2

'odoG_era_uoY{CYS'[::-1]+'niWf'[::-1]+'swod'[::-1]+'}'

飞翔的刘壮

文件: flappybird.apk

这道本来是一道Misc题,但逆向也十分容易。

apktool解压,看出是一个unity小游戏,一般来说unity的主要逻辑文件在assets\bin\Data\Managed\Assembly-CSharp.dll。用dnSpy打开,找到flag附近,加密算法就是ascii码加一。

flappybird

a='RXBzek3ooxa0qc^0r^r/^hmsdq2shm8 |'
print("".join([chr(ord(x)+1) for x in a]))

plain_snake

文件: plain_snake.txt

python字节码比汇编容易多了。

可以看到,主要的加密算法在fn2函数。稍微分析一下可以得到一下代码

def fn1(s):
  s=list(s.decode())
  s=map(lambda x: x^83,s)
  for i in range(0,len(s),2):
    s[i+1],s[i]=s[i],s[i+1]
    s[i]^=89
    s[i+1]^=67
  return s.encode()

再送到check函数检查base64是否正确。

exp:

import base64
b=list(base64.b64decode(b'c0BiZGQgSU9kJEhPVXU5RH5ofk9lIA=='))
for i in range(0,len(b),2):
    b[i],b[i+1]=b[i+1]^67^83,b[i]^89^83
print("SYC{"+str(bytes(b),'utf-8')+"}")

baby_re

文件: baby_re

baby_re_0

程序会根据是否在调试生成不同的值,干扰正常加密。可以在图中位置打上断点,先运行然后attach上去,就可以绕过了。就可以很轻松的将正确的v24的值导出。

加密函数比较容易,基本复制一下就行了。

baby_re_1

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

golang1

文件: golang1

先用upx -d golang1脱壳,IDA 7.2打开,用golang_loader_assist修复符号表。之后就容易了。

golang1

a=list(rb"SXAxpmcXb5`z[b6kaoe\v`pz")
for i in range(len(a)):
    a[i]^=i%8
print(str(bytes(a),'utf-8'))

参考文章

  1. PE文件格式 - Mi1k7ea