【CTF】Reverse Writeup deeprev+GameMaster等 强网杯 逆向学习
浏览 198 | 评论 0 | 字数 21123
Xunflash
2022年08月10日
  • 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和子进程调试那题再更在这里面

    本文作者:Xunflash
    本文链接:https://xunflash.top/index.php/archives/2022qwb.html
    最后修改时间:2022-08-10 13:31:29
    本站未注明转载的文章均为原创,并采用 CC BY-NC-SA 4.0 授权协议,转载请注明来源,谢谢!
    评论
    114514
    textsms
    支持 Markdown 语法
    email
    link
    评论列表
    暂无评论