跳转至

QCTF2018_RE

babymips

Download binary file

#include "stdafx.h"
#include <iostream>
using namespace std;

const unsigned char dst[] = { 0x52, 0xFD, 0x16, 0xA4, 0x89, 0xBD, 0x92, 0x80,
0x13, 0x41, 0x54, 0xA0, 0x8D, 0x45, 0x18, 0x81, 0xDE, 0xFC, 0x95, 0xF0, 0x16, 0x79, 0x1A, 0x15,
0x5B, 0x75, 0x1F };

int verify(unsigned char* input,int k) {
    unsigned char s[50] = { 0 };
    memcpy(s, input, sizeof(dst)+5);
    int i = 5;
    int v0 = sizeof(dst) + 5;
    while (i < v0) {
        if (i & 1 != 0) {
            unsigned int tmp1 = (((unsigned int)s[i] >> 2) << 24) >> 24;
            unsigned int tmp2 = (((unsigned int)s[i] << 6) << 24 ) >> 24;
            s[i] = ((tmp1 | tmp2) << 24) >> 24;
        }
        else {
            unsigned int tmp1 = (((unsigned int)s[i] << 2 ) << 24 ) >> 24;
            unsigned int tmp2 = (((unsigned int)s[i] >> 6 ) << 24 ) >> 24;
            s[i] = ((tmp1 | tmp2) << 24) >> 24;
        }
        i++;

    }
    return *(s + 5 + k) == dst[k];
}


int main() {
     unsigned char s[40] = { 'Q','|','j','{','g',0 };

    for (int i = 0; i < sizeof(dst) + 5; i++) {
        for (int j = 0; j < 0x100; j++) {
            *(s + 5 + i) = (unsigned char)j;

            if (verify(s,i)) {
                printf("get%d ", i);
                break;
            }
        }
    }

    for (unsigned int i = 0; i < 32; i++) {
        s[i] = s[i] ^ (32 - i);
    }

    printf("\n%s",s);
    system("pause");
    return 1;
}

babyre

Download binary file

def trans3(input):
    keys = [[7, 1], [4, 4], [5, 3], [2, 6]]
    input = list(input)
    for i in range(len(input)):
        k = 2
        input[i] = ((input[i] >> keys[(i + k) % 4][0]) & 0xff) | ((input[i] << keys[(i + k) % 4][1]) & 0xff)
    return input


def detrans3(input):
    keys = [[7, 1], [4, 4], [5, 3], [2, 6]]
    input = list(input)
    for i in range(len(input)):
        k = 2
        for test in range(0x100):
            if input[i] == ((test >> keys[(i + k) % 4][0]) & 0xff) | ((test << keys[(i + k) % 4][1]) & 0xff):
                input[i] = test
                break
    return input


def trans2(input):
    input = list(input)
    keys = [0x7, 0x12, 0x58, 0x81]
    for i in range(len(input)):
        input[i] = hex((ord(input[i]) + keys[i % 4]) & 0xff)
    return (input)


def detrans2(input):
    input = list(input)
    keys = [0x7, 0x12, 0x58, 0x81]
    for i in range(len(input)):
        input[i] = (input[i] - keys[i % 4]) & 0xff
    return (input)


def trans1(input):
    input = list(input)
    for i in range((int)(len(input) / 4)):
        input[4 * i + 1], input[4 * i + 3], input[4 * i], input[4 * i + 2] = input[4 * i], input[4 * i + 1], input[
            4 * i + 2], input[4 * i + 3]
    return input


def detrans1(input):
    input = list(input)
    for i in range((int)(len(input) / 4)):
        input[4 * i], input[4 * i + 1], input[4 * i + 2], input[4 * i + 3] = input[4 * i + 1], input[4 * i + 3], input[
            4 * i], input[4 * i + 2]
    return input


final = [0xDA, 0xD8, 0x3D, 0x4C, 0xE3, 0x63, 0x97, 0x3D, 0xC1, 0x91, 0x97, 0x0E, 0xE3, 0x5C, 0x8D, 0x7E, 0x5B, 0x91,
         0x6F, 0xFE, 0xDB, 0xD0, 0x17, 0xFE, 0xD3, 0x21, 0x99, 0x4B, 0x73, 0xD0, 0xAB, 0xFE]
print(bytearray(detrans1(detrans2(detrans3(final)))))

asong

Download binary file

读取 that_girl 中内容并统计频次,buf经过trans0分配后落在freq[v2]处,使该处计数器+1

while ( read(fd, &buf, 1uLL) == 1 )
  {
    v2 = trans0(buf);
    ++freq[v2];
  }

然后取输入flag{xxxx}的xxxx,each in xxxx经过trans0后为index,freq[index]替换掉each,将转换过的xxxx进行trans1、trans2变换,变换的结果写出到out中。

flag_freq[i] = freq[(signed int)trans0(flag_content[i])];

逆推:out->de_trans2->de_trans1得到 freq[(signed int)trans0(flag_content[i])]

由于freq理应无重复项,遍历查找得到(signed int)trans0(flag_content[i]),再进一步爆破得到flag_content[i]

trans1是简单的位移,trans2通过z3约束求逆。内存中dump出频次表freq[],把 trans0 拿来,约束一下字符范围再爆破即可得到flag。

