首页
社区
课程
招聘
[原创]2021MTCTF-Inject
2021-5-28 00:24 5814

[原创]2021MTCTF-Inject

2021-5-28 00:24
5814

Inject

这道题,我是真的无语,那有个点,卡了好久

 

没想到是猜出来的?????

 

详情请往下看

分析过程

1. check_key1_key2函数分析

拿到题目之后,解压得到一个Inject.exe和notepad2.exe

 

直接将Inject.exe拖入工具进行查壳,然后发现无壳直接拖入IDA进行分析

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
int check_key1_key2()
{
  unsigned __int64 v0; // r11
  double v1; // xmm0_8
  float chushu; // xmm0_4 float4个字节
  unsigned __int64 data; // r8
  __int64 count; // rcx
  unsigned __int64 v5; // r10
  __int64 count1; // rcx
  unsigned __int64 data1; // r9
  unsigned __int64 yushu; // rdx
  unsigned __int64 key2; // [rsp+20h] [rbp-18h] BYREF
 
  printf("Please input the key1 and key2:");
  scanf("%x %lld", &key1, &key2);
  v0 = key2;
  if ( (key2 & 0x8000000000000000ui64) != 0i64 )
    v1 = (double)(int)(key2 & 1 | (key2 >> 1)) + (double)(int)(key2 & 1 | (key2 >> 1));
  else
    v1 = (double)(int)key2;
  chushu = (double)(int)key1 / v1;              // 除法: key1 / key2
  HHHHHHHHHH = LODWORD(chushu);                 // 赋值给一个变量(这个变量之后会用来解密yyy文件的代码)
  if ( LODWORD(chushu) >= 0x75D05803ui64 )      // 必须<0x75D05803
    goto LABEL_14;
  data = 1i64;
  count = 8i64;
  v5 = LODWORD(chushu) % 0x75D05803ui64;        // v5 = (key1 / key2) % 0x75D05803
  do
  {
    data = v5 * data % 0x75D05803;              // 循环乘法,不就是次方吗,比赛脑子秀逗了?!
    --count;
  }
  while ( count );                              // data = pow(v5, 8) % 0x75D05803
  count1 = 2i64;
  data1 = 1i64;
  do
  {
    data1 = v5 * data1 % 0x75D05803;
    --count1;
  }
  while ( count1 );                             // data1 = pow(v5, 2) % 0x75D05803
  if ( (2 * (v5 % 0x75D05803) - data1 - 42 + data) % 0x75D05803 != 1 )// 关键的验证式子
    goto LABEL_14;
  yushu = key1 % key2;
  if ( yushu )
    v0 = sub_7FF6C0891280(key2, yushu);
  if ( v0 != 1 )
LABEL_14:
    exit(1);
  printf("You are right, let's to the next step.\n");
  return system("pause");
}

然后,稀里糊涂的就开始了爆破之旅(错误步骤啊,稍微看一下即可,也不是说错误,就只能爆出来一半,剩下一半爆不出来)

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
int main()
{
        unsigned int i = 0;
        for(i=0;i<0xFFFFFFFF;i++)
    {
        unsigned int data = 1;   // = (int)pow(i, 8) % 0x75D05803;
        //unsigned int data1;  // =(int)pow(i, 2) % 0x75D05803;
        int count = 8;
        do
        {
            data = i * data % 0x75D05803;              // 循环乘法,不就是次方吗,比赛脑子秀逗了?!
            --count;
        }while ( count );                              // data = pow(v5, 8) % 0x75D05803
 
        int count1 = 2;
        unsigned int data1 = 1;
        do
        {
            data1 = i * data1 % 0x75D05803;
            --count1;
        }while ( count1 );                             // data1 = pow(v5, 2) % 0x75D05803
 
        if((2 * (i % 0x75D05803) - data1 - 42 + data) % 0x75D05803 == 1)
        {
            printf("%x\n",i);
        }
    }
}

爆破出来两个满足的:

1
2
37e3e317
adb43b1a

然后重新动调将内存中那个HHHHHHHHHH变量和变量v5都设为37e3e317

 

然后验证只过了一个

 

最后的这里
图片描述

 

就会exit

2. create_file函数分析

图片描述

 

