https://ctf.bugku.com/challenges/detail/id/139.html

First_Mobile(xman)
分数: 20 金币: 3
题目作者: 未知
一  血: Tokeii
一血奖励: 2金币
解  决: 272
提  示:
描  述: XMAN{}
其  他:

思路

打开看下
image.png

话不多说。先把他反编译成jar。再用jd-gui查看源码

image.png

这里是调用了encode.check(输入的内容)作对比较

看下encode.check
image.png
有点乱 修改一下

package com.example.xman.easymobile;

public class encode {
  private static byte[] b = new byte[] { 
      23, 22, 26, 26, 25, 25, 25, 26, 27, 28, 
      30, 30, 29, 30, 32, 32 };
  
  public static boolean check(String paramString) {
    byte[] arrayOfByte1 = paramString.getBytes();
    byte[] arrayOfByte2 = new byte[16];
    for (i = 0; i < 16; i++)
      arrayOfByte2[i] = (byte)((arrayOfByte1[i] + b[i]) % 61); 
    for (j = 0; j < 16; j++)
      arrayOfByte2[j] = (byte)(arrayOfByte2[j] * 2 - b); 
    return (new String(arrayOfByte2)).equals(paramString);
  }
}

经过输入字符串字节和b字节计算后 arrayOfByte2 相等就返回true.

思路一:爆破

修改一下函数爆破。这里就不简化条件了。修改一下入参数。对比相应位上的结果。

import java.util.Arrays;

/**
 * @author 夜雨
 * @Web www.yeyusmile.top
 * @date 2022/4/4 
 */
public class JJTest {
    public static void main(String[] args) {
        byte[] flag = new byte[16];
        byte[] flag2 = new byte[16];
        for (int j = 0; j < flag.length; j++) {
            for (int i = 32; i < 126; i++) {
                if (check((byte) i, j)) {
                    flag[j] = (byte) i;
                    break;
                }
            }
        }
        System.out.println(new String(flag));
    }

    private static byte[] b = new byte[]{
            23, 22, 26, 26, 25, 25, 25, 26, 27, 28,
            30, 30, 29, 30, 32, 32};

    public static boolean check(byte cb, int k) {
        byte[] input = new byte[16];
        input[k] = cb;
        byte[] temp = new byte[16];
        for (int i = 0; i < 16; i++)
            temp[i] = (byte) ((input[i] + b[i]) % 61);
        for (int j = 0; j < 16; j++)
            temp[j] = (byte) (temp[j] * 2 - j);

        return new String(temp).substring(k, k + 1).equals(new String(input).substring(k, k + 1));//对比第k位结果
    }

}

思路二:还原算法

事实上。情况是不止一种。但考虑到英文,数字字符的ascii码有范围。
下面计算一波。

设 C=b[i] 0=<i<16
根据题意,要满足((x +C) % 61) * 2 - i == x

令((x +C) % 61) * 2 - i = x

情况一: (x + C) < 61 即x<C+61

 ====> (x + C) * 2 - x = i
 ====> 2x+2C-x=i
解得 x=i-2C  负数排除

情况二: 61<(x + C) < 122 即 61+C<x<122+C

=====> (x + C - 61) * 2 - x = i
=====> x + 2C - 122 = i
 解得 x=i+122-2C  可能

情况三 x + C >122

=====> (x + C - 122) * 2 - x = i
=====> (x + C - 122) * 2 - x = i

解得x=i+244-2C 超出范围 排除


可以看到实际只有一种实际情况。如果不相信可以都试试、

public class JJTest {
    private static byte[] b = new byte[]{
            23, 22, 26, 26, 25, 25, 25, 26, 27, 28,
            30, 30, 29, 30, 32, 32};

    public static void main(String[] args) {
        byte[] flag = new byte[16];
        for (int i = 0; i < 16; i++) {
            flag[i] = (byte) (i + 122 - 2 * b[i]); //x=i+122-2C
        }
        System.out.println(new String(flag));
    }


  }
}

Q.E.D.