部分节选自https://www.tuicool.com/articles/RRr2miE
https://www.cnblogs.com/Pinging/p/7622871.html
1.原理
- base64是怎么编码的?
- 字符对应ASCII转换成八位二进制( base64的基础单位是 3*8bit的二进制,若是不够3*8bit则在后面添加0字节(padding)直至满足)(例如:字符A-->八位二进制01000001不够3*8即不够24位后面补0直到满足3*8即 01000001 00000000 00000000)
- 3*8bit的二进制转换成4*6bit的二进制(01000001 00000000 00000000-->010000 010000 000000 000000)
- 4*6bit的二进制转换成十进制(010000 010000 000000 000000-->16 16 0 0)(注意后面的两个0在下一步不会变成base64对照表里的A而是你自己加上去的要变成等号(=))
- 对照base64表把十进制转换成字符(16 16 0 0-->Q Q = = )
就是说3个字符的字符串base64编码之后会转成4个字符的base64编码
- base64是怎么解码
- 检查base64编码后面有几个等于号
- 把字符串按照base64表转换成4*6的倍数位数二进制
- 删除等于号的个数*8的bit
- 按照6个bit一组转成字符
关键就是,解码的时候,会删除等于号的个数 *8的bit,而且我们只用6个bit表示一个等于号(000000),那么,意思就是我们可以控制等于号*2bit的字符
看图片上的两个例子:
如图,那么我们就可以在加粗的0的位子用二进制隐写(改成其他的二进制数)。这样子做,不影响原文的还原(因为解码的时候加粗位置被改的数是要被删除的),唯一的区别就是,上图的QQ==中第二个Q会变化,QkM=的M会变化,所以base64可以用于隐写
2.试试效果
下面的代码是对 UX==(X取A到Z)进行base64解码(python2.7)
import base64
b = ''
for i in range(26):
b = 'U' + chr(65 + i) + '=='
print b
print base64.b64decode(b)
E:\App\py_workspace\venv\Scripts\python.exe E:/App/py_workspace/asdf.py
UA==
P
UB==
P
UC==
P
UD==
P
UE==
P
UF==
P
UG==
P
UH==
P
UI==
P
UJ==
P
UK==
P
UL==
P
UM==
P
UN==
P
UO==
P
UP==
P
UQ==
Q
UR==
Q
US==
Q
UT==
Q
UU==
Q
UV==
Q
UW==
Q
UX==
Q
UY==
Q
UZ==
Q
看出来啥了没
如果我要发给你一个Q那么我发UZ==可以,但是发UY==也可以,
看代码↓
# coding:UTF8
# import base64
import string
def decode(flag1): # 把需要隐藏的密文变成二进制字符串
list_flag1 = list(flag1) # 把密文转为list例如:['I', ' ', 'a', 'm', ' ', 'a', ' ', 'C', 'T', 'F', 'e', 'r']
list_dec_flag1 = [] # 十进制密文例如:[73, 32, 97, 109, 32, 97, 32, 67, 84, 70, 101, 114]
for j in range(len(list_flag1)): # 把ascii码密文转换为十进制密文list
list_dec_flag1.append(ord(list_flag1[j]))
list_bin_flag1 = []
# 二进制密文例如:['1001001', '100000', '1100001', '1101101', '100000', '1100001', '100000', '1000011','1010100'...]
for j in range(len(list_dec_flag1)): # 把十进制密文转化为二进制密文
list_bin_flag1.append((bin(list_dec_flag1[j])[2:]).zfill(8))
str_bin_flag1 = ''.join(list_bin_flag1) # 把二进制密文list拼接成str
# 例如:010010010010000001100001011011010010000001100001001000000100001101010100010001100110010101110010
list_bin_every_flag1 = list(str_bin_flag1) # 把str二进制密文转换成list
# 例如:['1', '0', '0', '1', '0', '0', '1', '1', '0', '0', '0', '0', '0', '1', '1', '0', '0', '0', '0', '1'...]
return list_bin_every_flag1
if __name__ == '__main__':
dic = string.uppercase+string.lowercase+string.digits+'+/'
# a = raw_input()
flag = 'I am a CTFer'
list_bin_every_flag = decode(flag) # list二进制密文
# print len(list_bin_every_flag)
# 例如:['1', '0', '0', '1', '0', '0', '1', '1', '0', '0', '0', '0', '0', '1', '1', '0', '0', '0', '0', '1'...]
tip = 0 # 定义一个指针指向要写入base64的list二进制密文
# tt = 0
with open('hello.txt', 'rb') as h: # 打开明文
file_lines = h.readlines() # 把明文读取成一行
# 例如:['#include \r\n', '#include \r\n', 'main(){int i,n[]={(((1 <<1)<< (1<<1)...]
for line in file_lines: # 接下来是正文了
normal_line = line.replace('\r\n', '') # 每一行的明文
# print normal_line
# 例如:#include \r
equal_sign_num = 3 - (len(normal_line) % 3) # 每行base64加密后的等号数量
if equal_sign_num == 3: # 如果是3的倍数说明这一句没法进行隐写
equal_sign_num = 0 # 设其等号数量为0
# print 'equal_sign_num', equal_sign_num
# tt += equal_sign_num * 2
# print tt, 'tt'
list_normal_line = decode(normal_line) # 把明文也装换为list_bin_every_明文
# print list_normal_line
if equal_sign_num == 1: # 一个等号
for i in range(2):
# print 'tip', tip, 'list_bin_every_flag[tip]',list_bin_every_flag[tip]
list_normal_line.append(list_bin_every_flag[tip])
tip += 1
# print list_normal_line
elif equal_sign_num == 2: # 两个等号
for i in range(4):
# print 'tip', tip, 'list_bin_every_flag[tip]', list_bin_every_flag[tip]
list_normal_line.append(list_bin_every_flag[tip])
tip += 1
# print list_normal_line
# print tt
str_bin_normal_line = ''.join(list_normal_line)
# print str_bin_normal_line
b64 = ''
for i in range(0, len(str_bin_normal_line), 6):
b64 += dic[int(str_bin_normal_line[i: i+6], 2)] # 以6位为单位对照base64编码表
if equal_sign_num == 1:
b64 += '='
elif equal_sign_num == 2:
b64 += '=='
print b64
效果如下
E:\App\py_workspace\venv\Scripts\python.exe E:/App/py_workspace/mybase64隐写.py
I2luY2x1ZGU8c3RkaW8uaD5=
I2luY2x1ZGUgPHN0ZGxpYi5oPi==
bWFpbigpe2ludCBpLG5bXT17KCgoMSA8PDEpPDwoMTw8MSk8PCgxPDx=
ICAgICAgIDEpPDwoMTw8KDE+PjEpKSkrKCgxPDwxKTw8KDE8PDEpKSksICgoKDE=
ICAgICAgIDw8MSk8PCgxPDwxKTw8KDE8PDEpPDwoMTw8MSkpLSgoMTw8MSk8PCi=
ICAgIAkxPDwxKTw8KDE8PDEpKSsoKDE8PDEpPDwoMTw8KDE+PjEpKSkrKDE8PCgxPj4xKSkpLA==
ICAgICAgICgoKDE8PDEpPDwoMTw8MSk8PCgxPDwxKTw8KDE8PDEpKS0oKDEgPDwxKW==
ICAgICAgIDw8KDE8PDEpIDw8KDE8PCgxPj4xKSkpLSgoMTw8MSk8PCgxPDwoMT4+MSkpKSkgLB==
ICAgICAgICgoKDE8PDEpPDwoMTw8MSk8PCgxPDwxKTw8KCAxPDwxKSktKCgxIDw8MSk8PG==
ICAgICAgICAoMTw8MSk8PCgxIDw8KDE+PjEpKSktKCgxPDwxKTw8KDE8PCgxPj4xKSkpKSAgLN==
ICAgICAgICAoKCgxPDwxKTw8KDE8PDEpPDwoMTw8MSk8PCgxPDwxKSktKCgxPDwxKSA8PC==
ICAgICAgICAoMTw8MSk8PCgxPDwoMT4+MSkpKS0oMTw8KDE+PjEpKSksKCgoMTw8MSk8PA==
ICAgICAgICAoMTw8MSk8PCgxPDwxKSkrKCgxPDwxKTw8KDE8PDEpPDwoMTw8KDE+PjEpKSkgLW==
ICAgICAgICAoKDE8PDEpPDwoMTw8KDE+PjEpKSkpLCgoMTw8MSk8PCgxPDwxKTw8KDE8PDEpKR==
ICAgICAgICwoKCgxPDwxKTw8KDE8PDEpPDwoMTw8MSk8PCgxPDwxKSktKCgxPDwxKTw8KDE8PDEpKS==
ICAgICAgIC0oMTw8KDE+PjEpKSksKCgoMTw8MSk8PCgxPDwxKTw8KDE8PDEpPDwoMTw8MSkpLSgoMQ==
ICAgICAgIDw8MSk8PCgxPDwxKTw8KDE8PCgxPj4xKSkpLSgxPDwoMT4+MSkpKSwgICgoKDE8PDF=
ICAgICAgICk8PCgxPDwxKTw8KDE8PDEpPDwoMTw8MSkpLSgoMTw8MSk8PCAoMQ==
ICAgICAgIDw8MSk8PCgxPDwoMT4+MSkpKSsoMTw8MSkpLCgoKDE8PDEpPDwoMTw8MSAgKd==
ICAgICAgIDw8KDE8PDEpPDwoMTw8MSkpLSgoMTw8MSk8PCgxPDwxKTw8KDE8PCgxPj4xKSkpLV==
ICAgICAgICgoMTw8MSk8PCgxPDwoMT4+MSkpKSksKCgoMTw8MSk8PCgxPDwxKSA8PCgxPDwxKR==
ICAgICAgIDw8KDE8PDEpKS0oKDE8PDEpPDwoMTw8MSk8PCgxPDwxKSkrICgoMR==
ICAgICAgIDw8MSk8PCgxPDwoMT4+MSkpKSksKCgoMTw8MSk8PCgxPDwxKSAgPDwoMZ==
ICAgICAgIDw8MSkpKygxPDwoMT4+MSkpKSwoKCgxPDwxKTw8KDE8PDEpKSAgKygoMZ==
ICAgICAgIDw8MSk8PCAoMTw8KDE+PjEpKSkgKygxPDwgKDE+PjEpKSl9O2Zvcl==
ICAgICAgIChpPSgxPj4xKTtpPCgoKDE8PDEpPDwoMTw8MSkpKygoMSAgPDwxKTw8KM==
ICAgICAgIDE8PCgxPj4xKSkpKygxPDwxKSk7aSsrKSAgIHByaW50ZigiJWMiLG5baV0pO32=
Process finished with exit code 0
附送大家一个输出hello,world的c语言程序
#include
#include
main(){int i,n[]={(((1 <<1)<<(1<<1)<<(1<<
1)<<(1<<(1>>1)))+((1<<1)<<(1<<1))), (((1
<<1)<<(1<<1)<<(1<<1)<<(1<<1))-((1<<1)<<(
1<<1)<<(1<<1))+((1<<1)<<(1<<(1>>1)))+(1<<(1>>1))),
(((1<<1)<<(1<<1)<<(1<<1)<<(1<<1))-((1 <<1)
<<(1<<1) <<(1<<(1>>1)))-((1<<1)<<(1<<(1>>1)))) ,
(((1<<1)<<(1<<1)<<(1<<1)<<( 1<<1))-((1 <<1)<<
(1<<1)<<(1 <<(1>>1)))-((1<<1)<<(1<<(1>>1)))) ,
(((1<<1)<<(1<<1)<<(1<<1)<<(1<<1))-((1<<1) <<
(1<<1)<<(1<<(1>>1)))-(1<<(1>>1))),(((1<<1)<<
(1<<1)<<(1<<1))+((1<<1)<<(1<<1)<<(1<<(1>>1))) -
((1<<1)<<(1<<(1>>1)))),((1<<1)<<(1<<1)<<(1<<1))
,(((1<<1)<<(1<<1)<<(1<<1)<<(1<<1))-((1<<1)<<(1<<1))
-(1<<(1>>1))),(((1<<1)<<(1<<1)<<(1<<1)<<(1<<1))-((1
<<1)<<(1<<1)<<(1<<(1>>1)))-(1<<(1>>1))), (((1<<1
)<<(1<<1)<<(1<<1)<<(1<<1))-((1<<1)<< (1
<<1)<<(1<<(1>>1)))+(1<<1)),(((1<<1)<<(1<<1 )
<<(1<<1)<<(1<<1))-((1<<1)<<(1<<1)<<(1<<(1>>1)))-
((1<<1)<<(1<<(1>>1)))),(((1<<1)<<(1<<1) <<(1<<1)
<<(1<<1))-((1<<1)<<(1<<1)<<(1<<1))+ ((1
<<1)<<(1<<(1>>1)))),(((1<<1)<<(1<<1) <<(1
<<1))+(1<<(1>>1))),(((1<<1)<<(1<<1)) +((1
<<1)<< (1<<(1>>1))) +(1<< (1>>1)))};for
(i=(1>>1);i<(((1<<1)<<(1<<1))+((1 <<1)<<(
1<<(1>>1)))+(1<<1));i++) printf("%c",n[i]);}
3.解密的脚本如下:
def get_base64_diff_value(s1, s2):
base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
res = 0
for i in xrange(len(s2)):
if s1[i] != s2[i]:
return abs(base64chars.index(s1[i]) - base64chars.index(s2[i]))
return res
def solve_stego():
with open('3.txt', 'rb') as f:
file_lines = f.readlines()
bin_str = ''
for line in file_lines:
steg_line = line.replace('\n', '')
norm_line = line.replace('\n', '').decode('base64').encode('base64').replace('\n', '')
diff = get_base64_diff_value(steg_line, norm_line)
print diff
pads_num = steg_line.count('=')
if diff:
bin_str += bin(diff)[2:].zfill(pads_num * 2)
else:
bin_str += '0' * pads_num * 2
print goflag(bin_str)
def goflag(bin_str):
res_str = ''
for i in xrange(0, len(bin_str), 8):
res_str += chr(int(bin_str[i:i + 8], 2))
return res_str
if __name__ == '__main__':
solve_stego()
效果↓
E:\App\py_workspace\venv\Scripts\python.exe E:/App/py_workspace/Tools/base64隐写解密.py
1
�
2
�
1
I
0
I
2
I�
0
I
6
I �
1
I a
6
I a�
13
I am
2
I am�
0
I am
6
I am �
1
I am a
2
I am a�
0
I am a
1
I am a �
0
I am a �
13
I am a C�
5
I am a C�
1
I am a CT�
1
I am a CT�
9
I am a CTF�
9
I am a CTF�
5
I am a CTFe�
12
I am a CTFe�
2
I am a CTFer
Process finished with exit code 0