【CTF】Reverse Writeup deeprev+GameMaster等 强网杯 逆向学习

CTF · 2022-08-10 · 987 人浏览

deeprev

这题非常新颖,直接在elf里面的LOAD段写机器码,加载汇编并且跳转过去执行

最开始其实是常规动调,注意到链接了so文件并且读取了so里面的secret到elf中,那么直接在elf中的secret上面下一个内存读写断点。(这边我给check也下了)

img

然后运行,可以发现载入so库的时候就完成了加密,等到执行到main函数的时候check已经有值了。

我自己是通过一直f7步入,ida提示eip跳转到非代码段,从而发现了LOAD段藏起来的机器码。仔细看一下ida的注释就可以发现这边复制了so的secret

img

然后进一步动调加分析可以得到每一片段其实是这样的,每一行第二位是操作码,第一位是偏移地址,第三位是值。动调可以发现有很多重复的这样的片段,并且每一段都把第三行的第三位给第二行的偏移地址,简单理解R_X86_64_RELATIVE,操作码0x8是赋值。

在进一步动调之后发现0xc3操作码是标志下一步跳转进LOAD段执行代码

img

那么我们其实只需要把所有的机器码提取出来,再扔到机器码转汇编的网站上面解密就行了。

直接复制LOAD段内容,提取机器码

s=''
with open("qwbre2data","r") as file:
    for line in file:
        s+=line[line.find("<"):line.find(">")+1]
        s+='\n'
with open("qwbre2data1","w") as file1:
    file1.write(s)

f=0
with open("qwbre2data1","r") as file2:
    for line in file2:
        if "0C3" in line:
            f=1
            continue
        if f==1:
            temp=line[line.find(",")+1:]
            temp1=temp[temp.find(",")+2:temp.find("h")]
            if len(temp1)>8:
                if len(temp1)!=16 and len(temp1)>14:
                    temp1=temp1[::-1]
                    temp1+="0"
                    temp1=temp1[::-1]
                reopcode=temp1
                opcode=''
                for i in reversed(range(0,len(reopcode),2)):
                    opcode+=reopcode[i]
                    opcode+=reopcode[i+1]
                print(opcode)
            f=0
'''
803425CC40800016
800425CC4080
803425CC40800017
800425CC40800001
803425CC40800010
800425CC40800002
803425CC40800012
800425CC40800003
803425CC40800010
800425CC40800004
803425CC40800011
800425CC40800005
803425CC40800012
800425CC40800006
803425CC40800013
800425CC40800007
803425CC40800014
800425CC40800008
803425CC40800015
800425CC40800009
803425CC40800016
800425CC4080000A
803425CC40800017
800425CC4080000B
803425CC40800018
800425CC4080000C
803425CC40800019
800425CC4080000D
803425CC40800024
800425CC4080000E
803425CC4080002C
800425CC4080000F
803425CC40800026
800425CC40800010
803425CC4080001E
800425CC40800011
803425CC4080001F
800425CC40800012
803425CC40800020
800425CC40800013
803425CC40800020
800425CC40800014
803425CC40800021
800425CC40800015
803425CC40800023
800425CC40800016
803425CC40800027
800425CC40800017
803425CC40800024
800425CC40800018
803425CC40800025
800425CC40800019
803425CC40800026
800425CC4080001A
803425CC40800027
800425CC4080001B
803425FC40800070
803425FC4080007C
803425FC40800073
803425FC40800078
803425FC4080006F
803425FC40800027
803425FC4080002A
803425FC4080002C
803425FC4080007F
803425FC40800035
803425FC4080002D
803425FC40800032
803425FC40800037
803425FC4080003B
803425FC40800022
803425FC40800059
803425FC40800053
803425FC4080008E
803425FC4080003D
803425FC4080002A
803425FC40800059
803425FC40800027
803425FC4080002D
803425FC40800029
803425FC40800034
803425FC4080002D
803425FC40800061
803425FC40800032
8034255C4180006C
8034255C418000A100
8034255C418000B100
8034255C418000E500
'''

然后丢到网站里面shell-storm | Online Assembler and Disassembler

