BUUOJ | SimpleRev(字符对称加密)

题目地址

静态分析

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;
}
posted @ 2020-04-10 12:41  暖暖草果  阅读(907)  评论(1编辑  收藏  举报