某乱七八糟选拔赛 main2101075ff6b9adc84f9.zip

拿到文件发现有upx壳,脱壳。
静态分析发现用随机数与flag.png每一字节异或得到flag.png.enc,而随机数种子用的是生成文件的时间戳
查看flag.png.enc生成时间2020-12-18 21:14:01(北京时间)得到时间戳1608297241,然后异或得到文件flag.png

解题脚本

用linux g++编译后运行

  1. #include <stdlib.h>
  2. #include <iostream>
  3. #include <fstream>
  4. using namespace std;
  5. void decrypt(char *a1, int a2){
  6. long long timestamp = 1608297241; //GMT+8 2020-12-18 21:14:01
  7. srand(timestamp);
  8. for (int i = 0; ; ++i)
  9. {
  10. if ( (signed int)i >= a2)
  11. break;
  12. unsigned char v4 = a1[i];
  13. a1[i] = (unsigned long long)rand()^v4;
  14. }
  15. }
  16. int main(){
  17. ifstream infile;
  18. infile.open("flag.png.enc", ios::binary);
  19. infile.seekg(0, ios::end);
  20. int a2 = infile.tellg();// 0x5D9;
  21. infile.seekg(0, ios::beg);
  22. char *a1 = new char[a2];
  23. infile.read(a1, a2);
  24. decrypt(a1,a2);
  25. ofstream outfile;
  26. outfile.open("flag.png");
  27. outfile.write(a1, a2);
  28. }

Flag

flag.png文件
各种CTF逆向题目大杂烩 - 图1
扫一扫得到flag
flag{sRandANd_LCg_is_No_Safty}

NCTF-2020 re4

题目文件 qiandao.rar
脱壳后文件 Dumped.rar
Exeinfo PE打开exe发现有壳,并且打开时提示decode_shell.pdb,得知exe有壳。
题目提示“运行时关闭ida od”,所以先将ida和od关闭后打开exe,再用PE Tools选择exe进程Dump,从而获得脱壳后的exe。
用IDA打开,先复现一次加密函数(代码中的encode),发现(tmp[v1] | v1) & ~(tmp[v1] & v1)为异或运算,反运算后得到flag

解题脚本

byte_B731E8 = [
  0xA3, 0x4D, 0x44, 0x7F, 0x53, 0xD6, 0xE9, 0x88, 0x4D, 0x95, 
  0x1A, 0x72, 0x01, 0x3C, 0x71, 0x00, 0xE8, 0xCE, 0xA1, 0xF8, 
  0x51, 0x48, 0xF5, 0xE9, 0x6A, 0x02, 0x27, 0xD8, 0x96, 0x7F, 
  0x72, 0xD6, 0xF1, 0xE9, 0x9F, 0xC6, 0x5D, 0x60, 0xE4, 0x10, 
  0x64, 0x99, 0xA0, 0x00
]

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


def encode(text):
    tmp = [data+1 for data in text];v5 = 0;v6 = 0;v7 = 0;
    while True:
        v5 = (v5 + 1) % 256;
        v8 = Dst[v5];
        v6 = (v8 + v6) % 256;
        Dst[v5] = Dst[v6];
        Dst[v6] = v8;
        tmp[v7] ^= Dst[(v8 + Dst[v5])&0xFF];
        v7 += 1;
        if v7 >= 0x2B: break
    v1 = 0;
    while True:
        v2 = (tmp[v1] | v1) & ~(tmp[v1] & v1);
        tmp[v1] = v2;
        v1 += 1
        if v1 >= 43: break
    return tmp


def decode(text):
    encode_dict = []; v5 = 0;v6 = 0;v7 = 0;
    while True:
        v5 = (v5 + 1) % 256;
        v8 = Dst[v5];
        v6 = (v8 + v6) % 256;
        Dst[v5] = Dst[v6];
        Dst[v6] = v8;
        encode_dict.append(Dst[(v8 + Dst[v5])&0xFF]);
        v7 += 1;
        if v7 >= 0x2B: break

    tmp = [text[i]^i for i in range(len(text))]
    v7 = 0x2B-1;
    while True:
        tmp[v7] ^= encode_dict[v7];
        v7 -= 1;
        if v7 == 0: break
    return tmp 