就是一些创建文件等操作:

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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
_BYTE *create_file()
{
  size_t v0; // r8
  void **ptr; // rbx
  .....
  memset(Filename, 0, 0x104ui64);
  GetModuleFileNameA(0i64, Filename, 0x104u);   // 第一个参数为NULL, 该函数返回该应用程序全路径
  v37 = 0i64;
  v38 = 15i64;
  LOBYTE(exename[0]) = 0;
  v0 = -1i64;
  do
    ++v0;
  while ( Filename[v0] );
  strncpy(exename, Filename, v0);
  ptr = exename;
  if ( v38 >= 16 )
    ptr = (void **)exename[0];
  if ( v37 )
  {
    v39[0] = 0i64;
    v39[1] = 0i64;
    v39[2] = 0i64;
    v39[3] = 0i64;
    v39[4] = 0i64;
    v40 = 0i64;
    v41 = 0;
    memset(v43, 0, sizeof(v43));
    v42 = 1;
    v2 = (void **)((char *)ptr + v37 - 1);
    if ( *((_BYTE *)v39 + *(unsigned __int8 *)v2) )
    {
LABEL_9:
      v3 = (_DWORD)v2 - (_DWORD)ptr;
      goto LABEL_11;
    }
    while ( v2 != ptr )
    {
      v2 = (void **)((char *)v2 - 1);
      if ( *((_BYTE *)v39 + *(unsigned __int8 *)v2) )
        goto LABEL_9;
    }
  }
  v3 = -1;
LABEL_11:
  Size[0] = 0i64;
  Size[1] = 15i64;
  LOBYTE(Block[0]) = 0;
  v4 = v3;
  v5 = v3;
  if ( v37 < v3 )
    v5 = v37;
  v6 = exename;                                 // E:\SYJ\COMPETITIONS\2021美团\inject
  if ( v38 >= 16 )
    v6 = (void **)exename[0];
  strncpy(Block, v6, v5);
  v7 = strcat_0(Block, "\\flag.txt", 9ui64);    // 拼接字符串
                                                // v7 = E:\SYJ\COMPETITIONS\2021美团\inject\Inject.exe\flag.txt
  txt_path = 0ui64;
  *(_OWORD *)FileName = *v7;
  txt_path = v7[1];
  *((_QWORD *)v7 + 2) = 0i64;
  *((_QWORD *)v7 + 3) = 15i64;
  *(_BYTE *)v7 = 0;
  if ( Size[1] >= 0x10 )
  {
    v8 = Block[0];
    if ( Size[1] + 1 >= 0x1000 )
    {
      v8 = (void *)*((_QWORD *)Block[0] - 1);
      if ( (unsigned __int64)(Block[0] - v8 - 8) > 0x1F )
        invalid_parameter_noinfo_noreturn();
    }
    j_j_free(v8);
  }
  Size[0] = 0i64;
  Size[1] = 15i64;
  LOBYTE(Block[0]) = 0;
  Src[2] = 0i64;
  v31 = 15i64;
  LOBYTE(Src[0]) = 0;
  if ( v37 < v4 )
    v4 = v37;
  v9 = exename;
  if ( v38 >= 0x10 )
    v9 = (void **)exename[0];
  strncpy(Src, v9, v4);
  notepad_path = strcat_0(Src, "\\notepad2.exe ", 0xEui64);// 拼接字符串
                                                // E:\SYJ\COMPETITIONS\2021美团\inject\notepad2.exe
  v29 = 0ui64;
  *(_OWORD *)v28 = *notepad_path;
  v29 = notepad_path[1];
  *((_QWORD *)notepad_path + 2) = 0i64;
  *((_QWORD *)notepad_path + 3) = 15i64;
  *(_BYTE *)notepad_path = 0;
  v11 = FileName;
  if ( *((_QWORD *)&txt_path + 1) >= 16ui64 )
    v11 = (char **)FileName[0];
  v12 = strcat_0(v28, v11, txt_path);
  *(_OWORD *)Block = *v12;
  *(_OWORD *)Size = v12[1];
  *((_QWORD *)v12 + 2) = 0i64;
  *((_QWORD *)v12 + 3) = 15i64;
  *(_BYTE *)v12 = 0;
  if ( *((_QWORD *)&v29 + 1) >= 0x10ui64 )
  {
    v13 = v28[0];
    if ( (unsigned __int64)(*((_QWORD *)&v29 + 1) + 1i64) >= 0x1000 )
    {
      v13 = (void *)*((_QWORD *)v28[0] - 1);
      if ( (unsigned __int64)(v28[0] - v13 - 8) > 0x1F )
        invalid_parameter_noinfo_noreturn();
    }
    j_j_free(v13);
  }
  *(_QWORD *)&v29 = 0i64;
  *((_QWORD *)&v29 + 1) = 15i64;
  LOBYTE(v28[0]) = 0;
  if ( v31 >= 0x10 )
  {
    v14 = Src[0];
    if ( v31 + 1 >= 0x1000 )
    {
      v14 = (void *)*((_QWORD *)Src[0] - 1);
      if ( (unsigned __int64)(Src[0] - v14 - 8) > 0x1F )
        invalid_parameter_noinfo_noreturn();
    }
    j_j_free(v14);
  }
  v15 = (const char *)FileName;
  if ( *((_QWORD *)&txt_path + 1) >= 16ui64 )
    v15 = FileName[0];
  fp = fopen(v15, "wb");
  fwrite("key3:", 1ui64, 5ui64, fp);            // E:\SYJ\COMPETITIONS\2021美团\inject\Inject.exe\flag.txt里面写入key3:这4个字符
  fclose(fp);
  v17 = Size[0];
  v18 = Size[0] + 1;
  if ( Size[0] == -1i64 )
    v18 = -1i64;
  v19 = malloc(v18);
  v20 = v19;
  v21 = Block;
  v22 = (char *)Block[0];
  v23 = Size[1];
  if ( Size[1] >= 0x10 )
    v21 = (void **)Block[0];
  memcpy(v19, v21, v17);
  v20[v17] = 0;
  if ( v23 >= 0x10 )
  {
    v24 = v22;
    if ( v23 + 1 >= 0x1000 )
    {
      v22 = (char *)*((_QWORD *)v22 - 1);
      if ( (unsigned __int64)(v24 - v22 - 8) > 0x1F )
        invalid_parameter_noinfo_noreturn();
    }
    j_j_free(v22);
  }
  if ( *((_QWORD *)&txt_path + 1) >= 0x10ui64 )
  {
    v25 = FileName[0];
    if ( (unsigned __int64)(*((_QWORD *)&txt_path + 1) + 1i64) >= 0x1000 )
    {
      v25 = (char *)*((_QWORD *)FileName[0] - 1);
      if ( (unsigned __int64)(FileName[0] - v25 - 8) > 0x1F )
        invalid_parameter_noinfo_noreturn();
    }
    j_j_free(v25);
  }
  *(_QWORD *)&txt_path = 0i64;
  *((_QWORD *)&txt_path + 1) = 15i64;
  LOBYTE(FileName[0]) = 0;
  if ( v38 >= 0x10 )
  {
    v26 = exename[0];
    if ( v38 + 1 >= 0x1000 )
    {
      v26 = (void *)*((_QWORD *)exename[0] - 1);
      if ( (unsigned __int64)(exename[0] - v26 - 8) > 0x1F )
        invalid_parameter_noinfo_noreturn();
    }
    j_j_free(v26);
  }
  return v20;                    // 逐渐查看赋值链,得到这个返回的是notepad2.exe的路径
                                 // v20 = v19
                                 // memcpy(v19, v21, v17)
                                 // v21 = Block
                                 // *(_OWORD *)Block = *v12
                                 // v12 = ...
}