最后是要改一下,多了0删掉,少了0补上。得到汇编

xor byte ptr [0x8040cc], 0x16
add byte ptr [0x8040cc], 0
xor byte ptr [0x8040cc], 0x17
add byte ptr [0x8040cc], 1
xor byte ptr [0x8040cc], 0x10
add byte ptr [0x8040cc], 2
xor byte ptr [0x8040cc], 0x12
add byte ptr [0x8040cc], 3
xor byte ptr [0x8040cc], 0x10
add byte ptr [0x8040cc], 4
xor byte ptr [0x8040cc], 0x11
add byte ptr [0x8040cc], 5
xor byte ptr [0x8040cc], 0x12
add byte ptr [0x8040cc], 6
xor byte ptr [0x8040cc], 0x13
add byte ptr [0x8040cc], 7
xor byte ptr [0x8040cc], 0x14
add byte ptr [0x8040cc], 8
xor byte ptr [0x8040cc], 0x15
add byte ptr [0x8040cc], 9
xor byte ptr [0x8040cc], 0x16
add byte ptr [0x8040cc], 0xa
xor byte ptr [0x8040cc], 0x17
add byte ptr [0x8040cc], 0xb
xor byte ptr [0x8040cc], 0x18
add byte ptr [0x8040cc], 0xc
xor byte ptr [0x8040cc], 0x19
add byte ptr [0x8040cc], 0xd
xor byte ptr [0x8040cc], 0x24
add byte ptr [0x8040cc], 0xe
xor byte ptr [0x8040cc], 0x2c
add byte ptr [0x8040cc], 0xf
xor byte ptr [0x8040cc], 0x26
add byte ptr [0x8040cc], 0x10
xor byte ptr [0x8040cc], 0x1e
add byte ptr [0x8040cc], 0x11
xor byte ptr [0x8040cc], 0x1f
add byte ptr [0x8040cc], 0x12
xor byte ptr [0x8040cc], 0x20
add byte ptr [0x8040cc], 0x13
xor byte ptr [0x8040cc], 0x20
add byte ptr [0x8040cc], 0x14
xor byte ptr [0x8040cc], 0x21
add byte ptr [0x8040cc], 0x15
xor byte ptr [0x8040cc], 0x23
add byte ptr [0x8040cc], 0x16
xor byte ptr [0x8040cc], 0x27
add byte ptr [0x8040cc], 0x17
xor byte ptr [0x8040cc], 0x24
add byte ptr [0x8040cc], 0x18
xor byte ptr [0x8040cc], 0x25
add byte ptr [0x8040cc], 0x19
xor byte ptr [0x8040cc], 0x26
add byte ptr [0x8040cc], 0x1a
xor byte ptr [0x8040cc], 0x27
add byte ptr [0x8040cc], 0x1b
xor byte ptr [0x8040fc], 0x70
xor byte ptr [0x8040fc], 0x7c
xor byte ptr [0x8040fc], 0x73
xor byte ptr [0x8040fc], 0x78
xor byte ptr [0x8040fc], 0x6f
xor byte ptr [0x8040fc], 0x27
xor byte ptr [0x8040fc], 0x2a
xor byte ptr [0x8040fc], 0x2c
xor byte ptr [0x8040fc], 0x7f
xor byte ptr [0x8040fc], 0x35
xor byte ptr [0x8040fc], 0x2d
xor byte ptr [0x8040fc], 0x32
xor byte ptr [0x8040fc], 0x37
xor byte ptr [0x8040fc], 0x3b
xor byte ptr [0x8040fc], 0x22
xor byte ptr [0x8040fc], 0x59
xor byte ptr [0x8040fc], 0x53
xor byte ptr [0x8040fc], 0x8e
xor byte ptr [0x8040fc], 0x3d
xor byte ptr [0x8040fc], 0x2a
xor byte ptr [0x8040fc], 0x59
xor byte ptr [0x8040fc], 0x27
xor byte ptr [0x8040fc], 0x2d
xor byte ptr [0x8040fc], 0x29
xor byte ptr [0x8040fc], 0x34
xor byte ptr [0x8040fc], 0x2d
xor byte ptr [0x8040fc], 0x61
xor byte ptr [0x8040fc], 0x32
xor byte ptr [0x80415c], 0x6c
xor byte ptr [0x80415c], 0xa1
xor byte ptr [0x80415c], 0xb1
xor byte ptr [0x80415c], 0xe5

