鶴城杯 Reverse & Mobile Writeup(WP)
阿新 • • 發佈:2021-10-10
Mobile
AreYouRich
安卓層逆向,但用實際上是可能存在多解的,這點令人有些困惑。主要是輸入使用者名稱和密碼,然後有一系列校驗,以及一堆亂七八糟的操作,很多可能是用來迷惑眼睛的,但這並不重要的,主要演算法在這。
動態生成了一個table,並於輸入異或,隨後與加密資料v2進行比較。v2可以直接提取,table直接調解出來與加密資料異或即可,獲得token關鍵部分。
using System; namespace solu { class Program { static void Main(string[] args) { byte[] enc = { 0x51, 0xf3, 0x54, 0x92, 0x48, 0x4d, 0xa0, 0x4d, 0x20, 0x8d, 0xb5, 0xda, 0x9f, 0x45, 0xc0, 0x31, 0x8, 0xe5, 0x38, 0x72, 0xbc, 0xae, 0x4c, 0x96, 0xde }; char[] secret = "5FQ5AaBGbqLGfYwjaRAuWGdDvyjbX5nH".ToCharArray(); //char[] input_byte = "ffffffffff_DDDDDDDDDD@001_1633674507603".ToCharArray(); byte[] table = new byte[0x100]; int v9; for (v9 = 0; v9 < 0x100; ++v9) { table[v9] = (byte)v9; } { int v9_1 = 0; int v10 = 0; int v11 = 0; while (v9_1 < 0x100) { v11 = (secret[v10] & 0xFF) + (table[v9_1] & 0xFF) + v11 & 0xFF; byte v12 = table[v9_1]; table[v9_1] = table[v11]; table[v11] = v12; v10 = (v10 + 1) % secret.Length; ++v9_1; } } int secret_1 = enc.Length; int v6 = 16; int v9_2 = 0; int v10_1 = 0; int v11_1 = 0; while (v9_2 < secret_1) { v10_1 = v10_1 + 1 & 0xFF; v11_1 = (table[v10_1] & 0xFF) + v11_1 & 0xFF; byte v12_1 = table[v10_1]; table[v10_1] = table[v11_1]; table[v11_1] = v12_1; byte res = table[(table[v10_1] & 0xFF) + (table[v11_1] & 0xFF) & 0xFF]; Console.Write((char)(res ^ enc[v9_2])); ++v9_2; } } } }
獲得了token,裡面包含使用者名稱和密碼,直接輸入程式即可獲得flag。
flag{y0u_h@V3_@_107_0f_m0n3y!!}
designEachStep
3DES解密,了一個二進位制資料檔案,並且輸入的24個位元組作為3DES的金鑰。前8位元組直接gzip解壓提取一個檔案即可獲得,隨後另外的兩個8位元組,需要進行3DES取每次的檔案頭前8位元組。
實際上可以提取java程式碼到idea中,將一些必要的包用mavn匯入主要是lz4,去除一些不必要的程式碼,新增一部分程式碼,直接除錯,然後在equals函式下斷點提取每次check比對的正確資料即可,但注意每提取一次資料都需要將程式碼中的input修正一下,否則無法進入下一個equals函式。
package test.t3; import java.io.*; import java.security.InvalidKeyException; import java.security.Key; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.zip.GZIPInputStream; import java.util.zip.Inflater; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.SecretKeySpec; import net.jpountz.lz4.LZ4Factory; import net.jpountz.lz4.LZ4SafeDecompressor; public class test { public static String Read2(String infile) throws Exception { StringBuffer sb = new StringBuffer(); File file = new File(infile); FileInputStream fis = new FileInputStream(file); byte buffer[] = new byte[1024]; int len = 0; while((len = fis.read(buffer)) != -1) { sb.append(new String(buffer, 0, len)); //sb.append(new String(buffer, 0, len, "UTF-8")); //將byte轉String可以指定編碼方式 } fis.close(); return sb.toString(); } public static Key get_key(byte[] arg4) { int v0 = 8; byte[] v1 = new byte[v0]; int v2; for(v2 = 0; v2 < arg4.length; ++v2) { if(v2 >= v0) { break; } v1[v2] = arg4[v2]; } return new SecretKeySpec(v1, "DES"); } public static void main(String[] args) throws IOException { Cipher v5_8; byte[] enc_data; byte[] read_byte; byte[] data; String enc_algorithm_DES = "DES"; String input = "DE5_c0mpr355_m@yssssssss"; if(input.length() != 24) { return; } byte[] input_byte = input.getBytes(); int header_size = 8; byte[] input_header = new byte[header_size]; //讀取data.bin全部位元組 try { DataInputStream v5 = new DataInputStream(new FileInputStream("D:\\Project\\Java\\javaweb\\untitled1\\src\\main\\java\\test\\t3\\data.bin")); data = new byte[v5.available()]; v5.readFully(data); } catch(IOException v15_1) { return; } // 將input 前8個位元組拷貝至header System.arraycopy(input_byte, 0, input_header, 0, header_size); ByteArrayOutputStream data_stream = new ByteArrayOutputStream(); ByteArrayInputStream v6 = new ByteArrayInputStream(data); int v4_2 = 2; byte[] v7 = null; GZIPInputStream v8 = new GZIPInputStream(((InputStream)v6)); // 讀取gzip壓縮資料,即解壓縮gzip read_byte = new byte[0x100]; while(true) { int v9 = v8.read(read_byte); if(v9 < 0) { break; } data_stream.write(read_byte, 0, v9); } byte[] data_byte = data_stream.toByteArray(); //DE5_c0mp Z...AS.m if(data_byte.length >= header_size) { read_byte = new byte[header_size]; System.arraycopy(data_byte, 0, read_byte, 0, header_size); // DE5_c0mp enc_data = new byte[data_byte.length - header_size]; System.arraycopy(data_byte, header_size, enc_data, 0, data_byte.length - header_size); if(!Arrays.equals(read_byte, input_header)) { //check 輸入塊 } try { v5_8 = Cipher.getInstance(enc_algorithm_DES); v5_8.init(v4_2, get_key(input_header)); //將輸入前8個位元組作為DES的key,解密 data_byte = v5_8.doFinal(enc_data); // System.out.println("Hello"); } catch(InvalidKeyException v5_3) { v5_3.printStackTrace(); } catch(IllegalBlockSizeException v5_4) { v5_4.printStackTrace(); } catch(BadPaddingException v5_5) { v5_5.printStackTrace(); } catch(NoSuchPaddingException v5_6) { v5_6.printStackTrace(); } catch(NoSuchAlgorithmException v5_7) { v5_7.printStackTrace(); } if(data_byte == null) { return; } System.arraycopy(input_byte, header_size, input_header, 0, header_size); Inflater v6_2 = new Inflater(); v6_2.setInput(data_byte); ByteArrayOutputStream v8_2 = new ByteArrayOutputStream(data_byte.length); int v5_9 = 0x400; try { data_byte = new byte[v5_9]; while(!v6_2.finished()) { v8_2.write(data_byte, 0, v6_2.inflate(data_byte)); } } catch(Throwable v15_2) { } try { v8_2.close(); } catch(IOException v5_11) { v5_11.printStackTrace(); } v6_2.end(); data_byte = v8_2.toByteArray(); if(data_byte.length < header_size) { } read_byte = new byte[header_size]; System.arraycopy(data_byte, 0, read_byte, 0, header_size); enc_data = new byte[data_byte.length - header_size]; System.arraycopy(data_byte, header_size, enc_data, 0, data_byte.length - header_size); if(!Arrays.equals(read_byte, input_header)) { } try { v5_8 = Cipher.getInstance(enc_algorithm_DES); v5_8.init(v4_2, get_key(input_header)); data_byte = v5_8.doFinal(enc_data); } catch(InvalidKeyException v5_3) { v5_3.printStackTrace(); } catch(IllegalBlockSizeException v5_4) { v5_4.printStackTrace(); } catch(BadPaddingException v5_5) { v5_5.printStackTrace(); } catch(NoSuchPaddingException v5_6) { v5_6.printStackTrace(); } catch(NoSuchAlgorithmException v5_7) { v5_7.printStackTrace(); } byte[] v9_1 = data_byte; try { // label_141: // v5_10.printStackTrace(); } catch(Throwable v15_2) { // goto label_139; } try { v8_2.close(); } catch(IOException v5_11) { v5_11.printStackTrace(); } System.arraycopy(input_byte, 16, input_header, 0, header_size); LZ4SafeDecompressor v8_3 = LZ4Factory.safeInstance().safeDecompressor(); input_byte = new byte[v9_1.length * 5]; v5_9 = v8_3.decompress(v9_1, 0, v9_1.length, input_byte, 0); read_byte = new byte[v5_9]; System.arraycopy(input_byte, 0, read_byte, 0, v5_9); if(v5_9 >= header_size) { input_byte = new byte[header_size]; System.arraycopy(read_byte, 0, input_byte, 0, header_size); v5_9 -= header_size; enc_data = new byte[v5_9]; System.arraycopy(read_byte, header_size, enc_data, 0, v5_9); if(!Arrays.equals(input_byte, input_header)) { } try { Cipher v15_8 = Cipher.getInstance(enc_algorithm_DES); v15_8.init(v4_2, get_key(input_header)); v7 = v15_8.doFinal(enc_data); } catch(InvalidKeyException v15_3) { v15_3.printStackTrace(); } catch(IllegalBlockSizeException v15_4) { v15_4.printStackTrace(); } catch(BadPaddingException v15_5) { v15_5.printStackTrace(); } catch(NoSuchPaddingException v15_6) { v15_6.printStackTrace(); } catch(NoSuchAlgorithmException v15_7) { v15_7.printStackTrace(); } } } } }
flag{DE5_c0mpr355_m@y_c0nfu53}
Reverse
Petition
這個程式似乎將一些例如mv之類的指令等大量等效的用xor指令替代了,導致看起來有一堆xor指令,實際上題目也是裡面的一堆函式也是異或加密,每個加密一個位元組。
將每處的這幾條指令的三個立即數資料異或取位元組,即可解密一個位元組資料。實際上IDA幫助我們簡化了。
print(chr(0x1e^0x78),end='')
print(chr(0x6c^0x00),end='')
print(chr(0x7^0x66),end='')
print(chr(0xa9^0xce),end='')
print(chr(0xf9^0x82),end='')
print(chr(0x8c^0xb5),end='')
print(chr(0x88^0xbe),end='')
print(chr(0xcb^0xa8),end='')
print(chr(0x52^0x64),end='')
print(chr(0xa0^0x99),end='')
print(chr(0x19^0x2f),end='')
print(chr(0x21^0x15),end='')
print(chr(0x66^0x50),end='')
print(chr(0x3^0x2e),end='')
print(chr(0xaf^0x97),end='')
print(chr(0xf6^0xc7),end='')
print(chr(0x43^0x7b),end='')
print(chr(0x18^0x2c),end='')
print(chr(0xc9^0xe4),end='')
print(chr(0xfe^0xca),end='')
print(chr(0x66^0x55),end='')
print(chr(0x9c^0xaa),end='')
print(chr(0x4c^0x7f),end='')
print(chr(0x00^0x2d),end='')
print(chr(0x25^0x1d),end='')
print(chr(0xd6^0xb2),end='')
print(chr(0x9a^0xff),end='')
print(chr(0x7d^0x44),end='')
print(chr(0xbd^0x90),end='')
print(chr(0x45^0x72),end='')
print(chr(0x65^0x56),end='')
print(chr(0x6e^0x8),end='')
print(chr(0x85^0xb2),end='')
print(chr(0x12^0x21),end='')
print(chr(0x7f^0x46),end='')
print(chr(0x2b^0x13),end='')
print(chr(0x24^0x14),end='')
print(chr(0xfc^0xca),end='')
print(chr(0x24^0x12),end='')
print(chr(0x50^0x33),end='')
print(chr(0x12^0x23),end='')
print(chr(0xea^0x97),end='')
print(chr(0xb2^0xb2),end='')
flag{96c69646-8184-4363-8de9-73f7398066c1}
to be or not to be, is a question.