print("".join([chr(data) for data in decode(byte_B731E8)]))

得到flag:flag{Process_Hollowing_with_multithreading}

加壳源码

一份专供初学者食用的AES加密壳

NCTF-2019 WxyVM1WxyVM1.rar

虚拟机题目,不过当时做题的时候不觉得是虚拟机…很久之前做的题目了,分析过程早忘了,附上个脚本给有需要的人学习一下
WxyVM.py

NEFUCTF-2020 Test_your_mathTest_your_math.rar

静态分析发现flag是一个方程组的解,用sympy解出

解题脚本

from sympy import *

for i in range(11):
    if i+1 == 4: continue
    exec('v{} = Symbol(\'v{}\')'.format(str(i+1),str(i+1)))

answer = solve([
    98 * v3 + 73 * v10 + 86 * (v8 + v5) + 79 * (v2 - v1) - 22 * (v11 + 2 * v9) - 23 * v6 - 81 * v7 -20413,
    37 * v9 + 86 * v1 + 31 * v7 + 9 * v10 + 7 * (4 * v3 - v11) + 8 * v6 - 89 * v8 - 11 * v5 + 10 * v2 -2513,
    48 * v2 + -70 * v10 - 46 * (v5 + v9) - 88 * v7 - 28 * v3 - 95 * v8 - 81 * v1 - (v11 * 2**6) - 52 * v6 +43184,
    56 * v6 + 15 * v11 + 79 * v7 - 91 * v10 + 62 * v3 - 73 * v8 - 34 * v5 + 18 * v2 - 12 * v1 - 32 * v9 +5076,
    21 * v11 + 80 * v2 + 51 * v3 + 97 * v10 + -83 * v6 - 14 * (v5 + 7 * v7) - 68 * v8 - 82 * v1 - 32 * v9 +9282,
    33 * v2 + 51 * v8 + 14 * (v3 - 7 * v6) - 36 * v10 - 92 * v7 - 60 * v5 - 55 * v1 - 90 * v11 - 94 * v9 +30200,
    99 * v3 + 67 * v10 + 97 * v6 - 59 * v7 + 24 * v5 - 22 * v2 - 53 * v1 - 37 * v11 - 15 * v9 - v8 -8225,
    77 * v1 + 5 * v8 + 96 * v3 + -72 * v7 - (v10 * 2**6) - 47 * v5 - 97 * v2 + 56 * v6 + 49 * v11 + 78 * v9 +4117,
    52 * v6 + 35 * v2 + 43 * v3 + 20 * (v11 - 2 * v8) - 75 * v10 - 8 * v7 - 39 * v5 - 38 * v1 + 53 * v9 +2782,
    42 * v9 + 44 * v5 + 39 * v10 + 94 * v6 + 12 * (v3 + 2 * v8) + 10 * (v1 - 3 * v11) - 49 * v7 - 32 * v2 -12417,
    ],
[v1,v2,v3,v5,v6,v7,v8,v9,v10,v11])
# {v1: 55, v2: 110, v3: 57, v5: 77, v6: 85, v7: 95, v8: 121, v9: 70, v10: 104, v11: 64}

flag = []; index = [9,6,3,2,8,7,5,11,1,10]
for i in range(10):
    flag.append(eval("chr(answer[v{}])".format(str(index[i]))))
print("flag{"+"".join(flag)+"}")

得到flag:flag{FU9ny_M@7h}

VNCTF-2021 notsudoku notsudoku.zip

这题看了下官方wp前面步骤都不难(wp在这里可以找到),我接手的时候拿到了个用日文混淆的pynotsudoku_obfu.py
我用编辑器替换一下后,如下

import time, sys, hashlib

