紀念一下自己第一次嘗試 CTF ,比賽體驗很好,也收獲不少,雖然水平有些 too low(甚至連 IDA 都是在比賽開始之后才下載+現學現賣)
去年疫情在家刷知乎刷到過一些 CTF 相關的內容,當時感覺離自己十分遙遠,如今也算是稍稍見識了一下網絡安全這個未知但好玩的領域了(當然,以自己的層次大概連"入門"都還遠遠沒有達到吧)。
PWN 方向的題由於這周一直在 Windows 環境下,沒時間搞了,略微有些小遺憾。Reverse 從開賽后才想起來下載 IDA 到成功拿下兩道(簽到題)的二血,小小地驕傲一下(還有兩道 Reverse 由於不會破解代碼里的(看得讓人頭大的)加密算法,故半途而廢了
題目通過數量:
crypto | pwn | web | reverse | misc |
---|---|---|---|---|
1 | 0 | 1 | 2 | 1 |
附上兩道二血題目的 Writeup:(寫得略有點啰嗦 orz)
re_check_in
給了兩個文件,check_in.exe
和 hint.txt
。
由於題目說了直接運行 exe 會覆蓋 hint.txt
所以在動手解題之前先把 hint.txt
備份一下。
用 IDA 打開 check_in.exe
,在左側直接找到 main
函數點開,按 F5 反匯編查看 C 代碼:
反匯編出來的 C 代碼:
int __cdecl main(int argc, const char **argv, const char **envp)
{
_BYTE *v4; // [rsp+20h] [rbp-30h]
void *Buffer; // [rsp+28h] [rbp-28h]
int v6; // [rsp+34h] [rbp-1Ch]
int v7; // [rsp+34h] [rbp-1Ch]
FILE *v8; // [rsp+38h] [rbp-18h]
FILE *Stream; // [rsp+40h] [rbp-10h]
int i; // [rsp+4Ch] [rbp-4h]
_main(argc, argv, envp);
Stream = fopen("flag.jpg", "rb");
v8 = fopen("hint.txt", "wb");
if ( !Stream )
exit(1);
fseek(Stream, 0, 2);
v6 = ftell(Stream);
Buffer = malloc(v6 + 1);
v4 = malloc(v6 + 1);
rewind(Stream);
v7 = fread(Buffer, 1ui64, v6, Stream);
*((_BYTE *)Buffer + v7) = 0;
for ( i = 0; i < v7; ++i )
v4[i] = key[i] ^ *((_BYTE *)Buffer + i);
fwrite(v4, 1ui64, v7, v8);
fclose(Stream);
fclose(v8);
return 0;
}
可以看到第 12 行與第 13 行有 fopen
函數與兩個較為明顯的文件名。程序需要一個文件 flag.jpg
作為輸入,並將輸出寫入 hint.txt
。( flag.jpg
從哪來呢?)
本着試試看的態度,將原 hint.txt
改名為 flag.jpg
並運行 check_in.exe
,看到又生成了一個 hint.txt
。用文本編輯器打開發現是個二進制文件,並且前幾個字節中出現了 JFIF
字樣,推測出是一張圖片(當時自己並不認識 JFIF
文件頭,只是看到二進制文件並聯想起前面出現過的 flag.jpg
文件名猜出來是圖片)。
將程序生成的 hint.txt
擴展名改為 .jpg
打開即可得到 flag。
最后還是把 flag 放出來吧,紀念一下第一次接觸 CTF ^_^(圖片已打碼)
zerothree
請找出用戶 or4nge 的 license
題目只有一個附件 zerothree.exe
,下載下來直接用 IDA 打開,在左側找到 main
函數,F5 查看反編譯的 C 代碼:(果然第二題比第一題操作熟練許多了)
雖然沒有第一題那么明顯,但代碼邏輯還挺清晰的:
- 輸入一個字符串
Str
,根據題干得出這里應是or4nge
- "輸入"一個字符串
v40
(license),這里需要根據代碼去解出 license 的內容 - 將
Str
(長度不足就循環拼接) 與v40
逐位做異或,存入以局部變量v4
為起始的連續 36 字節的(棧區)空間中,也就是main
函數中連續定義的 36 個char
變量,這些變量都位於棧中,地址是連續的。- 變量
v##i
對應((char*)&v4)[i - 4]
- 變量
- 判斷
v4
到v39
這些變量是否滿足下面的一系列等式,如果滿足則輸入的 license 就是正確的 flag 。
附上 main
函數的 C 代碼(部分相似內容已略去)
int __cdecl main(int argc, const char **argv, const char **envp)
{
int result; // eax
char v4; // [rsp+160h] [rbp+E0h]
char v5; // [rsp+161h] [rbp+E1h]
/* ... Omitted 33 lines here ... */
char v39; // [rsp+183h] [rbp+103h]
char v40[48]; // [rsp+190h] [rbp+110h] BYREF
char Str[36]; // [rsp+1C0h] [rbp+140h] BYREF
int v42; // [rsp+1E4h] [rbp+164h]
int v43; // [rsp+1E8h] [rbp+168h]
int i; // [rsp+1ECh] [rbp+16Ch]
_main(argc, argv, envp);
puts("Please input your username:");
scanf("%20s", Str);
puts("Please input your license:");
scanf("%40s", v40);
v43 = strlen(Str);
v42 = strlen(v40);
if ( v42 != 36 )
goto LABEL_42;
for ( i = 0; i < v42; ++i )
*(&v4 + i) = Str[i % v43] ^ v40[i];
if ( 30 * v33
+ -99 * v14
/* ... Omitted 33 lines here ... */
- 67 * v22 == -12868i64
&& 30 * v9
/* ... Omitted 1251 lines (34 `&&`s and 34 `==`s) here ... */
+ 58 * v18 == 6529i64 )
{
printf("Congratulations! Flag is the license!");
result = 0;
}
else
{
LABEL_42:
printf("Invalid License!");
result = 0;
}
return result;
}
開始正式解題,解題的關鍵在於解出滿足條件的 v4
~ v39
,然后將它們與 Str
再做一遍異或即可還原出原始的 flag
。
觀察一下 if
的條件,要求若干個等式(方程)同時成立,並且每個方程的形式都是若干個"系數乘以變量"之和等於一個常數(這中間有極少數例外,沒有系數或者按位左移的形式,但都可以統一成變量乘系數)。
這分明就是個線性方程組!( Ctrl+F 搜索一下,&&
剛好有 35 個,==
剛好有 36 個,也就是剛好 36 個方程,對應 36 個未知數,如果方程之間兩兩線性無關則方程組有唯一解)
接下來的任務變成了從這一串長長的條件表達式中提取出系數和常數(將方程還原成矩陣形式 \(AX=b\) )。首先通過字符串的正則查找替換將表達式處理成統一的格式,然后編寫 Python 代碼進行系數、常數的提取。
字符串預處理(手動)
采用 VSCode 進行處理(在正則查找與替換下,替換目標文本中采用 $1
, $2
等來表示匹配模式串中小括號內的內容):
- 將所有條件合並到一行:在 C 語法配置下,右鍵-Format Document
- 根據
&&
分割,一行一個等式:&&
\(\rightarrow\)\n
- 去掉 IDA 反編譯出來的整數的
i64
后綴:(\d+)i64
\(\rightarrow\)$1
- 將右移轉換為乘法:
\((v\d+) << 6\)
\(\rightarrow\)64 * $1
- 給每一行的行首第一項前面補上
+
號(使得與后面的項格式一致):利用 Alt+Shift 同時選中多行,手動添加 - 給沒有系數的項補上系數 1:
([+\-]) (v\d+)
\(\rightarrow\)$1 1 * $2
經過上述處理后,將 if
條件處理成了一個格式統一的方程組,共 36 行,每行一個方程,並且每一項滿足正則表達式:([+\-]) (-?\d+) \* v(\d+)
(三個括號分別代表項的正負號,系數和變量的編號)
正式求解(Python)
采用 Python 的 re
庫解析上述的線性方程組,提取系數和常數,並將其填入矩陣和向量中的相應位置(假設下標從 0 開始):
- 第 \(i\) 個方程的常數項對應 \(b_i\)
- 第 \(i\) 個方程中變量 \(v_j\) 的系數對應系數矩陣中的 \(a_{i,j-4}\)
- 相應位置未出現過的系數為 0
還原出 \(A\) 和 \(b\) 后利用 numpy.linalg
庫求解線性方程組,還原出 v4
~ v39
對應的字符的 ascii 碼,然后與 Str
進行一遍異或即可還原出 flag。
expr = '''
+ 30 * v33 + -99 * v14 + 90 * v18 + -23 * v27 + -7 * v34 + 88 * v29 + -19 * v8 + -49 * v20 + 89 * v28 + -35 * v6 + -65 * v25 + 63 * v36 + 53 * v15 + 66 * v19 + -42 * v21 + 29 * v4 + 70 * v23 + -20 * v16 + -37 * v5 - 58 * v37 + 17 * v11 + 26 * v35 - 56 * v30 + 67 * v39 + 11 * v10 - 53 * v7 + 9 * v13 - 50 * v32 - 48 * v12 - 70 * v26 + 48 * v17 + 1 * v31 - 33 * v24 - 68 * v38 - 14 * v9 - 67 * v22 == -12868
+ 30 * v9 + 47 * v37 + 1 * v18 + -47 * v20 + -41 * v29 + 60 * v26 + 90 * v13 + 62 * v14 + 57 * v27 + -91 * v31 + 10 * v39 + 13 * v6 + 57 * v8 + 90 * v25 + -57 * v19 + 64 * v22 - 63 * v17 - 56 * v12 + 56 * v35 - 40 * v4 - 92 * v21 - 5 * v33 - 13 * v16 + 5 * v32 - 63 * v36 + 5 * v30 + 67 * v38 - 20 * v5 - 79 * v23 - 17 * v10 + 70 * v7 + 41 * v11 + 71 * v28 + 15 * v15 + 42 * v24 == 8520
+ 69 * v28 + 58 * v33 + 34 * v27 + 49 * v5 + 88 * v39 + 50 * v24 + 7 * v4 + -99 * v31 + -100 * v34 + 74 * v38 + 77 * v37 + -77 * v18 + 29 * v20 + 53 * v13 + -13 * v36 + 93 * v15 + -53 * v14 + 2 * v11 + 77 * v23 + 28 * v17 - 61 * v8 + 12 * v21 - 87 * v29 + 36 * v10 + 59 * v7 + 81 * v25 + 28 * v32 + 73 * v30 + 54 * v26 - 5 * v35 - 41 * v6 + 5 * v22 - 93 * v19 + 10 * v16 - 27 * v12 + 24 * v9 == 12936
+ -61 * v6 + -100 * v22 + -77 * v20 + 86 * v15 + -77 * v11 + -52 * v14 + 58 * v21 + 51 * v17 + 53 * v25 + 43 * v19 + -96 * v16 + -9 * v28 + -44 * v5 + -61 * v33 + 23 * v12 + 94 * v34 + 8 * v32 + 51 * v8 + -46 * v23 + -61 * v10 - 46 * v24 - 76 * v38 - 17 * v35 - 52 * v39 + 81 * v37 + 75 * v36 + 5 * v30 + 2 * v29 + 31 * v26 - 2 * v4 - 17 * v27 - 92 * v18 + 13 * v9 - 99 * v7 + 63 * v31 + 8 * v13 == -5016
+ 64 * v5 + 17 * v17 + 91 * v4 + -25 * v8 + -36 * v31 + 37 * v39 + 68 * v32 + 78 * v26 + -44 * v11 + 60 * v23 + -69 * v13 + -81 * v37 + -69 * v30 + 32 * v22 + -29 * v18 + 59 * v7 + 9 * v20 - 35 * v25 + 40 * v15 + 70 * v33 + 3 * v6 + 61 * v10 + 40 * v38 + 23 * v21 + 81 * v16 - 43 * v36 + 9 * v19 + 69 * v34 - 9 * v27 - 75 * v29 - 62 * v24 + 56 * v35 + 96 * v9 + 69 * v12 + 80 * v14 + 99 * v28 == 12113
+ -86 * v31 + 66 * v33 + 93 * v5 + 78 * v28 + -63 * v25 + 51 * v36 + -39 * v9 + -36 * v39 + -34 * v29 + 79 * v15 + -89 * v6 + 32 * v35 + -86 * v17 + -13 * v37 + 51 * v27 + 50 * v24 + 47 * v20 + -79 * v30 - 20 * v12 + 90 * v10 + 6 * v34 - 41 * v11 - 56 * v18 + 54 * v23 - 96 * v38 - 64 * v8 + 48 * v14 - 76 * v32 + 48 * v22 - 3 * v4 + 20 * v7 + 61 * v21 - 56 * v19 - 97 * v26 + 96 * v13 - 61 * v16 == -15499
+ -32 * v27 + -44 * v39 + 83 * v13 + -66 * v15 + -13 * v4 + 83 * v17 + 22 * v38 + 98 * v11 + 99 * v36 + 83 * v23 + 91 * v9 + 76 * v37 - 74 * v32 - 25 * v6 - 9 * v35 + 35 * v29 + 31 * v22 - 95 * v25 + 37 * v26 - 74 * v20 + 17 * v16 - 27 * v28 + 11 * v7 - 26 * v34 - 36 * v8 + 64 * v10 - 65 * v30 - 46 * v12 - 33 * v18 - 45 * v5 - 60 * v31 + 77 * v24 + 96 * v19 - 23 * v14 - 5 * v33 - 73 * v21 == 4675
+ -83 * v9 + -11 * v22 + 78 * v37 + -51 * v18 + 69 * v31 + 76 * v5 + -26 * v15 + -88 * v7 + 82 * v12 + -79 * v14 + 86 * v17 + -36 * v8 + 24 * v25 + -99 * v34 + 60 * v33 + -34 * v36 + 69 * v21 + -93 * v30 + 42 * v28 + 55 * v20 + 32 * v29 - 57 * v35 + 84 * v16 + 9 * v27 - 84 * v6 - 18 * v11 - 1 * v4 + 9 * v39 + 89 * v19 + 72 * v23 - 8 * v32 + 70 * v24 - 36 * v26 + 64 * v10 + 19 * v13 + 71 * v38 == -303
+ -60 * v5 + -16 * v33 + 79 * v14 + 65 * v36 + 50 * v34 + -70 * v12 + -59 * v23 + -58 * v11 + -51 * v9 + 94 * v13 + -57 * v29 + 88 * v22 + -20 * v15 + 86 * v4 + -68 * v8 + 57 * v18 + 28 * v32 + 29 * v16 + -31 * v21 + 75 * v10 + -54 * v6 - 80 * v19 + 82 * v17 - 18 * v27 - 2 * v7 + 94 * v35 - 6 * v25 + 26 * v20 - 62 * v38 - 82 * v31 + 25 * v24 - 66 * v39 - 62 * v28 + 89 * v30 + 12 * v26 - 86 * v37 == 12337
+ -88 * v8 + -63 * v4 + 83 * v22 + -49 * v38 + 72 * v12 + -11 * v6 + -30 * v17 + -46 * v10 + 77 * v27 + -7 * v35 + -7 * v28 + 14 * v30 + -75 * v26 + 38 * v7 + -11 * v21 - 91 * v24 + 53 * v39 + 31 * v9 + 47 * v23 + 48 * v37 + 74 * v5 - 24 * v34 + 87 * v13 + 33 * v15 + 86 * v32 + 37 * v25 - 97 * v31 + 31 * v18 + 30 * v14 + 72 * v33 - 59 * v20 + 5 * v11 - 3 * v19 + 13 * v16 - 73 * v36 - 56 * v29 == -5666
+ 26 * v29 + 84 * v6 + -52 * v7 + 49 * v4 + -81 * v12 + 59 * v27 + -66 * v38 + -85 * v26 + -27 * v5 + -70 * v14 + -95 * v17 + -89 * v16 + -66 * v32 + 77 * v34 + 14 * v19 + -97 * v10 - 74 * v24 - 91 * v8 - 5 * v23 - 94 * v33 - 24 * v39 - 7 * v36 + 63 * v9 - 49 * v18 - 96 * v22 - 100 * v11 + 81 * v20 + 70 * v15 + 3 * v25 + 28 * v28 - 14 * v13 + 59 * v21 + 24 * v35 - 25 * v31 + 20 * v37 - 77 * v30 == -16449
+ 60 * v6 + 69 * v14 + 55 * v27 + 30 * v9 + 34 * v10 + 53 * v39 + 70 * v23 + 2 * v11 + 98 * v32 + 42 * v15 + -91 * v30 + -63 * v33 + -58 * v8 + -53 * v26 + 1 * v20 + 22 * v25 + -19 * v17 + 83 * v19 + 69 * v22 + 55 * v28 + -69 * v29 + 33 * v24 + 28 * v38 + 5 * v7 + 35 * v12 + 27 * v5 - 31 * v31 + 10 * v16 + 84 * v37 + 24 * v18 - 2 * v21 + 68 * v36 + 21 * v4 - 1 * v13 + 60 * v35 - 60 * v34 == 16413
+ -17 * v36 + 1 * v34 + 14 * v18 + -97 * v31 + 32 * v8 + 90 * v33 + 50 * v12 + -92 * v17 + -61 * v19 + 64 * v22 + 60 * v15 + 76 * v14 + 70 * v38 + -68 * v16 + -81 * v13 + 38 * v23 + 15 * v35 - 96 * v25 + 89 * v24 + 33 * v6 + 79 * v32 - 80 * v39 - 38 * v9 + 5 * v10 - 8 * v30 - 59 * v27 + 9 * v28 + 34 * v21 - 60 * v5 + 98 * v29 + 48 * v20 - 88 * v26 - 96 * v7 + 97 * v11 - 96 * v4 + 54 * v37 == -5321
+ -98 * v26 + -57 * v34 + 53 * v12 + -58 * v36 + -82 * v14 + 68 * v37 + 57 * v35 + -92 * v16 + -98 * v32 + -50 * v4 + -45 * v20 + 60 * v29 + 49 * v21 - 7 * v7 - 22 * v27 + 33 * v17 - 15 * v9 + 36 * v33 - 88 * v19 + 12 * v25 + 71 * v18 - 48 * v39 + 79 * v38 - 5 * v23 - 2 * v8 - 29 * v28 - 28 * v30 - 16 * v22 - 64 * v31 + 32 * v15 + 73 * v6 - 38 * v24 + 27 * v13 - 7 * v11 - 30 * v5 - 35 * v10 == -16134
+ 58 * v20 + 91 * v12 + 91 * v19 + -31 * v25 + -69 * v37 + -86 * v32 + -78 * v21 + -20 * v34 + 19 * v16 + -22 * v15 + 71 * v31 + -85 * v23 + 29 * v24 + 60 * v18 + 4 * v35 - 43 * v22 - 36 * v33 + 95 * v13 + 6 * v38 + 49 * v10 + 13 * v14 - 23 * v17 + 17 * v11 - 79 * v26 + 12 * v7 - 7 * v8 - 12 * v6 - 91 * v27 - 56 * v9 + 59 * v30 + 18 * v36 - 87 * v39 - 30 * v28 + 54 * v29 - 5 * v5 - 94 * v4 == 2487
+ -33 * v15 + 80 * v10 + 9 * v20 + 63 * v5 + -44 * v27 + -71 * v30 + -78 * v17 + -95 * v9 + -94 * v14 + -11 * v23 + 97 * v4 + 52 * v19 + -89 * v25 + 56 * v31 + -87 * v8 + -73 * v39 + -85 * v24 + -17 * v13 - 93 * v16 - 87 * v28 - 80 * v29 - 92 * v33 - 20 * v21 - 13 * v12 + 80 * v35 - 1 * v37 + 37 * v34 + 64 * v36 - 18 * v22 - 76 * v38 + 65 * v7 + 61 * v11 + 11 * v26 - 39 * v18 - 62 * v6 - 74 * v32 == -38279
+ 75 * v20 + -95 * v12 + 77 * v35 + 69 * v33 + -85 * v38 + 59 * v10 + 43 * v37 + -65 * v23 + 63 * v19 + -40 * v18 + 20 * v17 + 36 * v27 + 31 * v9 + -45 * v29 + -61 * v28 + 65 * v26 + 54 * v24 - 9 * v13 + 47 * v8 - 40 * v6 - 64 * v16 + 81 * v14 - 35 * v4 - 12 * v31 + 35 * v34 + 31 * v22 - 42 * v39 + 33 * v15 + 76 * v36 - 4 * v30 - 19 * v7 + 65 * v25 - 78 * v11 - 48 * v32 - 77 * v21 == 3750
+ -25 * v32 + -51 * v5 + -92 * v31 + 47 * v35 + 33 * v36 + -37 * v13 + 95 * v9 + 67 * v27 + -38 * v14 + 35 * v10 + -63 * v34 + -93 * v38 + 28 * v12 + -41 * v11 + 71 * v28 + -73 * v19 + 76 * v17 + 35 * v24 + 55 * v21 - 12 * v4 + 84 * v16 - 72 * v7 - 4 * v20 + 99 * v15 + 10 * v8 - 98 * v39 - 9 * v22 + 22 * v25 - 6 * v30 - 71 * v29 + 96 * v18 + 82 * v6 - 6 * v37 - 13 * v33 + 25 * v26 - 35 * v23 == 8374
+ 88 * v38 + -65 * v32 + -50 * v29 + 56 * v19 + 78 * v6 + 93 * v12 + 64 * v25 + 98 * v20 + 2 * v34 + -41 * v22 + 87 * v11 + -34 * v21 + -49 * v8 + 54 * v4 + -72 * v17 + 87 * v28 + 79 * v31 - 52 * v33 - 17 * v27 + 45 * v14 - 17 * v37 - 81 * v15 + 37 * v39 - 46 * v13 + 25 * v36 - 45 * v18 - 30 * v16 + 83 * v23 + 24 * v5 - 51 * v10 - 17 * v30 - 76 * v7 - 36 * v35 + 77 * v24 - 62 * v9 + 67 * v26 == 19675
+ 82 * v36 + -25 * v8 + 61 * v14 + -71 * v34 + -29 * v11 + 30 * v5 + 34 * v39 + -74 * v17 + 8 * v37 + -50 * v29 + -35 * v33 + 75 * v35 + 92 * v10 + -70 * v30 + 55 * v25 + -21 * v23 + 37 * v21 + 29 * v28 - 10 * v19 - 75 * v20 + 24 * v22 + 98 * v4 + 41 * v24 - 54 * v32 - 5 * v27 - 66 * v13 + 3 * v9 + 62 * v26 - 40 * v38 + 90 * v7 - 36 * v18 - 66 * v6 + 15 * v16 - 74 * v31 + 31 * v12 - 68 * v15 == -21872
+ 37 * v20 + 84 * v26 + 77 * v35 + -75 * v12 + 55 * v39 + -83 * v33 + -79 * v28 + 35 * v30 + -71 * v10 + -66 * v11 + 64 * v29 + -69 * v7 + 98 * v13 + 28 * v21 + -11 * v23 + -13 * v19 - 34 * v17 + 75 * v38 + 19 * v36 - 94 * v37 - 72 * v22 - 32 * v31 + 76 * v5 + 80 * v32 + 66 * v14 + 3 * v16 - 99 * v18 + 17 * v34 - 94 * v4 + 12 * v6 + 61 * v24 - 24 * v27 + 62 * v15 - 65 * v25 - 2 * v8 - 90 * v9 == 13561
+ 19 * v23 + 21 * v5 + 68 * v37 + 39 * v27 + 43 * v15 + 64 * v19 + -34 * v30 + -20 * v35 + 31 * v21 + -10 * v39 + 47 * v13 + -42 * v36 + 80 * v28 + -37 * v8 + -94 * v20 + -76 * v6 + 24 * v7 - 31 * v11 - 65 * v4 - 23 * v26 - 48 * v24 - 95 * v10 - 30 * v38 - 67 * v16 + 81 * v18 - 21 * v31 + 65 * v22 + 60 * v29 - 17 * v25 - 58 * v17 + 96 * v12 - 32 * v34 - 83 * v32 + 20 * v9 - 3 * v33 + 7 * v14 == -15976
+ -80 * v25 + 48 * v21 + -88 * v22 + -37 * v34 + 1 * v7 + 67 * v15 + 52 * v10 + 14 * v31 + -82 * v27 + -52 * v11 + -15 * v17 + 56 * v23 + 97 * v36 + -55 * v12 + -41 * v35 + -46 * v16 + -84 * v39 + 55 * v13 + -91 * v19 + -59 * v30 + 93 * v6 + 53 * v24 + -92 * v28 + -82 * v26 - 76 * v4 - 90 * v9 + 3 * v38 + 77 * v29 - 40 * v20 - 93 * v8 + 37 * v37 - 16 * v14 + 1 * v18 + 17 * v33 - 94 * v32 - 12 * v5 == -9828
+ -52 * v35 + 22 * v22 + -12 * v33 + -89 * v23 + 22 * v29 + 42 * v34 + -26 * v4 + 46 * v13 + 53 * v5 + 34 * v16 + -91 * v19 + 23 * v24 + -91 * v37 + -25 * v27 + 84 * v15 + 68 * v6 + -35 * v20 + -74 * v31 + -85 * v17 + 58 * v7 + 95 * v32 + -79 * v30 + -94 * v14 + -76 * v8 + -55 * v9 - 71 * v25 - 87 * v18 - 65 * v38 - 16 * v28 + 34 * v36 - 16 * v11 + 83 * v26 + 5 * v21 - 71 * v10 + 41 * v39 + 68 * v12 == -17536
+ -18 * v5 + 35 * v8 + -59 * v14 + -98 * v35 + -95 * v34 + -50 * v17 + 64 * v18 + 95 * v21 + 59 * v26 + 54 * v9 + 89 * v31 + -87 * v7 + -19 * v23 - 97 * v16 + 62 * v30 + 6 * v24 - 68 * v20 + 10 * v4 - 1 * v6 - 1 * v32 + 17 * v22 - 76 * v10 - 24 * v27 - 76 * v15 + 33 * v38 - 53 * v12 + 9 * v36 - 45 * v13 - 60 * v33 - 74 * v39 + 31 * v11 + 50 * v28 + 25 * v25 - 83 * v37 + 25 * v29 + 52 * v19 == -9636
+ 99 * v23 + 70 * v36 + 98 * v37 + -53 * v24 + -54 * v34 + 30 * v32 + -42 * v39 + -34 * v19 + 77 * v25 + -68 * v9 + -50 * v7 + 44 * v6 + 88 * v5 + -39 * v10 + -79 * v21 + -29 * v17 + 52 * v33 + -55 * v15 + 40 * v14 + -45 * v30 + -54 * v11 + -73 * v18 + 84 * v38 - 27 * v29 - 97 * v22 + 73 * v31 + 32 * v28 - 80 * v4 - 2 * v26 - 44 * v35 - 62 * v12 - 51 * v8 + 12 * v20 - 55 * v13 + 40 * v16 + 76 * v27 == 9324
+ -39 * v16 + 9 * v11 + -28 * v12 + -17 * v21 + -83 * v37 + 16 * v20 + 74 * v34 + 20 * v15 + 70 * v9 + 69 * v7 + -82 * v30 + -78 * v35 + -31 * v32 + -76 * v23 + 70 * v17 + 86 * v24 + 77 * v18 + 48 * v19 + 95 * v10 - 60 * v8 + 30 * v31 + 3 * v33 - 29 * v36 + 5 * v28 + 55 * v4 + 36 * v27 - 90 * v26 + 37 * v39 + 78 * v38 - 64 * v5 + 16 * v6 - 62 * v14 + 46 * v13 + 63 * v25 - 64 * v22 - 27 * v29 == 1836
+ -20 * v30 + -60 * v14 + -79 * v36 + -29 * v31 + -97 * v38 + 85 * v20 + -55 * v7 + -7 * v23 + -71 * v6 + 97 * v25 + 89 * v19 + 58 * v17 + 39 * v27 + -82 * v21 + -46 * v13 + -63 * v16 + 64 * v12 + -39 * v34 + -47 * v9 + -89 * v15 + -57 * v28 + 92 * v10 + 7 * v4 - 81 * v5 + 33 * v33 + 89 * v11 - 14 * v24 + 97 * v37 + 10 * v39 - 46 * v18 + 81 * v8 + 50 * v32 + 81 * v26 - 44 * v35 + 18 * v22 + 91 * v29 == -20826
+ 69 * v25 + 64 * v23 + -22 * v19 + 67 * v33 + -41 * v14 + -47 * v8 + -63 * v17 + 98 * v12 + 82 * v32 + 91 * v37 + 88 * v36 + -48 * v10 + -5 * v5 + 92 * v35 + 88 * v34 + -45 * v28 + -70 * v15 + -93 * v39 + -89 * v29 + 52 * v22 + 49 * v21 + 44 * v30 - 16 * v26 - 8 * v13 - 1 * v20 - 4 * v31 - 79 * v16 - 18 * v6 + 23 * v24 - 20 * v18 + 91 * v9 - 6 * v11 + 84 * v7 - 6 * v38 - 4 * v27 - 80 * v4 == 13298
+ -29 * v14 + -29 * v4 + -35 * v12 + -94 * v16 + -69 * v26 + 99 * v24 + -46 * v36 + -28 * v39 + -57 * v19 + 72 * v6 + -73 * v21 + 34 * v18 + 84 * v34 + -39 * v29 + -51 * v8 + 27 * v20 + -92 * v35 + 61 * v11 + 89 * v15 + 99 * v25 - 48 * v28 - 92 * v22 - 14 * v17 - 1 * v23 + 2 * v13 + 3 * v33 - 61 * v37 - 6 * v30 - 8 * v31 - 72 * v10 - 2 * v27 - 23 * v38 + 41 * v7 + 42 * v32 == -12156
+ 28 * v17 + 44 * v25 + -51 * v28 + 88 * v18 + -49 * v26 + -29 * v24 + 22 * v33 + 74 * v16 + 58 * v34 + 90 * v23 + -84 * v22 + -37 * v13 + -98 * v19 + -21 * v30 + 49 * v32 + 44 * v5 + 75 * v38 + 32 * v37 + 43 * v14 + -66 * v36 + 85 * v12 + 62 * v29 + 60 * v8 - 40 * v4 + 78 * v20 + 96 * v39 - 2 * v11 + 43 * v6 - 28 * v10 - 77 * v7 - 30 * v21 - 95 * v9 + 5 * v27 + 85 * v35 + 5 * v31 + 47 * v15 == 25730
+ -95 * v7 + -68 * v6 + 91 * v39 + -85 * v16 + -66 * v4 + 57 * v19 + -89 * v24 + 4 * v33 + -92 * v30 + 30 * v5 + 68 * v18 + -59 * v31 + -15 * v20 + 85 * v14 + -91 * v9 + -25 * v28 + 83 * v27 + -54 * v11 + -92 * v10 + -85 * v8 + 50 * v35 + 46 * v37 + -88 * v22 - 100 * v29 - 91 * v12 + 73 * v36 + 44 * v23 + 5 * v38 - 32 * v25 - 26 * v34 - 56 * v21 - 16 * v17 - 76 * v15 - 48 * v13 - 88 * v26 + 65 * v32 == -28394
+ 4 * v21 + 8 * v15 + 49 * v39 + -45 * v11 + 16 * v16 + -58 * v22 + -35 * v28 + 85 * v34 + -55 * v29 + 84 * v20 + 88 * v13 + 5 * v5 + -41 * v23 + 62 * v6 + -19 * v25 + -23 * v27 + -71 * v17 - 49 * v24 + 46 * v19 - 2 * v9 + 77 * v10 - 6 * v30 + 51 * v37 - 96 * v35 + 59 * v18 - 62 * v12 - 32 * v38 + 69 * v36 - 48 * v32 + 54 * v26 - 33 * v8 - 21 * v31 + 31 * v4 - 98 * v14 - 96 * v33 - 71 * v7 == 25355
+ -81 * v23 + -88 * v15 + -78 * v36 + 99 * v20 + 66 * v28 + 84 * v38 + 88 * v16 + -42 * v8 + -66 * v31 + -66 * v10 + 26 * v12 + -61 * v4 + -69 * v5 + -93 * v13 + 53 * v32 + -100 * v9 + 28 * v19 + -46 * v25 + -50 * v6 + 74 * v24 + 89 * v37 - 30 * v35 - 45 * v26 + 13 * v18 - 29 * v7 + 33 * v14 + 54 * v27 + 18 * v34 - 21 * v39 + 25 * v22 - 39 * v33 + 15 * v17 + 83 * v30 - 28 * v11 + 2 * v29 == 4514
+ -11 * v14 + 62 * v18 + -7 * v31 + 97 * v9 + 64 * v32 + -5 * v20 + 46 * v4 + 88 * v34 + 59 * v12 + -50 * v10 + 1 * v30 + -7 * v16 + -38 * v13 + 44 * v33 + 40 * v24 + 14 * v37 - 97 * v26 - 43 * v15 + 31 * v17 - 68 * v7 - 36 * v5 - 34 * v19 + 10 * v8 + 84 * v22 + 13 * v11 + 14 * v29 + 10 * v35 + 60 * v28 + 27 * v38 - 31 * v36 - 48 * v23 - 55 * v39 - 96 * v6 - 83 * v27 == -4195
+ -72 * v20 + 4 * v35 + 58 * v38 + -10 * v39 + 26 * v9 + 90 * v36 + 45 * v21 + 16 * v16 + -32 * v24 + 39 * v33 + -54 * v29 + 57 * v28 + 2 * v11 + -57 * v12 - 99 * v8 - 91 * v5 - 30 * v15 - 59 * v32 + 7 * v6 - 88 * v7 + 36 * v19 - 73 * v10 - 6 * v31 + 99 * v17 - 96 * v4 - 45 * v30 - 40 * v13 + 97 * v14 + 6 * v26 + 55 * v25 + 27 * v23 + 79 * v27 - 28 * v22 - 90 * v34 - 6 * v37 + 58 * v18 == 6529
'''
# 把這個陰間式子轉換成矩陣形式
# 從 v4 開始
# 左移: r"\((v\d+) << 6\)" --> "64 * $1"
# 行首手動補上加號
# 乘1: r"([+\-]) (v\d+)" --> "$1 1 * $2"
# 提取項: r"([+\-]) (-?\d+) \* v(\d+)"
import re
import numpy as np
lines = expr.strip().split('\n')
m_vec_len = 36 # 變量個數
m_vec_off = 4 # 變量起始下標
m_b = np.zeros(len(lines), dtype=np.int64)
m_A = np.zeros((len(lines), m_vec_len), dtype=np.int64)
patt_fact = r"([+\-]) (-?\d+) \* v(\d+)"
re_patt_fact = re.compile(patt_fact)
for (ln, line) in enumerate(lines):
# 對每一行
sumex, sumval = line.split('==')
sumex = sumex.strip()
sumval = sumval.strip()
sumval = int(sumval)
m_b[ln] = sumval # 提取常數
facts = re_patt_fact.findall(line) # 拆出每一項
for fact in facts:
sgn, coe, vid = fact
coe, vid = int(coe), int(vid)
if sgn == '-':
coe = -coe
m_A[ln, vid - m_vec_off] = coe # 填入系數矩陣
print(m_A)
print(m_b)
vec_v = np.linalg.solve(m_A, m_b) # 線性方程組求解
vec_v = np.round(vec_v) # 轉成整數
vec_v = vec_v.astype(np.int64)
vec_v = list(vec_v)
print(vec_v)
'''
[ 9. 30. 85. 9. 28. 31. 10. 32. 4. 93. 56. 12. 75. 45.
64. 6. 84. 58. 13. 23. 1. 26. 56. 40. 46. 38. 92. 49.
20. 10. 94. 4. 113. 60. 70. 24.]
[9, 30, 85, 9, 28, 31, 10, 32, 4, 93, 56, 12, 75, 45, 64, 6, 84, 58, 13, 23, 1, 26, 56, 40, 46, 38, 92, 49, 20, 10, 94, 4, 113, 60, 70, 24]
'''
# 最后的解密!
c_Str = "or4nge"
c_v42 = 36
c_v43 = len(c_Str)
assert c_v42 == len(vec_v)
l_ans = [0] * 36
for i in range(c_v42):
l_ans[i] = ord(c_Str[i % c_v43]) ^ vec_v[i]
print("".join([chr(x) for x in l_ans])) # 最終 flag
zero3 is the best math solver!