鹤城杯 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}
to be or not to be, is a question.