三月DASCTF逆向 部分writeup by JamesHoi

drinkSomeTea

看到题目盲猜一波TEA加密,果不其然。之前没好好学,这次至少会做题了,之后有空要好好再看看详细的加密流程。附件给了个tea.png.out,即需要解密图片。
32位exe,无壳

image.png

在一开始的sub_401000函数里面,应该是判断是不是调试器(我没仔细看),用调试器的时候会退出程序,直接把call sub_401000 nop掉即可。
image.png

应该是一个加密函数,点进去看发现加花了
image.png

去花,Create Function,F5,发现是TEA加密,关于TEA加密脚本可以参考这个
image.png
image.png

魔改一下TEA加密即可,要注意的是,加密的时候需要用int指针(保留符号位),否则加密/解密出来的数据会不对。(我在这个地方调了很久,照着还原一次加密过程,动调的时候发现加密出来的数据怎么都不对)
最后用解密函数解密tea.png.out,脚本如下

#include <iostream>
#include <stdio.h>
#include<Windows.h>

void encrypt(int* v, uint32_t* k) {
    int v0 = v[0], v1 = v[1], sum = 0, i;           /* set up */
    int delta = 0x61C88647;                     /* a key schedule constant */
    int k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];   /* cache key */
    for (i = 0; i < 32; i++) {                       /* basic cycle start */
        sum -= delta;
        v0 += ((v1 >> 5) + k1) ^ (v1 + sum) ^ ((v1 << 4) + k0);
        v1 += ((v0 >> 5) + k3) ^ (v0 + sum) ^ ((v0 << 4) + k2);
    }                                              /* end cycle */
    v[0] = v0; v[1] = v1;
}

void decrypt(int* v, uint32_t* k) {
    int v0 = v[0], v1 = v[1], sum = 0xC6EF3720, i;  /* set up */
    int delta = 0x61C88647;                     /* a key schedule constant */
    int k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];   /* cache key */
    for (i = 0; i < 32; i++) {                         /* basic cycle start */
        v1 -= ((v0 >> 5) + k3) ^ (v0 + sum) ^ ((v0 << 4) + k2);
        v0 -= ((v1 >> 5) + k1) ^ (v1 + sum) ^ ((v1 << 4) + k0);
        sum += delta;
    }                                              /* end cycle */
    v[0] = v0; v[1] = v1;
}

int main()
{
    DWORD key[4] = { 0x67616C66, 0x6B61667B, 0x6C665F65, 0x7D216761 };
    HANDLE file = CreateFileA("tea.png.out", 0xC0000000, 0, 0, 3u, 0x80u, 0);
    HANDLE v4 = file;
    char *v7;
    DWORD v8;
    HANDLE v9;
    void *v10;
    DWORD NumberOfBytesRead;
    DWORD NumberOfBytesWritten;
    DWORD v6 = GetFileSize(file, 0);
    DWORD dword_409988[15000];
    if (v6 < 0xEA60)
    {
        SetFilePointer(v4, 0, 0, 0);
        NumberOfBytesRead = 0;
        ReadFile(v4, &dword_409988, v6, &NumberOfBytesRead, 0);
        CloseHandle(v4);
        if (v6 >> 3)
        {
            v7 = (char *)&dword_409988;
            v8 = v6 >> 3;
            do
            {
                decrypt((int *)v7, (uint32_t *)key);
                v7 += 8;
                --v8;
            } while (v8);
        }
        v9 = CreateFileA("tea.png", 0xC0000000, 0, 0, 2u, 0x80u, 0);
        v10 = v9;
        NumberOfBytesWritten = 0;
        WriteFile(v9, &dword_409988, v6, &NumberOfBytesWritten, 0);
        CloseHandle(v10);
    }
}

得到flag: DASCTF{09066cbb91df55502e6fdc83bf84cf45}

image.png

Enjoyit-1

Exeinfope发现是c#写的,用dnspy32位打开

image.png

一开始定位加密位置的时候想了一会,emm我最后用Console.WriteLine定位的,其实好像点开就行...
image.png

发现应该先是base64验证,中间有Thread.Sleep,然后最后直接输出flag
image.png

打开class b的定义,base64换表了
image.png

my_base64table = "abcdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZ"
std_base64table ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
s = "yQXHyBvN3g/81gv51QXG1QTBxRr/yvXK1hC="
s = s.translate(str.maketrans(my_base64table,std_base64table))
print(base64.b64decode(s))
#combustible_oolong_tea_plz

