CTF小白学习笔记(Reverse)-i春秋 SimpleGame

一.解题过程

静态分析

拿到题目运行,运行下发现是输入flag进行比对的题目。
先查壳:
在这里插入图片描述

二话不说,upx脱壳,然后开始ida分析:
main函数:
在这里插入图片描述

首先检查输入字符串长度是否为36,sub_401360功能是检查输入是否全是小写字母,不是返回-1。这里就不截图了。同样字符串下一步比对过程全在sub_401000,sub_4012C0和sub_401300就不截图了。

来看sub_401000,这段代码有点长,部分变量我也重命名过,input0,input1都是输入字符串,row和col为二维矩阵行列索引
在这里插入图片描述

这段代码就不全部截图了,大致流程就是将36个字符分成9组,每组4个字符分别用a0 a1 a2 a3表示,每次对第i组进行操作。每轮循环过后,i + 4。 然后根据a0 a2的情况,用a1 a3计算出row和col值

尝试IAT修复

这里就容易踩坑了,dword_403170中的值在运行时发生了改变。可能是在main函数的sub_4013C0中改动的。所以得在动态调试的过程中dump出来,可是upx脱壳后的程序不能运行。所以用ImportReConstructor进行IAT修复。

IAT修复用到了脱壳前的exe和upx脱壳后的exe,这里用IDA动态调试(7.0版是真的香)
这里用IDA打开脱壳前的exe
alt + t 搜索popa
在这里插入图片描述
打个断点后开始调试,这里一路F8,知道运行到0x40170C处
在这里插入图片描述
这个sub_401400就是main函数,F7进去。然后运行到下图处
在这里插入图片描述

0x40209C处保存着printf函数的地址,切换到堆栈里看看

在这里插入图片描述

这里可以看出IAT表是从0x402000 - 0x4020B4,用ImportReConstructor修复下:
在这里插入图片描述
但修复后的程序还是无法运行,这里main函数的地址是0x401400, start函数地址是0x401779,都试过了没用。只好在这里接着把403170处的数据dump出来,为:

dssdwasawawaaswddw

接着静态分析

从403170 dump出来的18个字符为输入字符串偶数位字符(索引0开始,a0 a2 a4 a6…)。也就是接下来我们要分析出奇数位的字符,现在大概明白了每四个4符一组,根据a0 a2不同情况(只能为a d s w 4个中的一个),用 a1 a3生成row, col值。row, col用法如下
在这里插入图片描述
这里unk_4021A0为9 * 4 * 4的矩阵, dword_403020为 9 * 9矩阵(静态分析 + 动态调试得知),在程序的9轮循环中 判断unk_4021A0第i个矩阵能否嵌入矩阵dword_403020。嵌入部分以第i轮生成(row,col)坐标为起点4*4的小矩阵中。 能够进行嵌入的条件是嵌入部分对应元素不能同时为非0元素。(比如a[i][j] == 3 b[i + row][j + col] == 15就不能嵌入),只要对应位置有至少1个非0元素(2个都是0也可以)就可以嵌入。嵌入完成后会修改dword_403020矩阵,并且每轮都能发现有多个潜在位置可以嵌入(但是答案唯一)。

所以现在的问题就是根据unk_4021A0, dword_403020的值推出一组坐标(用list保存,长度为9),这组坐标可以把unk_4021A0 9个矩阵嵌入到dword_403020中。然后根据这组坐标推出输入字符串奇数位。

先把unk_4021A0, dword_403020 dump出来。dump脚本为:

from idaapi import *
import json

def dump_403020():
    start_address = 0x403020
    data_length = 324
    datas = []
    count = 0
    for i in range(0, data_length, 4):
        data = get_byte(start_address + i)
        # if count == 0:
        datas.append(data)
        count += 1
        if count == 4:
            count = 0
    print datas
    print len(datas)
    fp = open('D:\projects\python\IDAscripts\datas\SimpleGame403020.json', 'wb')
    # fp.write(datas)
    json.dump(datas, fp)
    fp.close()


def dump_403170():
    start_address = 0x403170
    data_length = 72
    datas = []
    for i in range(0, data_length, 4):
        data = get_byte(start_address + i)
        # if count == 0:
        datas.append(data)

    print datas
    print len(datas)
    fp = open('D:\projects\python\IDAscripts\datas\SimpleGame403170.txt', 'wb')
    fp.write(''.join(map(chr,datas)))


def dump_4021A0():
    start_address = 0x4021A0
    data_length = 572
    datas = []

    for i in range(0, data_length, 4):
        data = get_byte(start_address + i)
        # if count == 0:
        datas.append(data)
    print datas
    print len(datas)
    fp = open('D:\projects\python\IDAscripts\datas\SimpleGame4021A0.json', 'wb')
    # fp.write(datas)
    json.dump(datas, fp)
    fp.close()


if __name__ == '__main__':
    dump_4021A0()
    dump_403020()

dump出来后dword_403020为:

[[15 15 15 15 15  0  0 15 15]
 [15  0  0  0  0 15  0 15 15]
 [15  0 15 15 15 15  0  0 15]
 [ 0  0  0  0 15 15 15  0 15]
 [ 0 15  0  0 15  0 15 15 15]
 [15  0 15 15  0  0 15  0 15]
 [15  0  0 15  0  0  0  0 15]
 [15 15  0  0  0  0 15  0 15]
 [15 15 15 15 15 15 15 15 15]]

unk_4021A0为:

[[[0 0 9 0]
  [0 9 9 0]
  [0 0 9 0]
  [0 0 0 0]]

 [[0 6 0 0]
  [0 6 0 0]
  [0 6 0 0]
  [0 6 0 0]]

 [[0 0 0 0]
  [0 3 0 0]
  [3 3 0 0]
  [3 0 0 0]]

 [[0 0 8 0]
  [0 0 8 0]
  [0 8 8 0]
  [0 0 0 0]]

 [[0 0 0 0]
  [0 5 5 0]
  [0 5 5 0]
  [0 0 0 0]]

 [[0 0 0 0]
  [2 2 2 2]
  [0 0 0 0]
  [0 0 0 0]]

 [[0 7 0 0]
  [0 7 7 0]
  [0 0 7 0]
  [0 0 0 0]]

 [[0 0 0 0]
  [0 0 4 0]
  [0 0 4 0]
  [0 0 0 0]]

 [[0 1 1 0]
  [0 0 1 0]
  [0 0 1 0]
  [0 0 0 0]]]

这里用dfs来解除坐标数组,解题脚本如下,得到坐标后根据前面的row col生成的算法就可以得到flag:

flag{dcsdscdbwbadsdabwaacwcacadsdwbdcdbwc}

二.解题脚本

import numpy as np
import json

ans = []
res = []

def dfs(step, a, b):
    # 答案唯一,找齐9个坐标dfs结束
    if step == 9:
        #print(ans)
        res.extend(ans)
        return
    else:
        # 找出所有能够嵌入的(row,col)坐标,并保存到pos中
        pos = []
        for row in range(6):
            for column in range(6):
                sum = 0
                for i in range(4):
                    for j in range(4):
                        if a[step, i, j]:
                            if b[i + row, j + column]:
                                break
                        sum += 1
                if sum == 16:
                    pos.append((row, column))

        # 对已找出的所有坐标进行嵌入操作
        for position in pos:
            # 1.嵌入
            for i in range(4):
                for j in range(4):
                    if a[step, i, j]:
                        b[i + position[0], j + position[1]] = a[step,i, j]
            # 2.开始dfs
            ans.append(position)
            dfs(step + 1, a, b)
            # 3.dfs结束后还原9*9的矩阵
            for i in range(4):
                for j in range(4):
                    if a[step, i, j] != 0:
                        b[i + position[0], j + position[1]] = 0
            ans.pop()

if __name__ == '__main__':
    unk_4021A0_file = '../datas/simpleGame/SimpleGame4021A0.json'
    unk_403020_file = '../datas/simpleGame/SimpleGame403020.json'
    unk_403170_file = '../datas/simpleGame/SimpleGame403170.txt'

    matrix_4021A0 = np.array(json.load(open(unk_4021A0_file))).reshape(9, 4, 4)
    matrix_403020 = np.array(json.load(open(unk_403020_file))).reshape(9, 9)

    print(matrix_4021A0)
    data_403170 = [c for c in open(unk_403170_file,'rb').read()]

    dfs(0, matrix_4021A0, matrix_403020)
    print(res)

    flag = ''

    for i in range(9):
        row, col = res[i]
        a0 = data_403170[2 * i]
        a2 = data_403170[2 * i + 1]

        if a0 == 97:
            a1 = 100 - col
            if a2 == 115:
                a3 = row + 95
            elif a2 == 119:
                a3 = 99 - row

        elif a0 == 100:
            a1 = 94 + col
            if a2 == 115:
                a3 = row + 95
            elif a2 == 119:
                a3 = 99 - row

        elif a0 == 115:
            a1 = row + 95
            if a2 == 97:
                a3 = 100 - col
            elif a2 == 100:
                a3 = col + 94

        elif a0 == 119:
            a1 = 99 - row
            if a2 == 97:
                a3 = 100 - col
            elif a2 == 100:
                a3 = col + 94

        flag += ''.join(list(map(chr,[a0, a1, a2, a3])))

    flag = 'flag{' + flag + '}'
    print(flag)

三.总结

这道题出现了久违的二维数组,甚至三维数组也来了,着实吐血。不过自己对于手动脱壳,IAT修复的了解几乎为0,以至于动态调试时要用脱壳前的程序来调试。希望路过的各位大佬能赐教赐教。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值