BUUCTF 逆向题目 [ACTF新生赛2020]rome
题目地址:
https://buuoj.cn/challenges#[ACTF%E6%96%B0%E7%94%9F%E8%B5%9B2020]rome
https://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
// 将字符串赋值给字符数组v12
strcpy(v12, "Qsw3sj_lz4_Ujw@l");
// 输出提示信息
printf("Please input:");
// 从标准输入读取一个字符串,并将其存储到变量v2中
scanf("%s", &v2);
// 将v2的值赋给result
result = 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数组中的元素赋给result
result = v12[*&v12[17]];
// 如果数组v1中的元素不等于result,说明用户输入的字符串不正确
if (*(v1 + *&v12[17]) != result)
// 返回result
return result;
// 递增索引
++*&v12[17];
}
// 如果上述条件都满足,输出提示信息
return printf("You are correct!");
}
}
}
}
}
}
// 返回result
return 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、l
char v12[] = "Qsw3sj_lz4_Ujw@l"; // 定义字符数组并初始化
l = strlen(v12); // 计算字符串的长度并赋值给变量 l
char 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 = char
result += modified_char
print(result)
flag{Cae3ar_th4_Gre@t}