静态分析
main 函数里面都是提示消息,从函数名可以看出要待分析内容在 Decry() 内
上图是程序进行初始化,strcpy() 和 strcat() 分别是 C 的字符串拷贝和连接函数我们已经很熟悉了
进入自定义函数 join() 内,发现其功能便是拼接传入的两个字符串
于是我们把分别位于栈空间和数据段的字符串拼接,形成新串 text 和 key(注意 17、20 行是以小端序显示字符串的,实际上要倒过来)
之后程序把 key 中的大写字母转换成小写
最后的代码是验证 text 和 str2 是否相等,str2 就是 flag 加密后得到的字符串
因为 text 是已知的,现在的目标便是逆向加密算法得出 flag
首先 flag 的每一位必须都是大写字母或者小写字母,否则无法进入加密将被 null 填充,与 text 便不匹配了
下面一句就是加密的核心代码:
str2[v2] = (v1 - 39 - key[v3++ % v5] + 97) % 26 + 97;
由于长度的限制,所以 v3++ % v5 就和 v2 等价了,下面将他们都视为 i
v1 和 flag[i] 等价,str2[v2] 与 text[i] 等价,于是:
(text[i] = (flag[i] - key[i] - 39 + 97 ) \% 26 + 97)
移项后:
(flag[i] = 26 * k + text[i] + key[i] - 155 ;;;;(k∈N))
虽然这个 k 是未知的,但是 flag 值的范围已被限制(必须是字母),所以可以枚举一下(也可以利用上下界 O(1) 算出)
如果对于某个 k 计算右式后的值落入了 flag 值的范围,则找到了 flag[i]
具体细节请见代码
逆向代码
#include <bits/stdc++.h>
using namespace std;
char key[13] = "ADSFKNDCLS";
char text[13] = "killshadow";
char flag[13];
int main() {
int v3 = 0, v5 = strlen(key);
for ( int i = 0; i < v5; ++i ) {
if ( key[v3 % v5] > 64 && key[v3 % v5] <= 90 )
key[i] = key[v3 % v5] + 32;
++v3;
}
for ( int i = 0; i < 10; ++i ) {
for ( int k = -10 ; k < 11 ; ++k ) {
int t = 26 * k + text[i] + key[i] - 155;
if ( ( t > 64 && t <= 90) || ( t > 97 && t <= 121) ) {
flag[i] = t; break;
}
}
}
printf("flag{%s}",flag);
return 0;
}