# Chal 1

Bài này IDA của mình không decomplie được nên sẽ phải debug trên assembly.
Tìm được đến đoạn có decrypt flag

Mò ngược lên trên thì thấy nó sẽ so sách username với ```"~#L-:4;f"```, nếu khác thì in ra "No you are not the right person" và thoát.

Vì xâu đó có sử dụng để decrypt nên mình chỉ có thể chính sửa username của mình cho khớp với nó.

Phía trên còn có đoạn check ptrace nếu khác 0 thì sẽ in "This doesn't seem right" và thoát.

Cuối cùng là đoạn này kiểm tra nếu ở main có breakpoint thì in ra "What's this now?" và thoát luôn.


Vậy mình có 3 đoạn cần pass qua:
* đầu tiên là break point ở 0x080488B2 để set eax thành 0 để nó nhảy qua được loc_80488D2 để chạy tiếp thay vì thoát
* tiếp theo là break point ở 0x080488F2 để chỉnh sửa username của mình thành "~#L-:4;f" để nó đem đi decrypt cho đúng chứ không chỉ cần pass qua chỗ đó bằng cách chính eax trước khi test như trên
* cuối cùng là break point ở 0x08048955 để set eax = 0 để khi cmp thì không bị nhảy ở lệnh jl short loc_804890B
Break 1:

kết quả là nó đã nhảy được qua đoạn đó rồi

Break 2:
Chuyển xâu "" sang hex được đoạn 0x663b343a2d4c237e, vậy nó sẽ chia một đoạn 4 byte và lưu trong 2 đoạn 8 bit như sau:
0x804a05c = 0x2d4c237e
0x804a05c + 4 = 0x663b343a
0x804a05c + 8 = 0x00000000 (kết thúc)
Vậy chỉ cần gán y hệt cho s1 là 0x804b5b0 là được

Sau khi set xong thì thấy nó đúng khớp nhau rồi nên nhảy qua thôi

Break 3:

0x0 - 0x198 sẽ bé hơn 0 nên sẽ bị nhảy, để không nhảy thì mình sẽ set eax về 0

Sau khi nhảy qua được tới đây rồi thì continue thôi để in ra flag luôn:

# Chal 2

Load file vào IDA, hàm start là một đoạn gì đó khá dài cho đến hàm chính ở đoạn cuối là sub_4012F0

Trong đó thì password cũng đã rõ trong 3 cái word_ kia là "I have a pen."



Chỉ vậy thôi mà không có thêm gì cả
Vậy thì phải thử debug.
Có rất nhiều chỗ anti-debug trong bài này nhưng hầu hết đề có thể bypass qua được bằng cách thay đổi giá trước khi so sánh cho phù hợp hoặc là chỉnh luôn các flag cho nhảy theo đúng hướng (mình sẽ đảo ZF = 0/1)

ZF từ 1 -> 0

ZF từ 1 -> 0

ZF từ 0 -> 1

tương tự với CheckRemoteDebuggerPresent, GetTickCount, FileName, ...
Nhưng đến đây thì bị lỗi (sub_401240)


Có vẻ là đoạn truyền dữ liệu qua các cổng gì đó bị lỗi. Research mãi không ra lỗi gì ;-; nên mình thử cho nhảy qua luôn đoạn check debug đó bằng các Set IP ở hàm tiếp theo đó.

Rồi F9 cho chạy hết luôn thì ra flag

# Chal 3

Bài này thì IDA nó decomplie được hàm main như sau:
```c
__int64 __fastcall main(int a1, char **a2, char **a3)
{
int i; // [rsp+8h] [rbp-8h]
int j; // [rsp+Ch] [rbp-4h]
pipe(pipedes);
__isoc99_scanf(&unk_2004, input);
len = strlen(input);
sub_11D9(&unk_4240);
sub_120D(&unk_4240, &unk_4100, (unsigned int)dword_4164);
sub_12D2(&unk_4240, (unsigned int)len, byte_4340);
for ( i = 0; i < len; ++i )
input[i] ^= byte_4340[i];
for ( j = 0; j < len; ++j )
{
if ( input[j] != byte_40C0[j] )
exit(1);
}
return 0LL;
}
```
```c
_BYTE *__fastcall sub_11D9(__int64 a1)
{
_BYTE *result; // rax
int i; // [rsp+14h] [rbp-4h]
for ( i = 0; i <= 255; ++i )
{
result = (_BYTE *)(i + a1);
*result = i;
}
return result;
}
```
```c
_BYTE *__fastcall sub_120D(__int64 a1, __int64 a2, int a3)
{
_BYTE *result; // rax
int v4; // [rsp+18h] [rbp-Ch]
int i; // [rsp+1Ch] [rbp-8h]
char v6; // [rsp+20h] [rbp-4h]
v4 = 0;
for ( i = 0; i <= 255; ++i )
{
v4 = (*(unsigned __int8 *)(i + a1) + v4 + *(unsigned __int8 *)(i % a3 + a2)) % 256;
v6 = *(_BYTE *)(i + a1);
*(_BYTE *)(i + a1) = *(_BYTE *)(v4 + a1);
result = (_BYTE *)(v4 + a1);
*result = v6;
}
return result;
}
```
```c
__int64 __fastcall sub_12D2(__int64 a1, int a2, __int64 a3)
{
__int64 result; // rax
int v5; // [rsp+18h] [rbp-10h]
int v6; // [rsp+1Ch] [rbp-Ch]
int v7; // [rsp+20h] [rbp-8h]
char v8; // [rsp+24h] [rbp-4h]
v5 = 0;
v6 = 0;
v7 = -1;
while ( a2 )
{
v5 = (v5 + 1) % 256;
v6 = (v6 + *(unsigned __int8 *)(v5 + a1)) % 256;
v8 = *(_BYTE *)(v5 + a1);
*(_BYTE *)(v5 + a1) = *(_BYTE *)(v6 + a1);
*(_BYTE *)(v6 + a1) = v8;
++v7;
result = *(unsigned __int8 *)((unsigned __int8)(*(_BYTE *)(v5 + a1) + *(_BYTE *)(v6 + a1)) + a1);
*(_BYTE *)(v7 + a3) = result;
--a2;
}
return result;
}
```
Main:
* Nhập input, lấy độ dài
* sub_11D9: unk_4240[i] = i
* sub_120D: với
* 
* 
Xem lại trong text view của IDA thì thấy có 2 hàm này:

