zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    Spring IOC(控制反转)思想笔记
    实战SpringBoot Admin
    包及权限配置&java存储机理绘制
    极验验证(滑动验证)的使用
    Java基础知识之this关键字知识讲解
    bean生命周期
    笔记-13-多线程 Thread方法 线程安全 生产者和消费者 死锁和阻塞 练习
    JAVA 进行图片中文字识别(准确度高)!!!
    Java 面试题关于包装类
    HashMap底层实现原理及面试常见问题
  • 原文地址:https://www.cnblogs.com/zhwer/p/12672697.html
Copyright © 2011-2022 走看看