首页
社区
课程
招聘
[原创]base64简单逆向分析(下)
2019-5-8 18:19 17859

[原创]base64简单逆向分析(下)

2019-5-8 18:19
17859

前言

上周大概介绍了一下base64的实现原理并且写了个简单的C语言来实现它,结尾举了个不恰当的例子,说将编码的table颠倒一下位置再加密网页就不能解密了,感谢@junkboy 老哥分享的:[解码工具](https://gchq.github.io/CyberChef/),该工具功能非常丰富,涵盖了当前主流算法的加解密,还可以选择base64的编码table进行解密。今天呢对base64的魔改进行一个逆向分析。

首先是站在有算法的角度

这个角度包括有源码或有程序可逆向,应用场景的话比如动态加密资源。或是ctf?(我不确定我瞎说的大佬轻喷) 用户输入一个字符串,然后加密判断是否和指定字符串加密得到的字符串相同。

首先对上个帖子编译出来的exe文件进行一个简单的逆向分析(传送门:https://bbs.pediy.com/thread-251117.htm)。将编译出的exe拖入到IDA中并查看字符串:
图片描述
可以很直接的看到编码的table为

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

然后查看main函数:
图片描述
逻辑非常清楚:先调用base64_encode进行加密,然后调用base64_decode进行解密。
查看加解密函数:
图片描述
这里逻辑和上篇帖子加密的逻辑一模一样,就不在重复。

x32dbg调试

使用x32dbg加载程序并在解密函数出下断点:
图片描述
F7跟进到函数:
图片描述
这里可以看到该函数传递进来的加密字符串是:R3V5,用于解密的编码table就是我们定义的table并且内存地址在404080,我们在下面的内存窗口中ctrl + g跳转到该地址:
图片描述
这里就是用于解密的编码table了。
选中该段内容,右键->二进制编辑->编辑:
图片描述
我们这里随便修改一下这个table的ASCII并保存:
图片描述
可以看到内存窗口中已经完成了修改:
图片描述
继续运行程序,得到输出结果:
图片描述
可以看到这里通过修改编码table已经影响了解密结果。
ps:做完这个操作之后发现好像没有什么用,只是说明一下base64加解密中我们可以操作编码table,然鹅实际中根本用不着。

小结

根据对base64加密算法的浅析,我们已经知道base64算法中,我们可控制的地方为编码table,所以大多数(也有可能是本人比较菜,见识不多)的base64魔改都可以通过修改编码table使其等同于加密时的编码table来还原,魔改base64一般有两种情况。

1. 直接定义新编码table
2. 动态生成新编码table

先来说说第一种,这种方法实现起来比较简单,只需要修改数组就可以。不过弊端是IDA字符串就可能直接暴露。
第二种实现起来稍微麻烦一点,破译难度也略高。接下来详细介绍第二种。

动态生成编码table

关于动态生成的话,我自己试验了两个比较简单的想法。

1. 将原始的编码table打乱并拆解为多个table,比如以六个字母为一组,将原始的编码table替换为十个小的table。
2. 使用代码对原始编码table进行处理,加密时使用新的编码table。

打乱并拆解原始table

将原始table拆分成六组并预定义六个变量
图片描述

 

然后改写加密算法,使其在索引不同的时候查找不同的table。
原始赋值代码为:

base64[j++] = base64char[(int)current];

改写后代码为:

         if((int)current<=10)
        {
            base64[j++] = table1[(int)current];
        }
        else if((int)current<=20)
        {
            base64[j++] = table2[(int)current-10];
        }
        else if((int)current<=30)
        {
            base64[j++] = table3[(int)current-20];
        }
        else if((int)current<=40)
        {
            base64[j++] = table4[(int)current-30];
        }
        else if((int)current<=58)
        {
            base64[j++] = table5[(int)current-40];
        }else{
            base64[j++] = table6[(int)current-58];
        }

删除解密算法和合并的编码table,运行程序如下:
图片描述

 

将该程序拖入到IDA中查看:
图片描述

 

这种情况下,我们可以通过阅读加密函数的源码,去找到对应的编码table,组合起来形成完整的编码table,最后去网上找一个base64的解码实现,然后替换原始table即可完成解密。

加密原始table

原始的编码table说白了就是一个长度为64,无重复字符的字符串,我们写一个加密函数对该字符串进行加密即可。
一个简单的变换:
首先将大写字母颠倒
然后将小写字母对应的转换为33到58的字符
将数字转为一部分小写
最后将两个特殊字符对应为大写字母

static int stringEncrypt(const uint8_t *data, char *enstr, int strlen)
{
    int count=5;
    for(int i=0;i<strlen;i++)
    {
        if(data[i]>=65 && data[i]<=90)
        {
            enstr[i] = 155-data[i];
        }
        if(data[i]>=97&&data[i]<=122)
        {
            enstr[i] = data[i]-64;
        }
        if(data[i]>=48&&data[i]<=57)
        {
            enstr[i] = data[i] + 50 ;
        }
        if(data[i]==43)
            enstr[i] = 121;
        if(data[i]==47)
            enstr[i] = 120;

    }
    return  1;
}

打印输出一下:
图片描述

 

同样的,删除解密函数之后编译并拖入到IDA
字符串表:
图片描述

 

调试器加载该程序,在解密函数处设置断点:
图片描述
F8运行函数之后,也可以得到真实的table
图片描述

 

如果再狠点,可以不使用变量接收处理过后的新table,每个字符加密的时候变换一次。
新定义一个加密单个字符的函数:

static char charEncrypt(int data)
{
        char *table = TABLE1;
        data = table[data];
        if(data>=65 && data<=90)
        {
            data = 155-data;
            return  (char)data;
        }
        if(data>=97&&data<=122)
        {
            data = data-64;
            return  (char)data;
        }
        if(data>=48&&data<=57)
        {
            data = data + 50 ;
            return  (char)data;
        }
        if(data==43)
        {
            data = 121;
            return  (char)data;
        }
        if(data==47)
            data = 120;
    return  (char)data;
}

该函数的功能是:对table中的单个字符进行加密。
参数是编码table的索引,返回值是加密后的编码table。
所以加密算法中的赋值方式也会发生改变:

base64[j++] = table1[(int)current];

直接变换为

 base64[j++] = charEncrypt((int)current);

运行程序:
图片描述

 

这样做的话就无法在内存中直接查看到变换的编码table,这种时候想要还原加密的字符串,要么就一直断点调试,要么就逆向charEncrypt的算法,将编码table跑出来。

无算法的角度

这种情况可能比较少见 比如某个字符串通过API接口得到一个加密的字符串。现在知道了原字符串和加密字符串,对算法进行一个逆向。

原字符串

base64encodetest

加密后

B-U:AGBbADg*"dI,$TE:$Z==

这种情况,先求原字符串正常加密的base64

YmFzZTY0ZW5jb2RldGVzdA==

通过比较可以得知:原本的大写Y(89)变换为了大写B(66)
m变换为了-
F变换为了U
z变换为了:
......

 

我这里对编码table的加密比较简单,大佬们应该一看就知道规律了。所以很容易得到变换的规律推出加密算法并重写。
所以我这种思路的命门在于:变化table时候的强度。

又没有算法,又没有原始字符串

这种情况怎么逆向

睡觉。

 

ps: 代码功底不深..写的较渣,论述过程中可能也不严谨有些许错误,希望大家多多包涵,也欢迎大佬们给点意见,我继续学习
图片描述


[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

最后于 2019-5-8 18:20 被jux1a编辑 ,原因:
收藏
点赞2
打赏
分享
最新回复 (11)
雪    币: 4709
活跃值: (1549)
能力值: ( LV2,RANK:15 )
在线值:
发帖
回帖
粉丝
如斯咩咩咩 2019-5-8 20:06
2
0
占楼,抢座
雪    币: 1725
活跃值: (27)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
vincen9931 2019-5-9 09:36
3
0
二楼也不错
雪    币: 1736
活跃值: (45)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sylingyy 2019-5-9 09:37
4
1
不知道想闹哪样,base64本身就不是为了安全存在的,叫编码解码比加密解密更合适。
雪    币: 1578
活跃值: (1280)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
网络枭红 2019-5-10 11:13
5
0
不懂,但好像很厉害的样子。只用过简单的 base64_encode、base64_decode 。不懂什么label。。。如果要用密钥加密。AES 岂不是更合适?
雪    币: 10014
活跃值: (2012)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
sjdkx 2019-5-11 17:15
6
0
base64不过是数值变换而已,也叫好意思叫加密?
雪    币: 1055
活跃值: (412)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
provence 2019-5-12 18:29
7
0
如斯咩咩咩 占楼,抢座
喵喵喵
雪    币: 1203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hare 2019-6-10 23:25
8
1
我想LZ的目的是为了让初学者更好的理解Base64,而不是像楼上几为表哥去讨论编解码和加解密.

这里感谢LZ让我对Base64有了更深的理解.
雪    币: 7601
活跃值: (1266)
能力值: ( LV12,RANK:256 )
在线值:
发帖
回帖
粉丝
丿feng 3 2019-7-20 20:01
9
0
base64本身就是一种编码手段吧,只要是base64理论上无论使用何种加密算法对table如何变换都是很容易解出来的
雪    币: 10845
活跃值: (1049)
能力值: (RANK:190 )
在线值:
发帖
回帖
粉丝
看场雪 3 2019-7-23 15:17
10
0
原则上讲,BASE64编码的目的,不是为了掩人耳目,而是为了传输和存储过程中的兼容性。
客观上它有一定的掩盖输入数据的效果。但要把它称作一种加密算法,有点勉强了。
专业事,找专业人。
要加密的话,去用真正的加密算法吧。

不过,LZ的文章确实让读者对BASE64有了更透彻的理解
雪    币: 951
活跃值: (6723)
能力值: (RANK:462 )
在线值:
发帖
回帖
粉丝
jux1a 8 2019-7-23 15:42
11
0
看场雪 原则上讲,BASE64编码的目的,不是为了掩人耳目,而是为了传输和存储过程中的兼容性。 客观上它有一定的掩盖输入数据的效果。但要把它称作一种加密算法,有点勉强了。 专业事,找专业人。 要加密的话 ...
首先感谢大佬肯定!
我之前表述有误,并不是想把base64当做一个加密算法来做研究。
只是在学习CTF的过程中发现有很多魔改base64 base32的题目,考虑到自己作为ctf新手遇到此类题目的一些坑,故分享一下自己的学习心得。
我非常尊敬密码学这门伟大的学科,自己也在不断努力学习中,清晰知道base64根本不能算是加密算法,希望之后能有机会分享一些真正实用的加密算法。
再次感谢大佬肯定和支持,小白会继续努力加油。

雪    币: 10014
活跃值: (2012)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
sjdkx 2019-7-23 21:24
12
0
base64只是个编码方法,谈不上·加密解密,不要把解码也说成解密。
游客
登录 | 注册 方可回帖
返回