目录

[SWPUCTF 2021 新生赛]简简单单的逻辑

目录

[SWPUCTF 2021 新生赛]简简单单的逻辑

1
2
3
4
5
6
7
8
flag = 'xxxxxxxxxxxxxxxxxx'
list = [47, 138, 127, 57, 117, 188, 51, 143, 17, 84, 42, 135, 76, 105, 28, 169, 25]
result = ''
for i in range(len(list)):
    key = (list[i]>>4)+((list[i] & 0xf)<<4)
    result += str(hex(ord(flag[i])^key))[2:].zfill(2)
print(result)
# result=bcfba4d0038d48bd4b00f82796d393dfec

  • >>:位右移运算符。x >> n 表示将 x 的二进制表示向右移动 n 位,移出的位将被丢弃,左边则用符号位填充(对于带符号整数)
  • <<:位左移运算符。x << n 表示将 x 的二进制表示向左移动 n 位,在右边填充零
  • &:按位与运算符。用于对两个二进制数的每一位执行与操作。对于每一对比特位,如果两个相应的位都是1,则结果位是1,否则是0
  • ^:按位异或运算符。它对两个二进制数的每一位执行异或操作。对于每一对比特位,如果两个相应的位不同,则结果位是1,如果相同则为0。
  • ord():将一个字符转换为对应的 ASCII 值
  • hex():将一个整数转换为十六进制字符串表示形式
  • str():将对象转换为字符串
  • [2:]:切片。从第3位开始
  • zfill():在字符串的左侧填充零,使字符串达到指定的宽度。即如果字符串的长度小于指定的宽度,则在左侧用零进行填充

1
key = (list[i]>>4)+((list[i] & 0xf)<<4)

key 的算法不用在意,不管正向还是逆向 key 都不变

1
result += str(hex(ord(flag[i])^key))[2:].zfill(2)

将 flag 的每一个字符与 key 异或运算后转成 ascii 码再转成 16 进制再转成字符串再截取第 3 位开始之后的内容,如果内容长度不到 2 则在前面用 0 补上

逆向算法:

将 result 字符串每隔两个转成 10 进制再和 key 异或再转为 ascii 对应的字符

1
2
3
4
5
6
7
flag = ''
list = [47, 138, 127, 57, 117, 188, 51, 143, 17, 84, 42, 135, 76, 105, 28, 169, 25]
result = 'bcfba4d0038d48bd4b00f82796d393dfec'
for i in range(len(list)):
    key = (list[i]>>4)+((list[i] & 0xf)<<4)
    flag+=chr(int(result[i*2:i*2+2],16)^key)
print(flag)
  • chr():将 Unicode 码点转换为对应的字符
  • int(hex_str, 16):将 16 进制转成 10 进制