最后的返回值就是notepad2.exe的全路径

3. write_code_to_yyy函数分析

图片描述

 

这里面其实就是像yyy中写入代码

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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
_BYTE *write_code_to_yyy()
{
 ....
  memset(Filename, 0, 0x104ui64);
  GetModuleFileNameA(0i64, Filename, 0x104u);   // 获取当前程序全路径
  v39 = 0i64;
  v40 = 15i64;
  LOBYTE(exename[0]) = 0;
  v0 = -1i64;
  do
    ++v0;
  while ( Filename[v0] );
  strncpy(exename, Filename, v0);
  v1 = exename;
  if ( v40 >= 16 )
    v1 = (void **)exename[0];
  if ( v39 )
  {
    v41[0] = 0i64;
    v41[1] = 0i64;
    v41[2] = 0i64;
    v41[3] = 0i64;
    v41[4] = 0i64;
    v42 = 0i64;
    v43 = 0;
    memset(v45, 0, sizeof(v45));
    v44 = 1;
    v2 = (void **)((char *)v1 + v39 - 1);
    if ( *((_BYTE *)v41 + *(unsigned __int8 *)v2) )
    {
LABEL_9:
      v3 = (_DWORD)v2 - (_DWORD)v1;
      goto LABEL_11;
    }
    while ( v2 != v1 )
    {
      v2 = (void **)((char *)v2 - 1);
      if ( *((_BYTE *)v41 + *(unsigned __int8 *)v2) )
        goto LABEL_9;
    }
  }
  v3 = -1;
LABEL_11:
  yyy_name[2] = 0i64;
  v35 = 15i64;
  LOBYTE(yyy_name[0]) = 0;
  v4 = v3;
  if ( v39 < v3 )
    v4 = v39;
  v5 = exename;
  if ( v40 >= 0x10 )
    v5 = (void **)exename[0];
  strncpy(yyy_name, v5, v4);
  v6 = strcat_0(yyy_name, "\\yyy.a", 6ui64);    // 拼接字符串之后:
                                                // E:\SYJ\COMPETITIONS\2021美团\inject\yyy.a
  *(_OWORD *)FileName = *v6;
  *(_OWORD *)Size = v6[1];
  *((_QWORD *)v6 + 2) = 0i64;
  *((_QWORD *)v6 + 3) = 15i64;
  *(_BYTE *)v6 = 0;
  if ( v35 >= 0x10 )
  {
    v7 = yyy_name[0];
    if ( v35 + 1 >= 0x1000 )
    {
      v7 = (void *)*((_QWORD *)yyy_name[0] - 1);
      if ( (unsigned __int64)(yyy_name[0] - v7 - 8) > 0x1F )
        invalid_parameter_noinfo_noreturn();
    }
    j_j_free(v7);
  }
  v8 = (const char *)FileName;
  if ( Size[1] >= 0x10 )
    v8 = FileName[0];
  fp = fopen(v8, "wb");                         // 打开文件E:\SYJ\COMPETITIONS\2021美团\inject\yyy.a
  v10 = FindResourceA(0i64, (LPCSTR)101, "code");// 查找CODE类型的资源
  v11 = SizeofResource(0i64, v10);
  v12 = LoadResource(0i64, v10);
  v13 = LockResource(v12);
  fwrite(v13, 1ui64, v11, fp);                  // 查找资源查找到之后(resource(101))直接写入E:\SYJ\COMPETITIONS\2021美团\inject\yyy.a
  v14 = FindResourceA(0i64, (LPCSTR)102, "code");
  v15 = SizeofResource(0i64, v14);
  v16 = LoadResource(0i64, v14);                // 装载指定资源到全局储存器
  ptr = LockResource(v16);                      // 锁定资源并得到资源在内存中的第一个字节的指针
  v18 = malloc((unsigned int)v15);
  count = 0;
  if ( (_DWORD)v15 )                            // 使用查找到的资源和之前我们在第一个函数里面key1 / key2得到的数据
  {                                             // 解密资源后存储到v18中
    v20 = v18;
    v21 = ptr - v18;                            // (resource(102)) ^ (key的8字节)
                                                // (以为key之前是8个字节的double)
    do
    {
      *v20 = v20[v21] ^ *((_BYTE *)&HHHHHHHHHH + (count++ & 7));// 异或8次进行解密
      ++v20;
    }
    while ( count < (unsigned int)v15 );
  }
  fwrite(v18, 1ui64, v15, fp);                  // 将v18中解密得到的数据,写入E:\SYJ\COMPETITIONS\2021美团\inject\yyy.a
  v22 = FindResourceA(0i64, (LPCSTR)103, "code");
  v23 = SizeofResource(0i64, v22);              // 看见这种FindResource函数,直接使用ResourceHacker工具可以查看
  v24 = LoadResource(0i64, v22);
  v25 = LockResource(v24);
  fwrite(v25, 1ui64, v23, fp);                  // 查找资源查找到之后又直接将(resource(103))写入E:\SYJ\COMPETITIONS\2021美团\inject\yyy.a
  fclose(fp);
  v26 = Size[0] + 1;
  if ( Size[0] == -1i64 )
    v26 = -1i64;
  v27 = malloc(v26);
  v28 = v27;
  v29 = FileName;
  if ( Size[1] >= 0x10 )
    v29 = (char **)FileName[0];
  v30 = Size[0];
  memcpy(v27, v29, Size[0]);
  v28[v30] = 0;
  if ( Size[1] >= 0x10 )
  {
    v31 = FileName[0];
    if ( Size[1] + 1 >= 0x1000 )
    {
      v31 = (char *)*((_QWORD *)FileName[0] - 1);
      if ( (unsigned __int64)(FileName[0] - v31 - 8) > 0x1F )
        invalid_parameter_noinfo_noreturn();
    }
    j_j_free(v31);
  }
  Size[0] = 0i64;
  Size[1] = 15i64;
  LOBYTE(FileName[0]) = 0;
  if ( v40 >= 0x10 )
  {
    v32 = exename[0];
    if ( v40 + 1 >= 0x1000 )
    {
      v32 = (void *)*((_QWORD *)exename[0] - 1);
      if ( (unsigned __int64)(exename[0] - v32 - 8) > 0x1F )
        invalid_parameter_noinfo_noreturn();
    }
    j_j_free(v32);
  }
  return v28;
}

