逆向学习-NSSCTF刷题1 [SWPUCTF 2021 新生赛]简简单单的逻辑的WP

0x00题目

根据以下代码解出flag

 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

0x01解题流程

1.分析代码

重在分析for循环里的代码

这段代码

  • 主要是将list列表中的每一个元素的前四位和后四位进行交换,即加密过程

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

这段代码

  • 首先将flag的每个元素先转成ASCII值,

  • 然后将结果与key取异或

  • 得到的值再转成十六进制字符串(str)

  • 并且去掉了十六进制的标识"0x"以及不满两位补0至两位,确保每个字符加密后的结果都是两位的十六进制数。

  • 最后将处理后的字符串追加到result中

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

2.思路

根据已知的result以及代码逻辑,写出逆向的脚本,得到flag

2.写脚本

 encrypted_result = "bcfba4d0038d48bd4b00f82796d393dfec"
 list = [47, 138, 127, 57, 117, 188, 51, 143, 17, 84, 42, 135, 76, 105, 28, 169, 25]
 flag = ''
 for i in range(0,len(encrypted_result),2):
     hex_pair = encrypted_result[i:i+2]
     decrypted_value = int(hex_pair,16)
     key = (list[i//2] >> 4) + ((list[i//2] & 0xf) << 4)
     flag += chr(decrypted_value^key)
 print(flag)
 #运行结果如下
 #NSSCTF{EZEZ_RERE}

0x02知识点

1.位运算及其应用

符号描述运算规则
&两个位都为1时,结果才为1
|两个位都为0时,结果才为0
^异或两个位相同为0,相异为1
~取反0变1,1变0
<<左移各二进位全部左移若干位,高位丢弃,低位补0
>>右移各二进位全部右移若干位,对无符号数,高位补0;有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移)
1. &
  • 清零

如果想将一个单元清零,即使其全部二进制位为0,只要与一个各位都为零的数值相与,结果为零。

  • 取一个数的指定位

比如取数 X=1010 1110 的低4位,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行按位与运算(X&Y=0000 1110)即可得到X的指定位。

  • 判断奇偶

只要根据最未位是0还是1来决定,为0就是偶数,为1就是奇数。因此可以用if ((a & 1) == 0)代替if (a % 2 == 0)来判断a是不是偶数。

2. |
  • 常用来对一个数据的某些位设置为1

比如将数 X=1010 1110 的低4位设置为1,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行按位或运算(X|Y=1010 1111)即可得到。

3. ~
  • 使一个数的最低位为零

使a的最低位为0,可以表示为:

 a & ~1

~1的值为 1111 1111 1111 1110,再按"与"运算,最低位一定为0。因为" ~"运算符的优先级比算术运算符、关系运算符、逻辑运算符和其他运算符都高。

4. ^
  • 翻转指定位

比如将数 X=1010 1110 的低4位进行翻转,只需要另找一个数Y,令Y的低4位为1,其余位为0,即Y=0000 1111,然后将X与Y进行异或运算(X^Y=1010 0001)即可得到。

  • 与0相异或值不变

例如:1010 1110 ^ 0000 0000 = 1010 1110

3)交换两个数

 void Swap(int &a, int &b){
     if (a != b){
         a ^= b;
         b ^= a;
         a ^= b;
     }
 }

5.>>

操作数每右移一位,相当于该数除以2。

6. <<

若左移时舍弃的高位不包含1,则每左移一位,相当于该数乘以2。

2.python语法

1.切片
  • 用法:

     object[start_index : end_index : step]
     #object[起始位置(包含) : 终止位置(不包含) : 步长]

如果没有缺省的话,表达式应该包含三个参数以及两个冒号,三个参数的意义分别如下:

  • start_index:切片的起始位置(包括该位置),0表示从第一个开始,1表示从第二个开始,以此类推。-1表示从倒数第一个开始,-2表示从倒数第二个开始,以此类推。缺省时取0或-1(即step为正数取0,负数取-1)

  • end_index:切片的结束位置(!!!且不包括该位置),0表示第一个为终点,1表示第二个为终点,以此类推。-1表示倒数第一个为终点,-2表示倒数第二个为终点,以此类推。缺省时默认为序列长度(step为正数取正,step负数取负)

  • step,表示步长。可取正负数,正数表示从左往右,负数表示从右往左。缺省时取1

  • 一些操作举例:

    连续切片操作

    按照顺序进行切片即可

     a=[9,2,8,7,4,5,1,5,6,8]
     a[:8][2:5][::-1]
     #a[:8]输出为[9,2,8,7,4,5,1,5]
     #a[:8][2:5]输出为[8,7,4]
     #a[:8][2:5][-1]输出为[4,7,8]

    其他序列的切片

     #字符串的切片
     str="ABCDEFG"
     str[1:3]        #结果为'BC'
     #元组的切片
     a=('a','b','c','d','e')
     a[::-1]         #结果为('e', 'd', 'c', 'b', 'a')

    python常用切片操作

     a=[9,2,8,7,4,5,1,5,6,8]
     #修改单个元素
     a[3]='hello china'  #序列变为[9, 2, 8, 'hello china', 4, 5, 1, 5, 6, 8]
     #插入某个元素
     a[3:3]='A'  #序列变为[9, 2, 8, 'A', 7, 4, 5, 1, 5, 6, 8]
     #替换一部分元素
     a[3:5] = ['hello','world']  #序列变为[9, 2, 8, 'hello', 'world', 5, 1, 5, 6, 8]
  • 总结:

    start:表示切片的开始索引位置(包括该位置),此参数也可以不指定,会默认为 0,也就是从序列的开头进行切片;

    end:表示切片的结束索引位置(不包括该位置),如果不指定,则默认为序列的长度;

    step:表示在切片过程中,隔几个存储位置(包含当前位置)取一次元素,也就是说,如果 step 的值大于1则在进行切片去序列元素时,会“跳跃式”的取元素。如果省略设置 step 的值,则最后一个冒号就可以省略。

2.zfill函数
功能
  • 为字符串定义长度,如不满足,缺少的部分用0填补

用法
  • 用法:newstr = string.zfill(width)

  • 参数:width新字符串希望的宽度

zfill的注意事项
  • 与字符串的字符无关

  • 如果定义长度小等于当前字符串长度,则不发生变化

 In [14]: name = 'insane'
 In [15]: new_name = name.zfill(10)
 In [16]: print(new_name)
 #0000insane

2.代码段中的一些知识
 result = ''
  • 表示初始化一个空字符串result

 result += str(hex(ord(flag[i])^key))[2:].zfill(2)
  • ord()函数在Python中返回某个字符对应的Unicode编码(整数值)。

  • hex(...):将异或操作后的整数值转换成十六进制字符串。

  • str()函数在Python中用于将非字符串类型的数据转换为字符串类型。

  • [2:]:切片操作,截取从第三个字符开始的子串。

  • .zfill(2):如果经过异或和转换后得到的十六进制数不足两位,那么用0填充左侧,确保结果始终是两位的十六进制数。

    decrypted_value = int(hex_pair,16)
  • int(hex_pair,16):十六进制转换成十进制

  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值