Lucifer2002 发表于 2022-3-28 16:02

关于base64隐写的问题

本帖最后由 Lucifer2002 于 2022-3-28 16:13 编辑

BASE64隐写先来看一下base64的概念


Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节,也就是说,转换后的字符串理论上将要比原来的长1/3。
规则
关于这个编码的规则:
1.把3个字符变成4个字符
2.每76个字符加一个换行符
3.最后的结束符也要处理
4.10个数字,26个大写字母,26个小写字母,1个+,一个/刚好64个字符


例子
为方便理解,举下例子
转换前 11111011, 11101111, 10111110 (二进制)
首先按每6位分开 111110, 111110, 111110, 111110
再到最高位添加两个0
转换后 00111110, 00111110, 00111110, 00111110 (二进制)
上面的三个字节是原文,下面的四个字节是转换后的Base64编码,其前两位均为0。
转换后,我们用一个码表来得到我们想要的字符串(也就是最终的Base64编码),这个表是这样的:


索引 对应字符
0 A
1 B
2 C
3 D
4 E
5 F
6 G
7 H
8 I
9 J
10 K
11 L
12 M
13 N
14 O
15 P
16 Q
17 R
18 S
19 T
20 U
21 V
22 W
23 X
24 Y
25 Z
26 a
27 b
28 c
29 d
30 e
31 f
32 g
33 h
34 i
35 j
36 k
37 l
38 m
39 n
40 o
41 p
42 q
43 r
44 s
45 t
46 u
47 v
48 w
49 x
50 y
51 z
52 0
53 1
54 2
55 3
56 4
57 5
58 6
59 7
60 8
61 9
62 +
63 /
虽然python解base64很方便
最好还是先写个脚本加深对base64的理解
文末我会贴出我的调试脚本那么base64隐写到底是什么东西呢?关键是base64解码的时候
1.检查base64编码后面有几个等于号
2.把字符串按照base64表转换成46的倍数位数二进制
3.__删除等于号的个数8的bit__(等于号不在base64规定的范围内,只是为了补足长度,所以解码时要删除)
4.按照6个bit一组转成字符
此处的关键就是,解码的时候,会删除等于号的个数8的bit
且我们只用6个bit表示一个等于号(xxxxxx)
那么,意思就是我们可以控制__等于号个数2bit__的字符NJCTF2017有一道misc是base64隐写
从里面抽出一条来
import base64
s = "QnkgcmVhc29uIG9mIGhpcyBmYWxsZW4gZGl2aW5pdHm="
print base64.b64decode(s)
print s
print base64.b64encode(base64.b64decode(s))



会发现返回
By reason of his fallen divinity
QnkgcmVhc29uIG9mIGhpcyBmYWxsZW4gZGl2aW5pdHm=
QnkgcmVhc29uIG9mIGhpcyBmYWxsZW4gZGl2aW5pdHk=

发现有区别,但是并不影响正常显示
来分析一下为啥,就拿我的昵称举例
首先是把每位字符转化成ascii的二进制形式
c | 0 | 1 | 4
01100011 | 00110000 | 00110001 | 00110100


进行base64编码时,按每6位分开,如果不能被6整除要用0补齐
011000 11|0011 0000|00 110001 | 001101 00
011000 | 110011 | 000000 | 110001 | 001101 | 000000

并且所有高位补两个0至8位
011000 | 110011 | 000000 | 110001 | 001101 | 000000
00011000 | 00110011 | 00000000 | 00110001 | 00001101 | 00000000

这样才能刚好用64个不同形式表示
00011000 | 00110011 | 00000000 | 00110001 | 00001101 | 00000000
Y | z | A | x | N | A

但是会发现字符只有6位数不够被4整除
所以到字符后面添加2个等号
YzAxNA
YzAxNA==

解密时
先找出YzAxNA==每位字符在base64码表中的位置
由于等号没有我就不表示了
Y | z | A | x | N | A
011000 | 110011 | 000000 | 110001 | 001101 | 000000


将二进制连接起来并按每八位划分
011000110011000000110001001101000000
01100011 | 00110000 | 00110001 | 00110100 | 0000

会发现末尾多了等号数*2bit的0
这些0在解密时是要被删除的
所以base64隐写的精髓就是这几bit可控

YzAxNA==
YzAxNB==
YzAxNC==
......
YzAxNO==
解密的到的都是一样的结果
调试脚本
# -*- coding:utf-8 -*-


base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

def encode(str):
s = str
s_bin = ""
for i in range(0,len(s)):
s_bin = s_bin + bin(ord(s)).replace("0b","").rjust(8,"0") #把每个字符二进制化
print s_bin

if len(s_bin) % 6 != 0: #判断二进制长度能否被6整除
for j in range(1,6):
if (len(s_bin) + j) % 6 == 0:
bin_length = len(s_bin) + j #获取二进制长度
break
s_bin = s_bin.ljust(bin_length,"0") #把二进制长度补到能被6整除
print s_bin

encode = ""
for k in range(0,len(s_bin)/6):
index = k * 6
each_bin = s_bin.zfill(8) #把6Bit再添两位高位0
print each_bin
each_enc = int(each_bin,2) #转化为10进制
print each_enc
encode = encode + base

# print encode
if len(encode) % 4 != 0: #判断解密后字符串是否能被4整除,如果不能,要在末尾加=
for l in range(1,4):
if (len(encode) + l) % 4 == 0:
encode_length = len(encode) + l
print encode.ljust(encode_length,"=")

def raw(str): #获取每位字符的二进制形式
s = str
for i in range(0,len(s)):
print s,bin(ord(s)).replace("0b","").rjust(8,"0")

版权声明:本文为博客园博主「SO-CAT」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://www.cnblogs.com/Elope/p/6725824.html

atxz 发表于 2022-3-28 19:16

不错,支持一波,提前学一下

chishingchan 发表于 2022-3-28 19:58

这个 BASE64 编码解码我手头上有 VBScript 版的,AutoIt3 版根据 VBScript 改编的。网上对于 BASE64 的编码解码都提供了免费程序(.exe),好像我手头上也有两个。
反正这个编码我用的还不少!

ff5500 发表于 2022-3-28 22:13

如果真的要隐写,凯撒密码加类推法。。。简单粗暴有效!

流云 发表于 2022-3-29 00:48

奇思妙想,学习了.
页: [1]
查看完整版本: 关于base64隐写的问题