用Resource Hacker直接查看他调用FindResource这个API获取的资源

 

它其实关键的加密就那一段:

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
v8 = (const char *)FileName;
 if ( Size[1] >= 0x10 )
   v8 = FileName[0];
 fp = fopen(v8, "wb");                         // 打开文件E:\SYJ\COMPETITIONS\2021美团\inject\yyy.a
 v10 = FindResourceA(0i64, (LPCSTR)101, "code");// 查找CODE类型的资源
 v11 = SizeofResource(0i64, v10);
 v12 = LoadResource(0i64, v10);
 v13 = LockResource(v12);
 fwrite(v13, 1ui64, v11, fp);                  // 查找资源查找到之后(resource(101))直接写入E:\SYJ\COMPETITIONS\2021美团\inject\yyy.a
 v14 = FindResourceA(0i64, (LPCSTR)102, "code");
 v15 = SizeofResource(0i64, v14);
 v16 = LoadResource(0i64, v14);                // 装载指定资源到全局储存器
 ptr = LockResource(v16);                      // 锁定资源并得到资源在内存中的第一个字节的指针
 v18 = malloc((unsigned int)v15);
 count = 0;
 if ( (_DWORD)v15 )                            // 使用查找到的资源和之前我们在第一个函数里面key1 / key2得到的数据
 {                                             // 解密资源后存储到v18中
   v20 = v18;
   v21 = ptr - v18;                            // (resource(102)) ^ (key的8字节)
                                               // (以为key之前是8个字节的double)
   do
   {
     *v20 = v20[v21] ^ *((_BYTE *)&HHHHHHHHHH + (count++ & 7));// 异或8次进行解密
     ++v20;
   }
   while ( count < (unsigned int)v15 );
 }
 fwrite(v18, 1ui64, v15, fp);                  // 将v18中解密得到的数据,写入E:\SYJ\COMPETITIONS\2021美团\inject\yyy.a
 v22 = FindResourceA(0i64, (LPCSTR)103, "code");
 v23 = SizeofResource(0i64, v22);              // 看见这种FindResource函数,直接使用ResourceHacker工具可以查看
 v24 = LoadResource(0i64, v22);
 v25 = LockResource(v24);
 fwrite(v25, 1ui64, v23, fp);                  // 查找资源查找到之后又直接将(resource(103))写入E:\SYJ\COMPETITIONS\2021美团\inject\yyy.a
 fclose(fp);