然后手搓一个解密,会发现给的flag缺了四位,看到hint给了sha256那直接加个sha256爆破(不爆破可能就要写脚本patchso文件了)

import hashlib
print(chr(0x6c))
enc=[0x70,0x7c,0x73,0x78,0x6f,0x27,0x2a,0x2c,0x7f,0x35,0x2d,0x32,0x37,0x3b,0x22,0x59,0x53,0x8e,0x3d,0x2a,0x59,0x27,0x2d,0x29,0x34,0x2d,0x61,0x32,0x6c,0xa1,0xb1,0xe5]
s=[0x16,0,0x17,1,0x10,2,0x12,3,0x10,4,0x11,5,0x12,6,0x13,7,0x14,8,0x15,9,0x16,0xa,0x17,0xb,0x18,0xc,0x19,0xd,0x24,0xe,0x2c,0xf,0x26,0x10,0x1e,0x11,0x1f,0x12,0x20,0x13,0x20,0x14,0x21,0x15,0x23,0x16,0x27,0x17,0x24,0x18,0x25,0x19,0x26,0x1a,0x27,0x1b]
s1=[]
s2=[]
for i in range(0,len(s),2):
    s1.append(s[i])
    s2.append(s[i+1])
flag=''
for i in range(len(s1)):
    enc[i]-=i
    enc[i]^=s1[i]
    flag+=chr(enc[i])
print(flag)
for i in range(127):
    for j in range(127):
        for p in range(127):
            flag='flag{366c950370fec47e34581a0'
            flag+=(chr(i)+chr(j)+chr(p)+"}")
            data_sha = hashlib.sha256(flag.encode('utf-8')).hexdigest()[0:16]
            if("f860464d767610bb"==data_sha):
                print(flag)
                break
print(len(s1))

GameMaster

感觉这个还能看一看...dnspy打开直接源码,给了三个文件,dll和exe拖进去,然后可以看到有个很长的金手指方法,输入14位字符再按esc即可

有几个金手指对数据文件进行了操作,第一个是异或,第二个是aes解密,第三个是反序列化 ,把反编译出来的三坨加密直接丢到vs里面跑一下,然后把文件保存一下,可以得到解密后的

//internal class Program

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Cryptography;

namespace test
{
    class Program
    {
        private static byte[] memory;
        private static byte[] m;

        static void Main(string[] args)
        {

            FileStream fileStream = File.OpenRead("D:\\CTF\\ctf比赛文件\\2022qwb\\gamemessage");
            int num = (int)fileStream.Length;
            Program.memory = new byte[num];
            fileStream.Position = 0L;
            fileStream.Read(Program.memory, 0, num);


            for (int i = 0; i < Program.memory.Length; i++)
            {
                byte[] array = Program.memory;
                int num1 = i;
                array[num1] ^= 34;
            }
            //Environment.SetEnvironmentVariable("AchivePoint1", game.Player.Balance.ToString());


            byte[] key = new byte[]
            {
    66,
    114,
    97,
    105,
    110,
    115,
    116,
    111,
    114,
    109,
    105,
    110,
    103,
    33,
    33,
    33
            };
            ICryptoTransform cryptoTransform = new RijndaelManaged
            {
                Key = key,
                Mode = CipherMode.ECB,
                Padding = PaddingMode.Zeros
            }.CreateDecryptor();
            Program.m = cryptoTransform.TransformFinalBlock(Program.memory, 0, Program.memory.Length);
            //Environment.SetEnvironmentVariable("AchivePoint2", game.Player.Balance.ToString());


            //Environment.SetEnvironmentVariable("AchivePoint3", game.Player.Balance.ToString());
            BinaryFormatter binaryFormatter = new BinaryFormatter();
            MemoryStream serializationStream = new MemoryStream(Program.m);
            binaryFormatter.Deserialize(serializationStream);
            FileStream fsWrite = File.OpenWrite("D:\\CTF\\ctf比赛文件\\2022qwb\\gamemessage1");
            int num2 = (int)Program.m.Length;
            fileStream.Position = 0L;
            fsWrite.Write(Program.m, 0, num2);
        }
    }
}