然后直接一次性把全部定义都复制到自己新建的一个c#程序,运行一次就跑出来了(而且当然要注释掉Thread.Sleep)
(代码篇幅有点长,抱歉)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {
        internal class b
        {
            // Token: 0x06000006 RID: 6 RVA: 0x00002234 File Offset: 0x00000434
            public bool B(string A_0)
            {
                for (int i = 0; i < A_0.Length; i++)
                {
                    if (A_0[i] < '_' || A_0[i] > 'z')
                    {
                        Console.WriteLine("Sorry,we don't have this tea");
                        return false;
                    }
                }
                return true;
            }

            // Token: 0x06000007 RID: 7 RVA: 0x00002278 File Offset: 0x00000478
            public string c(string A_0)
            {
                string text = "";
                int num = A_0.Length / 3;
                int i;
                for (i = 0; i < num; i++)
                {
                    byte index = Convert.ToByte((int)('?' & A_0[i * 3] >> 2));
                    byte index2 = Convert.ToByte((int)((int)(A_0[i * 3] & '\u0003') << 4 | A_0[1 + i * 3] >> 4));
                    byte index3 = Convert.ToByte((int)((int)(A_0[1 + i * 3] & '\u000f') << 2 | A_0[2 + i * 3] >> 6));
                    byte index4 = Convert.ToByte((int)(A_0[2 + i * 3] & '?'));
                    text += this.a[(int)index].ToString();
                    text += this.a[(int)index2].ToString();
                    text += this.a[(int)index3].ToString();
                    text += this.a[(int)index4].ToString();
                }
                if (i * 3 < A_0.Length)
                {
                    byte index = Convert.ToByte((int)('?' & A_0[i * 3] >> 2));
                    byte index2;
                    byte index3;
                    byte index4;
                    if (i * 3 + 1 < A_0.Length)
                    {
                        index2 = Convert.ToByte((int)((int)(A_0[i * 3] & '\u0003') << 4 | A_0[i * 3 + 1] >> 4));
                        index3 = Convert.ToByte((int)((int)(A_0[i * 3 + 1] & '\u000f') << 2));
                        index4 = 64;
                    }
                    else
                    {
                        index2 = Convert.ToByte((int)((int)(A_0[i * 3] & '\u0003') << 4));
                        index3 = 64;
                        index4 = 64;
                    }
                    text += this.a[(int)index].ToString();
                    text += this.a[(int)index2].ToString();
                    text += this.a[(int)index3].ToString();
                    text += this.a[(int)index4].ToString();
                }
                return text;
            }

            // Token: 0x06000008 RID: 8 RVA: 0x00002488 File Offset: 0x00000688
            public void B(byte[] A_0)
            {
                string text = "";
                for (int i = 0; i < A_0.Length; i++)
                {
                    text += A_0[i].ToString("x2");
                }
                Console.WriteLine(text);
            }

            // Token: 0x06000009 RID: 9 RVA: 0x000024C8 File Offset: 0x000006C8
            public void B(ref uint[] A_0, byte[] A_1)
            {
                uint num = 2654435464U;
                uint num2 = A_0[0];
                uint num3 = A_0[1];
                uint num4 = 0U;
                for (int i = 0; i < 32; i++)
                {
                    num2 += ((num3 << 4 ^ num3 >> 5) + num3 ^ num4 + (uint)A_1[(int)(num4 & 3U)]);
                    num4 += num;
                    num3 += ((num2 << 4 ^ num2 >> 5) + num2 ^ num4 + (uint)A_1[(int)(num4 >> 11 & 3U)]);
                }
                A_0[0] = num2;
                A_0[1] = num3;
            }

            // Token: 0x0600000A RID: 10 RVA: 0x00002534 File Offset: 0x00000734
            public void c(ref uint[] A_0, byte[] A_1)
            {
                uint num = 2654435769U;
                uint num2 = A_0[0];
                uint num3 = A_0[1];
                uint num4 = num * 32U;
                for (int i = 0; i < 32; i++)
                {
                    num3 -= ((num2 << 4 ^ num2 >> 5) + num2 ^ num4 + (uint)A_1[(int)(num4 >> 11 & 3U)]);
                    num4 -= num;
                    num2 -= ((num3 << 4 ^ num3 >> 5) + num3 ^ num4 + (uint)A_1[(int)(num4 & 3U)]);
                }
                A_0[0] = num2;
                A_0[1] = num3;
            }

            // Token: 0x04000003 RID: 3
            public string a = "abcdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZ=";
        }

        static void Main(string[] args)
        {
            string text = "";
            byte[] a_ = new byte[26];
            byte[] array = new byte[8];
            byte[] array2 = new byte[]
            {
            2,
            5,
            4,
            13,
            3,
            84,
            11,
            4,
            87,
            3,
            86,
            3,
            80,
            7,
            83,
            3,
            0,
            4,
            83,
            94,
            7,
            84,
            4,
            0,
            1,
            83,
            3,
            84,
            6,
            83,
            5,
            80
            };
            uint[] array3 = new uint[]
            {
            288U,
            369U
            };
            b b = new b();
            Console.WriteLine("Welcome to my room, and please enjoy some tea by write what you want in this machine:");
            string text2 = Console.ReadLine();
            if (!b.B(text2))
            {
                //Thread.Sleep(1000000);
            }
            if (b.c(text2) != "yQXHyBvN3g/81gv51QXG1QTBxRr/yvXK1hC=")
            {
                Console.WriteLine("Oops");
                //Thread.Sleep(1000000);
            }
            Console.WriteLine("And,wait a second!");
            for (int i = 0; i < 100000; i++)
            {
                //Thread.Sleep(1000);
                //Console.WriteLine(i + 1);
                break;
            }
            a_ = Encoding.Default.GetBytes(text2);
            b.B(ref array3, a_);
            Console.WriteLine("Here is your tea, and flag!");
            text += array3[0].ToString("x2");
            text += array3[1].ToString("x2");
            array = Encoding.Default.GetBytes(text);
            Console.Write("flag{");
            for (int j = 0; j < 32; j++)
            {
                byte[] array4 = array2;
                int num = j;
                array4[num] ^= array[j % array.Length];
            }
            Console.Write(Encoding.Default.GetString(array2));
            Console.Write("}");
            Console.ReadLine();
        }
    }
}

