最近做了一道 BUUCTF 的 Misc 板块的 Base64 隐写的题目,发现不了解清楚 Base64 编码的根本原理的话,好像也难以理清 Base64 隐写的原理,从接触 CTF 以来 Base64 就是接触得最多的编码方式,无论是 Misc、Crypto、Web、Reverse 反正几乎所有 CTF 方向的入门题里都有它的身影。可恨的是我还没搞清楚它的编码原理,所以就抽空在 B 站和 CSDN 上的文章里面学习了一下。
首先 Base64 编码当然是可逆的,所以不能依赖它进行加密。
Base64 编码过程
首先,要让原始的待编码数据每三个字节作为一组,每个字节是 8 个 bit,所以一共是 24 个 bit,我感觉理解这一步在理解 Base64 编码步骤里面十分重要。
接着,再将待编码数据的每一个字符的 Ascii 值转化为二进制,比如字母’A’的 Ascii 值为 65,转化为二进制之后为 1000001,因为每个字节是 8 个 bit,所以要在 1 前面在补个 0 方便后续编码,所以就是 01000001。
三个字节的数据进行这一步操作后就是 24 个 bit 的二进制数据,我们对此从前往后,重新以每 6 个 bit 的二进制数据为一组,得到四组,然后将每组的二进制数据转化为十进制,再对应 Base64 编码表,这个十进制数据在码表中对应的值即为编码后的数据,也就是说三个字符数据 Base64 之后会得到 4 个字符数据,实验一下,如图,确实如此,Man 在经过编码后变成了 TWFu
那么问题又来了,什么是 Base64 码表?
Base64 编码表(table)
也没什么,就是用来将以 6 个 bit 位为一组的二进制数据重新转换为十进制之后,对照来获得编码后的数据的对照编码表,它的常规编码表一般是下面这个,网上的在线 Base64 编码默认通常也是这个编码表
可以看到,总共有 64 个字符,是英文字母的大写和小写,加上 1234567890+/
比如 010000 转化为十进制为 16,对应的就是编码表中的 Q。
而在 CTF 的题目中,Base64 的码表可能会被修改,无论是 Misc 还是 Reverse。比如下面这题
[WUSTCTF2020]level3 – Arnold’s Blog (arnold66.top)
上面我介绍的文字太多可能还不够清楚,接下来是我对 ‘Arnold’ 6 个字符的手动进行 Base64 编码,看完这个应该就会明白一些。如图,第二行为每个字符在 Ascii 码表对应的值
第三行我将字符对应的 Ascii 表中对应的值转化为 8 个 bit 的二进制数据后,又以每 6 个 bit 为一组得到第四行
然后再转化回十进制,在 Base64 编码表中寻找对应的字符即可得到 Base64 编码后的数据,QXJub2xk
但是 Base64 强调以 3 个字节为一组,像 Arnold 总共 6 个字节,为三的倍数刚刚好,那么不是三的倍数的情况下又会如何编码呢?比如 woman、hello,这时候就会出现一个问题就是将二进制数据以 6 个为一组时,到最后的数据不够 6 个了,如下图所示
当二进制数据以 6 个 bit 为一组分完后,会最后剩下一个 4 个 bit 的数据 1110,这时候我们就要在这些数据后面补上两个 0,使得其为 6 个 bit 为一组的二进制数据,并且再补 6 个 0 作为一组,为什么要再补 6 个 0 呢?因为之前强调了 Base64 要让原始的待编码数据中每三个字节作为一组,每三个字节以 6 个 bit 分组会得到 4 组,因此最后要补全四组,再加上一组 000000,而在 Base64 中 000000 代表的就是等于号,这就是为啥 Base64 编码中经常会出现等于号,我们也不难发现当待编码数据的字节数为 3n+1 时,Base64 编码后会出现 2 个‘=’,而当带编码的数据字节数为 3n+2 时,Base64 编码会出现 1 个‘=’,例如 woman 进行 Base64 编码之后是 d29tYW4=,life 进行 Base64 编码之后是则是 bGlmZQ==。
我们再来看看再 Python 中如何借助库实现对 base64 的编码和解码,代码如下
然后是再逆向过程中经常遇到的 base64 换表
然后看看 Base64 加密在 C 语言当中的实现,我们在逆向工程中通常面对的是 IDA 中 C 语言的 Base64 加密,可以参考文章
Base64 加密算法以及在 IDA 中的识别 – Qsons – 博客园 (cnblogs.com)
C 语言实现 Base64 编码 / 解码_c 语言 base64 库 - CSDN 博客
反正要在 IDA 中能识别出 Base64 加密算法,我已经识别不出来好几次了
这就是 Base64 的编码原理了,而在 Base64 解码的过程中因为解码的过程的性质会出现 Base64 隐写的题目,后续再写。