在阅读fuzzing book 的mutation-based fuzzing一节时,碰到一个执行比特翻转的变异函数,代码如下
def flip_random_character(s):
"""Returns s with a random bit flipped in a random position"""
if s == "":
return s
pos = random.randint(0, len(s) - 1)
c = s[pos]
bit = 1 << random.randint(0, 6)
new_c = chr(ord(c) ^ bit)
# print("Flipping", bit, "in", repr(c) + ", giving", repr(new_c))
return s[:pos] + new_c + s[pos + 1:]
从代码中可以看出,这个函数输入的是字符串,确定字符串时非空的以后,会随机选中这个字符串中的某个字符,然后在随机生成一个变量bit,这个bit的特征是,转化成二进制后,只有一个位上是1,而其他位都是0,再用这个bit和选中的字符进行异或运算,再将异或之后的结果贴回原字符串。
如果我们这样使用下面的函数
seed_input = "A quick brown fox"
for i in range(10):
print(repr(flip_random_character(seed_input)))
可能得到下列输出
'A quick bRown fox' 'A quici brown fox' 'A"quick brown fox' 'A quick brown$fox' 'A quick bpown fox' 'A quick brown!fox' 'A 1uick brown fox' '@ quick brown fox' 'A quic+ brown fox' 'A quick bsown fox'
读完第一遍以后,我对这个函数的基本用途有了掌握,但是对它具体的写法还是有些困惑。
于是在gpt的帮助下写了下面这个程序
import random
# 初始字符
c = 'A'
print("初始字符:", c, "ASCII值:", ord(c), "二进制:", bin(ord(c)))
# 随机生成比特位
bit = 1 << random.randint(0, 6)
print("十进制:",bit)
print("比特位:", bin(bit))
# 对字符的 ASCII 值进行异或操作
new_c = chr(ord(c) ^ bit)
print("异或操作后的字符:", new_c, "ASCII值:", ord(new_c), "二进制:", bin(ord(new_c)))
# 再次对新字符进行异或操作,应该可以恢复原始字符
restored_c = chr(ord(new_c) ^ bit)
print("恢复原始字符:", restored_c, "ASCII值:", ord(restored_c))
上面的程序某一次的运行结果如下
初始字符: A ASCII值: 65 二进制: 0b1000001
十进制: 1 ?
比特位: 0b1
异或操作后的字符: @ ASCII值: 64 二进制: 0b1000000
恢复原始字符: A ASCII值: 65
再一次运行结果如下
初始字符: A ASCII值: 65 二进制: 0b1000001
十进制: 4
比特位: 0b100
异或操作后的字符: E ASCII值: 69 二进制: 0b1000101
恢复原始字符: A ASCII值: 65
可以看出,每一次bit这个变量的二进制为1的那一位上才会进行比特翻转。而将bit的1的个数控制在一个,也是为了保证变异的程度不要太大,否则就更可能得到非法的输入,失去了mutational fuzzing的最初目的。