也可参考这篇文章:
本题并不是拖入ida中,进行静态分析,下载文件后文件名是py,我们将其重命名(即修改后缀为.py) (如图)
打开后分析以下代码
逆向一下有点麻烦,看了大佬的题解,说是直接正向爆破一下:
flag = ''
result = 'v0b9n1nkajz@j0c4jjo3oi1h1i937b395i5y5e0e$i'
s = 'wesyvbniazxchjko1973652048@$+-&*<>'
for i in range(len(result)//2):
for j in range(32,126):
s1 = j//17
s2 = j%17
a=(s1+i)%34
b=-(s2+i+1)%34
if (result[2*i]==s[a] and result[2*i+1]==s[b]):
flag+=chr(j)
break
print(flag)
下面详细分析一下中间四步和if循环:
中间四步目的是为了找到原始字符 j 在加密过程中是如何被转换成加密字符串 result 中的两个字符的。
1.计算 s1 和 s2:
s1 = j//17
s2 = j%17
- s1 = j//17: 这一步计算了原始字符 j 的 ASCII 码值除以 17 的商。在加密过程中,这个商用于确定 s 字符串中的第一个字符的索引。
- s2 = j%17: 这一步计算了原始字符 j 的 ASCII 码值除以 17 的余数。在加密过程中,这个余数用于确定 s 字符串中的第二个字符的索引。
这两个值 s1 和 s2 是将原始字符 j 的 ASCII 码值分解为两部分,这两部分随后被用来从 s 字符串中选择字符。
2.计算索引 a 和 b:
a=(s1+i)%34
b=-(s2+i+1)%34
- a=(s1+i)%34: 这一步计算了 s 字符串中第一个字符的索引。由于加密过程中使用了 i(当前字符的索引)和 s1(原始字符 ASCII 码值的商),因此这里也要使用 i 来逆向计算索引 a。取模 34 是因为 s 字符串的长度是 34。
- b=-(s2+i+1)%34: 这一步计算了 s 字符串中第二个字符的索引。同样地,它使用了 i 和 s2(原始字符 ASCII 码值的余数)。这里使用 - 是因为加密过程中使用了负索引来从字符串的末尾选择字符。取模 34 同样是因为 s 字符串的长度是 34。
在加密过程中,原始字符 j 的 ASCII 码值被分解为两部分,这两部分随后被用来从 s 字符串中选择两个字符,并将它们组合起来形成加密结果的一部分。通过这个过程,我们可以从加密结果中提取出原始字符 j。
分析一下if语句:
1.分析条件检查:
if (result[2*i]==s[a] and result[2*i+1]==s[b]):
这个条件检查包含两个部分,它们必须同时满足:
- result[2*i]==s[a]: 这检查加密结果 result 中的第 2*i 个字符是否与我们通过当前猜测字符 j 计算出的 s 字符串中的索引 a 对应的字符相同。
- result[2*i+1]==s[b]: 这检查加密结果 result 中的第 2*i+1 个字符是否与我们通过当前猜测字符 j 计算出的 s 字符串中的索引 b 对应的字符相同。
这两个条件一起确保了通过当前的 j 值计算出的两个字符能够精确地匹配加密结果 result 中的对应字符。
2.如果条件满足:
flag+=chr(j)
如果上述条件为真,即我们找到了正确的字符 j,那么我们就将这个字符(通过 chr(j) 转换为字符)添加到 flag 字符串中。这是还原原始 flag 的过程。
3.跳出内层循环:
break
一旦找到正确的字符,就没有必要继续尝试其他字符了,因此使用 break 语句跳出内层循环。这可以节省时间,因为我们已经找到了当前字符的正确值,可以继续寻找下一个字符。
总结来说,这个 if 循环的作用是:
- 验证当前的猜测字符 j 是否能够产生加密结果 result 中的对应字符。
- 如果可以,则将这个字符添加到 flag 中,并继续寻找下一个字符。
- 如果不可以,则继续尝试下一个可能的字符,直到找到正确的字符为止。
这个过程重复进行,直到 flag 字符串中的所有字符都被找到。
Flag{Fake_RERE_QAQ}
也可参考这篇文章:NSSCTF RE [SWPUCTF 2021 新生赛]非常简单的逻辑题-CSDN博客