base64原理与逆向中的表现形式.
Base64编码 变形Base64编码 实现与逆向分析
一丶BASE64介绍
1.1 BASE64简介
所谓的BASE64 说白了就是有一个64个字符数组, 这64个字符分别是 小写a - z 大写A-Z 数字0-9 然后再加上"+" "/"符号来组成一个64字符的数组.但是其实我们有的时候还要加上"="作为字符,也就是说白了是65个字符,但是"="加密解密都会忽略所以就认为是64个字符.
从64个字符里面取出当前字符就形成了编码过程
下面说一下BASE64编码的过程
- 第一步 将三个字节作为一组 也就是有24个进制位
- 第二步 将三个字节转为四个字节 也就是24个进制位按照每6个字节一组的方式进行分割
- 第三步 扩展为4个字节 主要就是分组之后是6个进制为一组,再把每个6进制前边加上00
- 第四部 查表 根据base64编码表 然后进行查表动作.其索引就是按照6bit分组扩展为8bit的字节
下面就以C语言为表来表达
unsigned char base64_table[64]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
下面就实战转换 Man 这三个字符 如何进行编码的
- 三字符转为4字符
首先第一步就是将 M a n三个字符的Ascii提取出来. 第二步看一下其对应的8个bit位 第三步就是8bit 按照6bit分割
第四步就是前边补0 但是其实不补也可以,因为补了0一样还是代表原数.
那么在C/C++中的表现就可以用移位来进行编码.
简单伪代码如下
char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char Man[] = "Man";
char CodeTable[5] = { 0 };
int nindex = 0;
nindex = (Man[0] >> 0x2) & 0x3F;
CodeTable[0] = base64_table[nindex];
nindex = ((Man[0] & 0x03) << 4) | (Man[1] >> 4);
CodeTable[1] = base64_table[nindex];
nindex = ((Man[1] & 0x0F) << 2) | (Man[2] >> 6);
CodeTable[2] = base64_table[nindex];
nindex = ((Man[2] & 0x3F));
CodeTable[3] = base64_table[nindex];
通过移位可以将三个转为4个 最终输出为TWFu 当然我们可以用循环做.这里是简单看如何转换的.
-
2字节转为三字节
当只有两个字节的情况下,其对应的ASCII编码有两个.是可以转换为 2个6bit加剩下4个bit的数据
也就是可以将两组8bit转为三组.但是最后一组就剩下4个bit了. 所以最后一组我们要在前边补充两个0 后面补充两个0 来凑满8个字节 继续进行查表. 查表之后在最后一个字符后面添加一个"="
伪代码如下:
char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; char Man[] = "Ma"; char CodeTable[5] = { 0 }; int nindex = 0; nindex = (Man[0] >> 0x2) & 0x3F; CodeTable[0] = base64_table[nindex]; nindex = ((Man[0] & 0x03) << 4) | (Man[1] >> 4); CodeTable[1] = base64_table[nindex]; nindex = ((Man[1] & 0x0F) << 2); CodeTable[2] = base64_table[nindex]; CodeTable[3] = '=';
最终的输出结果就是 TWE=
-
一字节转换
一字节转换其原理就是 将一个字节转换为8个bit 按照6bit一组可以分为两组 最后一组前面除了加上两个0来扩充后面也要加上两个2来扩充,最终形成一个2个8bit字节.然后查表得出字符.但因为是一个字节所以后面两个字符要以'='结尾.
伪代码如下:
char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; char Man[] = "M"; char CodeTable[5] = { 0 }; int nindex = 0; nindex = (Man[0] >> 0x2) & 0x3F; CodeTable[0] = base64_table[nindex]; nindex = ((Man[0] & 0x03) << 4) | (Man[1] >> 4); CodeTable[1] = base64_table[nindex]; CodeTable[2] = '='; CodeTable[3] = '=';
最终则是TQ==
-
1.2 BASE64 c代码实现
1.2.1 自实现base64编码
使用C代码实现就很简单了,根据以上原理我们可以得出几个步骤
1.传入要编码的字节以及对应长度
2.以长度%3 %2 %1为分界线进行编码
长度 = 3 则用3转化为4的方式
长度 = 2 则用 2转化为3的方式 并且后面加一个=
长度为1 则用 1转化为2的方式i并且后面加上两个=
代码如下
string b64_EnCode(char EnCodeByte[], int EnCodeLen)
{
char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
string EnCode;
char EnCode3Array[3] = {0};
int i = 0;
while (EnCodeLen--)
{
//每次获取一个字符 当获取到3个字符进行一次操作
EnCode3Array[i++] = *(EnCodeByte++);
if (i == 3)
{
EnCode += base64_table[(EnCode3Array[0] >>2)& 0x3F];
EnCode += base64_table[((EnCode3Array[0] & 0x03) << 4) | (EnCode3Array[1] >> 4)];
EnCode += base64_table[((EnCode3Array[1] & 0x0F) << 2) | (EnCode3Array[2] >> 6)];
EnCode += base64_table[((EnCode3Array[2] & 0x3F))];
//重置i
i = 0;
}
}
//然后判断是否是2个字节的情况与一个字节的情况
if (i)
{
//置零
for (int j = i; j < 3; j++)
{
EnCode3Array[j] = 0;
}
//判断i = 2 还是1
if (i == 2)
{
EnCode += base64_table[(EnCode3Array[0] >> 2) & 0x3F];
EnCode += base64_table[((EnCode3Array[0] & 0x03) << 4) | (EnCode3Array[1] >> 4)];
EnCode += base64_table[((EnCode3Array[1] & 0x0F) << 2)];
EnCode += '=';
}
if (i == 1)
{
EnCode += base64_table[(EnCode3Array[0] >> 2) & 0x3F];
EnCode += base64_table[((EnCode3Array[0] & 0x03) << 4) | (EnCode3Array[1] >> 4)];
EnCode += '=';
EnCode += '=';
}
}
return EnCode;
}
int main()
{
char Man[] = "HelloWorld1";
printf("%s\r\n", b64_EnCode(Man,strlen(Man)).c_str());
system("pause");
return 0;
}
输出值为: SGVsbG9Xb3JsZDE=
1.2.2 其它优秀实现
上面是自己实现的 base64还有更多种实现,比如下面的移位也不一样但是结果是一样的.
#include "base64.h"
#include <iostream>
// there are 64 characters
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
std::string base64_encode(const char *bytes_to_encode, unsigned int in_len) {
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3]; // store 3 byte of bytes_to_encode
unsigned char char_array_4[4]; // store encoded character to 4 bytes
while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++); // get three bytes (24 bits)
if (i == 3) {
// eg. we have 3 bytes as ( 0100 1101, 0110 0001, 0110 1110) --> (010011, 010110, 000101, 101110)
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; // get first 6 bits of first byte,
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); // get last 2 bits of first byte and first 4 bit of second byte
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); // get last 4 bits of second byte and first 2 bits of third byte
char_array_4[3] = char_array_3[2] & 0x3f; // get last 6 bits of third byte
for (i = 0; (i < 4); i++)
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if (i)
{
for (j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
for (j = 0; (j < i + 1); j++)
ret += base64_chars[char_array_4[j]];
while ((i++ < 3))
ret += '=';
}
return ret;
}
std::string base64_decode(const std::string& encoded_string) {
size_t in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i == 4) {
for (i = 0; i < 4; i++)
char_array_4[i] = base64_chars.find(char_array_4[i]) & 0xff;
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
}
if (i) {
for (j = 0; j < i; j++)
char_array_4[j] = base64_chars.find(char_array_4[j]) & 0xff;
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
}
return ret;
}
优秀实现2:
const char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char *
base64_encode(const unsigned char *input, int length)
{
int i=0, j=0, s=0;
unsigned char char_array_3[3], char_array_4[4];
int b64len = (length+2 - ((length+2)%3))*4/3;
char *b64str = (char *) malloc(b64len + 1);
while (length--) {
char_array_3[i++] = *(input++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (i = 0; i < 4; i++)
b64str[s++] = base64_chars[char_array_4[i]];
i = 0;
}
}
if (i) {
for (j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; j < i + 1; j++)
b64str[s++] = base64_chars[char_array_4[j]];
while (i++ < 3)
b64str[s++] = '=';
}
b64str[b64len] = '\0';
return b64str;
}
inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
unsigned char *
base64_decode(const char *input, int length, int *outlen)
{
int i = 0;
int j = 0;
int r = 0;
int idx = 0;
unsigned char char_array_4[4], char_array_3[3];
unsigned char *output = (unsigned char *)malloc(length*3/4);
while (length-- && input[idx] != '=') {
//skip invalid or padding based chars
if (!is_base64(input[idx])) {
idx++;
continue;
}
char_array_4[i++] = input[idx++];
if (i == 4) {
for (i = 0; i < 4; i++)
char_array_4[i] = strchr(base64_chars, char_array_4[i]) - base64_chars;
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
output[r++] = char_array_3[i];
i = 0;
}
}
if (i) {
for (j = i; j <4; j++)
char_array_4[j] = 0;
for (j = 0; j <4; j++)
char_array_4[j] = strchr(base64_chars, char_array_4[j]) - base64_chars;
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++)
output[r++] = char_array_3[j];
}
*outlen = r;
return output;
}
二丶 魔改Base64 使用python解密
原理只需要把魔改的编码表进行一一映射转换回来即可.
import base64
a = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbn/+m1234567890"
b = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
base_fix = "ZXFWtmKgDZCyrmC5B+CiVfsyXUCQVfsyZRFzDU4yX2YCD/F5Ih8="
table = ''.maketrans(a, b)
print(base64.b64decode(base_fix.translate(table)))
坚持两字,简单,轻便,但是真正的执行起来确实需要很长很长时间.当你把坚持两字当做你要走的路,那么你总会成功. 想学习,有问题请加群.群号:725864912(收费)群名称: 逆向学习小分队 群里有大量学习资源. 以及定期直播答疑.有一个良好的学习氛围. 涉及到外挂反外挂病毒 司法取证加解密 驱动过保护 VT 等技术,期待你的进入。
详情请点击链接查看置顶博客 https://www.cnblogs.com/iBinary/p/7572603.html
本文来自博客园,作者:iBinary,未经允许禁止转载 转载前可联系本人.对于爬虫人员来说如果发现保留起诉权力.https://www.cnblogs.com/iBinary/p/14052616.html
欢迎大家关注我的微信公众号.不定期的更新文章.更新技术. 关注公众号后请大家养成 不白嫖的习惯.欢迎大家赞赏. 也希望在看完公众号文章之后 不忘 点击 收藏 转发 以及点击在看功能. QQ群: