Category: Reverse Engineering
Score: 100
Original description: Welcome to the first lab of Course ML10001 from Sekai University! The Lab 1 assignment should be pretty easy...
У нас есть файл.class.
.class относится к java. Воспользуемся онлайн декомпилятором и получим код:
public class Sekai
{
private static int length;
public static void main(final String[] array) {
final Scanner scanner = new Scanner(System.in);
System.out.print("Enter the flag: ");
final String next = scanner.next();
if (next.length() != 43) {
System.out.println("Oops, wrong flag!");
return;
}
final String substring = next.substring(0, Sekai.length);
final String substring2 = next.substring(Sekai.length, next.length() - 1);
final String substring3 = next.substring(next.length() - 1);
if (substring.equals("SEKAI{") && substring3.equals("}")) {
assert substring2.length() == Sekai.length * Sekai.length;
if (solve(substring2)) {
System.out.println("Congratulations, you got the flag!");
}
else {
System.out.println("Oops, wrong flag!");
}
}
else {
System.out.println("Oops, wrong flag!");
}
}
public static String encrypt(final char[] array, final int n) {
final char[] data = new char[Sekai.length * 2];
int n2 = Sekai.length - 1;
int length = Sekai.length;
for (int i = 0; i < Sekai.length * 2; ++i, ++i) {
data[i] = array[n2--];
data[i + 1] = array[length++];
}
for (int j = 0; j < Sekai.length * 2; ++j) {
final char[] array2 = data;
final int n3 = j;
array2[n3] ^= (char)n;
}
return String.valueOf(data);
}
public static char[] getArray(final char[][] array, final int n, final int n2) {
final char[] array2 = new char[Sekai.length * 2];
int n3 = 0;
for (int i = 0; i < Sekai.length; ++i) {
array2[n3] = array[n][i];
++n3;
}
for (int j = 0; j < Sekai.length; ++j) {
array2[n3] = array[n2][Sekai.length - 1 - j];
++n3;
}
return array2;
}
public static char[][] transform(final char[] array, final int n) {
final char[][] array2 = new char[n][n];
for (int i = 0; i < n * n; ++i) {
array2[i / n][i % n] = array[i];
}
return array2;
}
public static boolean solve(final String s) {
final char[][] transform = transform(s.toCharArray(), Sekai.length);
for (int i = 0; i <= Sekai.length / 2; ++i) {
for (int j = 0; j < Sekai.length - 2 * i - 1; ++j) {
final char c = transform[i][i + j];
transform[i][i + j] = transform[Sekai.length - 1 - i - j][i];
transform[Sekai.length - 1 - i - j][i] = transform[Sekai.length - 1 - i][Sekai.length - 1 - i - j];
transform[Sekai.length - 1 - i][Sekai.length - 1 - i - j] = transform[i + j][Sekai.length - 1 - i];
transform[i + j][Sekai.length - 1 - i] = c;
}
}
return "oz]{R]3l]]B#50es6O4tL23Etr3c10_F4TD2".equals(invokedynamic(makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;, encrypt(getArray(transform, 0, 5), 2), encrypt(getArray(transform, 1, 4), 1), encrypt(getArray(transform, 2, 3), 0)));
}
static {
Sekai.length = (int)Math.pow(2.0, 3.0) - 2;
}
}
- Длинна строки=43;
- Первые 6 символов="SEKAI{";
- Последний символ="}";
- Sekai.length=6(видим это в конце кода);
- Переменная substring2 содержит строки, которые находяться между скобками SEKAI{ };
- Вызывается медот
solve(substring2). - В конце класса происходит сравнение со строкой
oz]{R]3l]]B#50es6O4tL23Etr3c10_F4TD2. Методыencrypt(getArray(transform, 0, 5), 2)encrypt(getArray(transform, 1, 4), 1)encrypt(getArray(transform, 2, 3), 0)возвращают строки, которые конкатенируются друг с другом.
Для решения вызова используем z3-solver. Перепишем действия, которые выполняются в методе solve() и зададим условие. Сценарий реализации решения можно найти здесь.
flag is: SEKAI{m4tr1x_d3cryP710N_15_Fun_M4T3_@2D2D!}