Bài dễ thì mình làm chậm mà bài khó thì không làm được :((
Do mình làm bài chưa được tốt nên sẽ cố gắng viết WU chi tiết và đầy đủ ý nhất
# REVERSE
## HIDDEN

mở ida dễ dàng thấy flag

submit thử thì báo incorrect, rõ ràng là fakeflag
vào functions thấy hàm printFlag khả nghi

Xem mã giả ta dễ dàng thấy đây chỉ là mã hóa xor từng byte của v2 với \x88

bài này warmup nên có thể giải nhanh bằng cách debug và nhảy RIP đến hàm printFlag

Flag: ~~KCSC{you_can't_see_me:v}~~

## easyre

chạy thử:

pseudo code:
```C=
int __cdecl sub_7FF78B081280(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]
__int128 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 = 0i64;
*(_OWORD *)Buffer = 0i64;
v24 = 0;
v20 = 0i64;
v25 = 0;
memset(v22, 0, sizeof(v22));
sub_7FF78B081010("Enter flag: ");
v3 = _acrt_iob_func(0);
fgets(Buffer, 33, v3);
v4 = strcspn(Buffer, "\n");
if ( v4 >= 0x21 )
{
sub_7FF78B081558(
v6,
v5,
v7,
v8,
*(_QWORD *)Buffer,
*(_QWORD *)&Buffer[8],
v20,
*((_QWORD *)&v20 + 1),
v21,
*(_QWORD *)&v22[0],
*((_QWORD *)&v22[0] + 1));
JUMPOUT(0x7FF78B08141Ei64);
}
Buffer[v4] = 0;
v9 = -1i64;
do
++v9;
while ( Buffer[v9] );
if ( v9 == 32 )
{
sub_7FF78B081070(Buffer, v22);
v10 = 0;
v11 = 0;
v12 = 0i64;
do
{
v13 = (__m128)_mm_loadu_si128((const __m128i *)&byte_7FF78B085078[v12]);
v11 += 32;
v14 = (__m128)_mm_loadu_si128((const __m128i *)&v22[v12 / 0x10]);
v12 += 32i64;
*(__m128 *)&dword_7FF78B085058[v12 / 4] = _mm_xor_ps(v14, v13);
*(__m128 *)&qword_7FF78B085068[v12 / 8] = _mm_xor_ps(
(__m128)_mm_loadu_si128((const __m128i *)((char *)&v20 + v12 + 8)),
(__m128)_mm_loadu_si128((const __m128i *)&qword_7FF78B085068[v12 / 8]));
}
while ( v11 < 0x20 );
v15 = (int)v11;
if ( (unsigned __int64)(int)v11 < 0x2C )
{
do
{
++v11;
byte_7FF78B085078[v15] ^= *((_BYTE *)v22 + v15);
++v15;
}
while ( v11 < 0x2C );
}
v16 = 0i64;
while ( byte_7FF78B0832F0[v16] == byte_7FF78B085078[v16] )
{
++v10;
++v16;
if ( v10 >= 0x2C )
{
v17 = "Correct!\n";
goto LABEL_13;
}
}
}
v17 = "Incorrect!\n";
LABEL_13:
sub_7FF78B081010(v17);
return 0;
}
```
xem qua ta có thể thấy chương trình gọi một số hàm mã hóa và cuối cùng là check để kiểm tra flag có đúng không

tuy code khá dài tuy nhiên ta có thể chú ý một số hàm mã hóa chính như sau
lần 1:

chương trình kiểm tra xem đầu vào mà ta nhập có phải là 32 ký tự hay không
nếu đúng thì sẽ gọi hàm ```sub_7FF7EEA81070``` để mã hóa
nội dung hàm khá dài và khó nhìn tuy nhiên ta có thể check output để xem hàm làm gì với input
output:


ta có thể dễ dàng nhận ra đây là mã hóa base64 của input ```aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa``` mà ta đã nhập vào trước đó
lần 2:

xor từng bytes của ```v18``` (output của base64 trước đó) với từng bytes của ```byte_7FF6E4DF5078``` và lưu trữ kết quả luôn vào ```byte_7FF6E4DF5078```
cuối cùng là check: ```byte_7FF6E4DF5078``` với ```byte_7FF6E4DF32F0```

nếu tất cả các bytes ```byte_7FF6E4DF5078``` và ```byte_7FF6E4DF32F0``` đều giống nhau thì báo ```Correct!``` nếu không thì báo ```Incorrect!```
Tổng kết:
\- nhận vào chuỗi 32 ký tự
\- mã hóa base64
\- xor với ```byte_7FF6E4DF5078```
\- kiểm tra
Ta dễ dàng viết script decrypt:
```python=
import base64
byte_7FF6E4DF32F0=[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]
byte_7FF6E4DF5078=[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]
a=''
for i in range(len(byte_7FF6E4DF5078)):
a+=chr(byte_7FF6E4DF5078[i]^byte_7FF6E4DF32F0[i])
p=base64.b64decode(a.encode())
print(p.decode())
#KCSC{eNcoDe_w1th_B4sE64_aNd_XoR}
```
Flag: ~~KCSC{eNcoDe_w1th_B4sE64_aNd_XoR}~~
## Spy Room

đây là 1 bài dotnet đơn giản, không có gì phức tạp, chủ yếu là kiểm tra khả năng xài dnspy và cryptography cơ bản
mở dnspy:

bài flagchecker gọi khá nhiều hàm xor
ta có thể dùng GPT gen chương trình decode :\(\(
```python=
def xor(a, b):
num = max(len(a), len(b))
result = []
for i in range(num):
if len(a) >= len(b):
result.append(chr(ord(a[i]) ^ ord(b[i % len(b)])))
else:
result.append(chr(ord(a[i % len(a)]) ^ ord(b[i])))
return result
def reverse_xor(source, url):
source_chars = [chr(e) for e in source]
array6 = xor(source_chars, list(url))
num = len(array6)
array2 = array6[:num // 4]
array3 = array6[num // 4:num // 2]
array4 = array6[num // 2:3 * num // 4]
array5 = array6[3 * num // 4:]
array5 = xor(array5, array2)
array4 = xor(array4, array5)
array3 = xor(array3, array4)
array2 = xor(array2, array3)
decoded_array = array2 + array3 + array4 + array5
return ''.join(decoded_array)
def main():
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
]
url = "https://www.youtube.com/watch?v=L8XbI9aJOXk"
decoded_text = reverse_xor(source, url)
print(decoded_text)
if __name__ == "__main__":
main()
#VXpCT1ZGRXpkRVpaV0U0MVdEQldkVmt6U2pWalNGSndZakkxWmxZeWJEQmhSamxGWWpOU1QxSldVbVpWU0VwMldqTkthR0pVYjNwbVVUMDk=
```
output là chuỗi đã bị mã hóa base64 nhiều lần

Flag : ~~KCSC{Easy_Encryption_With_DotNET_Program:3}~~
## EzRev

Pseudocode IDA:
```C=
int __cdecl 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 sơ qua thì đây có thể là 1 bài flagchecker với một số hàm mã hóa cơ bản
lần 1:

chương trình nhận vào input và kiểm tra 1 điều kiện gì đấy

qua kiểm tra thì đây có thể là một loại hash nào đấy
vì không thể dịch ngược được và không ảnh hưởng quá nhiều đến chương trình nên mình sẽ patch luôn tại đây để bỏ qua bước kiểm tra điều kiện này

lần 2:

đếm số phần tử có trong ```byte_7FF64BE347A8``` (là input ta nhập vào) và kiểm tra xem có đủ 40 ký tự không
gọi hàm ```sub_7FF64BE31000``` để mã hóa

hàm ```sub_7FF64BE31000``` lấy từng bytes của input rồi xor với các phép toán dịch bit ROR, ROL nhiều lần rồi lưu các giá trị đó vào ```dword_7FF64BE34700```
Cuối cùng là kiểm tra từng phần tử (dword) trong mảng ```dword_7FF64BE34700``` và ```dword_7FF64BE34080``` với nhau:

Tổng kết:
\- kiểm tra hash (bỏ qua)
\- mã hóa qua hàm ```sub_7FF64BE31000```
\- kiểm tra
do mã hóa từng bytes một nên mình sẽ bruteforce luôn để tiết kiệm thời gian dịch ngược
Script solve:
```python=
def _rol(val, bits, bit_size=32):
return (val << bits % bit_size) & (2 ** bit_size - 1) | ((val & (2 ** bit_size - 1)) >> (bit_size - (bits % bit_size)))
def _ror(val, bits, bit_size=32):
return ((val & (2 ** bit_size - 1)) >> bits % bit_size) | (val << (bit_size - (bits % bit_size)) & (2 ** bit_size - 1))
def sub_7FF765091000(a1):
for i in range(len(a1)):
v2 = a1[i]
v5 = 4
v6 = 6
for j in range(5):
v2 ^= _rol(v2, v5) ^ _ror(v2, v6)
v5 *= 2
v6 *= 2
return (v2)
enc=[
0x0F30C0330, 0x340DDE9D, 0x750D9AC9, 0x391FBC2A, 0x9F16AF5B, 0x0E6180661,
0x6C1AAC6B, 0x340DDE9D, 0x0B60D5635, 0x9F16AF5B, 0x0A3195364, 0x681BBD3A,
0x0F30C0330, 0x0A3195364, 0x0AB1B71C6, 0x0F30C0330, 0x0F21D5274, 0x9F16AF5B,
0x0E6180661, 0x300CCFCC, 0x0F21D5274, 0x9F16AF5B, 0x0AB1B71C6, 0x0A3195364,
0x750D9AC9, 0x0A3195364, 0x9F16AF5B, 0x0F21D5274, 0x0F30C0330, 0x0A3195364,
0x0F21D5274, 0x351C8FD9, 0x710C8B98, 0x0F70D1261, 0x2D1AE83F, 0x0F30C0330,
0x0EE1A24C3, 0x0F70D1261, 0x6108CEDC, 0x6108CEDC
]
flag=''
for e in enc:
for i in range(33,127):
a=sub_7FF765091000((flag+chr(i)).encode())
if a==e:
flag=flag+chr(i)
print(flag)
break
#345y_fl46_ch3ck3r_f0r_kc5c_r3cru17m3n7!!
```
Mình có tham khảo script chuyển ROR,ROL sang python tại: https://github.com/tandasat/scripts_for_RE/blob/master/rotate.py
Flag: ~~KCSC{345y_fl46_ch3ck3r_f0r_kc5c_r3cru17m3n7!!}~~
Thông thường mình sẽ không quá để ý việc dịch ngược hay chuyển code sang python cho những bài flagchecker như này mà sẽ hay xài gdb để bruteforce nhanh flag.
Tuy nhiên lần này gdb không decompile được nên mình đã không thể xài lại trick cũ, đây cũng là bài học cho mình để thay đổi tư duy làm bài và nghiên cứu nghiêm túc hơn trong tương lai!
có thể tham khảo 1 số bài mình đã giải bằng gdb tại: https://hackmd.io/@robertowen/rkXtc16N1l
## Reverse me

Pseudocode (khá dễ nhìn):
```C=
__int64 __fastcall main(int a1, char **a2, char **a3)
{
int i; // [rsp+18h] [rbp-58h]
int j; // [rsp+1Ch] [rbp-54h]
char s[56]; // [rsp+30h] [rbp-40h] BYREF
unsigned __int64 v7; // [rsp+68h] [rbp-8h]
v7 = __readfsqword(0x28u);
memset(s, 0, 0x31uLL);
printf("FLAG: ");
__isoc99_scanf("%48s", s);
for ( i = 0; i <= 47; i += 8 )
sub_12D4(&s[i], &s[i + 4]);
for ( j = 0; ; ++j )
{
if ( j > 47 )
{
puts("Correct!");
return 0LL;
}
if ( s[j] != byte_4040[j] )
break;
}
puts("Incorrect!");
return 0LL;
}
```
Vì mình không cài IDA lên WSL nên mình sẽ debug remote như này


Do chương trình cũng đơn giản nên ta chỉ phân tích nhanh

\- chương trình nhận vào 48 bytes từ input và mã hóa thông qua hàm ```sub_5555555552D4```, lưu trữ luôn vào s
\- kiểm tra với ```byte_555555558040```, nếu đúng thì trả về Correct, sai thì Incorrect
Hàm mã hóa ```sub_5555555552D4```:

ta có thể nhận ra đây là mã hóa XTEA khá quen thuộc
Mình có tham khảo chương trình decrypt XTEA bằng python tại: https://github.com/niklasb/ctf-tools/blob/master/crypto/xtea.py
Script:
```python=
from Crypto.Util.number import*
dword_5555555580C0=[0x126575B, 0x51903231, 0x8AAB8F5E, 0x0CA51930F]
byte_555555558040=[473413356, 2967692918, 1094173039, 1162692205, 2047540795, 593189689, 3392237974, 2109325366, 3133376540, 144254372, 4264188329, 2498107430]
rounds = 32
mask = 0xffffffff
delta = 0x9E3779B9
def decrypt(v, key):
v=list(v)
sum=(delta*rounds)&mask
for _ in range(rounds):
v[1] -= (((v[0] << 4) ^ (v[0] >> 5)) + v[0]) ^ (sum + key[(sum>>11) & 3])
v[1] &= mask
sum = (sum-delta)&mask
v[0] -= (((v[1] << 4) ^ (v[1] >> 5)) + v[1]) ^ (sum + key[sum & 3])
v[0] &= mask
return v
if __name__ == "__main__":
n=b''
for j in range(0,len(byte_555555558040),2):
a=(decrypt(byte_555555558040[j:j+2], dword_5555555580C0))
for i in range(2):
n+=(long_to_bytes(a[i])[::-1])
print(n)
#b'\xec\xb0LNQ\xa7r\xdd}\x1d\x0c\x9c\x0f\x9e\x93\x8ez\xb6\x1d\xedC\xea{H\xa93\x9f\x1a\rj\xa9\xc9m\xb5\xbc\xf1%\xc6\xb6.\x80,II\x1e\xb3\x103'
```
đến đây mình mới phát hiện ra điều gì đấy không đúng, ngồi fix lại chương trình decrypt khá lâu vì nghĩ chắc là sai ở đâu đấy, cuối cùng mình đã phải xem xét lại kỹ file binary

trong functions mình thấy chương trình có gọi ```ptrace``` \- là syscall chống debug trong Linux
do đây không phải là file Windows excutable nên sẽ không có các WinAPI như ```IsDebuggerPresent()``` hay ```NtQueryInformationProcess()``` nên ta cần lưu ý khi làm bài
ta trỏ đến địa chỉ gọi ptrace:

Nếu ta debug thì chương trình sẽ chuyển sang luồng fake, dẫn đến key decrypt XTEA bị sai
xem pseudo code để có cái nhìn trực quan hơn:

ta có thể nhận thấy khác nhau ở ```off_555555558080``` và ```off_555555558090``` giữa luồng fake và luồng real dẫn đến chương trình trả về 2 key khác nhau
cần sửa ZF hoặc patch để chương trình đưa vào luồng đúng
lúc này ta có thể lấy ```dword_5555555580C0``` chuẩn ra và bỏ vào script solve:
```python=
from Crypto.Util.number import*
#dword_5555555580C0=[0x126575B, 0x51903231, 0x8AAB8F5E, 0x0CA51930F]
dword_5555555580C0=[
0x3AB27278,
0x0A840805B,
0x0E864925B,
0x0B7B1EEDE]
byte_555555558040=[473413356, 2967692918, 1094173039, 1162692205, 2047540795, 593189689, 3392237974, 2109325366, 3133376540, 144254372, 4264188329, 2498107430] #dword
rounds = 32
mask = 0xffffffff
delta = 0x9E3779B9
def decrypt(v, key):
v=list(v)
sum=(delta*rounds)&mask
for _ in range(rounds):
v[1] -= (((v[0] << 4) ^ (v[0] >> 5)) + v[0]) ^ (sum + key[(sum>>11) & 3])
v[1] &= mask
sum = (sum-delta)&mask
v[0] -= (((v[1] << 4) ^ (v[1] >> 5)) + v[1]) ^ (sum + key[sum & 3])
v[0] &= mask
return v
if __name__ == "__main__":
n=b''
for j in range(0,len(byte_555555558040),2):
a=(decrypt(byte_555555558040[j:j+2], dword_5555555580C0))
for i in range(2):
n+=(long_to_bytes(a[i])[::-1])
print(n)
#b'KCSC{XTEA_encryption_and_debugger_detection_:>>}'
```
Flag: ~~KCSC{XTEA_encryption_and_debugger_detection_:>>}~~
## ChaChaCha

Bài này mình tốn cả chiều để viết script decrypt tuy nhiên cuối cùng mình lại giải được mà không cần decrypt \:\(\( làm mình khá đuối sức và buồn ngủ

Để cho ta 3 file, 1 file dump, 1 file txt và 1 file exe
mở important_note.txt bằng hex editor và nhìn kích thước file thì ta có thể đoán rằng đây là 1 file đã bị mã hóa:

mở file ChaChaCha.exe bằng IDA ta có pseudo code như sau:
```C=
int __cdecl main(int argc, const char **argv, const char **envp)
{
HMODULE LibraryA; // eax
BOOLEAN (__stdcall *SystemFunction036)(PVOID, ULONG); // eax
HMODULE v5; // eax
BOOLEAN (__stdcall *ProcAddress)(PVOID, ULONG); // eax
HANDLE FileW; // eax
void *v8; // ebx
signed int FileSize; // edi
_BYTE *v11; // ebx
int v12; // ecx
_BYTE *v13; // ecx
signed int v14; // esi
signed int v15; // ebx
_BYTE *v16; // eax
char v17; // al
char v18; // [esp+0h] [ebp-D8h]
HANDLE hFile; // [esp+Ch] [ebp-CCh]
signed int v20; // [esp+10h] [ebp-C8h]
char *v21; // [esp+14h] [ebp-C4h]
_BYTE *v22; // [esp+18h] [ebp-C0h]
char *v23; // [esp+1Ch] [ebp-BCh]
DWORD NumberOfBytesWritten; // [esp+20h] [ebp-B8h] BYREF
DWORD NumberOfBytesRead; // [esp+24h] [ebp-B4h] BYREF
char v26[48]; // [esp+28h] [ebp-B0h] BYREF
int v27; // [esp+58h] [ebp-80h]
char v28[64]; // [esp+68h] [ebp-70h] BYREF
char v29[32]; // [esp+A8h] [ebp-30h] BYREF
char v30[12]; // [esp+C8h] [ebp-10h] BYREF
LibraryA = LoadLibraryA("advapi32.dll");
SystemFunction036 = (BOOLEAN (__stdcall *)(PVOID, ULONG))GetProcAddress(LibraryA, "SystemFunction036");
SystemFunction036(v29, 32);
v5 = LoadLibraryA("advapi32.dll");
ProcAddress = (BOOLEAN (__stdcall *)(PVOID, ULONG))GetProcAddress(v5, "SystemFunction036");
ProcAddress(v30, 12);
FileW = CreateFileW(FileName, 0xC0000000, 0, 0, 3u, 0x80u, 0);
v8 = FileW;
hFile = FileW;
if ( FileW == (HANDLE)-1 )
{
sub_401590("Cannot Open File", v18);
CloseHandle((HANDLE)0xFFFFFFFF);
return 1;
}
else
{
FileSize = GetFileSize(FileW, 0);
v20 = FileSize;
v21 = (char *)malloc(FileSize);
if ( ReadFile(v8, v21, FileSize, &NumberOfBytesRead, 0) )
{
v11 = malloc(FileSize);
v22 = v11;
sub_4013D0(v12, v30);
v14 = 0;
if ( FileSize > 0 )
{
v23 = v28;
do
{
sub_401000(v26, v28, v13);
++v27;
v15 = v14 + 64;
if ( !__OFSUB__(v14, v14 + 64) )
{
v16 = v22;
do
{
if ( v14 >= FileSize )
break;
v13 = &v16[v14];
v17 = v23[v14] ^ v16[v14 + v21 - v22];
++v14;
FileSize = v20;
*v13 = v17;
v16 = v22;
}
while ( v14 < v15 );
}
v23 -= 64;
v14 = v15;
}
while ( v15 < FileSize );
v11 = v22;
}
SetFilePointer(hFile, 0, 0, 0);
if ( WriteFile(hFile, v11, FileSize, &NumberOfBytesWritten, 0) )
{
CloseHandle(hFile);
sub_401590("Some important file has been encrypted!!!\n", (char)FileName);
return 0;
}
else
{
sub_401590("Cannot Write File", v18);
CloseHandle(hFile);
return 1;
}
}
else
{
sub_401590("Cannot Read File", v18);
CloseHandle(v8);
return 1;
}
}
}
```
phân tích:
Đầu tiên chương trình tạo 1 Buffer ngẫu nhiên 32 bytes và 1 Buffer 12 bytes:

tiếp đến là các bước mở file, đọc file gì đấy tuy nhiên mình sẽ không đi phân tích phần này:

tiếp đến gọi hàm ```sub_8913D0```:

Bên trong có khá nhiều phép toán bitwise, có thể là thuật toán tạo khóa nào đấy:

ta để ý:
```python!
qmemcpy(a2, "expand 32-byte k", 16);
```
đây có thể là gọi sig của mã hóa salsa20 hoặc chacha20, tuy nhiên đề bài là ChaChaCha nên khả năng cao là chacha20
Ta có thể hiểu là tạo ma trận 4x4, hàng 1 là chuỗi “expand 32-byte k”, 2 hàng tiếp theo là 32 bytes key, 4 bytes đầu tiên của hàng cuối là counter = 1129530187 = 'KCSC' và 12 bytes cuối là nonce

tìm hiểu thêm tại https://xilinx.github.io/Vitis_Libraries/security/2019.2/guide_L1/internals/chacha20.html
đặt breakpoint như sau và mở hexview, ta có thể thấy key và nonce đã được lưu trữ:

tiếp theo:

gọi hàm ```sub_891000``` là mã hóa file bằng thuật toán chacha20
sau đó là xor gì đấy mình không hiểu lắm, có lẽ đây là nguyên nhân khiến mình viết chương trình decrypt cả chiều không được (sau khi tham khảo các WU khác thì thấy mọi người sử dụng CyberChef để decrypt)
Tạm dừng ở đây, ta sẽ phân tích file dump:
search strings "expand 32-byte k" trong IDA:

click vào để tìm địa chỉ lưu nó:

Do file dump này trích được memory lúc file bị mã hóa thành important_note.txt nên đây sẽ là key và nonce để decrypt file
dump lấy bytes:
```
[0x65, 0x78, 0x70, 0x61, 0x6E, 0x64, 0x20, 0x33, 0x32, 0x2D, 0x62, 0x79, 0x74, 0x65, 0x20, 0x6B, 0xD9, 0xFA, 0xBB, 0x42, 0x0C, 0x2D, 0xB8, 0x08, 0xD1, 0xF8, 0xBF, 0xA5, 0x89, 0x0A, 0xC3, 0xB3, 0x84, 0x9F, 0x69, 0xE2, 0xF3, 0x30, 0xD4, 0xA9, 0x0D, 0xB1, 0x19, 0xBD, 0x4E, 0xA0, 0xB8, 0x30, 0x4B, 0x43, 0x53, 0x43, 0xDB, 0x7B, 0xE6, 0x93, 0xEE, 0x9B, 0xC1, 0xA4, 0x70, 0x73, 0xCA, 0x4B]
```
Do chacha20 có thể dùng chương trình mã hóa để giải mã(mã dòng), nên mình sẽ patch luôn bộ nhớ tại key hiện tại thành key lấy từ file dump để giải mã file important_note.txt
đặt breakpoint tại:

ta chạy script sau để thay đổi thay đổi bộ nhớ (không thấy ai xài cách này nên tâm đắc vl 😈)
```python=
import idaapi
import idc
start_addr = 0x00AFFAA0#địa chỉ sẽ khác nhau mỗi lần debug, cần thay đổi khi thử chạy
end_addr = start_addr+63
new_data = [
0x65, 0x78, 0x70, 0x61, 0x6E, 0x64, 0x20, 0x33, 0x32, 0x2D, 0x62, 0x79,
0x74, 0x65, 0x20, 0x6B, 0xD9, 0xFA, 0xBB, 0x42, 0x0C, 0x2D, 0xB8, 0x08,
0xD1, 0xF8, 0xBF, 0xA5, 0x89, 0x0A, 0xC3, 0xB3, 0x84, 0x9F, 0x69, 0xE2,
0xF3, 0x30, 0xD4, 0xA9, 0x0D, 0xB1, 0x19, 0xBD, 0x4E, 0xA0, 0xB8, 0x30,
0x4B, 0x43, 0x53, 0x43, 0xDB, 0x7B, 0xE6, 0x93, 0xEE, 0x9B, 0xC1, 0xA4,
0x70, 0x73, 0xCA, 0x4B
]
for i in range(len(new_data)):
addr = start_addr + i
idc.patch_byte(addr, new_data[i])
print(f"Thay đổi bộ nhớ thành công từ {hex(start_addr)} đến {hex(end_addr)}")
```
sau khi thay đổi bộ nhớ, tiếp tục chạy hết chương trình để mã hóa lại file
mở lại file important_note.txt lúc nãy ra, ta thấy file đã được decrypt thành công

Nhìn header ta có thể thấy đây là một file Windows excutable
chạy file exe, ta được:


## WaiterFall

Mở IDA:

nhìn có vẻ rất khủng bố :O
Tuy nhiên đây chỉ là 1 dạng bài sử dụng Z3 rất kinh điển
solve Script: (byClaude)
```python=
from z3 import *
def solve_challenge():
s = Solver()
chars = [BitVec(f'char_{i}', 8) for i in range(62)]
v3 = 0
v5 = 0x1000008020020
v7 = 0x60010020000100
v8 = 0x100020080408000
v9 = 0x844000044000
for i, char in enumerate(chars):
s.add(char >= 32) # Space
s.add(char <= 126) # ~
conditions = []
conditions.append(If(char == ord('C'), If((i - 1) & 0xFFFFFFFD == 0, 1, 0), 0))
conditions.append(If(char == ord('K'), If(i == 0, 1, 0), 0))
conditions.append(If(char == ord('S'), If(i == 2, 1, 0), 0))
conditions.append(If(char == ord('c'), If(i == 37, 1, 0), 0))
conditions.append(If(char == ord('d'), If(i == 20, 1, 0), 0))
conditions.append(If(char == ord('g'), If(Or(i == 11, i == 60), 1, 0), 0))
conditions.append(If(char == ord('u'), If(i == 24, 1, 0), 0))
conditions.append(If(char == ord('{'), If(i == 4, 1, 0), 0))
conditions.append(If(char == ord('}'), If(i == 61, 1, 0), 0))
if i <= 0x31: # For '_'
if (0x2101004011000 >> i) & 1:
conditions.append(If(char == ord('_'), 1, 0))
if i <= 0x34: # For 'a'
if (0x10000210000040 >> i) & 1:
conditions.append(If(char == ord('a'), 1, 0))
if i <= 0x37: # For 'e'
if (0x80000040200000 >> i) & 1:
conditions.append(If(char == ord('e'), 1, 0))
if i <= 0x32: # For 'f'
if (0x4200100802000 >> i) & 1:
conditions.append(If(char == ord('f'), 1, 0))
if i <= 0x3A: # For 'i'
if (0x400000000000280 >> i) & 1:
conditions.append(If(char == ord('i'), 1, 0))
if i <= 0x33: # For 'l'
if (0x8480C02000000 >> i) & 1:
conditions.append(If(char == ord('l'), 1, 0))
if i <= 0x3B: # For 'n'
if (0xA00008000080400 >> i) & 1:
conditions.append(If(char == ord('n'), 1, 0))
if i <= 0x2F: # For 'o'
if (v9 >> i) & 1:
conditions.append(If(char == ord('o'), 1, 0))
if i <= 0x38: # For 'r'
if (v8 >> i) & 1:
conditions.append(If(char == ord('r'), 1, 0))
if i <= 0x36: # For 't'
if (v7 >> i) & 1:
conditions.append(If(char == ord('t'), 1, 0))
if i <= 0x30: # For 'w'
if (v5 >> i) & 1:
conditions.append(If(char == ord('w'), 1, 0))
v3 = v3 + Sum(conditions)
s.add(v3 == 62)
if s.check() == sat:
m = s.model()
result = ''
for i in range(62):
c = m[chars[i]].as_long()
result += chr(c)
return result
return None
result = solve_challenge()
if result:
print("Flag:", result)
else:
print("No solution found")
#Flag: KCSC{waiting_for_wonderful_waterfall_control_flow_flatterning}
```
Flag: ~~KCSC{waiting_for_wonderful_waterfall_control_flow_flatterning}~~
## STEAL
# Crypto
:((