BUUCTF 逆向题目 [ACTF新生赛2020]rome
题目地址:
https://buuoj.cn/challenges#[ACTF%E6%96%B0%E7%94%9F%E8%B5%9B2020]romehttps://files.buuoj.cn/files/588c32051222b5dba864ddeb07c44e74/attachment.tar查壳
信息:文件名: H:/第七届“强网杯”全国网络安全挑战赛/BUUCTF/[ACTF新生赛2020]rome/rome.exe大小: 28635(27.96 KiB)操作系统: Windows(95)架构: I386模式: 32 位类型: 控制台字节序: LE
32位程序,这个是关键,后面会用到!
用IDA32打开程序
F5
int func(){int result; // 存储函数返回值的变量int v1[4]; // 一个包含4个整数的数组unsigned __int8 v2; // 存储单字节字符的变量unsigned __int8 v3; // 存储单字节字符的变量unsigned __int8 v4; // 存储单字节字符的变量unsigned __int8 v5; // 存储单字节字符的变量unsigned __int8 v6; // 存储单字节字符的变量int v7; // 存储整数的变量int v8; // 存储整数的变量int v9; // 存储整数的变量int v10; // 存储整数的变量unsigned __int8 v11;// 存储单字节字符的变量char v12[29]; // 存储字符串的字符数组,长度为29// 将字符串赋值给字符数组v12strcpy(v12, "Qsw3sj_lz4_Ujw@l");// 输出提示信息printf("Please input:");// 从标准输入读取一个字符串,并将其存储到变量v2中scanf("%s", &v2);// 将v2的值赋给resultresult = v2;// 检查用户输入的字符串是否符合预期的条件if (v2 == 'A'){result = v3;if (v3 == 'C'){result = v4;if (v4 == 'T'){result = v5;if (v5 == 'F'){result = v6;if (v6 == '{'){result = v11;if (v11 == '}'){// 如果输入的字符串符合条件,将v7、v8、v9、v10的值分别赋给数组v1的元素v1[0] = v7;v1[1] = v8;v1[2] = v9;v1[3] = v10;// 将v12数组的第18个元素(索引为17)设置为零*&v12[17] = 0;// 循环遍历v12数组的元素,对符合条件的字符进行修改while (*&v12[17] <= 15){// 如果数组v1中的元素大于64且小于等于90(大写字母A-Z)if (*(v1 + *&v12[17]) > 64 && *(v1 + *&v12[17]) <= 90)// 将大写字母转换为它在字母表中向前偏移 3 位后的字母(实现了 Caesar 密码的位移)*(v1 + *&v12[17]) = (*(v1 + *&v12[17]) - 51) % 26 + 65;// 如果数组v1中的元素大于96且小于等于122(小写字母a-z)if (*(v1 + *&v12[17]) > 96 && *(v1 + *&v12[17]) <= 122)// 将小写字母转换为它在字母表中向前偏移 13 位后的字母(也是 Caesar 密码的位移)*(v1 + *&v12[17]) = (*(v1 + *&v12[17]) - 79) % 26 + 97;// 递增索引++*&v12[17];}// 将索引重新设置为零*&v12[17] = 0;// 再次循环遍历v12数组的元素,比较数组v1中的元素和v12中的元素while (*&v12[17] <= 15){// 将v12数组中的元素赋给resultresult = v12[*&v12[17]];// 如果数组v1中的元素不等于result,说明用户输入的字符串不正确if (*(v1 + *&v12[17]) != result)// 返回resultreturn result;// 递增索引++*&v12[17];}// 如果上述条件都满足,输出提示信息return printf("You are correct!");}}}}}}// 返回resultreturn result;}
分析代码
在分析关键代码的时候,我一直把自己绕晕了,主要问题是V7到V10,我一直以为是4个字符,但是下面运算的循环有16次,这里卡了很久,一直无从下手。
后来才发现,是因为自己触发了知识盲区。
char myChar = 'A';int myInt = myChar; // 将字符'A'的ASCII码值65赋给整型变量
整型到字符:可以将整型值赋给字符型变量,但需要注意整型值是否在字符表示范围内,否则结果可能不符合预期。
int myInt = 65;char myChar = myInt; // 将整型值65赋给字符型变量,表示字符'A'
需要注意的是,虽然可以进行字符和整数之间的转换,但在使用时需要谨慎,确保数据的合法性和正确性。字符和整数之间的转换在一些特定情况下是很有用的,但在一般情况下,建议使用适当的数据类型来存储不同类型的数据。
根据代码分析,v1[4]是一个存储4个整型int的数组,里面包含整型int类型的v7、v8、v9、v10,相当于16个字符char的存储空间。
*(v1 + *&v12[17]) = (*(v1 + *&v12[17]) - 51) % 26 + 65;这一行代码主要是对数组 v1 中的某个元素进行修改。让我们逐步解释这行代码:
*(v1 + *&v12[17]): 这部分是通过指针操作来访问数组 v1 中的一个特定位置。v1 是一个整数数组,v1 + *&v12[17] 计算出数组中的一个偏移位置,*&v12[17] 实际上就是 v12[17] 的值。然后 *(v1 + *&v12[17]) 就是数组 v1 中对应位置的元素的值。
(*(v1 + *&v12[17]) - 51): 这一部分是获取数组 v1 中的元素值,并将其减去 51。这个操作可能会将大写字母的 ASCII 值映射到一个较小的范围。
% 26: 对结果取模运算,这将确保减去 51 的值在一个循环的范围内,即 0 到 25 之间。
+ 65: 最后,将结果加上 65。这将把之前映射到较小范围的值重新映射到大写字母的 ASCII 范围。
综合起来,这行代码的作用是将大写字母转换为它在字母表中向前偏移 3 位后的字母(实现了 Caesar 密码的位移)。
*(v1 + *&v12[17]) = (*(v1 + *&v12[17]) - 79) % 26 + 97;这一行代码是对数组 v1 中的某个元素进行修改的操作。我们逐步解释这行代码:
*(v1 + *&v12[17]): 这部分通过指针操作来访问数组 v1 中的一个特定位置。v1 是一个整数数组,v1 + *&v12[17] 计算出数组中的一个偏移位置,*&v12[17] 实际上就是 v12[17] 的值。然后 *(v1 + *&v12[17]) 就是数组 v1 中对应位置的元素的值。
(*(v1 + *&v12[17]) - 79): 这一部分是获取数组 v1 中的元素值,并将其减去 79。这个操作可能会将大写字母的 ASCII 值映射到一个较小的范围。
% 26: 对结果取模运算,这将确保减去 79 的值在一个循环的范围内,即 0 到 25 之间。
+ 97: 最后,将结果加上 97。这将把之前映射到较小范围的值重新映射到小写字母的 ASCII 范围。
综合起来,这行代码的作用是将小写字母转换为它在字母表中向前偏移 13 位后的字母(也是 Caesar 密码的位移)。
编写C++代码
#include <stdio.h>#include <string.h>int main() {int i, j, l; // 定义整数变量 i、j、lchar v12[] = "Qsw3sj_lz4_Ujw@l"; // 定义字符数组并初始化l = strlen(v12); // 计算字符串的长度并赋值给变量 lchar v121[] = "Qsw3sj_lz4_Ujw@l"; // 定义字符数组并初始化for (i = 0; i < l; i++) {// 检查当前字符是否为大写字母(ASCII码值在65到90之间)if (v121[i] > 64 && v121[i] <= 90) {// 对大写字母进行一定的修改v121[i] = v121[i] - 65 + 51;// 如果修改后的值小于65,加上26,确保在大写字母的范围内if (v121[i] < 65)v121[i] += 26;}// 检查当前字符是否为小写字母(ASCII码值在97到122之间)else if (v121[i] > 96 && v121[i] <= 122) {// 对小写字母进行一定的修改v121[i] = v121[i] - 97 + 79;// 如果修改后的值小于97,加上26,确保在小写字母的范围内if (v121[i] < 97)v121[i] += 26;}// 输出修改后的字符printf("%c", v121[i]);}// 返回0,表示程序执行成功return 0;}
编写Python代码
v12 = "Qsw3sj_lz4_Ujw@l"result = ""for char in v12:if 64 < ord(char) <= 90: # 检查是否为大写字母modified_char = chr(ord(char) - 65 + 51)if modified_char < 'A':modified_char = chr(ord(modified_char) + 26)elif 97 <= ord(char) <= 122: # 检查是否为小写字母modified_char = chr(ord(char) - 97 + 79)if modified_char < 'a':modified_char = chr(ord(modified_char) + 26)else:modified_char = charresult += modified_charprint(result)
flag{Cae3ar_th4_Gre@t}