先向yyy.a写入resource101,然后将resource102和我们那个HHHHHHHH变量进行异或,总共8次,每次取HHHHHHHH变量的一个字节进行异或,然后向yyy.a写入异或之后的数据,然后再将resource103资源写入yyy.a
图片描述

 

然后,离谱的地方就来了,"因为resource103是直接写入yyy.a的,说明可以合理的猜测resouce102和我们的那个HHH....单字节异或之后的值也是0,就说明那个HHH...变量,也就是我们key1 / key2得到的那个变量,就是resource102的最后8字节"
图片描述

 

17 E3 E3 37 17 E3 E3 00

4. 重新调试

将HHHHHHH变量直接内存中修改为上面得到的那个变量就可以过掉所有的检测

 

在write_code_to_yyy函数下方直接下个断点,F9之后可以看到文件夹中生成了yyy.a和flag.txt

 

这些代码就是创建远程线程将我们的yyy.a(其实就是一个dll)注入进notepad2.exe

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if ( !CreateProcessA(0i64, v3, 0i64, 0i64, 0, 0, 0i64, 0i64, &StartupInfo, &ProcessInformation) )
  {
    printf("Create Fali!\n");
    exit(1);
  }
  v4 = OpenProcess(0x1FFFFFu, 0, ProcessInformation.dwProcessId);
  v5 = write_code_to_yyy();
  v6 = -1i64;
  v7 = v5;
  v8 = -1i64;
  do
    ++v8;
  while ( v5[v8] );
  v9 = VirtualAllocEx(v4, 0i64, v8 + 1, 0x1000u, 4u);
  v10 = v9;
  while ( v7[++v6] != 0 )
    ;
  WriteProcessMemory(v4, v9, v7, v6 + 1, 0i64);
  v12 = GetModuleHandleA("kernel32.dll");
  LoadLibraryA = (HMODULE (__stdcall *)(LPCSTR))GetProcAddress(v12, "LoadLibraryA");
  v14 = CreateRemoteThread(v4, 0i64, 0i64, (LPTHREAD_START_ROUTINE)LoadLibraryA, v10, 0, 0i64);
  WaitForSingleObject(v14, 0xFFFFFFFF);
  CloseHandle(v14);
  CloseHandle(v4);

