Multiplication

A Java jar with an anti-decompiler trick that breaks JD-GUI, read with CFR instead. The bug is a long overflow.

2026.08.18 Reversing original post

먼저 이 코드를 분석하기 위해서는 자바 디컴파일러가 필요합니다. 첫 번째로 JD-GUI 를 사용해 디컴파일링을 시도했지만, 이 문제는 의도적으로 JD-GUI 를 깨뜨리는 안티 디컴파일이 들어가 있습니다. 그래서 CFR 로 소스를 보기로 했다.

java -jar cfr.jar target.jar --outputdir out

밑에는 내가 얻어낸 소스다.

Figure 1

코드를 보면 이 문제는 long 오버플로우를 이용하는 문제라는 걸 알 수 있습니다. 그걸 뒷받침하는 증거 몇 개를 찾아낼 수 있습니다.

1. long 타입

long var1 — Java long 은 signed 64-bit 이고, 범위는 -2^63 ~ 2^63 - 1 입니다.

2. 정상적인 산술 역산이 실패한다

만약 오버플로우가 아니라면, 문제는 이렇게 단순해야 합니다.

l = (-1536092243306511225) / 26729

하지만 실제로는:

  • 나눗셈 결과가 정수가 아님 (유리수임)
  • Java long 은 소수를 허용하지 않음
  • 즉 정상적인 수학 문제로 성립하지 않음

CrackMe 에서 “정수 입력”을 요구하는데 정수 해가 없다는 건 의도적인 함정입니다.

long l = Long.decode(stringArray[0]);
if ((l *= 26729L) == -1536092243306511225L) {
    System.out.println("Correct!");
}

이 수식으로부터, Java long 은 64-bit 2의 보수이므로 모든 연산은 mod 2⁶⁴ 입니다.

l × 26729 ≡ −1536092243306511225   (mod 2^64)
l         ≡ −1536092243306511225 × 26729^-1   (mod 2^64)

이제 계산은 코드를 만들어 하면 됩니다. 저는 AI 에게 이 로직을 가지고 코드 생성을 부탁했습니다.

import java.math.BigInteger;

public class SolveMultiplicative {
    public static void main(String[] args) {
        // 2^64 (long overflow의 모듈러)
        BigInteger MOD = BigInteger.ONE.shiftLeft(64);

        // 문제에서 비교하는 결과값 (long literal)
        BigInteger target = BigInteger.valueOf(-1536092243306511225L);

        // 곱해지는 상수
        BigInteger multiplier = BigInteger.valueOf(26729);

        /*
         * 핵심 수학:
         *   x * 26729 ≡ target        (mod 2^64)
         *   x         ≡ target * inverse(26729)  (mod 2^64)
         */
        BigInteger inverse = multiplier.modInverse(MOD);
        BigInteger x = target.multiply(inverse).mod(MOD);

        /*
         * JVM long은 signed 64bit이므로
         * MSB(63bit)가 1이면 음수로 변환
         */
        if (x.testBit(63)) {
            x = x.subtract(MOD);
        }
        System.out.println("Answer = " + x);
    }
}

답, 플래그는: -8978084842198767761