# Bài 2025
## 1.Hidden ( warm-up)
- Chạy thử file exe này trên linux, thì thấy flag luôn

~~mỡ đấy mà húp~~, đây là flag fake, như cái tên của challenge thì flag bài này đã bị giấu
- LOAD IDA

Thấy 1 hàm khá đáng ngờ , tên là `printflag`

- Bên trong nó thì có cho ta 1 mảng `v2` với 3 phần tử với hậu tó uLL ( `unsign long long` ) là
+ 0xFDE7F1F3CBDBCBC3
+ 0xFBD7FCAFE6E9EBD7
+ 0xF5FEB2EDE5D7EDED
- Mấu chốt ở đây là công thức
```=cpp
v1 = *((char *)v2 + i);
LOBYTE(v1) = *((_BYTE *)v2 + i) ^ 0x88;
result = printf_0("%c", v1);
```
-`v1 = *((char *)v2 + i)` : đọc giá trị của byte thứ `i` trong mảng `v2`
-` LOBYTE(v1) = *((_BYTE *)v2 + i) ^ 0x88;` : Lệnh `*((_BYTE *)v2 + i)` coi số lớn kia là 1 mảng byte, và nó duy chuyển từng byte theo giá trị `i`, sau đó `xor` với 0x88.
→ Như vậy thì mình cần chuyển 3 số lớn trên thành từng byte, và vì đây là 1 chương trình trên window nên máy sẽ đọc theo kiểu `little endian`
```
C3 CB DB CB F3 F1 E7 FD
D7 EB E9 E6 AF FC D7 FB
ED ED D7 E5 ED B2 FE F5
```
Python :
```=python
data = [
[0xC3, 0xCB, 0xDB, 0xCB, 0xF3, 0xF1, 0xE7, 0xFD],
[0xD7, 0xEB, 0xE9, 0xE6, 0xAF, 0xFC, 0xD7, 0xFB],
[0xED, 0xED, 0xD7, 0xE5, 0xED, 0xB2, 0xFE, 0xF5]
]
flag = ""
for arr in data:
for b in arr:
flag += chr(b^0x88)
```
<details>
<summary>FLAG</summary>
KCSC{you_can't_see_me:v}
</details>
## 2.Easy Rev

- Có vẻ như bài này muốn ta tìm 1 cái gì nhập vào.
LOAD IDA :
```=cpp
int __fastcall main(int argc, const char **argv, const char **envp)
{
FILE *v3; // rax
size_t v4; // rax
__int64 v5; // rdx
__int64 v6; // rcx
__int64 v7; // r8
__int64 v8; // r9
__int64 v9; // rax
unsigned int v10; // edx
unsigned int v11; // r8d
unsigned __int64 v12; // rax
__m128 v13; // xmm0
__m128 v14; // xmm1
__int64 v15; // rcx
__int64 v16; // rax
char *v17; // rcx
char Buffer[16]; // [rsp+20h] [rbp-68h] BYREF
__int128 v20; // [rsp+30h] [rbp-58h] BYREF
int v21; // [rsp+40h] [rbp-48h]
_OWORD v22[2]; // [rsp+48h] [rbp-40h] BYREF
__int64 v23; // [rsp+68h] [rbp-20h]
int v24; // [rsp+70h] [rbp-18h]
char v25; // [rsp+74h] [rbp-14h]
LOBYTE(v21) = 0;
v23 = 0LL;
*(_OWORD *)Buffer = 0LL;
v24 = 0;
v20 = 0LL;
v25 = 0;
memset(v22, 0, sizeof(v22));
sub_140001010("Enter flag: ");
v3 = _acrt_iob_func(0);
fgets(Buffer, 33, v3);
v4 = strcspn(Buffer, "\n");
if ( v4 >= 0x21 )
sub_140001558(
v6,
v5,
v7,
v8,
*(_QWORD *)Buffer,
*(_QWORD *)&Buffer[8],
v20,
*((_QWORD *)&v20 + 1),
v21,
*(_QWORD *)&v22[0],
*((_QWORD *)&v22[0] + 1));
Buffer[v4] = 0;
v9 = -1LL;
do
++v9;
while ( Buffer[v9] );
if ( v9 == 32 )
{
sub_140001070(Buffer, v22);
v10 = 0;
v11 = 0;
v12 = 0LL;
do
{
v13 = (__m128)_mm_loadu_si128((const __m128i *)&byte_140005078[v12]);
v11 += 32;
v14 = (__m128)_mm_loadu_si128((const __m128i *)&v22[v12 / 0x10]);
v12 += 32LL;
*(__m128 *)&dword_140005058[v12 / 4] = _mm_xor_ps(v14, v13);
*(__m128 *)&qword_140005068[v12 / 8] = _mm_xor_ps(
(__m128)_mm_loadu_si128((const __m128i *)((char *)&v20 + v12 + 8)),
(__m128)_mm_loadu_si128((const __m128i *)&qword_140005068[v12 / 8]));
}
while ( v11 < 0x20 );
v15 = (int)v11;
if ( (unsigned __int64)(int)v11 < 0x2C )
{
do
{
++v11;
byte_140005078[v15] ^= *((_BYTE *)v22 + v15);
++v15;
}
while ( v11 < 0x2C );
}
v16 = 0LL;
while ( byte_1400032F0[v16] == byte_140005078[v16] )
{
++v10;
++v16;
if ( v10 >= 0x2C )
{
v17 = "Correct!\n";
goto LABEL_13;
}
}
}
v17 = "Incorrect!\n";
LABEL_13:
sub_140001010(v17);
return 0;
}
```
`NHỜ CHATGPT tóm tắt cách code này hoạt động `
<div style="background-color: #DFF2FF; color: #0B3D91; padding:10px; border-radius:5px;">
1. Nhập flag tối đa 32 ký tự.
2. Kiểm tra độ dài = 32 ký tự.
3. Xử lý flag (hàm sub_140001070).
4. XOR flag đã xử lý với dữ liệu reference.
5. So sánh kết quả với dữ liệu chuẩn.
6. In "Correct!" nếu trùng khớp, "Incorrect!" nếu không.
</div>

- Xử lí input

- Mã hóa input

- Tại đây thì `xor` và `so sánh`

- Đây là xor_byte

- Đây là chuỗi so sánh
```=python
byte78 = [
0x92, 0xA1, 0x27, 0xE0, 0x37, 0xCA, 0x70, 0x7E, 0xE6, 0xBE,
0x33, 0x1D, 0x5D, 0xFE, 0x29, 0x93, 0xB6, 0x66, 0xF9, 0x02,
0x6A, 0x74, 0x0D, 0xDF, 0xD6, 0xEC, 0x5A, 0x71, 0xC8, 0xA3,
0xFD, 0x84, 0xC5, 0x13, 0x1E, 0x87, 0xC7, 0x52, 0x50, 0x55,
0x01, 0x16, 0xFD, 0xCF
]
bytef0 = [
0xC1, 0x91, 0x69, 0xB4, 0x66, 0xF9, 0x04, 0x12, 0xB2, 0xD3,
0x7D, 0x6B, 0x0F, 0xB9, 0x7F, 0xF5, 0xD2, 0x1C, 0xBF, 0x32,
0x0B, 0x32, 0x34, 0x9C, 0x98, 0xA4, 0x14, 0x37, 0x86, 0xC9,
0xAF, 0xE2, 0x9C, 0x46, 0x2B, 0xEC, 0x9F, 0x63, 0x38, 0x23,
0x54, 0x78, 0xCD, 0xF2
]
flag = ""
for i in range(len(bytef0)):
flag+= (chr(byte78[i]^bytef0[i]))
print(flag)
```
KẾT QUẢ:
- Đây là chuỗi input sau khi bị sub
`S0NTQ3tlTmNvRGVfdzF0aF9CNHNFNjRfYU5kX1hvUn0=`
Chuỗi chỉ gồm các ký tự `[A–Z]` `[a–z]` `[0–9]` `+/=.`
Có thể nó là `Base64`

<details>
<summary>FLAG</summary>
KCSC{eNcoDe_w1th_B4sE64_aNd_XoR}
</details>
## 3.Waiterfall
```=c
int __fastcall main(int argc, const char **argv, const char **envp)
{
unsigned __int8 v3; // di
unsigned int v4; // esi
__int64 v5; // r14
__int64 v6; // rbp
__int64 v7; // r15
__int64 v8; // r12
__int64 v9; // r13
char v10; // al
__int64 v11; // rdx
char *v12; // rcx
__int64 v14; // rcx
__int64 v15; // rcx
__int64 v16; // rcx
__int64 v17; // rcx
__int64 v18; // rcx
__int64 v19; // rcx
__int64 v20; // rcx
_BYTE v21[80]; // [rsp+20h] [rbp-88h] BYREF
v3 = 0;
sub_7FF702711020("Show your skill :))\n");
v4 = 0;
v5 = 0x1000008020020LL;
v6 = 0LL;
v7 = 0x60010020000100LL;
v8 = 0x100020080408000LL;
v9 = 0x844000044000LL;
do
{
sub_7FF702711080("%c", &v21[v4]);
v10 = v21[v6];
if ( (unsigned __int8)v10 <= 0x42u )
{
LABEL_190:
Sleep(0x2710u);
goto LABEL_191;
}
switch ( v10 )
{
case 'C':
v3 += ((v4 - 1) & 0xFFFFFFFD) == 0;
break;
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
goto LABEL_190;
case 'K':
v3 += v4 == 0;
break;
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
goto LABEL_190;
case 'S':
v3 += v4 == 2;
break;
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
case '[':
case '\\':
case ']':
case '^':
goto LABEL_190;
case '_':
if ( v4 <= 0x31 )
{
v20 = 0x2101004011000LL;
if ( _bittest64(&v20, v4) )
++v3;
}
break;
case '`':
goto LABEL_190;
case 'a':
if ( v4 <= 0x34 )
{
v19 = 0x10000210000040LL;
if ( _bittest64(&v19, v4) )
++v3;
}
break;
case 'b':
goto LABEL_190;
case 'c':
v3 += v4 == 37;
break;
case 'd':
v3 += v4 == 20;
break;
case 'e':
if ( v4 <= 0x37 )
{
v18 = 0x80000040200000LL;
if ( _bittest64(&v18, v4) )
++v3;
}
break;
case 'f':
if ( v4 <= 0x32 )
{
v17 = 0x4200100802000LL;
if ( _bittest64(&v17, v4) )
++v3;
}
break;
case 'g':
if ( v4 == 11 || v4 == 60 )
++v3;
break;
case 'h':
goto LABEL_190;
case 'i':
if ( v4 <= 0x3A )
{
v16 = 0x400000000000280LL;
if ( _bittest64(&v16, v4) )
++v3;
}
break;
case 'j':
case 'k':
goto LABEL_190;
case 'l':
if ( v4 <= 0x33 )
{
v15 = 0x8480C02000000LL;
if ( _bittest64(&v15, v4) )
++v3;
}
break;
case 'm':
goto LABEL_190;
case 'n':
if ( v4 <= 0x3B )
{
v14 = 0xA00008000080400LL;
if ( _bittest64(&v14, v4) )
++v3;
}
break;
case 'o':
if ( v4 <= 0x2F && _bittest64(&v9, v4) )
++v3;
break;
case 'p':
case 'q':
goto LABEL_190;
case 'r':
if ( v4 <= 0x38 && _bittest64(&v8, v4) )
++v3;
break;
case 's':
goto LABEL_190;
case 't':
if ( v4 <= 0x36 && _bittest64(&v7, v4) )
++v3;
break;
case 'u':
v3 += v4 == 24;
break;
case 'v':
goto LABEL_190;
case 'w':
if ( v4 <= 0x30 && _bittest64(&v5, v4) )
++v3;
break;
case 'x':
case 'y':
case 'z':
goto LABEL_190;
case '{':
v3 += v4 == 4;
break;
case '|':
goto LABEL_190;
case '}':
v3 += v4 == 61;
break;
default:
if ( v10 > 125
|| v10 == (char)0x80
|| v10 == -127
|| v10 == -126
|| v10 == -125
|| v10 == -124
|| v10 == -123
|| v10 == -122
|| v10 == -121
|| v10 == -120
|| v10 == -119
|| v10 == -118
|| v10 == -117
|| v10 == -116
|| v10 == -115
|| v10 == -114
|| v10 == -113
|| v10 == -112
|| v10 == -111
|| v10 == -110
|| v10 == -109
|| v10 == -108
|| v10 == -107
|| v10 == -106
|| v10 == -105
|| v10 == -104
|| v10 == -103
|| v10 == -102
|| v10 == -101
|| v10 == -100
|| v10 == -99
|| v10 == -98
|| v10 == -97
|| v10 == -96
|| v10 == -95
|| v10 == -94
|| v10 == -93
|| v10 == -92
|| v10 == -91
|| v10 == -90
|| v10 == -89
|| v10 == -88
|| v10 == -87
|| v10 == -86
|| v10 == -85
|| v10 == -84
|| v10 == -83
|| v10 == -82
|| v10 == -81
|| v10 == -80
|| v10 == -79
|| v10 == -78
|| v10 == -77
|| v10 == -76
|| v10 == -75
|| v10 == -74
|| v10 == -73
|| v10 == -72
|| v10 == -71
|| v10 == -70
|| v10 == -69
|| v10 == -68
|| v10 == -67
|| v10 == -66
|| v10 == -65
|| v10 == -64
|| v10 == -63
|| v10 == -62
|| v10 == -61
|| v10 == -60
|| v10 == -59
|| v10 == -58
|| v10 == -57
|| v10 == -56
|| v10 == -55
|| v10 == -54
|| v10 == -53
|| v10 == -52
|| v10 == -51
|| v10 == -50
|| v10 == -49
|| v10 == -48
|| v10 == -47
|| v10 == -46
|| v10 == -45
|| v10 == -44
|| v10 == -43
|| v10 == -42
|| v10 == -41
|| v10 == -40
|| v10 == -39
|| v10 == -38
|| v10 == -37
|| v10 == -36
|| v10 == -35
|| v10 == -34
|| v10 == -33
|| v10 == -32
|| v10 == -31
|| v10 == -30
|| v10 == -29
|| v10 == -28
|| v10 == -27
|| v10 == -26
|| v10 == -25
|| v10 == -24
|| v10 == -23
|| v10 == -22
|| v10 == -21
|| v10 == -20
|| v10 == -19
|| v10 == -18
|| v10 == -17
|| v10 == -16
|| v10 == -15
|| v10 == -14
|| v10 == -13
|| v10 == -12
|| v10 == -11
|| v10 == -10
|| v10 == -9
|| v10 == -8
|| v10 == -7
|| v10 == -6
|| v10 == -5
|| v10 == -4
|| v10 == -3
|| v10 == -2 )
{
goto LABEL_190;
}
break;
}
LABEL_191:
++v4;
++v6;
}
while ( (int)v4 < 62 );
v11 = -1LL;
do
++v11;
while ( v21[v11] );
v12 = "Correct\n";
if ( v3 != v11 )
v12 = ":((";
sub_7FF702711020(v12);
return 0;
}
```
Ở bài này, đọc lệnh ở hàm main thì em hiểu được là chương trình sẽ check kí tự ta nhập vào, nếu nhập sai kí tự sẽ dẫn đến nhãn `LABEL_190` , sau đó sẽ bị sleep vài giây.
Biết được là vậy, nên em sẽ liệt ra loại trừ bớt các kí tự dẫn tới Label.
**TA CÒN CÁC KÍ TỰ AN TOÀN NHƯ SAU :**
$$\texttt{K, C, S, \{, \}, w, a, i, t, n, g, _, f, o, r, d, e, u, l, c}$$
- Công việc còn lại chính là sắp xếp các kí tự này lại thành FLAG
- Trước mặt thì ta xếp được chữ `KCSC{...}`
- Phần bếp trong thì được sắp xếp bằng câu lệnh `_bittest64`
Thật sự thì em không biệt câu lệnh bittest này hoạt động như nào. Và em đã lên mạng tìm hiểu thì có thể hiểu đơn giản đây là 1 hàm kiểm tra và tùy chọn bit thứ `n` trong dãy số nguyên 64bit. Và đối với bài này khi kết hợp với toán tử `&` cùng với câu lệnh khác, nó sẽ giúp sắp xếp được kí tự trong chương trình thành flag
VÍ DỤ:
```=c
case 'a':
if ( v4 <= 0x34 )
{
v19 = 0x10000210000040LL;
if ( _bittest64(&v19, v4) )
++v3;
```
Trước tiên thi kiểm tra các kí tự phải <=0x34, tức là `<= 52`
Cho v19 = 0x10000210000040, suy ra mã nhị phân nó là:
`0001 0000 0000 0000 0000 0010 0001 0000 0000 0000 0000 0000 0100 0000`
Hàm trả về 1 ở vị trí bit = 1, tức là các vị trí `6, 28, 33, 56`
Kết hợp với điều kiện ban đầu vậy là `a` sẽ xuất hiện ở vị trí `6, 28, 33`
> Nếu không được dùng AI hỗ trợ viết code thì chắc em sẽ ngồi viết giấy dò từng kí tự, câu trúc lệnh này lạ quá em hỏng biết cách tự viết code python tìm flag.
CODE python:
```=python
V5 = 0x1000008020020
V7 = 0x60010020000100
V8 = 0x100020080408000
V9 = 0x844000044000
V14 = 0xA00008000080400
V15 = 0x8480C02000000
V16 = 0x400000000000280
V17 = 0x4200100802000
V18 = 0x80000040200000
V19 = 0x10000210000040
V20 = 0x2101004011000
def bittest64(mask, index):
return bool((mask >> index) & 1)
flag_chars = [''] * 62
for v4 in range(62):
char_match = None
if v4 == 1 or v4 == 3:
char_match = 'C'
if v4 == 0:
char_match = 'K'
if v4 == 2:
char_match = 'S'
if v4 <= 0x31 and bittest64(V20, v4):
char_match = '_'
if v4 <= 0x34 and bittest64(V19, v4):
char_match = 'a'
if v4 == 37:
char_match = 'c'
if v4 == 20:
pass
if v4 <= 0x37 and bittest64(V18, v4):
char_match = 'e'
if v4 <= 0x32 and bittest64(V17, v4):
char_match = 'f'
if v4 == 11 or v4 == 60:
char_match = 'g'
if v4 <= 0x3A and bittest64(V16, v4):
char_match = 'i'
if v4 <= 0x33 and bittest64(V15, v4):
char_match = 'l'
if v4 <= 0x3B and bittest64(V14, v4):
char_match = 'n'
if v4 <= 0x2F and bittest64(V9, v4):
char_match = 'o'
if v4 <= 0x38 and bittest64(V8, v4):
char_match = 'r'
if v4 <= 0x36 and bittest64(V7, v4):
char_match = 't'
if v4 == 24:
char_match = 'u'
if v4 <= 0x30 and bittest64(V5, v4):
char_match = 'w'
if v4 == 4:
char_match = '{'
if v4 == 61:
char_match = '}'
if char_match is None:
flag_chars[v4] = 'w'
else:
flag_chars[v4] = char_match
# In Flag hoàn chỉnh
final_flag = "".join(flag_chars)
print(final_flag)
```
<details>
<summary>FLAG</summary>
KCSC{waiting_for_wonwerful_waterfall_control_flow_flatterning}
</details>
## 4. SpyRoom

- Sử dụng Detect It Easy để kiểm tra xem chương trình viết bằng gì, thì thấy viết bằng C#, và IDA không decompile được C#
- Như tên của challenge `SPY`ROOM, sử dụng `dnSPY` để mở chương trình.
```c
using System;
using System.Linq;
namespace TestEzDotNET
{
// Token: 0x02000002 RID: 2
internal class Program
{
// Token: 0x06000001 RID: 1 RVA: 0x00002050 File Offset: 0x00000250
private static void Main()
{
Console.Write("Enter Something: ");
char[] array = Console.ReadLine().ToCharArray();
int num = array.Length;
char[] array2 = array.Take(num / 4).ToArray<char>();
char[] array3 = array.Skip(num / 4).Take(num / 4).ToArray<char>();
char[] array4 = array.Skip(2 * num / 4).Take(num / 4).ToArray<char>();
char[] array5 = array.Skip(3 * num / 4).ToArray<char>();
array2 = Program.Xor(array2, array3);
array3 = Program.Xor(array3, array4);
array4 = Program.Xor(array4, array5);
array5 = Program.Xor(array5, array2);
char[] array6 = array2.Concat(array3).Concat(array4).Concat(array5).ToArray<char>();
string text = "https://www.youtube.com/watch?v=L8XbI9aJOXk";
array6 = Program.Xor(array6, text.ToCharArray());
byte[] source = new byte[]
{
85,
122,
105,
71,
17,
94,
71,
24,
114,
78,
107,
11,
108,
106,
107,
113,
121,
51,
91,
117,
86,
110,
100,
18,
124,
104,
71,
66,
123,
3,
111,
99,
74,
107,
69,
77,
111,
2,
120,
125,
83,
99,
62,
99,
109,
76,
119,
111,
59,
32,
1,
93,
69,
117,
84,
106,
73,
85,
112,
66,
114,
92,
61,
80,
80,
104,
111,
72,
98,
28,
88,
94,
27,
120,
15,
76,
15,
67,
86,
117,
81,
108,
18,
37,
34,
101,
104,
109,
23,
30,
62,
78,
88,
10,
2,
63,
43,
72,
102,
38,
76,
23,
34,
62,
21,
97,
1,
97
};
if (!array6.SequenceEqual((from e in source
select (char)e).ToArray<char>()))
{
Console.WriteLine("Wrong!!");
return;
}
Console.WriteLine("Decode It!!");
}
// Token: 0x06000002 RID: 2 RVA: 0x00002178 File Offset: 0x00000378
private static char[] Xor(char[] a, char[] b)
{
int num = Math.Max(a.Length, b.Length);
char[] array = new char[num];
for (int i = 0; i < num; i++)
{
if (a.Length >= b.Length)
{
array[i] = (a[i] ^ b[i % b.Length]);
}
else
{
array[i] = (a[i % a.Length] ^ b[i]);
}
}
return array;
}
}
}
```

- Với những câu lệnh đầu tiên
+ Chương trình nhận tất cả input , đưa chung vào mảng `array`
+ Sau đó từ `array` sẽ chia đều vào `array 2 3 4 5`, bằng cách chia `arrray` làm 4 rồi đưa vào từng mảng mới.
```=c#
array2 = input[0 : num/4]
array3 = input[num/4 : 2*num/4]
array4 = input[2*num/4 : 3*num/4]
array5 = input[3*num/4 : end]
```

- Tiếp theo
- Sau khi đã chia được các mảng, tiến hành `XOR` chép các mảng
```=p
array2 = array2 XOR array3
array3 = array3 XOR array4
array4 = array4 XOR array5
array5 = array5 XOR array2 # (lúc này array2 là cái array2 XOR array3)
array6 sẽ bằng các array 2 3 4 5 kết nối lại với nhau
Sau cùng thì array6 sẽ XOR với chuỗi URL youtube :
"https://www.youtube.com/watch?v=L8XbI9aJOXk"
```
- Tiếp đến phần source:
- byte[] source = { 85, 122, 105, 71, 17, 94, ... }; → Có tổng cộng 108 kí tự, tương đương với mảng `array6` cũng có 108 kí tự, vậy là mỗi mảng `array 2 3 4 5` sẽ có 27 kí tự

- Nếu như các kí tự của mảng `array6` tương đương với mảng `source` thì in dòng `Decode It!!` và ngược lại in `Wrong!!`
```py
source = [
85,122,105,71,17,94,71,24,114,78,107,11,108,106,107,113,121,51,91,117,86,110,
100,18,124,104,71,66,123,3,111,99,74,107,69,77,111,2,120,125,83,99,62,99,109,
76,119,111,59,32,1,93,69,117,84,106,73,85,112,66,114,92,61,80,80,104,111,72,
98,28,88,94,27,120,15,76,15,67,86,117,81,108,18,37,34,101,104,109,23,30,62,
78,88,10,2,63,43,72,102,38,76,23,34,62,21,97,1,97
]
youtube = "https://www.youtube.com/watch?v=L8XbI9aJOXk"
def xor_arrays(a, b):
L = max(len(a), len(b))
return [a[i% len(a)] ^ b[i% len(b)] for i in range(L)]
array6 =xor_arrays(source, list(map(ord,youtube)))
q = len(array6) //4
a2, a3, a4, a5 = array6[:q], array6[q:2*q], array6[2*q:3*q], array6[3*q:]
orig5 = xor_arrays(a5, a2)
orig4 = xor_arrays(a4, orig5)
orig3 = xor_arrays(a3, orig4)
orig2 = xor_arrays(a2, orig3)
original_input = orig2 + orig3 + orig4 + orig5
result = ''.join(map(chr, original_input))
print(result)
```

`Decode It!!`

<details>
<summary>FLAG</summary>
KCSC{Easy_Encryption_With_DotNET_Program:3}
</details>
## 5.EzRev
IDA :
```c
int __fastcall main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rdx
unsigned int *v4; // r8
int i; // [rsp+20h] [rbp-28h]
__int64 v7; // [rsp+28h] [rbp-20h]
sub_140001200("Enter Something: ", argv, envp);
sub_1400012D0("%s", byte_1400047A8);
if ( (unsigned int)sub_140001100(byte_1400047A8) == -1982483102 )
{
v7 = -1i64;
do
++v7;
while ( byte_1400047A8[v7] );
if ( v7 == 40 )
{
sub_140001000(byte_1400047A8);
dword_1400047A0 = 1;
for ( i = 0; i < 40; ++i )
{
v4 = dword_140004700;
v3 = dword_140004700[i];
if ( dword_140004080[i] != (_DWORD)v3 )
dword_1400047A0 = 0;
}
}
}
if ( dword_1400047A0 )
sub_140001200("Excellent!! Here is your flag: KCSC{%s}", byte_1400047A8);
else
sub_140001200("You're chicken!!!", v3, v4);
return 0;
}
```
Phân tích lệnh

- Với câu lệnh này, nhận input lưu vào`byte_1400047A8` sau đó gọi hàm checksum xem có bằng `-1982483102` hay không

- Đếm số kí tự của `byte_1400047A8` coi có bằng 40 hay không, đến bằng thì tiếp tục chương trình.
- `sub_140001000(byte_1400047A8);` → Gọi 1 hàm biến đổi dữ liệu input
- `dword_140004700` → Mảng sau khi đã biến đổi với sub_140001000
- Tiếp đến duyệt từng kí tự, so sánh với mảng cố định `dword_140004080`, nếu chuẩn hết thì in flag.
GIỜ THÌ ĐÀO VÀO CÁC HÀM VÀ MẢNG
- Hàm checksum đầu tiên
```c
__int64 __fastcall sub_140001100(__int64 a1)
{
unsigned int v2; // [rsp+0h] [rbp-28h]
unsigned int i; // [rsp+4h] [rbp-24h]
__int64 v4; // [rsp+10h] [rbp-18h]
v2 = -2128831035;
v4 = -1i64;
do
++v4;
while ( *(_BYTE *)(a1 + v4) );
for ( i = 0; i < (unsigned int)v4; ++i )
v2 = 16777619 * (*(char *)(a1 + (int)i) ^ v2);
return v2;
}
```
- Hàm biến đổi input:
```c
__int64 __fastcall sub_140001000(__int64 a1)
{
__int64 result; // rax
unsigned int v2; // [rsp+0h] [rbp-38h]
unsigned int i; // [rsp+4h] [rbp-34h]
int j; // [rsp+8h] [rbp-30h]
int v5; // [rsp+Ch] [rbp-2Ch]
int v6; // [rsp+10h] [rbp-28h]
__int64 v7; // [rsp+18h] [rbp-20h]
v7 = -1i64;
do
++v7;
while ( *(_BYTE *)(a1 + v7) );
for ( i = 0; ; ++i )
{
result = (unsigned int)v7;
if ( i >= (unsigned int)v7 )
break;
v5 = 4;
v6 = 6;
v2 = *(unsigned __int8 *)(a1 + (int)i);
for ( j = 0; j < 5; ++j )
{
v2 ^= __ROL4__(v2, v5) ^ __ROR4__(v2, v6);
v5 *= 2;
v6 *= 2;
}
dword_140004700[i] = v2;
}
return result;
}
```
- Mảng cố định kiểm tra :

Code python lấy flag : (**em dùng gemini hỗ trợ , các lệnh và công thức trên lạ quá nên không thể tự viết nổi**)
```c
TARGET_DATA = [
0xF30C0330, 0x340DDE9D, 0x750D9AC9, 0x391FBC2A, 0x9F16AF5B,
0xE6180661, 0x6C1AAC6B, 0x340DDE9D, 0xB60D5635, 0x9F16AF5B,
0xA3195364, 0x681BBD3A, 0xF30C0330, 0xA3195364, 0xAB1B71C6,
0xF30C0330, 0xF21D5274, 0x9F16AF5B, 0xE6180661, 0x300CCFCC,
0xF21D5274, 0x9F16AF5B, 0xAB1B71C6, 0xA3195364, 0x750D9AC9,
0xA3195364, 0x9F16AF5B, 0xF21D5274, 0xF30C0330, 0xA3195364,
0xF21D5274, 0x351C8FD9, 0x710C8B98, 0xF70D1261, 0x2D1AE83F,
0xF30C0330, 0xEE1A24C3, 0xF70D1261, 0x6108CEDC, 0x6108CEDC
]
def rol4(value, shift):
shift &= 0x1F # Chỉ lấy 5 bit cuối (shift % 32)
return ((value << shift) | (value >> (32 - shift))) & 0xFFFFFFFF
def ror4(value, shift):
shift &= 0x1F
return ((value >> shift) | (value << (32 - shift))) & 0xFFFFFFFF
def transform_char(char_byte):
v2 = char_byte & 0xFF # Bắt đầu với 8 bit đầu vào
v5 = 4
v6 = 6
for _ in range(5):
v2 ^= rol4(v2, v5) ^ ror4(v2, v6)
v5 *= 2
v6 *= 2
return v2 & 0xFFFFFFFF
decryption_map = {}
for byte_val in range(256):
transformed_val = transform_char(byte_val)
decryption_map[transformed_val] = byte_val
flag_bytes = []
for target_val in TARGET_DATA:
if target_val in decryption_map:
flag_bytes.append(decryption_map[target_val])
else:
flag_bytes.append(ord('?'))
flag_component = "".join(chr(b) for b in flag_bytes)
final_flag = f"KCSC{{{flag_component}}}"
print(final_flag)
```
<details>
<summary>FLAG</summary>
KCSC{345y_fl46_ch3ck3r_f0r_kc5c_r3cru17m3n7!!}
</details>
# 2024
## TUNG QUEN ( warm up)
**~~chắc chắn đây không phải warmup, bài gì khó vcl, mò sml toàn mấy cái lạ lạ, hơn 6 tiếng ngồi làm không được gì luônnnn~~**
```c
int __fastcall main(int argc, const char **argv, const char **envp)
{
__time32_t v3; // eax
__int64 i; // rbx
HANDLE FileW; // rdi
int FileSize; // ebp
__int64 v7; // rbx
void *v8; // rsi
int v9; // r8d
_BYTE *v10; // rdx
int v11; // eax
DWORD NumberOfBytesRead; // [rsp+40h] [rbp-28h] BYREF
__int128 v14; // [rsp+48h] [rbp-20h]
v14 = 0LL;
v3 = time32(0LL);
srand(v3);
NumberOfBytesRead = 0;
for ( i = 0LL; i < 16; ++i )
*((_BYTE *)&v14 + i) = rand();
BYTE12(v14) = dword_140005088;
BYTE13(v14) = dword_140005080;
BYTE14(v14) = dword_14000508C;
HIBYTE(v14) = dword_140005084;
FileW = CreateFileW(FileName, 0xC0000000, 3u, 0LL, 3u, 0x80u, 0LL);
if ( FileW == (HANDLE)-1LL )
sub_140001010(aCannotOpenFile);
FileSize = GetFileSize(FileW, 0LL);
v7 = FileSize;
v8 = malloc(FileSize);
if ( !v8 )
{
CloseHandle(FileW);
sub_140001010(aFileIsEmpty);
}
ReadFile(FileW, v8, FileSize, &NumberOfBytesRead, 0LL);
v9 = 0;
if ( FileSize > 0 )
{
v10 = v8;
do
{
v11 = v9 % 16;
++v9;
*v10++ ^= *((_BYTE *)&v14 + v11);
--v7;
}
while ( v7 );
}
sub_140001010(aHayGiupBenjLol);
SetFilePointer(FileW, 0, 0LL, 0);
WriteFile(FileW, v8, FileSize, &NumberOfBytesRead, 0LL);
CloseHandle(FileW);
sub_140001010(aHoacGui200kVao);
sub_140001010(aNoiDungChuyenK);
sub_140001010(aNoteSaiCuPhapL);
system(Command);
return 0;
}
```
### Kiến thức kì lạ trước (srand và rand)
- `rand()`: Hàm rand là hàm sinh ra 1 số tự nhiên ngẫu nhiên từ 0 đến RAND_MAX, trong đó RAND_MAX là 1 hằng số có giá trị là 32767.
- `srand()`: Là 1 hàm seed dành cho `rand()`, khi dùng `srand` trước khi dùng `rand`, nó sẽ tạo ra những chuỗi số ngẫu nhiên khác ( với `srand(x) | x > 1`), seed này giống như là 1 công thức cho hàm `rand` để tạo ra 1 chuỗi ngẫu nhiên khác bình thường.
### Phân tích chương trình

- `__int128 v14;` được khai báo là 1 khối dữ liệu có 128bit <=> 16 byte
→ v14 là mảng có 16 kí tự
- `v3 = time32(0);
srand(v3);
` Chương trình lấy thời gian thực, seed rand() lúc chạy.
```c
for(i = 0; i < 16; i++)
*((BYTE*)&v14 + i) = rand();
```
- Với vòng lặp này mỗi lần chạy rand sinh ra 15bit, gán vào BYTE 8 bit thấp (`key[0..15] = rand() & 0xFF`)
+`(BYTE*)&v14 → ép v14 thành con trỏ đến từng byte`
+`+ i → trỏ đến byte thứ i trong 16 byte`
+`*((...) ) = rand(); → gán byte đó giá trị rand() & 0xFF`
- các key[12 13 14 15] của mảng `v14` được chỉnh sửa thành các dữ liệu cố định
→ 12 byte đầu: thay đổi mỗi lần chạy
→ 4 byte cuối: giá trị cố định, không thay đổi

- Tiếp tục nào

- Chương trình đọc file

và file đó là file .txt challenge cho sẵn. `v8` sẽ chứa buffer nội dung file
```c
v10 = v8;
v11 = v9 % 16;
*v10++ ^= *((BYTE*)&v14 + v11);
```
`v8` : Chứa buffer
`v10`: Gán buffer vào, xong thêm con trỏ để trỏ vào từng dữ liệu trong buffer
`v11 = v9 % 16`: v9 cứ tăng dần, %16 để giúp lặp key theo chu kì 16 byte, khi ấy v11 chạy từ 0 đến 16 rồi lặp lặp lại 0 -> 16...
- Cuối cùng là XOR từng giá trị của buffer với mảng key theo [i]
Kiểu vậy nè ↓
new[0] = file[0] ^ key[0]
new[1] = file[1] ^ key[1]
new[2] = file[2] ^ key[2]
- Tiếp tục nào

Câu lệnh mật nết nhất ở đây
```c
SetFilePointer(FileW, 0);
WriteFile(FileW, v8, FileSize);
```
Nó ghi đè hết dữ liệu mã hóa đó vào file txt ban đầu, do đó nếu như lúc tải challenge về, giải xem và `RUN` nó thử, thì các dữ liệu hex của mình ban đầu sẽ bị mã hóa hết, khi ấy việc dịch ngược lại sẽ vô cùng khó khăn
Và vì key = rand(time) nên cũng không thể chạy chương trình lại để nó tự trả về mã hex ban đầu trong file txt được.
### Giải
- Đầu tiên là không run chương trình.
- Với format của flag là : `KCSC{` thì có thể đoán rằng các byte đầu là `0x4b, 0x43, 0x53, 0x43, 0x7b`
- Giờ việc cần làm là tìm `seed` sao cho các byte cuối giá trị random của nó = `file[i] ^ KCSC{[i]`

- Dùng cyberchef để xem mã hex từng kí tự trong file .txt đó, ta đã có phần `[file]`
- Và điều gì sẽ xảy ra nếu ta RUN chương trình khiến nó ghi đè dữ liệu mã hóa lên file txt này ????

- Nó sẽ lộn xộn hết như này, và vì nó mã hóa theo `time` nên dịch ngược nó hơi bất khả thi.
Tiếp tục có :
`[file] ^ [16key random] = [flag]`
Tìm seed để cho các mã hex trong file ^ với 16key random đó ra các từ đầu là KCSC{
Cũng tính sẵn luôn là XOR 5 kí tự đầu của file và flag là : `0xbf, 0xf5, 0x27, 0x04, 0x43`
```c
#include <iostream>
#include <cstdlib>
using namespace std;
int file[101] = {
0xf4, 0xb6, 0x74, 0x47, 0x38, 0x1a, 0xae, 0x65, 0xd4, 0x82,
0xa5, 0xbb, 0xea, 0x9f, 0xd0, 0x87, 0x9f, 0x97, 0x48, 0x6d,
0x63, 0x06, 0xa9, 0x65, 0x9a, 0xc3, 0xae, 0xbe, 0xea, 0x8a,
0xd6, 0x9a, 0xde, 0xd5, 0x55, 0x6b, 0x2a, 0x54, 0xb2, 0x65,
0xd7, 0x82, 0xa5, 0xbb, 0xea, 0x92, 0xdf, 0x82, 0x9f, 0x99,
0x48, 0x6d, 0x63, 0x15, 0xa8, 0x64, 0x9a, 0xc1, 0xa8, 0xa3,
0xab, 0xde, 0xca, 0x9a, 0xd1, 0x92, 0x07, 0x60, 0x22, 0x19,
0xe6, 0x62, 0xd5, 0xcb, 0xe0, 0xb7, 0xa4, 0x96, 0x9e, 0x96,
0xda, 0x80, 0x07, 0x69, 0x2c, 0x00, 0xe6, 0x6d, 0xd3, 0x82,
0xb4, 0xbe, 0xaf, 0xde, 0xd0, 0x8e, 0xc6, 0xd4, 0x06, 0x79
};
int flag[6] = { 0x4b, 0x43, 0x53, 0x43, 0x7b };
int seed[6] = { 0xbf, 0xf5, 0x27, 0x04, 0x43 };
int main(){
for (unsigned int i = 0; i < 0xFFFFFFFF; i++) {
srand(i);
bool ok = true;
for (int j = 0; j < 5; j++) {
int tmp = rand() & 0xFFl;
if (tmp != seed[j]) {
ok = false;
break;
}
}
if (ok) {
cout << i << endl;
break;
}
}
return 0;
}
```
SEED : `13973678`
Giờ có seed rồi, ra tìm lại 12 key random còn thiếu, và thêm vào 4 key cố định để giải flag
```c
#include <iostream>
#include <cstdlib>
using namespace std;
int file[100] = {
0xf4, 0xb6, 0x74, 0x47, 0x38, 0x1a, 0xae, 0x65, 0xd4, 0x82,
0xa5, 0xbb, 0xea, 0x9f, 0xd0, 0x87, 0x9f, 0x97, 0x48, 0x6d,
0x63, 0x06, 0xa9, 0x65, 0x9a, 0xc3, 0xae, 0xbe, 0xea, 0x8a,
0xd6, 0x9a, 0xde, 0xd5, 0x55, 0x6b, 0x2a, 0x54, 0xb2, 0x65,
0xd7, 0x82, 0xa5, 0xbb, 0xea, 0x92, 0xdf, 0x82, 0x9f, 0x99,
0x48, 0x6d, 0x63, 0x15, 0xa8, 0x64, 0x9a, 0xc1, 0xa8, 0xa3,
0xab, 0xde, 0xca, 0x9a, 0xd1, 0x92, 0x07, 0x60, 0x22, 0x19,
0xe6, 0x62, 0xd5, 0xcb, 0xe0, 0xb7, 0xa4, 0x96, 0x9e, 0x96,
0xda, 0x80, 0x07, 0x69, 0x2c, 0x00, 0xe6, 0x6d, 0xd3, 0x82,
0xb4, 0xbe, 0xaf, 0xde, 0xd0, 0x8e, 0xc6, 0xd4, 0x06, 0x79
};
int main(){
srand(13973678);
int a[16];
for (int i = 0; i < 12; i++) {
int tmp = rand();
a[i] = tmp & 0xFF;
}
a[12] = 0xCA;
a[13] = 0xFE;
a[14] = 0xBE;
a[15] = 0xEF;
for (int i = 0; i < 100; i++) {
char flag = file[i] ^ a[i % 16];
cout << flag;
}
return 0;
}
```
<details>
<summary>FLAG</summary>
KCSC{nhin em anh boi roi anh thua roi tim em lam loi anh chua tung dam noi anh yeu mot ai the nay!!}
</details>