鹤城杯 Reverse & Mobile Writeup(WP)

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}

posted @ 2021-10-10 12:22  辰星-cxing  阅读(236)  评论(0编辑  收藏  举报