第11届极客大挑战-Re WriteUp
No RE no gain
文件: HelloRE.exe
IDA打开,有手就行。
我真不会写驱动!
文件: SycDriver.sys
有手就行。
WhatsApk
文件: WhatsApk.apk
apktool解压,vscode搜索SYC{
。
HelloAndroid
文件: HelloAndroid
同上。
re00
文件: re00
简单的异或。
maze
文件: maze.exe
通过字符串找到主函数为sub_401A10
。
迷宫宽度为0x1F
,o
为墙,E
为终点。起点是0xD9
,换算一下坐标是(7,0)
,这道题有一个特殊之处,它的坐标是用一个量表示的,所以可以通过左右从边缘移动到上一行或下一行。
把地图提取出来,可以用正则替换来实现0x1F
个字符换行。.{31}
替换成$0\n
。
地图不大,没有分叉,看看就行。
Hello .NET
文件: WpfAppCS.exe
dnSpy
打开。简单的加密函数。
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
。
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
提醒:
- 一定要关杀毒!!!
- 文件不要有中文名
- 要以管理员身份运行
上来就发现一个很可疑的函数sub_401200
,8000行的mov指令,之后就是写文件的操作。动调一下发现文件在C:\SYC_DLL.dll
。
以管理员身份运行得到那个文件。直接IDA打开发现只能以二进制文件打开。需要修复一下文件头。
IDA打开,找到关键函数,只做了一个简单的字符串拼接,因为是在栈里直接拼接、传参,所以字符是倒序,用python
简单拼接一下就行。
'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码加一。
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
程序会根据是否在调试生成不同的值,干扰正常加密。可以在图中位置打上断点,先运行然后attach上去,就可以绕过了。就可以很轻松的将正确的v24
的值导出。
加密函数比较容易,基本复制一下就行了。
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修复符号表。之后就容易了。
a=list(rb"SXAxpmcXb5`z[b6kaoe\v`pz")
for i in range(len(a)):
a[i]^=i%8
print(str(bytes(a),'utf-8'))