首页
社区
课程
招聘
[原创] CTF签到题
2021-5-11 10:51 1665

[原创] CTF签到题

2021-5-11 10:51
1665

签到题 拜师学艺

目录

定位到Main函数

1

 

发现sub_401470这个函数是对后面的代码进行解密,执行完sub_401470这个函数后,将程序dump下来,我们就可以在IDA中F5看伪代码了

查看IDA伪代码

2

 

阅读上面代码我们知道Flag的长度为0xC, 形式为flag(xxx), 很明显sub_401050就是关键函数,我们来看下这个函数的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
unsigned char byte_403188[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
unsigned char szDstBuf[10000] = {};
 
unsigned char* sub_401050(unsigned char* szFlag, int nFlagLen)
{
    int v3; // edi
    int v4; // edx
    unsigned int v5; // esi
    int v7; // eax
    int nSum; // edi
    char v9; // al
    int v10; // edi
    unsigned char* v11; // [esp+Ch] [ebp-4h]
 
    v11 = szFlag;
    v3 = 0;
    v4 = 0;
    v5 = 0;
    if (!szFlag)
    {
        return 0;
    }
 
    for (int i = 0; i < nFlagLen; i++)
    {
        if (v5 >= 8187)
        {
            break;
        }
        v7 = *szFlag;
        ++v4;
        ++szFlag;
        nSum = v7 + v3;
        if (v4 == 3)
        {
            szDstBuf[v5] = byte_403188[nSum >> 18];
            szDstBuf[v5 + 1] = byte_403188[(nSum >> 12) & 0x3F];
            szDstBuf[v5 + 2] = byte_403188[(nSum >> 6) & 0x3F];
            szDstBuf[v5 + 3] = byte_403188[nSum & 0x3F];
 
            v3 = 0;
            v4 = 0;
            v5 += 4;
        }
        else
        {
            v3 = nSum << 8;
        }
 
    }
 
    szDstBuf[v5] = 0;
    return szDstBuf;
}

这个算法很简单,就是把我们输入的Flag分成3个字母为一组,将这3个字母进行移位相加存到nSum这个变量中,最后对nSum进行4次计算,得到4个下标值, 去byte_403188数组中取出4个字母.

 

Flag的长度为0xC, 3个字母一组,分为4组,每组可以在byte_403188数组中取出4个字母,最后将每组取出的字母进行拼接,若计算出来的字符串为"ZmxhZ3trYW54dWV9", 则说明Flag有效

 

假如我们输入的Flag为 flag{LuoHun}

fla g{L uoH un}
对应的十六进制 0x66 0x6C 0x61 0x67 0x7B 0x4C 0x75 0x6F 0x48 0x75 0x6E 0x7D
nSum 0x666c61 0x677B4C 0x756F48 0x756E7D
nSum >> 18 0x19 0x19 0x1d 0x1d
nSum >> 12) & 0x3F 0x26 0x37 0x16 0x16
(nSum >> 6) & 0x3F 0x31 0x2d 0x3d 0x39
nSum & 0x3F 0x21 0xc 0x8 0x3d
 

最后在byte_403188数组中取出的字符串为"ZmxhZ3tMdW9IdW59"

逆运算代码

知道了正向计算过程,我们来逆向计算下Flag吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
 
#define BYTEn(x, n)   (*((BYTE*)&(x)+n))
#define BYTE1(x)   BYTEn(x,  1)      
#define BYTE2(x)   BYTEn(x,  2)
 
unsigned char byte_403188[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
void SortFindIndex(int nCurrentIndex, char* szFind, int nFindLen, int* szFindIndex)
{
    for (int i = 0; i < nFindLen; i++)
    {
        if (byte_403188[nCurrentIndex] == szFind[i])
        {
            szFindIndex[i] = nCurrentIndex;
        }
    }
}
 
void LuoFind(char* szFind, int* szFindIndex, int nFindLen)
{
    int nSize = sizeof(byte_403188);
 
    int nCount = 0;
 
    for (int i = 0; i < nSize; i++)
    {
        if (byte_403188[i] == szFind[0] ||
            byte_403188[i] == szFind[1] ||
            byte_403188[i] == szFind[2] ||
            byte_403188[i] == szFind[3])
        {
            //对找到的下标, 按照szFind中的字母顺序进行排序
            SortFindIndex(i, szFind, nFindLen, szFindIndex);
 
            if (++nCount == nFindLen)
            {
                break;
            }
 
        }
    }
 
}
 
bool LuoCalcSum(int& nSum, int* szFindIndex)
{
    for (unsigned int i = 1; i < 0x99999999; i++)
    {
        if ((i >> 18) == szFindIndex[0]          &&
            ((i >> 12) & 0x3F) == szFindIndex[1] &&
            ((i >> 6) & 0x3F) ==  szFindIndex[2] &&
            (i & 0x3F) == szFindIndex[3])
        {
            nSum = i;
            return true;
        }
 
    }
 
    return false;
}
 
void PrintFlag(int nSum)
{
    printf("%c%c%c", BYTE2(nSum), BYTE1(nSum), nSum);
}
 
void LuoCalcFlag(char* szDstCmpStr, int nCmpStrLen)
{
    char* szFind = NULL;
    int szFindIndex[100] = {};
    int nSum = 0;
    bool nFlag = false;
 
    printf("szFlag: ");
    for (int i = 0; i < nCmpStrLen; i += 4)
    {
        szFind = &szDstCmpStr[i];
 
        //4个字母一组.查找在byte_403188数组中的下标
        LuoFind(szFind, szFindIndex, sizeof(szFind));
 
        //穷举爆破nSum的值
        nFlag = LuoCalcSum(nSum, szFindIndex);
 
        if (nFlag == true)
        {
            //打印flag
            PrintFlag(nSum);
        }
    }
    printf("\r\n");
}
 
int main()
{
   char szDstCmpStr[] = "ZmxhZ3trYW54dWV9";
   int nCmpStrLen = strlen(szDstCmpStr);
 
   //计算flag
   LuoCalcFlag(szDstCmpStr, nCmpStrLen);
 
    system("pause");
}

运行上述代码,即可计算出Flag

 

3


[培训]《安卓高级研修班(网课)》月薪三万计划

最后于 2021-5-11 10:52 被夏洛魂编辑 ,原因:
上传的附件:
收藏
点赞0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回