【逆向分析】BUUCTF 逆向题目 [ACTF新生赛2020]rome
2023-12-14 00:0:51 Author: 利刃信安攻防实验室(查看原文) 阅读量:8 收藏

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次,这里卡了很久,一直无从下手。

后来才发现,是因为自己触发了知识盲区。

在C语言中,整型(int)字符(char)虽然是不同的数据类型,但它们之间存在一些关系和转换规则。以下是它们之间的一些关系:
存储方式:
int(整型):通常占用4个字节(32位系统)或8个字节(64位系统)的内存空间,用于存储整数值。
char(字符):通常占用1个字节的内存空间,用于存储单个字符。
字符的表示:
char类型:可以用于存储字符,例如字母、数字或符号。字符在内存中以ASCII码的形式存储,每个字符都对应一个整数值。
int类型:也可以用于存储字符的ASCII码值,因为字符在C语言中被视为整数类型。例如,字符'A'的ASCII码是65,可以存储在int类型的变量中。
字符型变量和整型变量的转换:
字符到整型:可以将字符赋值给整型变量,此时整型变量将存储该字符对应的ASCII码值。
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 中的某个元素进行修改。让我们逐步解释这行代码:

  1. *(v1 + *&v12[17]): 这部分是通过指针操作来访问数组 v1 中的一个特定位置。v1 是一个整数数组,v1 + *&v12[17] 计算出数组中的一个偏移位置,*&v12[17] 实际上就是 v12[17] 的值。然后 *(v1 + *&v12[17]) 就是数组 v1 中对应位置的元素的值。

  2. (*(v1 + *&v12[17]) - 51): 这一部分是获取数组 v1 中的元素值,并将其减去 51。这个操作可能会将大写字母的 ASCII 值映射到一个较小的范围。

  3. % 26: 对结果取模运算,这将确保减去 51 的值在一个循环的范围内,即 0 到 25 之间。

  4. + 65: 最后,将结果加上 65。这将把之前映射到较小范围的值重新映射到大写字母的 ASCII 范围。

综合起来,这行代码的作用是将大写字母转换为它在字母表中向前偏移 3 位后的字母(实现了 Caesar 密码的位移)。

*(v1 + *&v12[17]) = (*(v1 + *&v12[17]) - 79) % 26 + 97;

这一行代码是对数组 v1 中的某个元素进行修改的操作。我们逐步解释这行代码:

  1. *(v1 + *&v12[17]): 这部分通过指针操作来访问数组 v1 中的一个特定位置。v1 是一个整数数组,v1 + *&v12[17] 计算出数组中的一个偏移位置,*&v12[17] 实际上就是 v12[17] 的值。然后 *(v1 + *&v12[17]) 就是数组 v1 中对应位置的元素的值。

  2. (*(v1 + *&v12[17]) - 79): 这一部分是获取数组 v1 中的元素值,并将其减去 79。这个操作可能会将大写字母的 ASCII 值映射到一个较小的范围。

  3. % 26: 对结果取模运算,这将确保减去 79 的值在一个循环的范围内,即 0 到 25 之间。

  4. + 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}

文章来源: http://mp.weixin.qq.com/s?__biz=MzU1Mjk3MDY1OA==&mid=2247508688&idx=1&sn=3f382550af910b2891cbda0c7827c902&chksm=fae2a5ea9639ea807d235c0cfc3b6060dfca1db0633e36cecc93037a651af416121f10a435c4&scene=0&xtrack=1#rd
如有侵权请联系:admin#unsafe.sh