---
# System prepended metadata

title: 'KCSC Recruitment '
tags: [kcsc]

---

#  KCSC_rec 2026



## LLM
llmao
Chạy thử trước chương trình thì mình thấy nó bắt 3 key (bằng số) để lấy được flag. Đọc description của challenge thì em thấy nó là linked list của DSA (đã học đâu~)

Vào hàm main:
```c
int __fastcall main(int argc, const char **argv, const char **envp)
{
  __int64 v3; // rdx
  __int64 v4; // r8
  int v6; // [rsp+20h] [rbp-78h]
  unsigned __int8 *v7; // [rsp+28h] [rbp-70h]
  _BYTE *Block; // [rsp+30h] [rbp-68h]
  __int64 v9; // [rsp+48h] [rbp-50h]
  __int64 v10; // [rsp+50h] [rbp-48h]
  __int64 v11; // [rsp+58h] [rbp-40h] BYREF
  __int64 v12; // [rsp+60h] [rbp-38h] BYREF
  __int64 v13; // [rsp+68h] [rbp-30h] BYREF
  __int64 v14; // [rsp+70h] [rbp-28h] BYREF
  unsigned __int8 v15; // [rsp+78h] [rbp-20h] BYREF

  v12 = 0;
  v13 = 0;
  v11 = 0;
  v14 = 0;
  sub_140001070(aEnterKeyToGetF, argv, envp);
  v7 = (unsigned __int8 *)off_1400040A8;
  v6 = 0;
  while ( v7 )
  {
    sub_140001070("Key%d : ", v6);
    sub_140001140("%d", (unsigned int)&v15);
    sub_140001230(&v12, &v13, v15, v7[9]);
    v7 = *(unsigned __int8 **)(v7 + 10);
    ++v6;
  }
  sub_1400012C0(off_1400040A8, v12, &v11, &v14);
  v9 = sub_1400013F0(v11, 1337);
  v10 = sub_1400013F0(v11, 9999);
  if ( v9 == 0xD427202CB4B2LL )
  {
    sub_140001070(aCorrect, v3, v4);
    Block = malloc(0x31u);
    sub_140001490(&unk_140004078, 48, v10, Block);
    Block[48] = 0;
    sub_140001070("Flag: %s\n", Block);
    free(Block);
  }
  else
  {
    sub_140001070(aWrong, v3, v4);
  }
  return 0;
}
```
non na thì nó sẽ kiểm tra kết quả bằng cách tính giá trị x=1337, nếu đúng sử dụng giá trị x=9999 để giải mã flag
cấu trúc của linked listed 
![image](https://hackmd.io/_uploads/r17NcWnMZl.png)
và đây là các node 
![image](https://hackmd.io/_uploads/S1TLv8nzbx.png)

mỗi node có cấu trúc 18 byte
```
Offset 0x0-0x7   (8 byte): Con trỏ prev (trỏ đến node trước)
Offset 0x8       (1 byte):  Hệ số (coefficient)
Offset 0x9       (1 byte):  Số mũ (exponent)
Offset 0xA-0x11  (8 byte): Con trỏ next (trỏ đến node sau)
-gpt go
```

tính từng node ra:
```
unk_140003288
node 0 = 0  
hệ số = 0x24 = 36
số mũ = 0x04 = 4 
trỏ node sau = 0x140003270 
vậy = 36x^4
```
cứ như vậy tính 2 node sau:
```
node 1 = 0x140003288 
hệ số = 0x12 = 18
số mũ = 0x02 = 2
trỏ node sau = 0x1400032A0 
vậy = 18x^2
```
```
node 2= 0x140003270 
hệ số= 0x07 = 7
số mũ= 0x00 = 0
trỏ node sau= 0 
vậy = 7x^0
```
kết hợp 3 node lại có công thức
P(x) = (**36** + key0)x^4 + (**18** + key1)x^2 + (7 + key2)`

```
 v7 = sub_1400013F0(v9, 1337);
  v8 = sub_1400013F0(v9, 9999);
  if ( v7 == 0xD427202CB4B2LL )
````
tức P(1337) = 0xD427202CB4B2LL
tính key
```
P(1337) = 36 × 1337^4 + 18 × 1337^2 + 7
        = 36 × 3,195,402,929,761 + 18 × 1,787,569 + 7
        = 115,034,537,647,645
        
0xD427202CB4B2LL= 233,264,508,613,810
độ chênh lệch = 233,264,508,613,810 - 115,034,537,647,645 = 118,229,970,966,165

=> key0 × 1337^4 + key1 × 1337^2 + key2 = 118,229,970,966,165

giải pt 

key0 = 118,229,970,966,165 / 3,195,402,929,761 = 37
key1 = 62,565,008 / 1,787,569 = 35 
key2 = 93
```


![image](https://hackmd.io/_uploads/S1L5gM3Mbe.png)


## Just_Ez_Rev





Khi mở bằng IDA lên thì em thấy rằng không thấy main đâu cả, vậy nên em sẽ tìm string để xem có chữ nào liên quan đến main không. Dùng shift f12, và có vẻ như đây là main của chúng ta: __int64 sub_140002934()
```c
{
  FILE *v0; // rax
  signed __int64 v1; // rax
  double v2; // xmm6_8
  double v3; // xmm0_8
  size_t v4; // rax
  _QWORD *v5; // rcx
  __int64 v6; // rdx
  char *Str; // [rsp+20h] [rbp-10h]
  int i; // [rsp+2Ch] [rbp-4h]

  sub_14000E1F7();
  sub_140018900("%s", aEnterTheFlag);
  v0 = __acrt_iob_func(0);
  fgets(Buffer, 100, v0);
  Buffer[strcspn(Buffer, "\n")] = 0;
  v1 = strlen(Buffer);
  if ( v1 < 0 )
  {
    v3 = (double)(int)(v1 & 1 | ((unsigned __int64)v1 >> 1));
    v2 = v3 + v3;
  }
  else
  {
    v2 = (double)(int)v1;
  }
  if ( v2 == sub_140019F60(6, 2) )
  {
    v4 = strlen(Buffer);
    Str = (char *)sub_1400027A8((__int64)Buffer, v4, 1);
    for ( i = 0; i < strlen(Str); i += 2 )
    {
      strncpy(Destination, &Str[i], 2u);
      sub_140002753(Destination, &qword_140026120);
      v5 = (_QWORD *)((char *)&unk_1400261A0 + dword_1400263A0);
      v6 = qword_140026128;
      *v5 = qword_140026120;
      v5[1] = v6;
      dword_1400263A0 += 16;
    }
    if ( !memcmp(&unk_1400261A0, &unk_14001B040, 512u) )
    {
      sub_140018900("Correct!\n");
      return 1;
    }
    else
    {
      sub_140018900("Incorrect!\n");
      return 0;
    }
  }
  else
  {
    sub_140018900("Incorrect length!\n");
    return 0;
  }
}
```


Hàm này là nó kiểm tra chiều dài ```if ( v2 == sub_140019F60(6, 2) )```
6^2=64 nếu ko đúng sẽ ra output "Incorrect length!"
 Sau đó em trace theo sub_1400027A8:
 
```c
__int64 __fastcall sub_1400027A8(__int64 a1, unsigned __int64 a2, char a3)
{
  __int64 v3; // rax
  __int64 v4; // rax
  __int64 v5; // rax
  __int64 v7; // [rsp+28h] [rbp-28h]
  unsigned __int64 i; // [rsp+30h] [rbp-20h]
  int v9; // [rsp+38h] [rbp-18h]
  unsigned int v10; // [rsp+3Ch] [rbp-14h]
  __int64 v11; // [rsp+40h] [rbp-10h]
  unsigned __int64 v12; // [rsp+48h] [rbp-8h]

  v12 = 8 * ((a2 + 4) / 5);
  if ( a3 != 1 )
    v12 = (8 * a2 + 4) / 5;
  v7 = sub_140019FC0(v12 + 1);
  v11 = 0;
  v10 = 0;
  v9 = 0;
  for ( i = 0; i < a2; ++i )
  {
    v10 = (v10 << 8) | *(unsigned __int8 *)(a1 + i);
    for ( v9 += 8; v9 > 4; v9 -= 5 )
    {
      v3 = v11++;
      *(_BYTE *)(v7 + v3) = aAbcdefghijklmn[(v10 >> (v9 - 5)) & 31];
    }
  }
  if ( v9 > 0 )
  {
    v4 = v11++;
    *(_BYTE *)(v7 + v4) = aAbcdefghijklmn[(v10 << (5 - v9)) & 31];
  }
  if ( a3 )
  {
    while ( (v11 & 7) != 0 )
    {
      v5 = v11++;
      *(_BYTE *)(v7 + v5) = 61;
    }
  }
  *(_BYTE *)(v7 + v11) = 0;
  return v7;
}
```

em nhận thấy rằng nó đang mã hóa theo base32

`ABCDEFGHIJKLMNOPQRSTUVWXYZ234567`

và với input là 64 byte chúng ta có công thức sau 

```
64 × 8 = 512 bit
512 ÷ 5 = 102.4, làm tròn lên = 103 ký tự
103 không chia hết cho 8 → cần 104 tức thêm 1 padding (=)
```
![image](https://hackmd.io/_uploads/H1QtcehGWl.png)

truy vào unk_14001B040 thì em thấy có rất nhiều byte và sau khi feed cho thầy thì em mới biết đó là hash MD5, em hỏi thầy  nữa thì mới biết MD5 hash là việc dùng hàm băm MD5 để biến dữ liệu thành một chuỗi cố định 32 ký tự hex. Sau đó "em" đã băm nó ra :3 

```python
hex = """D9 B2 52 86 6A 25 98 6F D8 EC 8A 6C 9B DE D2 75 C7 9B DA 0E 66 F0 7B EE 66 2A 68 40 B9 07 BF 39 8D 36 B3 61 A4 79 44 22 C7 06 81 58 6A 95 73 50 18 2B E0 C5 CD CD 50 72 BB 18 64 CD EE 4D 3D 6E AC CB 66 F0 EC D8 26 AA C8 90 65 99 0E 1D A9 7F 56 9B 3C ED 35 55 BF AE 63 CA DB 65 58 A6 FC BE 33 D2 A0 8E EE 4C 17 81 19 40 FE FB C4 E0 97 78 6B A8 9A B4 18 23 AF 9B 65 EA 5D 23 30 31 B9 F8 E4 A5 9D F8 B9 72 06 10 9E B4 B7 F2 FE 52 8A 4D AD 44 AC 8C 02 28 5F 6B 91 64 A0 84 92 A7 8F 92 0A 5B 65 72 5F 6A 3B A9 58 21 CE C6 1D BB 46 D3 2F F2 D4 5E 98 3C 58 E9 6C 9B A3 3D 69 72 1C E8 51 F5 81 93 77 65 89 0F 2A 70 6C 77 EA 8A F3 CC A3 6C 71 EB 23 9A 02 31 BA 0C 6E 7A 45 90 F0 62 42 AD C7 77 F3 C2 C9 70 05 15 0C B7 B8 61 65 B6 C2 3F A9 99 69 25 B6 10 71 0D 93 E2 8C 59 A3 E2 D5 C4 42 58 D5 16 59 F9 62 79 C4 70 CE 81 85 DC 6E 02 9F BF A8 17 DF C4 58 59 8A 5D 38 A6 75 5F 7C 78 EB B4 C2 23 C9 6F 8E 6C CC 29 F7 3C C2 8E 76 AA 96 36 9A BB BA 52 E6 21 BF A8 3D A8 E6 4F BA 7D 08 34 D2 3B 91 50 4B ED 68 59 01 DC 3A C5 38 F9 9A BB C1 D3 39 C2 77 C0 66 9E 7B C3 73 C0 0A 5B 65 72 5F 6A 3B A9 58 21 CE C6 1D BB 46 D3 85 3B C5 5C 10 41 F2 4B 93 92 06 93 31 E6 53 36 F2 14 A7 D4 2E 0D E5 87 5D 55 18 9E 01 E2 E1 87 7B 7C D2 4E A6 F0 8B 71 1C F4 05 3B EA C4 3C C5 64 F3 BD 17 41 AB 8D 6B A5 45 A1 AE 09 BB 87 28 8A 6B 17 8D 3A F0 A5 A9 B2 74 4C A3 19 21 D5 E2 BF D2 34 39 10 37 8A 1B 53 7C 3C 80 36 A5 C0 7E 20 63 84 97 17 D3 2D D1 9E 53 4B 77 CA BA C5 17 20 63 84 97 17 D3 2D D1 9E 53 4B 77 CA BA C5 17 20 63 84 97 17 D3 2D D1 9E 53 4B 77 CA BA C5 17"""
hex = hex.replace(" ", "").lower()

hashes = [hex[i:i+32] for i in range(0, len(hex), 32)]
for h in hashes:
    print(f'"{h}",')
```
Output:
```
"d9b252866a25986fd8ec8a6c9bded275",
"c79bda0e66f07bee662a6840b907bf39",
"8d36b361a4794422c70681586a957350",
"182be0c5cdcd5072bb1864cdee4d3d6e",
"accb66f0ecd826aac89065990e1da97f",
"569b3ced3555bfae63cadb6558a6fcbe",
"33d2a08eee4c17811940fefbc4e09778",
"6ba89ab41823af9b65ea5d233031b9f8",
"e4a59df8b97206109eb4b7f2fe528a4d",
"ad44ac8c02285f6b9164a08492a78f92",
"0a5b65725f6a3ba95821cec61dbb46d3",
"2ff2d45e983c58e96c9ba33d69721ce8",
"51f581937765890f2a706c77ea8af3cc",
"a36c71eb239a0231ba0c6e7a4590f062",
"42adc777f3c2c97005150cb7b86165b6",
"c23fa9996925b610710d93e28c59a3e2",
"d5c44258d51659f96279c470ce8185dc",
"6e029fbfa817dfc458598a5d38a6755f",
"7c78ebb4c223c96f8e6ccc29f73cc28e",
"76aa96369abbba52e621bfa83da8e64f",
"ba7d0834d23b91504bed685901dc3ac5",
"38f99abbc1d339c277c0669e7bc373c0",
"0a5b65725f6a3ba95821cec61dbb46d3",
"853bc55c1041f24b9392069331e65336",
"f214a7d42e0de5875d55189e01e2e187",
"7b7cd24ea6f08b711cf4053beac43cc5",
"64f3bd1741ab8d6ba545a1ae09bb8728",
"8a6b178d3af0a5a9b2744ca31921d5e2",
"bfd2343910378a1b537c3c8036a5c07e",
"2063849717d32dd19e534b77cabac517",
"2063849717d32dd19e534b77cabac517",
"2063849717d32dd19e534b77cabac517",
```
1 MD5 hash chỉ = 2 ký tự trong base32 gốc thế thì mình bruteforce ngược lại md5 base32 sau đó ghép base32 lại rồi decode

```py
import hashlib
import base64

base32_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"


expected_hashes = [
    "d9b252866a25986fd8ec8a6c9bded275",
"c79bda0e66f07bee662a6840b907bf39",
"8d36b361a4794422c70681586a957350",
"182be0c5cdcd5072bb1864cdee4d3d6e",
"accb66f0ecd826aac89065990e1da97f",
"569b3ced3555bfae63cadb6558a6fcbe",
"33d2a08eee4c17811940fefbc4e09778",
"6ba89ab41823af9b65ea5d233031b9f8",
"e4a59df8b97206109eb4b7f2fe528a4d",
"ad44ac8c02285f6b9164a08492a78f92",
"0a5b65725f6a3ba95821cec61dbb46d3",
"2ff2d45e983c58e96c9ba33d69721ce8",
"51f581937765890f2a706c77ea8af3cc",
"a36c71eb239a0231ba0c6e7a4590f062",
"42adc777f3c2c97005150cb7b86165b6",
"c23fa9996925b610710d93e28c59a3e2",
"d5c44258d51659f96279c470ce8185dc",
"6e029fbfa817dfc458598a5d38a6755f",
"7c78ebb4c223c96f8e6ccc29f73cc28e",
"76aa96369abbba52e621bfa83da8e64f",
"ba7d0834d23b91504bed685901dc3ac5",
"38f99abbc1d339c277c0669e7bc373c0",
"0a5b65725f6a3ba95821cec61dbb46d3",
"853bc55c1041f24b9392069331e65336",
"f214a7d42e0de5875d55189e01e2e187",
"7b7cd24ea6f08b711cf4053beac43cc5",
"64f3bd1741ab8d6ba545a1ae09bb8728",
"8a6b178d3af0a5a9b2744ca31921d5e2",
"bfd2343910378a1b537c3c8036a5c07e",
"2063849717d32dd19e534b77cabac517",
"2063849717d32dd19e534b77cabac517",
"2063849717d32dd19e534b77cabac517",

]

hash_to_pair = {}

for c1 in base32_alphabet:
    for c2 in base32_alphabet:
        pair = c1 + c2
        md5_hash = hashlib.md5(pair.encode()).hexdigest()
        hash_to_pair[md5_hash] = pair

hash_to_pair["2063849717d32dd19e534b77cabac517"] = "=="

base32_string = ""
for i, expected_hash in enumerate(expected_hashes):
    pair = hash_to_pair[expected_hash]
    base32_string += pair

flag = base64.b32decode(base32_string).decode('ascii')
print(f"\nFLAG: {flag}")
#cam on thay
```
Output:
`
FLAG: KCSC{3z_bru73_md5_4nd_d3cod3_b4s332}
`


## 33,550,337th 
amphoreus' 33,550,337th loop

bài này cho mình một file APK lúc đầu em cứ mở ida lên xem mãi mới biết rằng mình bị lùa gà một lúc sau em tải ldplayer và mở file APK thì nhận thấy nó cần chúng ta click 33550337 lần để lấy flag sau đó thì em nhớ tới cheat engine. Nhưng CE thì đâu có đổi giá trị trên emulator được nên em lên mạng xem cách hack apk và em theo [video](https://www.youtube.com/watch?v=cOcKEumJX4Y) này, tải game guardian, cơ chế hoạt động của game guardian giống cheat engine điền string rồi đi scan từng address, trúng address xong e modify nó lên max là ra flag

![image](https://hackmd.io/_uploads/By06AfhzWx.png)
![image](https://hackmd.io/_uploads/rJMRAMnMZe.png)


PS: em làm ra từ hồi 3-4h sáng mà buồn ngủ quá quên submit flag  T_T


## anti-debugger
Nhà có 5 anti-debugger

load IDA vào main:
```c
int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned int v3; // eax
  int v4; // edi
  unsigned int v5; // edx
  unsigned int v6; // ecx
  unsigned int v7; // eax
  int v9; // [esp-44h] [ebp-48h]
  int v10; // [esp-30h] [ebp-34h]
  int v11; // [esp-1Ch] [ebp-20h]

  __debugbreak();
  dword_4043D8 = IsDebuggerPresent();
  __debugbreak();
  dword_4043D0 = IsDebuggerPresent();
  __debugbreak();
  v11 = dword_4043D8;
  IsDebuggerPresent();
  __debugbreak();
  v10 = dword_4043D8;
  IsDebuggerPresent();
  __debugbreak();
  v9 = dword_4043D0;
  IsDebuggerPresent();
  v3 = dword_4043E0;
  if ( dword_4043E0 )
  {
    if ( byte_40449F[dword_4043E0] == 10 )
      v3 = --dword_4043E0;
    if ( v3 && byte_40449F[v3] == 13 )
      dword_4043E0 = --v3;
  }
  if ( v3 >= 0x40 )
    __report_rangecheckfailure(
      v9,
      byte_4044A0,
      64,
      &dword_4043E0,
      0,
      v10,
      "Enter flag: ",
      12,
      &unk_4043DC,
      0,
      v11,
      "Welcome to KCSC!\n",
      17,
      &unk_4043DC,
      0,
      -10,
      -11);
  byte_4044A0[v3] = 0;
  __debugbreak();
  IsDebuggerPresent();
  __debugbreak();
  IsDebuggerPresent();
  __debugbreak();
  IsDebuggerPresent();
  dword_4043E8 = (dword_4043E0 + 7) & 0xFFFFFFF8;
  __debugbreak();
  IsDebuggerPresent();
  __debugbreak();
  IsDebuggerPresent();
  __debugbreak();
  IsDebuggerPresent();
  dword_4043CC = dword_4043E8;
  if ( dword_4043E8 == 40 )
  {
    v4 = 1;
    dword_4043EC = 0;
    v5 = 0;
    v6 = 0;
    v7 = 0;
    while ( byte_4044E0[v7] == byte_403184[v6] )
    {
      v6 = ++v5;
      dword_4043EC = v5;
      v7 = v5;
      if ( v5 >= 0x28 )
        goto LABEL_14;
    }
    v4 = 0;
LABEL_14:
    if ( v4 )
    {
      __debugbreak();
      IsDebuggerPresent();
      __debugbreak();
      IsDebuggerPresent();
    }
  }
  __debugbreak();
  IsDebuggerPresent();
  __debugbreak();
  IsDebuggerPresent();
  return 0;
}
```
đập vào mắt là một dãy winapi IsDebuggerPresent lần đầu nhìn vào em liền lao đầu vào debugger mà patch, patch một hồi không được thì em đi tìm hiểu các functions khác.
em phát hiện ra function mà chưa từng thấy bao giờ là 
`TlsCallback_0` và `Handler`, search trên google thì em thấy rằng khi có function tlscallback thì dù cho mình đặt breakpoint ở entry rồi chạy debugger thì nó cũng detect được và không dừng ở breakpoint của mình. [source](https://hex-rays.com/blog/tls-callbacks)

đây là hàm tlscallback 
```c
void __stdcall TlsCallback_0(int a1, int a2, int a3)
{
    if (a2 == 1)  // DLL_PROCESS_ATTACH
    {
        if (Handle)
            RemoveVectoredExceptionHandler(Handle);
        Handle = AddVectoredExceptionHandler(1, Handler);
    }
}
```
chúng ta có thể nhận thấy nó cũng liên quan tới function handle, `AddVectoredExceptionHandler` đăng ký một exception handler. Handler này sẽ bắt tất cả các exception xảy ra trong chương trình 

Quay lại main chúng ta có thể thấy có rất nhiều lệnh như thế này 
![image](https://hackmd.io/_uploads/By8Sa4hzWe.png)
thì... 
debugbreak() tạo lệnh INT 3, INT 3 là software break khi chạy bình thường, INT 3 gây ra exception và exception được xử lý bởi handler đã đăng ký

![image](https://hackmd.io/_uploads/H1_9AE2fZe.png)

nó cứ tới `VectoredExceptionHandle` vậy VEH là gì
[VEH](https://learn.microsoft.com/en-us/windows/win32/debug/vectored-exception-handling) là cơ chế xử lý exception trong win

tại hàm handler
```c
LONG __stdcall Handler(struct _EXCEPTION_POINTERS *ExceptionInfo)
{
  PCONTEXT ContextRecord; // esi
  PVOID v2; // eax

  if ( ExceptionInfo->ExceptionRecord->ExceptionCode != -2147483645 )
    return 0;
  ContextRecord = ExceptionInfo->ContextRecord;
  sub_4012F0();
  if ( dword_4043E4 < 15 )
  {
    sub_401240(off_4031B4[dword_4043E4]);
    ++dword_4043E4;
  }
  if ( Handle )
    RemoveVectoredExceptionHandler(Handle);
  v2 = AddVectoredExceptionHandler(1u, sub_4013F0);
  ++ContextRecord->Eip;
  Handle = v2;
  return -1;
}
```
kiểm tra từ trên xuống thì nó đang kiểm tra exception code
vào sub_4012F0 
ngoài ra còn có `EIP` nó là thanh ghi CPU x86 giữ địa chỉ lệnh tiếp theo sẽ được thực thi.
ở đây nó tăng `EIP` vậy Bỏ qua lệnh INT 3 tiếp theo nó đăng ký handler tiếp theo cho lần INT 3 sau
```c
// write access to const memory has been detected, the output may be wrong!
void sub_4012F0()
{
  HANDLE CurrentProcess; // eax
  DWORD flOldProtect; // [esp+0h] [ebp-8h] BYREF

  if ( !dword_404058 )
  {
    VirtualProtect(IsDebuggerPresent, 5u, 0x40u, &flOldProtect);
    IsDebuggerPresent = (BOOL (__stdcall *)())dword_404480;
    *((_BYTE *)&IsDebuggerPresent + 4) = byte_404484;
    VirtualProtect(IsDebuggerPresent, 5u, flOldProtect, &flOldProtect);
    CurrentProcess = GetCurrentProcess();
    FlushInstructionCache(CurrentProcess, IsDebuggerPresent, 5u);
  }
}
```
em trace một hồi thì vào hàm này, có quá nhiều cái lạ mà em có search cũng không hiểu 
    
``
``
``
``
``
``
đến đây em quá nản và không có ý tưởng nên đưa vài cái prompt cho claude... xin lỗi a robert



```py
def rc4_init(key):
    """Khởi tạo RC4 state với key"""
    S = list(range(256))
    j = 0
    for i in range(256):
        j = (j + S[i] + key[i % len(key)]) % 256
        S[i], S[j] = S[j], S[i]
    return S

def rc4_crypt(S, data):
    """giải mã RC4"""
    S = S.copy()
    i = 0
    j = 0
    result = []
    
    for byte in data:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        k = S[(S[i] + S[j]) % 256]
        result.append(byte ^ k)
    
    return bytes(result)

def tea_decrypt_block(v0, v1, key):
    """TEA """
    k0, k1, k2, k3 = key
    delta = 0x9E3779B9
    sum_val = (delta * 32) & 0xFFFFFFFF
    
    for _ in range(32):
        v1 = (v1 - (((v0 << 4) + k2) ^ (v0 + sum_val) ^ ((v0 >> 5) + k3))) & 0xFFFFFFFF
        v0 = (v0 - (((v1 << 4) + k0) ^ (v1 + sum_val) ^ ((v1 >> 5) + k1))) & 0xFFFFFFFF
        sum_val = (sum_val - delta) & 0xFFFFFFFF
    
    return v0, v1

def tea_decrypt(data, key):
    """TEA"""
    # Chuyển key bytes thành 4 giá trị u32 (little-endian)
    key_u32 = []
    for i in range(0, 16, 4):
        val = int.from_bytes(key[i:i+4], 'little')
        key_u32.append(val)
    
    result = []
    # Xử lý từng 
    for i in range(0, len(data), 8):
        v0 = int.from_bytes(data[i:i+4], 'little')
        v1 = int.from_bytes(data[i+4:i+8], 'little')
        
        v0_dec, v1_dec = tea_decrypt_block(v0, v1, key_u32)
        
        result.extend(v0_dec.to_bytes(4, 'little'))
        result.extend(v1_dec.to_bytes(4, 'little'))
    
    return bytes(result)

def unpad_pkcs7(data):
    """Xóa PKCS#7 padding"""
    if not data:
        return data
    pad_len = data[-1]
    if pad_len > 0 and pad_len <= 8:
        if all(b == pad_len for b in data[-pad_len:]):
            return data[:-pad_len]
    return data



# Keys 
rc4_key1 = bytes([0x1a, 0x89, 0x14, 0x92, 0x22, 0x5d, 0x4f])
tea_key = bytes([0xef, 0xbe, 0xad, 0xde, 0xbe, 0xba, 0xfe, 0xca, 
                 0x37, 0x13, 0x37, 0x13, 0x0d, 0xf0, 0xad, 0xba])
rc4_key2 = bytes([0x36, 0xbd, 0xd1, 0x3b, 0x9a, 0xa8, 0xef, 0x29, 0xff])

# encrypted result
encrypted = bytes([
    0x7b, 0x6f, 0xb4, 0xf7, 0x81, 0x3d, 0xef, 0xee,
    0xb2, 0x1e, 0x7e, 0x8d, 0x0c, 0x9d, 0x67, 0x41,
    0xcb, 0x20, 0x53, 0xfd, 0x47, 0x71, 0xad, 0xc6,
    0xbc, 0x0e, 0xf2, 0xa2, 0x69, 0x04, 0xa3, 0xb2,
    0x5e, 0xd7, 0xd0, 0x6e, 0x63, 0x6f, 0x72, 0x9e
])

print("=" * 70)
print("GIẢI MÃ")
print("=" * 70)
print(f"\n[*] Dữ liệu mã hóa ({len(encrypted)} bytes):")
print(f"    {encrypted.hex()}")


print("\n[*] Bước 1: Giải mã RC4 với key 2 (9 bytes)...")
print(f"    Key: {rc4_key2.hex()}")
S2 = rc4_init(rc4_key2)
after_rc4_2 = rc4_crypt(S2, encrypted)
print(f"    Kết quả: {after_rc4_2.hex()}")


print("\n[*] Bước 2: Giải mã TEA với key 128-bit...")
print(f"    Key: {tea_key.hex()}")
after_tea = tea_decrypt(after_rc4_2, tea_key)
print(f"    Kết quả: {after_tea.hex()}")


print("\n[*] Bước 3: Giải mã RC4 với key 1 (7 bytes)...")
print(f"    Key: {rc4_key1.hex()}")
S1 = rc4_init(rc4_key1)
flag_padded = rc4_crypt(S1, after_tea)


print("\n[*] Bước 3: Giải mã RC4 với key 1 (7 bytes)...")
print(f"    Key: {rc4_key1.hex()}")
S1 = rc4_init(rc4_key1)
flag_padded = rc4_crypt(S1, after_tea)
print(f"    Kết quả (có padding): {flag_padded.hex()}")


print("\n[*] Bước 4: Loại bỏ PKCS#7 padding...")
flag = unpad_pkcs7(flag_padded)

print("\n" + "=" * 70)
print("[+] FLAG THU ĐƯỢC:")
try:
    print(flag.decode())
except UnicodeDecodeError:
    print(flag)
print("=" * 70)
```

```
Output:

[*] Dữ liệu mã hóa (40 bytes):
    7b6fb4f7813defeeb21e7e8d0c9d6741cb2053fd4771adc6bc0ef2a26904a3b25ed7d06e636f729e

[*] Bước 1: Giải mã RC4 với key 2 (9 bytes)...
    Key: 36bdd13b9aa8ef29ff
    Kết quả: 8dcb81f25bb9fc18d730ad183e054a6a20010ba1c659341c3c02a9743bcc5eaae4290f52465d5c20

[*] Bước 2: Giải mã TEA với key 128-bit...
    Key: efbeaddebebafeca371337130df0adba
    Kết quả: 37412f325ea184f0519ed74f969ec28b8f4971cee2820e17b018140a71062f74a21a795c78030303

[*] Bước 3: Giải mã RC4 với key 1 (7 bytes)...
    Key: 1a891492225d4f

[*] Bước 3: Giải mã RC4 với key 1 (7 bytes)...
    Key: 1a891492225d4f
    Kết quả (có padding): 4b4353437b6e6f775f796f755f6b6e6f775f686f775f746f5f686f6f6b5f57494e4150497d41f2be

[*] Bước 4: Loại bỏ PKCS#7 padding...

[+] FLAG THU ĐƯỢC:
b'KCSC{now_you_know_how_to_hook_WINAPI}A\xf2\xbe'
```

## keygenme


Đầu tiên em chạy thử chương trình thì thấy challenge nó check cả username lẫn serial key. Đúng cả 2 thì mới ra flag đúng.

Mở bằng IDA thì em thấy toàn là functions nên tìm string, vì không thấy string nào liên quan đến chương trình nên em mò từng function từ trên xuống thì em thấy 2 function này

`sub_1400017A6`
```c
int __fastcall sub_1400017A6(HWND hWndParent, LPCWSTR lpText, int a3)
{
  HWND Window; // rcx
  int v7; // edi
  int v8; // ebp
  int SystemMetrics; // ebx
  int v10; // eax
  const WCHAR *v11; // r8
  UINT v12; // r9d
  tagMSG Msg; // [rsp+60h] [rbp-D8h] BYREF
  tagRECT Rect; // [rsp+90h] [rbp-A8h] BYREF
  WNDCLASSW WndClass; // [rsp+A0h] [rbp-98h] BYREF
  WCHAR ClassName[36]; // [rsp+F0h] [rbp-48h] BYREF

  dword_140020EE0 = a3;
  wcscpy_s(&Destination, 0x800u, lpText);
  wcscpy(ClassName, L"KCSCFlgDialog");
  *(_QWORD *)&WndClass.style = 0;
  *(_QWORD *)&WndClass.cbClsExtra = 0;
  WndClass.hIcon = 0;
  *(_OWORD *)&WndClass.hbrBackground = 0;
  WndClass.lpfnWndProc = (WNDPROC)sub_140001B4E;
  WndClass.hInstance = (HINSTANCE)GetWindowLongPtrW(hWndParent, -6);
  WndClass.lpszClassName = ClassName;
  WndClass.hCursor = LoadCursorW(0, (LPCWSTR)0x7F00);
  WndClass.hbrBackground = 0;
  if ( !a3 )
  {
    WndClass.hIcon = LoadIconW(0, (LPCWSTR)0x7F01);
    RegisterClassW(&WndClass);
    Window = CreateWindowExW(
               9u,
               ClassName,
               L"Activation Failed",
               0x90C80000,
               0,
               0,
               650,
               360,
               hWndParent,
               0,
               WndClass.hInstance,
               0);
    hWnd = Window;
    if ( Window )
      goto LABEL_3;
    v11 = L"Activation Failed";
    v12 = 16;
    return MessageBoxW(hWndParent, lpText, v11, v12);
  }
  WndClass.hIcon = LoadIconW(0, (LPCWSTR)0x7F04);
  RegisterClassW(&WndClass);
  Window = CreateWindowExW(
             9u,
             ClassName,
             L"Activation Successful",
             0x90C80000,
             0,
             0,
             650,
             360,
             hWndParent,
             0,
             WndClass.hInstance,
             0);
  hWnd = Window;
  if ( !Window )
  {
    v11 = L"Activation Successful";
    v12 = 64;
    return MessageBoxW(hWndParent, lpText, v11, v12);
  }
LABEL_3:
  GetWindowRect(Window, &Rect);
  v7 = Rect.right - Rect.left;
  v8 = Rect.bottom - Rect.top;
  SystemMetrics = GetSystemMetrics(0);
  v10 = GetSystemMetrics(1);
  SetWindowPos(hWnd, HWND_MESSAGE|0x2LL, (SystemMetrics - v7) / 2, (v10 - v8) / 2, 0, 0, 1u);
  EnableWindow(hWndParent, 0);
  while ( GetMessageW(&Msg, 0, 0, 0) > 0 && IsWindow(hWnd) )
  {
    TranslateMessage(&Msg);
    DispatchMessageW(&Msg);
  }
  EnableWindow(hWndParent, 1);
  SetForegroundWindow(hWndParent);
  SetFocus(hWndParent);
  return UnregisterClassW(ClassName, WndClass.hInstance);
}
```
đây là một function checker

sang bên main function là `sub_1400022F2`

```c
__int64 __fastcall sub_1400022F2(HWND hWndParent, UINT a2, WPARAM a3, LPARAM a4)
{
  HINSTANCE WindowLongPtrW; // rsi
  HWND Window; // rax
  HWND v9; // rax
  HWND v10; // rax
  HWND v11; // rbx
  HFONT FontW; // rax
  __int64 result; // rax
  HDC v14; // rbx
  HBRUSH v15; // r8
  COLORREF v16; // r8d
  HPEN Pen; // rbp
  HGDIOBJ v18; // r12
  HGDIOBJ StockObject; // rax
  HGDIOBJ v20; // rdi
  unsigned int v21; // eax
  CHAR String[256]; // [rsp+70h] [rbp-448h] BYREF
  __m128i Str; // [rsp+170h] [rbp-348h] BYREF
  _BYTE chText[280]; // [rsp+270h] [rbp-248h] BYREF
  char v25; // [rsp+388h] [rbp-130h]

  if ( a2 == 43 )
  {
    result = 0;
    if ( *(_DWORD *)(a4 + 4) == 3 )
    {
      v14 = *(HDC *)(a4 + 32);
      Str = _mm_loadu_si128((const __m128i *)(a4 + 40));
      v15 = (HBRUSH)qword_140020F18;
      if ( dword_140020F08 )
        v15 = hbr;
      FillRect(v14, (const RECT *)&Str, v15);
      v16 = 12156969;
      if ( dword_140020F08 )
        v16 = 14391348;
      Pen = CreatePen(0, 1, v16);
      v18 = SelectObject(v14, Pen);
      StockObject = GetStockObject(5);
      SelectObject(v14, StockObject);
      RoundRect(v14, Str.m128i_i32[0], Str.m128i_i32[1], Str.m128i_i32[2], Str.m128i_i32[3], 5, 5);
      SelectObject(v14, v18);
      DeleteObject(Pen);
      GetWindowTextW(*(HWND *)(a4 + 24), (LPWSTR)chText, 256);
      SetBkMode(v14, 1);
      SetTextColor(v14, 0xFFFFFFu);
      v20 = SelectObject(v14, (HGDIOBJ)h);
      DrawTextW(v14, (LPCWSTR)chText, -1, (LPRECT)&Str, 0x25u);
      SelectObject(v14, v20);
      return 1;
    }
  }
  else if ( a2 > 0x2B )
  {
    if ( a2 == 307 )
    {
      SetTextColor((HDC)a3, 0x503E2Cu);
      SetBkColor((HDC)a3, 0xFFFFFFu);
      return (__int64)GetStockObject(0);
    }
    if ( a2 == 312 )
    {
      SetTextColor((HDC)a3, 0x503E2Cu);
      SetBkColor((HDC)a3, 0xF5F0F0u);
      return (__int64)qword_140020F20;
    }
    if ( a2 != 273 )
      return DefWindowProcW(hWndParent, a2, a3, a4);
    result = 0;
    if ( (_WORD)a3 == 3 && (a3 & 0xFFFF0000) == 0 )
    {
      GetWindowTextA(qword_140020F50, String, 256);
      GetWindowTextA(qword_140020F48, Str.m128i_i8, 256);
      if ( String[0] && Str.m128i_i8[0] )
      {
        if ( lpAddress
          && (unsigned int)((__int64 (__fastcall *)(CHAR *, __m128i *, void *))lpAddress)(String, &Str, &unk_140016520) == 1 )
        {
          qmemcpy(chText, &unk_140016020, sizeof(chText));
          v21 = strlen(Str.m128i_i8);
          sub_1400021BD(&Str, v21, chText, 280);
          v25 = 0;
          sub_1400153B0(Buffer, 0x400u, (wchar_t *)Format);
          sub_1400017A6(hWndParent, Buffer, 1);
        }
        else
        {
          sub_140002242(&unk_1400161A0, &unk_140016140);
          sub_1400153B0(Buffer, 0x400u, (wchar_t *)Format);
          sub_1400017A6(hWndParent, Buffer, 0);
        }
        return 0;
      }
      else
      {
        MessageBoxW(hWndParent, L"Please enter both Username and Serial Key!", "I", 0x30u);
        return 0;
      }
    }
  }
  else
  {
    if ( a2 != 2 )
    {
      if ( a2 == 20 )
      {
        GetClientRect(hWndParent, (LPRECT)chText);
        FillRect((HDC)a3, (const RECT *)chText, (HBRUSH)qword_140020F20);
        return 1;
      }
      if ( a2 == 1 )
      {
        WindowLongPtrW = (HINSTANCE)GetWindowLongPtrW(hWndParent, -6);
        h = (WPARAM)CreateFontW(20, 0, 0, 0, 400, 0, 0, 0, 1u, 0, 0, 5u, 0, "S");
        wParam = (WPARAM)CreateFontW(22, 0, 0, 0, 700, 0, 0, 0, 1u, 0, 0, 5u, 0, "S");
        qword_140020F20 = CreateSolidBrush(0xF5F0F0u);
        qword_140020F18 = CreateSolidBrush(0xB98029u);
        hbr = CreateSolidBrush(0xDB9834u);
        Window = CreateWindowExW(
                   0,
                   "S",
                   L"KCSC Software Activation",
                   0x50000001u,
                   0,
                   15,
                   500,
                   30,
                   hWndParent,
                   0,
                   WindowLongPtrW,
                   0);
        SendMessageW(Window, 0x30u, wParam, 1);
        CreateWindowExW(0, "S", &word_140017222, 0x50000010u, 20, 55, 460, 2, hWndParent, 0, WindowLongPtrW, 0);
        v9 = CreateWindowExW(0, "S", L"Username:", 0x50000000u, 30, 80, 100, 20, hWndParent, 0, WindowLongPtrW, 0);
        SendMessageW(v9, 0x30u, h, 1);
        qword_140020F50 = CreateWindowExW(
                            0x200u,
                            L"EDIT",
                            &word_140017222,
                            0x50000080u,
                            140,
                            75,
                            320,
                            30,
                            hWndParent,
                            (HMENU)1,
                            WindowLongPtrW,
                            0);
        SendMessageW(qword_140020F50, 0x30u, h, 1);
        v10 = CreateWindowExW(0, "S", L"Serial Key:", 0x50000000u, 30, 125, 100, 20, hWndParent, 0, WindowLongPtrW, 0);
        SendMessageW(v10, 0x30u, h, 1);
        qword_140020F48 = CreateWindowExW(
                            0x200u,
                            L"EDIT",
                            &word_140017222,
                            0x50000080u,
                            140,
                            120,
                            320,
                            30,
                            hWndParent,
                            (HMENU)2,
                            WindowLongPtrW,
                            0);
        SendMessageW(qword_140020F48, 0x30u, h, 1);
        qword_140020F40 = CreateWindowExW(
                            0,
                            L"BUTTON",
                            L"Activate License",
                            0x5000000Bu,
                            175,
                            170,
                            150,
                            40,
                            hWndParent,
                            (HMENU)3,
                            WindowLongPtrW,
                            0);
        SendMessageW(qword_140020F40, 0x30u, h, 1);
        SetWindowSubclass(qword_140020F40, pfnSubclass, 0, 0);
        v11 = CreateWindowExW(
                0,
                "S",
                L"Enter your username and serial key to activate",
                0x50000001u,
                0,
                230,
                500,
                20,
                hWndParent,
                0,
                WindowLongPtrW,
                0);
        FontW = CreateFontW(16, 0, 0, 0, 400, 0, 0, 0, 1u, 0, 0, 5u, 0, "S");
        SendMessageW(v11, 0x30u, (WPARAM)FontW, 1);
        return 0;
      }
      return DefWindowProcW(hWndParent, a2, a3, a4);
    }
    if ( lpAddress )
      VirtualFree(lpAddress, 0, 0x8000u);
    if ( h )
      DeleteObject((HGDIOBJ)h);
    if ( wParam )
      DeleteObject((HGDIOBJ)wParam);
    if ( qword_140020F20 )
      DeleteObject(qword_140020F20);
    if ( qword_140020F18 )
      DeleteObject(qword_140020F18);
    if ( hbr )
      DeleteObject(hbr);
    PostQuitMessage(0);
    return 0;
  }
  return result;
}
```

```c
 if ( (_WORD)a3 == 3 && (a3 & 0xFFFF0000) == 0 )
    {
      GetWindowTextA(qword_140020F50, String, 256);
      GetWindowTextA(qword_140020F48, Str.m128i_i8, 256);
      if ( String[0] && Str.m128i_i8[0] )
      {
        if ( lpAddress
          && (unsigned int)((__int64 (__fastcall *)(CHAR *, __m128i *, void *))lpAddress)(String, &Str, &unk_140016520) == 1 )
      
```  
và ở khúc này đây là nó đang gọi username và key sau đó gọi lpAddress để check, và `unk_140016520` chứa một data nào đó mà cứ 2 byte lại được cách bởi 2 byte trống nên để anh lgbt giải thích thì thực ra nó là `uint32_t`, có 32-bit cái này em thấy nó sú sú nên cứ để đó đã

xong em sẽ đi tìm cái lpAddress nó được store ở đâu, may thay ngay hàm dưới `sub_140002C82` 
```c
v6 = VirtualAlloc(0, 0x110u, 0x3000u, 0x40u);
  lpAddress = v6;
  if ( v6 )
  {
    *v6 = qword_140016600;
    v6[33] = qword_140016708;
    qmemcpy(
      (void *)((unsigned __int64)(v6 + 1) & 0xFFFFFFFFFFFFFFF8uLL),
      (const void *)((char *)&qword_140016600 - ((char *)v6 - ((unsigned __int64)(v6 + 1) & 0xFFFFFFFFFFFFFFF8uLL))),
      8LL * (((unsigned int)v6 - (((_DWORD)v6 + 8) & 0xFFFFFFF8) + 272) >> 3));
```
trong qword_140016600 thì em được mã hex như thế này:

```85 C0 57 56 53 48 89 D3 0F 94 C2 08 D0 0F 85 ED 00 00 00 31 C0 48 85 C9 0F 84 E2 00 00 00 80 3C 01 00 74 0B 48 FF C0 48 3D 00 01 00 00 75 EF 31 D2 80 3C 13 00 74 14 48 FF C2 48 81 FA 00 01 00 00 75 EE 41 BB 00 01 00 00 EB 03 41 89 D3 45 85 DB 0F 84 A9 00 00 00 83 F8 0C 0F 85 A0 00 00 00 31 C0 80 39 6B 0F 85 97 00 00 00 80 79 02 61 0F 85 8D 00 00 00 80 79 04 33 0F 85 83 00 00 00 80 79 06 33 75 7D 80 79 08 35 75 77 80 79 0A 6E 75 71 80 79 01 6D 75 6B 80 79 03 72 75 65 80 79 05 76 75 5F 80 79 07 72 75 59 80 79 09 21 75 53 80 79 0B 39 75 4D 45 31 D2 41 B9 37 13 00 00 BE 0C 00 00 00 44 89 D0 42 0F BE 2C 13 99 F7 FE 44 89 C8 44 31 CD 48 63 D2 0F B6 3C 11 31 D2 F7 F6 31 EF 89 D2 44 0F B6 0C 11 41 01 F9 47 39 0C 90 75 0F 49 FF C2 45 39 D3 7F CA B8 01 00 00 00 EB 02```

sau đó em dùng ảo thuật đen, bấm c chuyển nó sang code
![image](https://hackmd.io/_uploads/B1tyK4azWe.png)
em nhận thấy là `ptr [rcx]` nó đang bị rối từ 0 lên 2 lên 4 lên 6,.... nên em sắp xếp lại. Từ đó ra được như thế này:
`kmar3v3r5!n9` vậy là có được user



sau đó thì em chả biết làm gì tiếp nên e dùng AI, đưa nó tất cả những gì ở trên rồi nó suy ra code 
```py
USERNAME = "kmar3v3r5!n9"
def generate_serial(username, expected):
    if username != USERNAME:
        raise ValueError("Username must be exactly 'kmar3v3r5!n9'")

    h = 0x1337
    serial = []

    for i, target in enumerate(expected):
        a, b = i % 12, h % 12

        ch = ((target - ord(username[b])) ^ h ^ ord(username[a])) & 0xFF

        if not 32 <= ch <= 126:
            for c in range(32, 127):
                if ((h ^ c ^ ord(username[a])) + ord(username[b])) & 0xFFFFFFFF == target:
                    ch = c
                    break

        serial.append(chr(ch))
        h = ((h ^ ch ^ ord(username[a])) + ord(username[b])) & 0xFFFFFFFF

    return "".join(serial)


expected_hashes = [
    0x1350, 0x13E9, 0x13FC, 0x1400, 0x1453, 0x1489, 0x14F7, 0x1529,
    0x15A0, 0x15DF, 0x166D, 0x1677, 0x169B, 0x1733, 0x17B8, 0x1803,
    0x1875, 0x1858, 0x188D, 0x18F3, 0x1905, 0x199D, 0x1A39, 0x1AC8,
    0x1AC1, 0x1AB9, 0x1B23, 0x1B6E, 0x1B9A, 0x1C2F, 0x1CBB, 0x1D36,
    0x1DA8, 0x1E02, 0x1EA2, 0x1EFF, 0x1F27, 0x1F90, 0x1FEC, 0x201E,
    0x20D9, 0x20BB, 0x212D, 0x212E, 0x21A4, 0x2200, 0x228D, 0x2366,
    0x239F
]

print("Serial:  ", generate_serial(USERNAME, expected_hashes))

```
`Output : KCSC-2026-JU57-R341-UX0R-4ndd-U4DD-W!TH-U53R-N4M3`

![image](https://hackmd.io/_uploads/Hk66tr6Gbe.png)
xong decode bên cyberchef em ra được flag 
`KCSC{C0n9r4tu14t!0n5_Y0u_H4v3_Succ355fu11y_4ct!v4t4t3d_7h3_L!c3n53_S0ftw4r3_W!th_RC4_4nd_D3c0d3_Base64_3_T!m3s__=)))}`


## after word
mấy anh ra đề rất ác, nhưng mà đề nào em thấy cũng rất hay, tuy nhiên e đã dùng AI rất nhiều và chưa tự giải cũng như là tự tìm hiểu, hi vọng mấy anh cho em biết thêm kĩ lăng debug