class Class:

    def __init__(self):
        self.a_dict = {}
        self.arr1 = []
        self.text = ''
        self.arr2 = []
        self.num = 65

    def wrapper(self, key):

        def fun(f):
            self.a_dict[key] = f
            return f

        return fun

    def get_data(self, key):
        return self.a_dict.get(key)

    def checkflag(self):
        i = 0
        while True:
            data1 = self.arr1[i][0]
            data2 = self.arr1[i][1]
            data3 = self.arr1[i][2]
            fun = self.get_data(data1)
            fun(data2, data3)
            i += 1


obj = Class()

@obj.wrapper('a')
def f(a, b):
    if a == 1:
        obj.arr2 += b


@obj.wrapper('b')
def f(a, b):
    if a == 1:
        print(obj.text)
    else:
        if a == 2:
            print(obj.arr2)
        else:
            if a == 3:
                print((obj.flag), end='')
            else:
                print(a, end='')


@obj.wrapper('c')
def f(a, b):
    sys.exit()


@obj.wrapper('d')
def f(a, b):
    obj.text = input()


@obj.wrapper('e')
def f(a, b):
    time.sleep(a)


@obj.wrapper('f')
def f(a, b):
    if len(obj.text) % 2 != 0:
        sys.exit()
    for i in obj.text:
        if ord(i) > 52 or ord(i) < 48:
            sys.exit()

    x = str(hashlib.new('md5', bytes((obj.text), encoding='utf8')).hexdigest())
    if x[:6] != 'e3a912':
        pass#sys.exit()
    obj.flag = x


@obj.wrapper('g')
def f(a, b):
    j = 0
    for i in range(0, len(obj.text), 2):
        j += 1
        a = int(obj.text[i])
        b = int(obj.text[(i + 1)])
        obj.arr2[a][b] = j


@obj.wrapper('h')
def f(a, b):
    if obj.arr2[0][1] != 24 or obj.arr2[4][3] != 2:
        sys.exit()
    if obj.arr2[0][2] != 1 or obj.arr2[2][3] != 20:
        sys.exit()
    if obj.arr2[1][0] != 23 or obj.arr2[3][4] != 3:
        sys.exit()


@obj.wrapper('k')
def f(a, b):
    num = 0
    if b == -1:
        for i in range(5):
            num += obj.arr2[a][i]

        if num != obj.num:
            sys.exit()
    else:
        for i in range(5):
            num += obj.arr2[i][b]

        if num != obj.num:
            sys.exit()


obj.arr1 = [
 [
  'b', 'welcome baby~ ', 0],
 [
  'b', 'input your flag~:', 0],
 [
  'd', 0, 0],
 [
  'b', 'your input is:', 0],
 [
  'b', 1, 0],
 [
  'b', "let's check......", 0],
 [
  'e', 0.5, 0],
 [
  'a', 1, [[0 for i in range(5)]]],
 [
  'a', 1, [[0 for i in range(5)]]],
 [
  'a', 1, [[0 for i in range(5)]]],
 [
  'a', 1, [[0 for i in range(5)]]],
 [
  'a', 1, [[0 for i in range(5)]]],
 [
  'f', 0, 0],
 [
  'g', 0, 0],
 [
  'h', 0, 0],
 [
  'k', 0, -1],
 [
  'k', 1, -1],
 [
  'k', 2, -1],
 [
  'k', 3, -1],
 [
  'k', 4, -1],
 [
  'k', 0, 0],
 [
  'k', 0, 1],
 [
  'k', 0, 2],
 [
  'k', 0, 3],
 [
  'k', 0, 4],
 [
  'b', 'Goodjob!', 0],
 [
  'b', 'The flag is vnctf{', 0],
 [
  'b', 3, 0],
 [
  'b', '}', 0],
 [
  'c', 0, 0]]
obj.checkflag()

仔细看看就知道是用wrapper写了个虚拟机,将文字作为指令然后调用函数。程序流程是弄了个5x5的数组然后每行或者每列加起来为65,且数组里面1到25每个数字不能重复,最后弄了个md5验证。

