解題過程中,雖然解出來了,但是磕磕絆絆犯了一些錯誤,記錄一下
分析過程
PE查殼
有一個upx殼,最下面給了脫殼提示: upx.exe -d Replace.exe
脫殼結束,丟到IDA裡,SHIF+F12,檢視字串,看到一個可疑的”Well Done!\n“,點進去看看,發現就是主函式,反彙編主函式
- Buffer很明顯是輸入,且長度要<=37
- 判斷函式==1就成功,顯然這就是關鍵
sub_401090函式(改了一點名稱)
1 // 最後要輸出1 2 // a1是輸入,a2是輸入的長度且為35 3 int __fastcall sub_401090(int a1, int a2) 4 { 5 int v4; // edx 6 char char_v5; // al 7 int high4; // esi 8 int low4; // edi 9 char char_v8; // al 10 int v9; // eax 11 char char_v10; // cl 12 int v11; // eax 13 int v12; // ecx 14 15 if ( a2 != 35 ) 16 return -1; 17 v4 = 0; 18 while ( 1 ) 19 { 20 char_v5 = *(_BYTE *)(v4 + a1); 21 high4 = (char_v5 >> 4) % 16; // 先右移4位,相當於把原來8位的高4位數移動到低4位,新高4位全都置零——再%16,相當於取出變換後新8位的低4位——也就是取出原來數的高4位 22 low4 = ((16 * char_v5) >> 4) % 16; // 先*16,相當於左移4位,原來的低4位移動到高4位,新的低4位置零——再右移4位,相當於移回來了,不過高4位都是0——再%16,取出低4位——原就是取出原來數的低4位 23 char_v8 = byte_402150[2 * v4]; 24 if ( char_v8 < 48 || char_v8 > 57 ) 25 v9 = char_v8 - 87; 26 else 27 v9 = char_v8 - 48; 28 char_v10 = byte_402151[2 * v4]; 29 v11 = 16 * v9; // v9*16,相當於左移4位————為後面組成新的8位做準備,作為新數的高4位 30 if ( char_v10 < 48 || char_v10 > 57 ) 31 v12 = char_v10 - 87; 32 else 33 v12 = char_v10 - 48; // 作為新數的低4位 34 if ( (unsigned __int8)byte_4021A0[16 * high4 + low4] != ((v11 + v12) ^ 25) )// 16 * high4 + low4——操作的目的是組成新的8位數——其實就是原來輸入的數 35 // ((v11 + v12) ^ 25)——將上面獲得v11與v12組成新的數,與25異或 36 // 最後進行比較,相等才能return 1 37 break; 38 if ( ++v4 >= 35 ) 39 return 1; 40 } 41 return -1; 42 }
總而言之,從byte_402150取一個元素作為char_v8,變換後獲得組成高位的v11;從byte_402151取一個元素作為char_v10,變換後獲得組成低位的v12,最後組成一個新的數去異或
【異或後得到的值】要與 【將輸入作為下標,從byte_4021A0中取出的數】 相等
byte_402150與byte_402151
!!在這裡我就犯了一個錯誤,我還以為是我IDA又出現問題了....byte_402150陣列的32h後面沒有 0 表示結束,所以要繼續往下讀取,一直到出現 0 ,即byte_402150是50+byte_402151
unsigned char ida_chars[] = { 50,97, 52, 57, 102, 54, 57, 99, 51, 56, 51, 57, 53, 99, 100, 101, 57, 54, 100, 54, 100, 101, 57, 54, 100, 54, 102, 52, 101, 48, 50, 53, 52, 56, 52, 57, 53, 52, 100, 54, 49, 57, 53, 52, 52, 56, 100, 101, 102, 54, 101, 50, 100, 97, 100, 54, 55, 55, 56, 54, 101, 50, 49, 100, 53, 97, 100, 97, 101, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; unsigned char ida_chars[] = { 97, 52, 57, 102, 54, 57, 99, 51, 56, 51, 57, 53, 99, 100, 101, 57, 54, 100, 54, 100, 101, 57, 54, 100, 54, 102, 52, 101, 48, 50, 53, 52, 56, 52, 57, 53, 52, 100, 54, 49, 57, 53, 52, 52, 56, 100, 101, 102, 54, 101, 50, 100, 97, 100, 54, 55, 55, 56, 54, 101, 50, 49, 100, 53, 97, 100, 97, 101, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
byte_4021A0
選中全部,SHIF+E-->選中‘C unsigned char array (decimal)’,得到陣列的值(上面也是這麼得到的)
unsigned char ida_chars[] = { 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22 };
解題指令碼(自己寫的常規版本)
1 key1=[ 2 50,97, 52, 57, 102, 54, 57, 99, 51, 56, 51, 3 57, 53, 99, 100, 101, 57, 54, 100, 54, 100, 4 101, 57, 54, 100, 54, 102, 52, 101, 48, 50, 5 53, 52, 56, 52, 57, 53, 52, 100, 54, 49, 6 57, 53, 52, 52, 56, 100, 101, 102, 54, 101, 7 50, 100, 97, 100, 54, 55, 55, 56, 54, 101, 8 50, 49, 100, 53, 97, 100, 97, 101, 54 9 ] 10 key2=[ 11 97, 52, 57, 102, 54, 57, 99, 51, 56, 51, 12 57, 53, 99, 100, 101, 57, 54, 100, 54, 100, 13 101, 57, 54, 100, 54, 102, 52, 101, 48, 50, 14 53, 52, 56, 52, 57, 53, 52, 100, 54, 49, 15 57, 53, 52, 52, 56, 100, 101, 102, 54, 101, 16 50, 100, 97, 100, 54, 55, 55, 56, 54, 101, 17 50, 49, 100, 53, 97, 100, 97, 101, 54 18 ] 19 str=[ 20 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 21 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 22 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 23 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 24 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 25 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 26 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 27 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 28 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 29 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 30 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 31 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 32 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 33 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 34 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 35 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 36 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 37 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 38 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 39 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 40 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 41 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 42 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 43 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 44 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45 45, 15, 176, 84, 187, 22 46 ] 47 flag = "" 48 for i in range(35): 49 v8 = key1[2*i] 50 if v8 < 48 or v8 > 57: 51 v11 = 16 * (v8 - 87) 52 else: 53 v11 = 16 * (v8 - 48) 54 v10 = key2[2 * i] 55 if v10 < 48 or v10 > 57: 56 v12 = v10 - 87 57 else: 58 v12 = v10 - 48 59 v4=((v11 + v12) ^ 25) 60 flag += chr(str.index(v4)) 61 62 print(flag)
這裡我犯了一個弱智錯誤
- 最初寫指令碼的時候,想照著反彙編程式碼的思路去寫,在後面寫了一個 for j in range(len(str_data)): if str[i]==((v11 + v12) ^ 25):v4=((v11 + v12) ^ 25)
- 結果導致執行沒有報錯,也沒有結果
-
str[i]==((v11 + v12) ^ 25)這一行程式碼在每次迴圈中都會遍歷str列表來查詢是否存在相等的值,這會導致程式在執行時花費很長時間,因為它的時間複雜度是 O(n),其中 n 是str列表的長度。由於列表長度非常大,因此這種線性搜尋的方法會非常慢,尤其是在內層迴圈中還巢狀了一個迴圈。這也解釋了為什麼程式碼沒有輸出也沒有報錯,因為它可能需要很長時間才能完成執行
解題指令碼(列舉正向爆破)
這個版本是我參考別的大佬的wp時候學到的,記錄一下
由於用了取餘 % 運算,所以採用列舉正向爆破的方法,讓flag中的每一個字元遍歷常用的字元(ascii碼錶中32-126),帶入加密演算法,如果成功,就把這個flag存入
list1=[50, 97, 52, 57, 102, 54, 57, 99, 51, 56, 51, 57, 53, 99, 100, 101, 57, 54, 100, 54, 100, 101, 57, 54, 100, 54, 102, 52, 101, 48, 50, 53, 52, 56, 52, 57, 53, 52, 100, 54, 49, 57, 53, 52, 52, 56, 100, 101, 102, 54, 101, 50, 100, 97, 100, 54, 55, 55, 56, 54, 101, 50, 49, 100, 53, 97, 100, 97, 101, 54] list2=[97, 52, 57, 102, 54, 57, 99, 51, 56, 51, 57, 53, 99, 100, 101, 57, 54, 100, 54, 100, 101, 57, 54, 100, 54, 102, 52, 101, 48, 50, 53, 52, 56, 52, 57, 53, 52, 100, 54, 49, 57, 53, 52, 52, 56, 100, 101, 102, 54, 101, 50, 100, 97, 100, 54, 55, 55, 56, 54, 101, 50, 49, 100, 53, 97, 100, 97, 101, 54] list3=[99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] v4=0 flag="" for i in range(35): v8=list1[2*i] if v8 < 48 or v8 > 57: v9=v8 - 87 else: v9=v8 - 48 v10=list2[2*i] v11=16*v9 if v10 <48 or v10 > 57: v12=v10-87 else: v12=v10-48 v4=((v11+v12)^25) for a in range(32,127): v5=a v6=(v5>>4)%16 v7=((16*v5)>>4)%16 if list3[16*v6+v7] == v4: flag+=chr(a) print(flag)
flag
flag{Th1s_1s_Simple_Rep1ac3_Enc0d3}