解出来这个文件就好做了,丢到010看一下,在中间发现了MZ头标志,提取出来发现还是.NET

然后再丢到dnspy里面可以看到加密方法

using System;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace T1Class
{
    // Token: 0x02000002 RID: 2
    public class T1
    {
        // Token: 0x06000001 RID: 1 RVA: 0x00002050 File Offset: 0x00000250
        private static void Check1(ulong x, ulong y, ulong z, byte[] KeyStream)
        {
            int num = -1;
            for (int i = 0; i < 320; i++)
            {
                x = (((x >> 29 ^ x >> 28 ^ x >> 25 ^ x >> 23) & 1UL) | x << 1);
                y = (((y >> 30 ^ y >> 27) & 1UL) | y << 1);
                z = (((z >> 31 ^ z >> 30 ^ z >> 29 ^ z >> 28 ^ z >> 26 ^ z >> 24) & 1UL) | z << 1);
                bool flag = i % 8 == 0;
                if (flag)
                {
                    num++;
                }
                KeyStream[num] = (byte)((long)((long)KeyStream[num] << 1) | (long)((ulong)((uint)((z >> 32 & 1UL & (x >> 30 & 1UL)) ^ (((z >> 32 & 1UL) ^ 1UL) & (y >> 31 & 1UL))))));
            }
        }

        // Token: 0x06000002 RID: 2 RVA: 0x00002110 File Offset: 0x00000310
        private static void ParseKey(ulong[] L, byte[] Key)
        {
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    Key[i * 4 + j] = (byte)(L[i] >> j * 8 & 255UL);
                }
            }
        }

        // Token: 0x06000003 RID: 3 RVA: 0x0000215C File Offset: 0x0000035C
        public T1()
        {
            try
            {
                string environmentVariable = Environment.GetEnvironmentVariable("AchivePoint1");
                string environmentVariable2 = Environment.GetEnvironmentVariable("AchivePoint2");
                string environmentVariable3 = Environment.GetEnvironmentVariable("AchivePoint3");
                bool flag = environmentVariable == null || environmentVariable2 == null || environmentVariable3 == null;
                if (!flag)
                {
                    ulong num = ulong.Parse(environmentVariable);
                    ulong num2 = ulong.Parse(environmentVariable2);
                    ulong num3 = ulong.Parse(environmentVariable3);
                    ulong[] array = new ulong[3];
                    byte[] array2 = new byte[40];
                    byte[] array3 = new byte[40];
                    byte[] array4 = new byte[12];
                    byte[] first = new byte[]
                    {
                        101,
                        5,
                        80,
                        213,
                        163,
                        26,
                        59,
                        38,
                        19,
                        6,
                        173,
                        189,
                        198,
                        166,
                        140,
                        183,
                        42,
                        247,
                        223,
                        24,
                        106,
                        20,
                        145,
                        37,
                        24,
                        7,
                        22,
                        191,
                        110,
                        179,
                        227,
                        5,
                        62,
                        9,
                        13,
                        17,
                        65,
                        22,
                        37,
                        5
                    };
                    byte[] array5 = new byte[]
                    {
                        60,
                        100,
                        36,
                        86,
                        51,
                        251,
                        167,
                        108,
                        116,
                        245,
                        207,
                        223,
                        40,
                        103,
                        34,
                        62,
                        22,
                        251,
                        227
                    };
                    array[0] = num;
                    array[1] = num2;
                    array[2] = num3;
                    T1.Check1(array[0], array[1], array[2], array2);
                    bool flag2 = first.SequenceEqual(array2);
                    if (flag2)
                    {
                        T1.ParseKey(array, array4);
                        for (int i = 0; i < array5.Length; i++)
                        {
                            array5[i] ^= array4[i % array4.Length];
                        }
                        MessageBox.Show("flag{" + Encoding.Default.GetString(array5) + "}", "Congratulations!", MessageBoxButtons.OK);
                    }
                }
            }
            catch (Exception)
            {
            }
        }
    }
}