解题脚本

直接用z3约束求解然后再每一个md5一下就找到flag,z3的脚本我参考了解数独的脚本
Python Z3约束求解器解决数独问题

from z3 import *
import hashlib

# 约束变元数组,变元名为a_行_列
arr=[[Int('a_%d_%d'%(i,j)) for i in range(5)] for j in range(5)] 

# 初始条件,数字表示提示数,0表示未填入
problem=((00,24, 1,00,00),
         (23,00,00,00,00),
         (00,00,00,20,00),
         (00,00,00,00, 3),
         (00,00,00, 2,00))

# 数独规则约束
Sudoku = []
Sudoku=[And(arr[i][j]>0,arr[i][j]<=25) for i in range(5) for j in range(5)]      # 数字为1~25的整数
for i in range(5):
    Sudoku+=[arr[i][0]+arr[i][1]+arr[i][2]+arr[i][3]+arr[i][4]==65]
    Sudoku+=[arr[0][i]+arr[1][i]+arr[2][i]+arr[3][i]+arr[4][i]==65]
for i in range(25):
    for j in range(5):
        for k in range(5):
            if int(i/5) == j and i%5 == k: continue
            Sudoku+=[arr[int(i/5)][i%5]!=arr[j][k]]        # 所有元素不能相等

def SolveSudoku(board):
    """使用Z3约束求解器求解数独,若有解,返回表示可行解的5*5列表;若无解返回None"""
    global Sudoku,arr
    for i in range(5):
        for j in range(5):
            if board[i][j]!=0:
                Sudoku+=[arr[i][j]==board[i][j]]                                # 将初始数字作为约束条件添加
    s=Solver()
    n = 0
    s.add(Sudoku)

    while(s.check()==sat):                                                              # 检查是否有解
        #fp=open("log.txt","a",encoding="utf-8")
        m=s.model()                                                             # 获取解的模型
        res=[[m[arr[i][j]] for j in range(5)] for i in range(5)]
        #for k in res:
        #    print(k)
        text = ["" for i in range(25)]
        for i in range(5):
            for j in range(5):
                text[m[arr[i][j]].as_long()-1] = str(i)+str(j)
        t = "".join(text)
        n += 1
        output = str(n).zfill(4)+": "+t
        print(output)
        #fp.write(output+"\n")
        #fp.close()
        x = str(hashlib.new('md5', bytes(t, encoding='utf8')).hexdigest())
        if x[:6] == 'e3a912':
            print("Found!",n)
            print("The flag is vnctf{%s}"%x)
            sys.exit()
        s.add(Or(arr[0][0]!=res[0][0],arr[0][1]!=res[0][1],arr[0][2]!=res[0][2],arr[0][3]!=res[0][3],arr[0][4]!=res[0][4],
                 arr[1][0]!=res[1][0],arr[1][1]!=res[1][1],arr[1][2]!=res[1][2],arr[1][3]!=res[1][3],arr[1][4]!=res[1][4],
                 arr[2][0]!=res[2][0],arr[2][1]!=res[2][1],arr[2][2]!=res[2][2],arr[2][3]!=res[2][3],arr[2][4]!=res[2][4],
                 arr[3][0]!=res[3][0],arr[3][1]!=res[3][1],arr[3][2]!=res[3][2],arr[3][3]!=res[3][3],arr[3][4]!=res[3][4],
                 arr[4][0]!=res[4][0],arr[4][1]!=res[4][1],arr[4][2]!=res[4][2],arr[4][3]!=res[4][3],arr[4][4]!=res[4][4]))
    else:
        return None                                                             # 无解返回None

SolveSudoku(problem)
'''
......
4640: 02433420112112034430403122130414004132233324100142
Found! 4640
The flag is vnctf{e3a912c1e911ad82544af0c3d753f44f}
'''

第一次做这种限制md5的题目,最后爆了一段时间(大概半小时)才爆出来