
在ctf里reverse经常会有base64相关的题型,每次写到这类题型只能凭经验猜测考点来解题,特此出一个base64相关的博客,加深对base64的理解,下次再看到伪代码也不会觉得慌了,毕竟纵使实现形式不同,代码的核心逻辑还是大差不差的。
base64编码原理及代码实现
1. 简介
base64编码是一种以64个可打印字符来表示和传输数据的编码,通常base64编码的数据是没有含义的,base64编码后的数据要通过base64解码才有意义。
2. 原理
base64编码是由64(2^6)个可打印字符来表示的,占用6位,这6位数据正好从0到63对应64个字符,而1 byte = 8 bit,如何用6bit来表示1byte(8bit) 的数据呢,如果每3byte为一组,对应每4个base64编码数据,3 * 8 bit = 4 * 6 bit,这样就解决了这个问题。
2.1 base64编码表
索引和字符的对应关系被叫做base64编码表,如下图所示
| 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 | / |
2.2 当待编码数据正好为3的倍数时
2.2.1 对abc进行base64编码
以abc这个数据为例,对其进行base64编码,如下图所示,abc——>YWNE
可以看到3字节的倍数的数据是可以完美适配base64编码的,但如果我想将非3字节倍数的数据进行base64编码呢?
2.3 当待编码数据不为3的倍数时
2.3.1 对a进行base64编码
a占一个字节(8 bit),而base64编码最少需要3 * 8 bit= 24 bit,因此需要在a后面再补2个空字符,这一组字符中,前6 bit的大小仍为24,对应的字符为Y,还剩下2 bit,则需要补0 直至补满6 bit,补满之后的数据大小为16,对应字符为Q,接下来的 2*6 bit = 12 bit 则填 2个 =,得到base64编码后的数据YQ
==,这样就解决了对一个字节进行base64编码的问题

2.3.2 对ab进行base64编码
ab共占二个字节(2 *8 bit = 16 bit),由上可知需要再补 1 byte达到 3 byte,对应的4个base64字符,其中,前两个分别为Y和Q,对于第三个,其前4bit是有数据的,而后2bit则需要补0,大小为8,对应字符为I,最后6 bit则用一个=来补齐。这样得到base64编码后的数据YWI=

2.4 小结
根据上面的个例,我们可以往数据量更大的情况考虑,假设一个数据有n byte(n > 3),如果 n % 3 = 0 ,则其base64编码后不存在=,因为它正好是 24 byte的倍数;如果n % 3 = 1,由于n = 3 * m + 1,3 * m 正好是24 byte的倍数,这部分不存在=,剩下最后 1 byte ,则按照上面2.3.1的步骤对其进行操作,后补 = =;如果n % 3 = 2,由于n = 3 * m + 2,3 * m 正好是24 byte的倍数,这部分不存在=,剩下最后 2 byte ,则按照上面2.3.2的步骤对其进行操作,后补 = 。
3. 代码实现
对于base64编码的代码,我这里学了两个版本,其中一个是在写ctf的reverse题时看到的,由于赛题是伪代码且逻辑不完整,所以我对其进行了完善,还有一个是我在学base64编码的时候看到的,其中第一个的代码量较小且更加利于理解,如果第一个的代码无法接受的也可以看看第二个,因人而异。
贴一下那道ctf的wp:
[WUSTCTF2020]level3
3.1 其一
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//data是代编码数据
char data[] = "abcdefsdadasdsad2131324rfa2615";
//data_len表示代编码数据能分成几组(3 * 8bit = 4 * 6 bit = 24bit)
int data_len= strlen(data) / 3;
//data_add表示分组后剩下几个
int data_add = strlen(data) % 3;
//开辟空间给src数组
char *src = (char*)malloc(data_len * 4 + 4 + 1);//+4是为了给可能多的1或2个数据及后边要添的=留位置,+1是为了给'\0'留位置来表示字符串结尾
int temp = 0;
int tmp = 0;
int n =0;
//以4 * 6bit为单位将编码后的值传入src
while (temp < data_len)
{
src[n++] = base64_table[data[tmp] >

本文详细介绍了Base64编码的原理,包括当待编码数据为3的倍数和非3的倍数时的具体处理方式,并通过实例展示了对'a'、'ab'进行编码的过程。此外,文章还探讨了不同字节数数据进行Base64编码时'='的使用规则,并提供了两个不同的代码实现示例。

1万+

被折叠的 条评论
为什么被折叠?



