事情的原由是以前同窗叫我幫他用Python修改一個壓縮包的二進制內容用來作fuzz,根據他的要求,把壓縮包test.rar以十六進制的方式打開,每次修改其中一個十六進制字符串並保存爲一個新的rar用來fuzz,因而我原本的打算是用傳統的函數
open()函數來實現工具
file = open('test.rar','rb') data = file.read()
經過open函數以二進制的方式打開,由於在Python中對二進制流的處理十分簡單粗暴,默認的是以字節串bytes來表示的,形式則是以十六進制,好比b'\xff\x0f',可問題出現了,print(data)輸出的字節串中的每個十六進制數和使用工具hexedit打開顯示的不徹底同樣,上例子編碼
而Python中默認的輸出結果爲spa
對照一看能夠發現ff d8 ff e0 00 10 4a 46,而Python中是ff d8 ff e0 00 10 JFIF,不對,這是爲啥?3d
這就要說到Python中默認的轉義機制了,一般我門知道的轉義字符無非是\r \n \t等等,可是Python默認支持\x + 十六進制的轉義字符,好比轉義字符\x61,在終端輸入\x61,返回的結果是字母a,而這是轉義字符,它是字符串,若是是字節串形式的呢?答案是同樣的code
b'\x61' == b'a',OK,水落石出,Python默認狀況下當遇到符合轉義字符的字符串時會自動將他們轉義,也就是說,在上面的hexedit中,'4a464946'的轉義結果其實就是'JFIF',下面上證實:對象
按理來講,'a'編碼後的字節串應爲b'\x61',但在終端中使用encode編碼以後結果顯示是這樣的:blog
編碼事後的字節串依然被Python給轉義了,服字符串
可見,不管是單純的字符串仍是字節串,只要符合轉義,Python解釋器會默認將其轉義。it
Python中有一個bytes類,其中一個方法fromhex()能夠直接將十六進制字符轉換爲字節串形式,例如:
狀況如上,也就是說其實Python的輸出是沒錯的可是表現形式不同而已,而緣由就是它默認的轉義機制。
下面介紹幾個經常使用的關於字節串bytes和十六進制和十進制互相轉換的方法
(1)
print(bin(1))#以二進制表示
print(hex(255))#將0-255內的十進制整數以十六進制表示(仍是字符串)
print(ord('\x0f'),' ',ord(b'\xff'))#將十六進制轉義字符串和字節串轉換爲十進制數字
print(bytes.fromhex('ff')) #將十六進制字符串轉換爲字節串
for i in '\xff\x0f': print(i)#print默認會解碼這些轉義字符
for i in b'\xff\x0f': print(i)#默然輸出的是每一個字節的十進制整數 %x表示將其格式化爲十六進制字符串 字節串也是可迭代對象,可是沒有字符串自帶的方法多。
0b1 0xff
15 255 b'\xff' ÿ 255
15
之後更新以十六進制讀取任意文件並修改字節