LeetCode-可能是己亥年最有趣的比赛-Q4: SYM 的🔑


概述

第一次参加 LeetCode,就是个简单的 RE,轻松一血,入门难度不知道为什么标成 Hard。

题目链接:https://leetcode-cn.com/contest/sf-2020/problems/happy-new-year-2020-bomb/

题意:下载二进制文件,解决问题。

Linux: https://assets.leetcode-cn.com/NewYear2020/bomb

Windows: https://assets.leetcode-cn.com/NewYear2020/bomb.exe

MacOS: https://assets.leetcode-cn.com/NewYear2020/bomb_macos

解题过程

反编译二进制文件

可以直接使用 IDA 反编译看源代码。推荐去搞 Linux ELF64 的,有符号表;Windows PE 那个可执行文件符号表给删了,看的很难受。

分析 main 函数

简单看就是运行了这两个函数:

firstStage();
secondStage();

我们来逐一解决。

分析 firstStage() 函数

if ( strcmp(s, "1eetC0de") ) {
    puts("Wrong password!");
    exit(0);
}

直接输入 1eetC0de 就完事了

分析 secondStage() 函数

根据文本提示,你可以输入 [0, 5] 之间的整数去测试函数 puzzle(long long a1) 的结果(answer),最终推算出 puzzle(202020202020) 的返回值。

随后输入 -1 进入答案提交阶段,将 puzzle(202020202020) 的返回值输入,获取题目最终的答案(key)。

scanf("%lld", &v3);
if (v3 == -1) {
    // Generate key
} else if (v3 <= 0 || v3 >= 5) {
    // EXIT
} else {
    v0 = puzzle(v3);
    printf("Finished!!! The answer is:\n%lld\n\n", v0);
    secondStage(1LL);
}

所以我们先把 puzzle() 提取出来看看。

long long puzzle(long long a1) {
    s = malloc(4 * a1);
    // Calculation
}

申请了与 a1 成线性的内存空间,这意味着我们不可能简单的绕过区间判断去输入 202020202020,不妨先试一试规律。

for (int i = 0; i < 100; i++) {
    printf("%d\t%lld\n", i, puzzle(i));
}

得到结果:

1 0
2 0
3 2
4 0
5 2
6 4
7 6
8 0
9 2
...

显然,返回值为 a1 二进制表示去掉首位 1 后剩余值的两倍。

10111100001001010101111010011000100100
00111100001001010101111010011000100100
01111000010010101011110100110001001000

得到答案为 129162497096

输入,得到 key 为 gcCjMlq9j5KD