5.分析生成的yyy.a

查壳发现有upx壳,利用工具FUPX脱一下就行

 

然后拖入IDA进行分析

 

创建线程钩取了WriteFile函数

 

DLLMain:

1
2
3
4
5
6
7
8
9
10
11
BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
  HANDLE v3; // rax
 
  if ( fdwReason == 1 )                         // 如果调用原因是DLL_PROCESS_ATTACH,进程调用DLL
  {
    v3 = CreateThread(0i64, 0i64, (LPTHREAD_START_ROUTINE)ThreadProc, 0i64, 0, 0i64);// 创建线程
    CloseHandle(v3);
  }
  return 1;
}

进入ThreadProc

 

(这里就钩取的关键函数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
__int64 __fastcall ThreadProc(LPVOID lpThreadParameter)
{
  HMODULE kernel32_base_addr; // rax
  BOOL (__stdcall *WriteFile)(HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED); // rax
  char *v3; // rbx
  DWORD flOldProtect; // [rsp+20h] [rbp-18h] BYREF
 
  MessageBoxA(
    0i64,
    "Now input key3 in notepad like `key3:abcdef`.\nSave it.Reopen the file, you will get the flag.\n",
    "Message",
    0);
  kernel32_base_addr = GetModuleHandleA("kernel32.dll");
  WriteFile = (BOOL (__stdcall *)(HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED))GetProcAddress(
                                                                                   kernel32_base_addr,
                                                                                   "WriteFile");
  v3 = (char *)WriteFile + *(unsigned int *)((char *)WriteFile + 2);
  fucn = *(__int64 (__fastcall **)(_QWORD, _QWORD, _QWORD, _QWORD, _QWORD))(v3 + 6);
  VirtualProtect(v3 + 6, 8ui64, 4u, &flOldProtect);
  check_key3_addr = (__int64)check_key3;
  *(_QWORD *)(v3 + 6) = check_key3;             // 赋值成我们的check_key3的函数地址
  VirtualProtect(v3 + 6, 8ui64, flOldProtect, &flOldProtect);
  return 0i64;
}

将WriteFile函数直接改成了我们的check_key3函数

 

而且这里还有提示,"Now input key3 in notepad like key3:abcdef.\nSave it.Reopen the file, you will get the flag.\n",

6. check_key3函数分析

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
__int64 __fastcall check_key3(__int64 a1, char *real_key3, __int64 a3, __int64 a4, __int64 a5)
{
  unsigned int v6; // edi
  char *flag; // rax
  int v10; // er9
  char *adr; // r11
  const char *flag_; // r10
  int i; // er8
  unsigned __int64 j; // rdx
  __int64 v15; // rbx
  char temp_char; // al
  int v17; // eax
  char v18; // cl
  __int64 v19; // r8
  const char *v20; // rdx
 
  v6 = a3;
  if ( a5 )
  {
    fucn(a1, real_key3, a3, a4, a5);
  }
  else
  {
    if ( strstr(real_key3, "key3:") == real_key3 )// 加个验证
    {
      sscanf(real_key3, "key3:%x", &save_area);
      *(float *)&data = (double)save_area * 1.818989403545856e-12 * 1.818989403545856e-12 * 0.00000002980232238769531;
      if ( check() )                            // 检测key3之后,才会运行生成flag的代码
      {
        flag = (char *)malloc(0x2Bui64);
        v10 = 5;
        adr = &byte_180003280;
        flag_ = flag;
        i = 0;
        j = 5i64;
        qmemcpy(flag, "flag{", 5);
        v15 = 0x10842000i64;
        do
        {
          if ( j <= 0x1C && _bittest64(&v15, j) )// 分隔符
          {
            temp_char = '-';
          }
          else
          {
            v17 = i % 8;
            v18 = *adr;
            ++i;
            ++adr;
            temp_char = v18 ^ *((_BYTE *)&data + v17);
          }
          flag_[j] = temp_char;
          ++v10;
          ++j;
        }
        while ( i < 32 );
        v19 = 42i64;
        v20 = flag_;
        *(_WORD *)&flag_[v10] = '}';
      }
      else
      {
        v19 = 0x17i64;
        v20 = "your key isn't correct.";
      }
      fucn(a1, v20, v19, a4, 0i64);
      exit(0);
    }
    fucn(a1, real_key3, v6, a4, 0i64);
  }
  return 1i64;
}

7. 爆破key3

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
bool check(unsigned input)
{
  unsigned long long v0; // r8
  unsigned long long v1; // r9
  unsigned long long v2; // rcx
  unsigned long long v3; // r11
  unsigned long long v4; // r10
  unsigned long long v5; // rcx
  unsigned long long v6; // rbx
 
  v0 = 1;
  v1 = 1;
  v2 = 4;
  v3 = input % 0x6440DB83u;
  do
  {
    v1 = v3 * v1 % 0x6440DB83;
    --v2;
  }
  while ( v2 );
  v4 = 1;
  v5 = 3;
  do
  {
    v4 = v3 * v4 % 0x6440DB83;
    --v5;
  }
  while ( v5 );
  v6 = 2;
  do
  {
    v0 = v3 * v0 % 0x6440DB83;
    --v6;
  }
  while ( v6 );
  return (2 * v0 - v4 + v1 - 32) % 0x6440DB83 == 1;
}
 
int main()
{
    for(unsigned int i=0;i<0xffffffff;i++)
    {
        if(check(i))
        {
            printf("%u\n",i);
            break;
        }
    }
    //爆破得到值为386499290
    unsigned int input_=0;
    for(unsigned int i=0;i<0xffffffff;i++)
    {
        *(float *)&input_ = (double)i
                       * 1.818989403545856e-12
                       * 1.818989403545856e-12
                       * 0.00000002980232238769531;
        if((input_)==386499290)
        {
            printf("爆破得到我们的key3为:%x",i);
            break;
        }
    }
    //爆破得到我们的key3为: 44c16d
    return 0;
}

8. 得到flag

然后在notepad2.exe中的key3:之后输入44c16d即可

 

然后保存后退出,再重新点开flag.txt,就可以得到flag

 

图片描述
flag{5ae282a6-db32-11ea-b30a-00d861d79b00}


[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

最后于 2021-5-28 00:28 被SYJ-Re编辑 ,原因:
上传的附件:
收藏
点赞2
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回