script1 in python:

# coding = utf-8
from z3 import *

final = [0xEC, 0x29, 0xE3, 0x41, 0xE1, 0xF7, 0xAA, 0x1D, 0x29, 0xED, 0x29, 0x99, 0x39, 0xF3, 0xB7, 0xA9,
         0xE7, 0xAC, 0x2B, 0xB7, 0xAB, 0x40, 0x9F, 0xA9, 0x31, 0x35, 0x2C, 0x29, 0xEF, 0xA8, 0x3D, 0x4B,
         0xB0, 0xE9, 0xE1, 0x68, 0x7B, 0x41]

de_exc = [1, 7, 3, 18, 17, 25, 2, 9, 12, 6, 11, 21, 13, 16, 19, 24, 23, 14, 10, 20, 22, 8, 0, 15, 5, 26, 35, 28, 29, 30,
          4, 32, 33, 34, 36, 37, 27, 31]

freq = [0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x68, 0x1E, 0x0F, 0x1D, 0xA9, 0x13, 0x26, 0x43, 0x3C, 0x0, 0x14,
        0x27, 0x1C, 0x76, 0xA5, 0x1A, 0x00, 0x3D, 0x33, 0x85, 0x2D, 0x07, 0x22, 0x0, 0x3E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
        0x28, 0x47, 0x0, 0x0, 0x42, 0xF5]

def de_trans2(input):
    solver = Solver()
    final = input
    vars = [BitVec('var%d' % i, 8) for i in range(len(final))]
    for i in range(len(final)):
        solver.add(((8 * vars[i])) | (LShR(vars[(i + 1) % len(final)] ,5)) == final[i])
        # z3中 unsigned >> 需要使用 LShR
    if solver.check() == sat:
        m = solver.model()
        s = []
        for i in range(len(final)):
            s.append(m[vars[i]].as_long())
        return s
    else:
        return 'error'

def de_trans1(input):
    i = 0
    tmp = input[0]
    while (de_exc[i] != 0):
        input[i] = input[de_exc[i]]
        i = de_exc[i]
    input[i] = tmp
    return input

def get_freq_index(input):
    for i in range(len(freq)):
        if (freq[i] == input):
            return i
    return -1

result = []
var = de_trans2(final)
for each in de_trans1(var):
    result.append(get_freq_index(each))
print(result)

# output: [29, 17, 10, 29, 46, 16, 18, 27, 21, 46, 28, 10, 34, 18, 23, 16, 46, 23, 24, 46, 15, 24, 27, 46, 34, 24, 30, 27, 46, 31, 18, 23, 13, 18, 12, 10, 29, 14]

script2 in c++:

#include "stdafx.h"

__int64 __fastcall trans0(char a1)
{
    __int64 result; // rax

    result = (unsigned int)(a1 - 10);
    switch (a1)
    {
    case '\n':
        result = (unsigned int)(a1 + 35);
        break;
    case ' ':
    case '!':
    case '"':
        result = (unsigned int)(a1 + 10);
        break;
    case '\'':
        result = (unsigned int)(a1 + 2);
        break;
    case ',':
        result = (unsigned int)(a1 - 4);
        break;
    case '.':
        result = (unsigned int)(a1 - 7);
        break;
    case ':':
    case ';':
        result = (unsigned int)(a1 - 21);
        break;
    case '?':
        result = (unsigned int)(a1 - 27);
        break;
    case '_':
        result = (unsigned int)(a1 - '1');
        break;
    default:
        if (a1 <= '/' || a1 > '9')
        {
            if (a1 <= '@' || a1 > 'Z')
            {
                if (a1 > '`' && a1 <= 'z')
                    result = (unsigned int)(a1 - 0x57);
            }
            else
            {
                result = (unsigned int)(a1 - '7');
            }
        }
        else
        {
            result = (unsigned int)(a1 - '0');
        }
        break;
    }
    return result;
}

int main()
{
    char keys[] = { 29, 17, 10, 29, 46, 16, 18, 27, 21, 46, 28, 10, 34, 18, 23, 16, 46, 23, 24, 46, 15, 24, 27, 46, 34, 24, 30, 27, 46, 31, 18, 23, 13, 18, 12, 10, 29, 14 };
    char map[256] = { 0 };

    for (int k = 0; k < sizeof(keys); k++) {
        for (int i = 32; i < 126; i++) {
            if (keys[k] == trans0(i) && ((i >= '0' && i <= '9') || (i >= 'A' && i <= 'Z') || (i >= 'a' && i <= 'z') || i == '_')) {
                keys[k] = i;
                break;
            }
        }
    }
    char* keys_s = new char[sizeof(keys) + 1];
    memcpy(keys_s, keys, sizeof(keys));
    keys_s[sizeof(keys)] = 0;
    printf("QCTF{%s}\n", keys_s);
    return 0;
}

// output: QCTF{THAT_GIRL_SAYING_NO_FOR_YOUR_VINDICATE}
// 将 || (i >= 'A' && i <= 'Z') 条件去除,可以得到:
// QCTF{that_girl_saying_no_for_your_vindicate} 事实上大小写无关