【ISCC 2023】变形记
收获
熟悉伪代码中 Base64 算法的不同实现方法
熟悉一些逆向的代码逻辑
(2023年5月1日-2023年5月25日)【ISCC 2023】变形记
思路
定位到主函数:
查看字符串:
发现形似 Base64 加密的字符串和 Base64 加密的码表
跟进码表位置:
这里先将 Base64 码表 BASE64_table_404200
赋值给了 v6
和 v56
由于每一步 if else
都会执行 sub_401960()
函数,跟进:
该函数的作用是在堆上分配一段新的内存空间,并将原始数据从源地址复制到新分配的内存中
即:该函数可用于扩展内存空间并复制数据
根据 sub_401180()
代码中的替换规则:
步骤 | 代码 |
---|---|
一:第一个字符右移 2 位,取前 6 位作为索引值,查找对应字符 | v10 = v6[*(v7 - 2) >> 2] sub_401960(Src, v8, v48, v10) |
二:第一个字符取后 2 位与第二个字符的前 4 位拼接,查找对应字符 | v13 = 16 * (*(v7 - 2) & 3) v31 = v56[v13] sub_401960(Src, v32, v42, v31) v14 = v56[v13 + (*(v7 - 1) >> 4)] sub_401960(Src, v15, v47, v14) |
三:第二个字符取后 4 位与第三个字符的前 2 位拼接,查找对应字符 | v18 = 4 * (*(v7 - 1) & 0xF) v26 = v56[v18] sub_401960(Src, v27, v44, v26) v19 = v56[v18 + (*v7 >> 6)] sub_401960(Src, v20, v46, v19) |
四:第三个字符取后 6 位作为索引,查找对应字符 | v23 = v56[*v7 & 0x3F] sub_401960(Src, v24, v45, v56[*v7 & 0x3F]) |
符合 Base64 加密的算法逻辑
所以 sub_401180()
函数其实就是 Base64Encode()
即:主函数中 sub_4014C0(v39, Block, v17, v32)
进行的是 Base64 加密
分析可知 sub_401820()
为 strcpy()
函数
存在 Base64 的字符串:=onQzpXUjFldhl3YWpnVyEWe6Jke
后面这一段代码进行了字符串的反转:
v37[]
存储的是 =onQzpXUjFldhl3YWpnVyEWe6Jke
,v49[]
是一个新的数组,v18
为 v37[]
的长度,v20
为索引位置,v49[v20 - 2] = *(v22 + v18 - v20 - 1)
将 v37[]
反向复制到 v49[]
于是使用 在线字符串反转 反向并进行 Base64 解密发现解密成功:zBzya2VzVcyavQcQzsBz
但是 ISCC{zBzya2VzVcyavQcQzsBz}
结果不对
发现在前面还有一段代码:
其中:
while ( 1 )
{
v13 = v37;
v14 = v37;
if ( v39 >= 0x10 )
v13 = v9;
if ( v39 >= 0x10 )
v14 = v9;
if ( *(v13 + v11) != *(v14 + v11 + 1) )
break;
++v12;
LABEL_37:
if ( ++v11 >= v38 )
goto LABEL_38;
}
设置了两个指针 v13
和 v14
,用于寻找两个相同且相邻的元素
如果遇到两个相同且相邻的元素,就累加重复次数 v12
,直到遇到不相等的元素为止
并且:
LABEL_37:
if ( ++v11 >= v38 )
goto LABEL_38;
}
v15 = v37;
if ( v39 >= 0x10 )
v15 = v9;
v49[v10 - 2] = *(v15 + v11);
if ( v12 < 10 )
{
++v10;
if ( v12 == 1 )
{
LABEL_36:
v12 = 1;
goto LABEL_37;
}
}
else
{
v49[v10 - 1] = v12 / 10 + 48;
v10 += 2;
}
v9 = v37[0];
v49[v10++ - 2] = v12 % 10 + 48;
goto LABEL_36;
}
这段代码根据重复次数 v12
将重复的字母替换成对应的数字,并存储在数组 v49
中
换成数字的规则是:
① 如果重复次数 v12
小于 10,则直接将其转换为字符存储
② 如果重复次数 v12
大于等于 10,则将十位数和个位数分别转换为字符存储
因此,直接将数字替换为前面一个字符即可,得到 flag 为:ISCC{zBzyaaVzVcyavQcQzsBz}
综上所述,程序逻辑如下:
① 在用户输入的数据中,先将重复的字母替换成对应的数字
② 然后进行 Base64 加密
③ 再将加密后的字符串反转
④ 与 =onQzpXUjFldhl3YWpnVyEWe6Jke
进行比较,如果相等则正确
脚本
import base64
ss = "=onQzpXUjFldhl3YWpnVyEWe6Jke"
res = ss[::-1]
re = ""
re += str(base64.b64decode(res).decode('utf-8')) # Base64解密
print(re)
result = ""
for i in range(0, len(re)):
if ord(re[i]) <= 57: # 重复次数小于等于9(个位数)
tmp = ord(re[i]) - 48 - 1
result += re[i - 1] * tmp
continue
result += re[i]
print("ISCC{" + result + "}")
结果
ISCC{zBzyaaVzVcyavQcQzsBz}