很多题目ida伪代码是具有相当的辨识度的,RC4,base系列的大佬们基本上是一眼破的
所以想总结一个逆向常见的算法,还有原理和特征
base系列
base64的原理比较简单
一个字节有8位,这是计算机的编码方式
但是base64先构造了一张由64个可打印字符组成的表
把明文以6位一组的方式读入,因为2^6=64
所以每一组读入的数据在base64表中对应着一个密文
比如说读入一个3字节的数据就会返回4字节的密文
但是这种编码方式会在位数不是6的倍数的时候出现长度不齐的现象
所以在缺4位的时候会补上4个0,再在密文的末尾补上两个==
同理缺两位的情况下会补上2个0,在在密文的末尾补上一个=
其他base系列的加密方法都是类似的
这类加密方法具有的显著特征有:
1.密文后可能常见‘“=”
2.可能有base表存在,并且base表的长度为2^n
3.加密代码中常见移位取余之类的截取操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| #include <stdio.h> #include "string.h" #include "stdlib.h"
const char base[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; static char find_pos(char ch); char *base64_encode(const char* data, int data_len,int *len);
static char find_pos(char ch) { char *ptr = (char*)strrchr(base, ch); return (ptr - base); }
char *base64_encode(const char* data, int data_len,int *len) { int prepare = 0; int ret_len; *len=0; int temp = 0; char *ret = NULL; char *f = NULL; int tmp = 0; char changed[4]; int i = 0; ret_len = data_len / 3; temp = data_len % 3; if (temp > 0) { ret_len += 1; } ret_len = ret_len*4 + 1; ret = (char *)malloc(ret_len); if ( ret == NULL) { printf("No enough memory.n"); exit(0); } memset(ret, 0, ret_len); f = ret;
while (tmp < data_len) { temp = 0; prepare = 0; memset(changed, 0, 4); while (temp < 3) { if (tmp >= data_len) { break; } prepare = ((prepare << 8) | (data[tmp] & 0xFF)); tmp++; temp++; } prepare = (prepare<<((3-temp)*8)); for (i = 0; i < 4 ;i++ ) { if (temp < i) { changed[i] = 0x40; } else { changed[i] = (prepare>>((3-i)*6)) & 0x3F; } *f = base[ changed[ i ] ]; f++; (*len)++; } } strcpy(f,""); return ret; }
|
RC4
RC4是流密码的一种,所谓流密码就是逐字节加密的加密方式
RC4在电子领域是很常见的
RC4是需要接收密钥的
解密的时候也需要密钥
在CTF题目中密钥一般都会给出
当然也有可能需要爆破密钥,因为之前已经提到了,RC4是逐字节加密的,所以爆破不会很麻烦
加密过程比较多:
1.初始化状态向量s[256](一般都是256)
常见的就是是s[i]=i
2.输入密钥key[x]
在这里如果x<256的话会进行一个轮转操作,就是用key填满256位,被填满的数组就叫他k[256]
3.对状态向量s进行打乱
1 2 3 4 5
| j=0; for (int i=0;i<256;i++){ j=(j+s[i]+k[i]) % 256; swap(s[i],s[j]); }
|
这样处理完的话s基本上就被打乱了
4.最后就是密钥流的生成
假如说需要加密的明文长度(字节数)是lenth
那么加密轮数就是lenth
1 2 3 4 5 6 7 8 9 10
| i=0; j=0; while(lenth--){ i = (i + 1) % 256; j = (j + S[i]) % 256; swap(S[i] , S[j]); t = (S[i] + S[j])% 256; k = S[t]; }
|
假如说我们用k对每一位密文异或了
那么实际上密钥不变化的话我们再次输入密文得到的结果就是明文了,毕竟异或两次就回去了
但是如果我们用的是+ - *的操作,那样话可能要自己搓一个脚本跑一下了
如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !