BASE64编码原理分析脚本实现及逆向案例

BASE64编码原理分析脚本实现及逆向案例

0x01 简单介绍

数据传送时并不支持所有的字符,很多时候只支持可见字符的传送。但是数据传送不可能只传送可见字符为解决这个问题就诞生了base64编码。base64编码将所有待编码字符转换成64个可见字符表中的字符。

0x02 编码原理

被Base64编码之后所得到的所有字符都是在以下这个表当中的。

上表中总共有64个字符,2^6=64所以只需要6个bit位就足够描述所有的表中字符了。计算机中1个字节8个bit,一个ASCII码占1个字节。因此多出来的两位用0填充。比如我用00000110来表示表中数值为6的字符即G

计算机中1个字节8个bit,一个ASCII码占1个字节。因此多出来的两位用0填充。比如我用00000110来表示表中数值为6的字符即G

那么如何用上表中的字符来表达所有的字符呢?

Base64在编码时,首先将所有的待转换字符转成二进制的形式。

例如将”abc”转成110000111000101100011 之后在每个6位比特之前加上00也就是将3个8位字节转换成4个6位字节

由于base64编码是将3个8位字节变成4个6位字节因此最后所得到的字节数目一定是4的倍数。如果不是4的倍数要用=填充

我们从一个例子当中来具体体会一下转换过程

假设待转化的字符是 “example”

转化成二进制之后得到

01100101 01111000 01100001 01101101 01110000 01101100 01100101

example的长度是7因此为了使得最后得到的字符是4的倍数我们要再添上两个字符

01100101 01111000 01100001 01101101 01110000 01101100 01100101 00000000 00000000

然后我们将其按照6位1字符排好

011001 010111 100001 100001 011011 010111 000001 101100 011001 010000 000000 000000

填充00之后得到

00011001 00010111 00100001 00100001 00011011 00010111 00000001 00101100 00011001 00010000 00000000 00000000

再将这些二进制转换成十进制

25 23 33 33 27 23 1 44 25 16 0 0

对照表用字符替换之后得到

ZXhhbXBsZQAA

再将最后的AA换成==即可

ZXhhbXBsZQ==

放到python中解码验证一下

0x03 Python脚本实现

先附上代码

  1. def myBase64Encode(preCoding) :

  2.  

    charTable = ‘ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/‘ #字符表

  3.  

  4.  

    if len(preCoding) < 0 :

  5.  

    return ‘‘  #字符串为空则返回空

  6.  

    lackCharNums = 3-len(preCoding)%3

  7.  

    if lackCharNums == 3 : lackCharNums = 0 #整除说明不缺字符

  8.  

    #待转换字符不是3的倍数的情况补全它

  9.  

    for i in range(lackCharNums) :

  10.  

    preCoding = preCoding + b‘\x00‘

  11.  

    result = ‘‘ #用于保存最终结果的str数据

  12.  

    rp = ‘‘ #处理补全字符时的暂存变量

  13.  

    #每三个字符处理一轮

  14.  

    for i in range(int(len(preCoding)/3)) :

  15.  

    threeChar = preCoding[i*3:i*3+3] #取三个字符出来

  16.  

    tCode = ‘‘ #用于存放三个字符拼接后的二进制数值 文本形式

  17.  

    pCode = ‘‘ #暂存变量

  18.  

    for j in range(3) :

  19.  

    pCode = bin(threeChar[j])[2:]  #把省略的0补上

  20.  

    lackZeroNums = 8-len(pCode) #省略的0的个数

  21.  

    for x in range(lackZeroNums) :

  22.  

    pCode = ‘0‘+pCode

  23.  

    tCode = tCode + pCode

  24.  

    pCode = ‘‘

  25.  

    for j in range(4) : #每6位一个字符

  26.  

    pCode = tCode[j*6:j*6+6]

  27.  

    rp = rp + charTable[int(pCode,2)]

  28.  

    #处理补全的00字符

  29.  

    result = rp[:len(rp)-lackCharNums]

  30.  

    for j in range(lackCharNums) :

  31.  

    result = result + ‘=‘

  32.  

    return bytes(result,encoding="utf-8")

  33.  

  34.  

    def myBase64Decode(encodedBin) :

  35.  

    charTable = ‘ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/‘ #字符表

  36.  

  37.  

    #如果字符不是4的倍数 返回空

  38.  

    if not len(encodedBin)%4 == 0 :

  39.  

    return ‘‘

  40.  

  41.  

    tCode = ‘‘ #用于存放最终的二进制文本字符串

  42.  

    pCpde = ‘‘ #暂存变量

  43.  

    #遍历encodedBin每一个字符

  44.  

    for i in encodedBin :

  45.  

    for j in range(len(charTable)) : #找到表中对应坐标

  46.  

    if chr(i) == charTable[j] :

  47.  

    pCode = bin(j)[2:]  #转二进制去除开头的0b

  48.  

    lackZeroNums = 6-len(pCode) #省略的0的个数

  49.  

    for x in range(lackZeroNums) :

  50.  

    pCode = ‘0‘+pCode

  51.  

    tCode = tCode + pCode

  52.  

    pCode = ‘‘

  53.  

    result = ‘‘ #储存最终结果

  54.  

    for i in range(int(len(tCode)/8)) :

  55.  

    pCode = tCode[i*8:i*8+8]

  56.  

    result = result + chr(int(pCode,2))

  57.  

    return bytes(result,encoding="utf-8")

写的不是很好,仅供参考。这里的解码函数只支持ASCII,如果需要支持所有的字符,可以去了解一下UTF-8 UTF-16 unicode的关系

0x04 逆向案例分析

这是一道在Bugku上看到的逆向题。先来执行看看

提示输入flag。一般这种题目就要看算法了

在确认无壳之后用IDA打开分析

先打开strings窗口

找到right flag跳转


查看交叉引用

找到主要执行的部分

直接F5查看伪代码

注意到需要让Dest和Str2相同才会输出right flag

而Str2是已知的,那么就可以大概推测出需要将Str2进行某种逆运算才能知道flag

再往上看可以看到

将Dest每一位都进行了移位处理,再往前看关注到一个函数

跟进查看一下

为了方便理解我已经把一些变量名重命名。

其中input为我们输入的字符串,length为输入字符串的长度

可以看到v9首先将总长度除以3。然后在将v9*4 仔细分析之后会发现v10保存的值就是最后Dst变量的长度。这跟Base64编码前和编码后的长度关系是非常相似的。

v11变量保存了length的值作为循环的条件变量,然后将threeChar数组初始化。

在经过一个循环之后threeChar数组中存放了i个字符。

三个case分别为三种情况。case 3即i=3时,threeChar正好取了三个字符。

case 2即i=2时,threeChar只取了两个字符。case 1即i=1时,threeChar只取了一个字符。

我们先来分析case 3

首先将threeChar[0]字符右移2位,相当于只取这个字符的前6位并在6位前补上2个0。补全了之后转成了signed int也就变成了字符表中的位置。charTable就是Base64编码的字符表

同样的道理我们再往下看

由于刚刚threeChar[0]字符的前6位已经被取过,我们应该取threeChar[0]的后两位和threeChar[1]的前4位拼接成一个6位再补全0成8位。

这里首先将threeChar[1]与0xF0进行与运算。0xF0转成二进制是11110000,即只保留threeChar[1]的前4位后4位则置0。接着的右移操作将这4位数据移动到二进制的最低位。后边的threeChar[0]&3运算则是保留threeChar[0]的最后2位前边6位置0

看到这里就会发现和Base64编码的原理都对应上了。另外两种情况也都是类似的分析,只不过最后的时候加了一个补全=的代码

到此就可以写出解题脚本了

  1. import base64

  2.  

    a = ‘[email protected]@dH‘

  3.  

    b = []

  4.  

    for i in range(len(a)) :

  5.  

    b.append(chr(ord(a[i])-i))

  6.  

    print(base64.b64decode(‘‘.join(b)))

理解都比较初浅,如果有哪里讲得不对,希望各位大佬多多指点~

原文地址:https://www.cnblogs.com/ichunqiu/p/10038813.html

时间: 2024-10-26 04:09:28

BASE64编码原理分析脚本实现及逆向案例的相关文章

Base64编码原理分析

Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,在了解Base64编码之前,先了解几个基本概念:位.字节. 位:"位(bit)"是计算机中最小的数据单位.每一位的状态只能是0或1: 字节:8个二进制位构成1个"字节(Byte)",字节是存储空间的基本计量单位.1个字节可以储存1个英文字母,2个字节可以存储1个汉字: Base64编码的作用 因为有些网络传送渠道并不支持所有的字节,例如传统的邮件只支持可见字符的传送,像ASCII码的控制字符就不能通

Atitit.Base64编码原理与实现设计

Atitit.Base64编码原理与实现设计 1. Base64编码1 1.1. 为什么要用自己的base64编码方案1 2. Base64编码由来1 3. Base64编码原理1 3.1. 具体来说,转换方式可以分为四步:2 3.2. 注意2 3.3. Padding3 4. URL安全的Base64编码3 1. Base64编码 1.1. 为什么要用自己的base64编码方案 防止apache codec  jdk的jar冲突. 2. Base64编码由来 Base64最早是用来解决电子邮件

Base64 编码原理

1.编码表 2.原理[汉字不能base64编码] base64 编码就是将字符以3个为一组,因为一个字符由8个位组成,3*8=24位,然后以顺序以6个位拿出,前面补2位,凑成8位--一个字节 原字节不能被3整除的,在后面补 由8个0,构成的单字节,一般补1个或是2个(0000 0000),这些后面补的字节不能用base64编码对应,应该是异常字符,用“=”号替换, 所以,base64编码一般最后会有1~2个“=”号 示例: base64编码前:Lucy L u c yASCII: 76 117

Base64编码原理及应用

最近在做一个H5上传图片并压缩的项目,其过程主要是先将图片上传通过readAsDataURL获取上传图片base64编码,然后根据高宽比将图片画到canvas上实现压缩,在通过toDataURL获取压缩后的图片.点击可查看demo在该过程中用到base64编码,于是就想弄清楚base64编码原理,才有了这篇博客. Base64编码的来历 为什么会有Base64编码呢?因为有些网络传送渠道并不支持所有的字节,例如传统的邮件只支持可见字符的传送,像ASCII码的控制字符就不能通过邮件传送.这样用途就

一篇文章彻底弄懂Base64编码原理

在互联网中的每一刻,你可能都在享受着Base64带来的便捷,但对于Base64的基础原理又了解多少?今天这篇博文带领大家了解一下Base64的底层实现. Base64的由来 目前Base64已经成为网络上常见的传输8Bit字节代码的编码方式之一.在做支付系统时,系统之间的报文交互都需要使用Base64对明文进行转码,然后再进行签名或加密,之后再进行(或再次Base64)传输.那么,Base64到底起到什么作用呢? 在参数传输的过程中经常遇到的一种情况:使用全英文的没问题,但一旦涉及到中文就会出现

知识扩展——(转)一篇文章彻底弄懂Base64编码原理

在互联网中的每一刻,你可能都在享受着Base64带来的便捷,但对于Base64的基础原理又了解多少?今天这篇博文带领大家了解一下Base64的底层实现. 一.Base64的由来 目前Base64已经成为网络上常见的传输8Bit字节代码的编码方式之一.在做支付系统时,系统之间的报文交互都需要使用Base64对明文进行转码,然后再进行签名或加密,之后再进行(或再次Base64)传输.那么,Base64到底起到什么作用呢? 在参数传输的过程中经常遇到的一种情况:使用全英文的没问题,但一旦涉及到中文就会

Base64编码原理

转自: http://blog.chacuo.net/719.html Base64编码,是我们程序开发中经常使用到的编码方法.它是一种基于用64个可打印字符来表示二进制数据的表示方法.它通常用作存储.传输一些二进制数据编码方法!也是MIME(多用途互联网邮件扩展,主要用作电子邮件标准)中一种可打印字符表示二进制数据的常见编码方法!它其实只是定义用可打印字符传输内容一种方法,并不会产生新的字符集!有时候,我们学习转换的思路后,我们其实也可以结合自己的实际需要,构造一些自己接口定义编码方式.好了,

Base64编码原理与应用

本文内容转自网络,如需详细内容,请参考相关网址. http://my.oschina.net/goal/blog/201032 代码参考:http://blog.csdn.net/prsniper/article/details/7097643 Base64,它用作把任意序列的8位字节描述为一种不易被人直接识别的形式,常用作开发中用于传递参数.浏览器的img标签通过base64字符串来渲染图片以及电子邮件的正文编码等等. 在计算机中显示的字符,比如英文字母.数字以及英文标点符号就是用一个字节来存

BASE64编码原理与Golang代码调用

一.概念简介 Base64是一种基于64个可打印字符来表示二进制数据的表示方法.由于2^6=64,所以每6个比特为一个单元,对应某个可打印字符.3个字节有24个比特,对应于4个Base64单元,即3个字节可由4个可打印字符来表示.它可用来作为电子邮件的传输编码.在Base64中的可打印字符包括字母A-Z.a-z.数字0-9,这样共有62个字符,此外两个可打印符号在不同的系统中而不同. Base64常用于在通常处理文本数据的场合,表示.传输.存储一些二进制数据 二.代码调用 在Golang中提供了