base64隐写

部分节选自https://www.tuicool.com/articles/RRr2miE
                  https://www.cnblogs.com/Pinging/p/7622871.html

1.原理

  • base64是怎么编码的?
  1. 字符对应ASCII转换成八位二进制( base64的基础单位是 3*8bit的二进制,若是不够3*8bit则在后面添加0字节(padding)直至满足)(例如:字符A-->八位二进制01000001不够3*8即不够24位后面补0直到满足3*8即 01000001 00000000 00000000)
  2. 3*8bit的二进制转换成4*6bit的二进制(01000001 00000000 00000000-->010000 010000 000000 000000)
  3. 4*6bit的二进制转换成十进制(010000 010000 000000 000000-->16 16 0 0)(注意后面的两个0在下一步不会变成base64对照表里的A而是你自己加上去的要变成等号(=))
  4. 对照base64表把十进制转换成字符(16 16 0 0-->Q Q = = )

就是说3个字符的字符串base64编码之后会转成4个字符的base64编码

  • base64是怎么解码
  1. 检查base64编码后面有几个等于号
  2. 把字符串按照base64表转换成4*6的倍数位数二进制
  3. 删除等于号的个数*8的bit
  4. 按照6个bit一组转成字符

关键就是,解码的时候,会删除等于号的个数 *8的bit,而且我们只用6个bit表示一个等于号(000000),那么,意思就是我们可以控制等于号*2bit的字符
看图片上的两个例子:


1207957-20171002220446021-12904647.jpg

如图,那么我们就可以在加粗的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 <stdio.h>\r\n', '#include <stdlib.h>\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 <stdio.h>\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<stdio.h>
#include <stdlib.h>
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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,172评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,346评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,788评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,299评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,409评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,467评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,476评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,262评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,699评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,994评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,167评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,827评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,499评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,149评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,387评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,028评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,055评论 2 352

推荐阅读更多精彩内容

  • 前端知识体系http://www.cnblogs.com/sb19871023/p/3894452.html 前端...
    秋风喵阅读 12,372评论 7 163
  • 每天都坚持一点点,时间长了自然会形成习惯。 一定不要停下来
    皮球上的大象阅读 193评论 0 0
  • 汉赵帝国在大分裂时代的一大堆短命政权中,第一个撞上“接班人难题”,虽然以一种比较戏剧性的方式勉强渡过危机,但已经给...
    坤乾泰阅读 252评论 0 0
  • 这一段时间,发生了太多的事情。家里,工作里,都有不如愿的事情发生。 想想人到中年,真是有压力!加上很多的不可预知随...
    箜溪晓阅读 351评论 2 5