发现只有一坨位移加密,那么直接拿去z3即可

from z3 import *

solver = Solver()
byte1=[101,5,80,213,163,26,59,38,19,6,173,189,198,166,140,183,42,247,223,24,106,20,145,37,24,7,22,191,110,179,227,5,62,9,13,17,65,22,37,5]

x = [BitVec("x[%d]" % i,64) for i in range(3)]
KeyStream = [BitVec("KeyStream[%d]" % i,64) for i in range(len(byte1))]

num = -1
for i in range(320):
    x[0] = (((x[0] >> 29 ^ x[0] >> 28 ^ x[0] >> 25 ^ x[0] >> 23) & 1) | x[0] << 1)
    x[1] = (((x[1] >> 30 ^ x[1] >> 27) & 1) | x[1] << 1)
    x[2] = (((x[2] >> 31 ^ x[2] >> 30 ^ x[2] >> 29 ^ x[2] >> 28 ^ x[2] >> 26 ^ x[2] >> 24) & 1) | x[2] << 1)
    flag = (i % 8 == 0)
    if (flag):
        num+=1
    KeyStream[num] = ((KeyStream[num] << 1) | ((((x[2] >> 32 & 1 & (x[0] >> 30 & 1)) ^ (((x[2] >> 32 & 1) ^ 1) & (x[1] >> 31 & 1))))))
for i in range(len(byte1)):
    solver.add(KeyStream[i]==byte1[i])


if solver.check() == sat:
        m = solver.model()
        for d in m.decls():
            print('%s == %s'% (d.name(),int(str(m[d]))))
'''x[0] == 156324965
x[1] == 868387187
x[2] == 3131229747'''

解出来三个值

然后直接放到代码里面跑就行了,非常的简单

                static void Main(string[] args)
                {
                                        ulong num = 156324965;
                        ulong num2 = 868387187;
                        ulong num3 = 3131229747;
                                        ulong[] array = new ulong[3];
                                        byte[] array2 = new byte[40];
                                        byte[] array3 = new byte[40];
                                        byte[] array4 = new byte[12];
                                        byte[] first = new byte[]
                                        {
                                                101,
                                                5,
                                                80,
                                                213,
                                                163,
                                                26,
                                                59,
                                                38,
                                                19,
                                                6,
                                                173,
                                                189,
                                                198,
                                                166,
                                                140,
                                                183,
                                                42,
                                                247,
                                                223,
                                                24,
                                                106,
                                                20,
                                                145,
                                                37,
                                                24,
                                                7,
                                                22,
                                                191,
                                                110,
                                                179,
                                                227,
                                                5,
                                                62,
                                                9,
                                                13,
                                                17,
                                                65,
                                                22,
                                                37,
                                                5
                                        };
                                        byte[] array5 = new byte[]
                                        {
                                                60,
                                                100,
                                                36,
                                                86,
                                                51,
                                                251,
                                                167,
                                                108,
                                                116,
                                                245,
                                                207,
                                                223,
                                                40,
                                                103,
                                                34,
                                                62,
                                                22,
                                                251,
                                                227
                                        };
                                        array[0] = num;
                                        array[1] = num2;
                                        array[2] = num3;
                        Program.Check1(array[0], array[1], array[2], array2);
                                        bool flag2 = first.SequenceEqual(array2);
                                        if (flag2)
                                        {
                                                Program.ParseKey(array, array4);
                                                for (int i = 0; i < array5.Length; i++)
                                                {
                                                        array5[i] ^= array4[i % array4.Length];
                                                }
                                                MessageBox.Show("flag{" + Encoding.Default.GetString(array5) + "}", "Congratulations!", MessageBoxButtons.OK);
                                        }
                                }
                }

改过之后的main,拿着dnspy反编译出来的源码直接放到vs里面跑一下就行

img

上面这两题是比赛的时候穿的,后面的还没复现((((绝对不是懒

之后复现下apk和子进程调试那题再更在这里面

RE
Theme Jasmine by Kent Liao