Hàm init gọi đến:
```c
__int64 sub_1A20()
{
__int64 result; // rax
int i; // [rsp+0h] [rbp-Ch]
int j; // [rsp+4h] [rbp-8h]
int k; // [rsp+8h] [rbp-4h]
result = qword_4080;
if ( qword_4080 )
{
dword_4220 = 20;
dword_4224 = 23;
}
else
{
dword_4220 = 23;
dword_4224 = 20;
}
for ( i = 0; i <= 16; ++i )
{
result = i;
byte_4100[i] ^= (_BYTE)dword_4220 + (_BYTE)dword_4224;
}
for ( j = 0; j <= 20; ++j )
{
result = j;
s[j] ^= 0x14u;
}
for ( k = 0; k <= 12; ++k )
{
result = k;
aGqk9lLwyvj[k] ^= 0x1Eu;
}
return result;
}
```

Sau khi viết script để xor thử thì biết được 2 xâu đó là 'sorry, plz try again.' và 'you're right!'
Hàm fini gọi đến:
```c
unsigned __int64 sub_16C5()
{
int v1; // eax
__WAIT_STATUS stat_loc; // [rsp+4h] [rbp-2Ch] BYREF
int i; // [rsp+Ch] [rbp-24h]
int j; // [rsp+10h] [rbp-20h]
int k; // [rsp+14h] [rbp-1Ch]
__pid_t v6; // [rsp+18h] [rbp-18h]
int v7; // [rsp+1Ch] [rbp-14h]
int pipedes[2]; // [rsp+20h] [rbp-10h] BYREF
unsigned __int64 v9; // [rsp+28h] [rbp-8h]
v9 = __readfsqword(0x28u);
if ( pipe(pipedes) == -1 )
exit(1);
v6 = fork();
if ( v6 < 0 )
exit(1);
if ( v6 )
{
close(pipedes[0]);
v7 = 2;
HIDWORD(stat_loc.__iptr) = 3;
while ( SHIDWORD(stat_loc.__iptr) < len )
{
if ( SHIDWORD(stat_loc.__iptr) % v7 )
write(pipedes[1], (char *)&stat_loc.__iptr + 4, 4uLL);
else
++dword_4168;
++HIDWORD(stat_loc.__iptr);
}
close(pipedes[1]);
close(dword_43AC);
while ( (unsigned int)read(::pipedes[0], (char *)&stat_loc.__iptr + 4, 4uLL) )
{
v1 = dword_4164++;
byte_4100[v1] = BYTE4(stat_loc.__iptr);
}
close(::pipedes[0]);
wait((__WAIT_STATUS)&stat_loc);
if ( LODWORD(stat_loc.__uptr) )
{
puts(s);
exit(1);
}
v6 = fork();
if ( v6 < 0 )
exit(1);
if ( !v6 )
{
sub_120D((__int64)&unk_4240, (__int64)byte_4100, dword_4164);
for ( i = 0; i < dword_4168; ++i )
sub_12D2((__int64)&unk_4240, len, (__int64)byte_4340);
for ( j = 0; j < len; j += 2 )
{
input[j] = (input[j] + input[j + 1]) ^ byte_4340[j];
input[j + 1] = byte_4340[j + 1] ^ (input[j] - input[j + 1]);
}
for ( k = 0; k < len; ++k )
{
if ( input[k] != byte_4180[k] )
exit(1);
}
exit(0);
}
wait((__WAIT_STATUS)&stat_loc);
if ( LODWORD(stat_loc.__uptr) )
puts(s);
else
puts(aGqk9lLwyvj);
exit(0);
}
sub_13D8(pipedes);
return v9 - __readfsqword(0x28u);
}
```
```c
unsigned __int64 __fastcall sub_13D8(int *a1)
{
int v2; // eax
int buf; // [rsp+18h] [rbp-28h] BYREF
__WAIT_STATUS stat_loc; // [rsp+1Ch] [rbp-24h] BYREF
int i; // [rsp+24h] [rbp-1Ch]
int j; // [rsp+28h] [rbp-18h]
__pid_t v7; // [rsp+2Ch] [rbp-14h]
int pipedes[2]; // [rsp+30h] [rbp-10h] BYREF
unsigned __int64 v9; // [rsp+38h] [rbp-8h]
v9 = __readfsqword(0x28u);
close(a1[1]);
if ( !(unsigned int)read(*a1, &buf, 4uLL) )
exit(1);
if ( pipe(pipedes) == -1 )
exit(1);
v7 = fork();
if ( v7 < 0 )
exit(1);
if ( v7 )
{
close(pipedes[0]);
close(::pipedes[0]);
write(dword_43AC, &buf, 4uLL);
close(dword_43AC);
while ( (unsigned int)read(*a1, (char *)&stat_loc.__iptr + 4, 4uLL) )
{
if ( SHIDWORD(stat_loc.__iptr) % buf )
write(pipedes[1], (char *)&stat_loc.__iptr + 4, 4uLL);
else
++dword_4168;
}
close(pipedes[1]);
wait((__WAIT_STATUS)&stat_loc);
v2 = dword_4164++;
byte_4100[v2] = byte_4240[buf];
sub_120D((__int64)byte_4240, (__int64)byte_4100, dword_4164);
for ( i = 0; i < 256 - dword_4168; ++i )
{
sub_12D2((__int64)byte_4240, len, (__int64)byte_4340);
for ( j = 0; j < len; j += 2 )
{
input[j] = (input[j] + input[j + 1]) ^ byte_4340[j];
input[j + 1] = byte_4340[j + 1] ^ (input[j] - input[j + 1]);
}
}
exit(0);
}
sub_13D8(pipedes);
return v9 - __readfsqword(0x28u);
}
```
Tìm hiểu về cách hoạt động của fork() và pipe() (https://www.geeksforgeeks.org/c-program-demonstrate-fork-and-pipe/), mình hiểu được sơ sơ là fork() nó sẽ tạo process con giống với cái hiện tại còn pipe() để giao tiếp giữa các process đó. Khi kết hợp, pipe() được tạo trước khi gọi fork(). Nhờ vậy, cả process cha và con đều chia sẻ cùng một pipe để giao tiếp.
Vậy những thứ mình cần phân tích phải nằm sub_16C5 và sub_13D8, nhận thấy giống với mã hóa rc4 (https://codelearn.io/sharing/stream-cipher-rc4)
* sub_120D là hàm KSA
* sub_12D2 là hàm PRG
Vậy thì chỉ cần đi ngược lên từ đoạn so sánh input với byte_4180, ta có mảng như sau:

Còn một vấn đề cuối cùng là làm sao để tìm được key ban đầu (nằm ở byte_4340) nữa thôi.
```py
from Crypto.Cipher import ARC4
#byte_4180
input = [0xF7, 0x5F, 0xE7, 0xB0, 0x9A, 0xB4, 0xE0, 0xE7, 0x9E, 0x05, 0xFE, 0xD8, 0x35, 0x5C, 0x72, 0xE0, 0x86, 0xDE, 0x73, 0x9F, 0x9A, 0xF6, 0x0D, 0xDC, 0xC8, 0x4F, 0xC2, 0xA4, 0x7A, 0xB5, 0xE3, 0xCD, 0x60, 0x9D, 0x04, 0x1F]
byte_4100 = [0x7C, 0x4E, 0x1A, 0x48, 0x1B, 0x46, 0x18, 0x74, 0x5F, 0x1B, 0x74, 0x4F, 0x75, 0x18, 0x48, 0x5F, 0x4D]
# for i in range(len(byte_4100)):
# byte_4100[i] ^= 20 + 23
# byte_4240
s = []
for i in range(256):
s.append(i)
j = 0
for i in range(256):
j = (j + s[i] + byte_4100[i % len(byte_4100)]) % 256
#swap
s[i], s[j] = s[j], s[i]
# print(s)
i = 0
j = 0
key = []
for _ in range(36):
i = (i + 1) % 256
j = (j + s[i]) % 256
#swap
s[i], s[j] = s[j], s[i]
key.append(s[(s[i] + s[j]) % 256])
# print(hex(key[-1]), end = ' ')
#byte_4340
for i in range(0, 36, 2):
x = input[i + 1] ^ key[i + 1] # = input[i] - input[i + 1]
input[i + 1] = input[i] - x
input[i + 1] += 256
input[i + 1] %= 256
x = input[i] ^ key[i] # = input[i] + input[i + 1]
input[i] = x - input[i + 1]
input[i] += 256
input[i] %= 256
# print(input)
key = [0x57, 0x65, 0x31, 0x63, 0x30, 0x6D, 0x33, 0x5F, 0x74, 0x30, 0x5F, 0x64, 0x5E, 0x33, 0x63, 0x74, 0x66]
print(ARC4.new(bytes(key)).decrypt(bytes(input)))
```