输入,然后得到flag

image.png

flag{4645e180540ffa7a67cfa174cde105a2}
PS:其实这题可能能直接把flag输出出来,但我没试...flag出来了就行

replace

64位,无壳

image.png

这题一开始难点我预计错了...下次应该好好先把全部函数分析完先。在main可以看出是24位flag,然后sub_401550是验证输入是否为flag格式(即flag{xxxxxx})
image.png

sub_401AE7是假的加密函数,因为之后会在sub_401925再覆盖掉所需要验证的字符串
image.png

题外话:
把这个解出来之后是fakeflag,但其实出题人粗心了,就算这个题目是这个fakeflag,最后也不对,因为有一项是计算出来是f,但没在f前面加零,416f6b116549435c2c0f1143
image.png

再点进sub_401925函数,这里把IsDebuggerPresent hook了,下一次调用IsDebuggerPresent的时候会先调用sub_4015C3
image.png

加花了,去花
image.png

sub_4015C3开头把hook脱钩了,然后下面进行加密
image.png

加密后的byte_4080E0再和416f6b116549435c2c0f1143174339023d4d4c0f183e7828做比较
image.png

下面来分析一下加密流程,unk_404020是一个128位的数组,赋值给v0,v2[j] = v0[v2[j]]即换对照表,将对应的char值转成128位数组的 char值位置。for循环1到<=5,即换对照表五次
image.png

将换表完成的24个数据,分成六组数据,每一组中的每一位数据占八位bit,再用或运算拼一起,即一组数据为24+8=32bits。当中每一组数据当中的从左往右数前八位为flag[i],再数八位为flag[i+6],以此类推,循环六次。最后再将每一组合成的32bits用sprintf转成十六进制,即8个字符(两个字符占8bits,八个字符占32bits)
按照上述流程逆推即得flag,详细见如下脚本

enflag = "416f6b11 6549435c 2c0f1143 17433902 3d4d4c0f 183e7828"
#为了方便所以手动分成六组字符串,每组之间加空格

gen_dict = [
    0x80,0x65,0x2F,0x34,0x12,0x37,0x7D,0x40,0x26,0x16,
    0x4B,0x4D,0x55,0x43,0x5C,0x17,0x3F,0x69,0x79,0x53,
    0x18,0x02,0x06,0x61,0x27,0x08,0x49,0x4A,0x64,0x23,
    0x56,0x5B,0x6F,0x11,0x4F,0x14,0x04,0x1E,0x5E,0x2D,
    0x2A,0x32,0x2B,0x6C,0x74,0x09,0x6E,0x42,0x70,0x5A,
    0x71,0x1C,0x7B,0x2C,0x75,0x54,0x30,0x7E,0x5F,0x0E,
    0x01,0x46,0x1D,0x20,0x3C,0x66,0x6B,0x76,0x63,0x47,
    0x6A,0x29,0x25,0x4E,0x31,0x13,0x50,0x51,0x33,0x59,
    0x1A,0x5D,0x44,0x3E,0x28,0x0F,0x19,0x2E,0x05,0x62,
    0x4C,0x3A,0x21,0x45,0x1F,0x38,0x7F,0x57,0x3D,0x1B,
    0x3B,0x24,0x41,0x77,0x6D,0x7A,0x52,0x73,0x07,0x10,
    0x35,0x0A,0x0D,0x03,0x0B,0x48,0x67,0x15,0x78,0x0C,
    0x60,0x39,0x36,0x22,0x7C,0x58,0x72,0x68
]

flag = [0 for i in range(24)]
#将字符串转成十六进制数
data = [int(e,16) for e in enflag.split(" ")]

#把合成的数据分开,并保存到相应flag位置
for i in range(6):
    flag[i] = ((data[i] >> 24)&0xFF)
    flag[i+6] =  ((data[i] >> 16)&0xFF)
    flag[i+12] = ((data[i] >> 8)&0xFF)
    flag[i+18] = ((data[i])&0xFF)

#换对照表五次
flag = [gen_dict.index(f) for f in flag]
flag = [gen_dict.index(f) for f in flag]
flag = [gen_dict.index(f) for f in flag]
flag = [gen_dict.index(f) for f in flag]
flag = [chr(gen_dict.index(f)) for f in flag]

print("".join(flag))

得到flag{Sh1t_you_dec0d3_it},题目要求最后md5提交
最终输入4820904ccb9343f00fb7ddf8acc31e85提交

image.png

PS: 激动地就要猝死,最后半分钟成功提交flag

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