CTF逆向之常见算法识别

在 CTF 题目中,有些算法出现的频率很高,记录一下常见算法的识别技巧

参考:《从0到1》

常见算法介绍

base64

base64 主要是将输入中的每 3 字节(共 24 比特)按每 6 比特分成一组,变成 4 个小于 64 的索引值,然后通过一个索引表得到 4 个可见字符。

索引表为一个 64 字节的字符串,如果在代码中发现引用了索引表"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",那么基本上就可以确定用了 base64,此外还有一些变种的 base64,主要是改变了索引表

TEA

TEA 是一种常见的分组加密算法,密钥为 128 比特位,吗,明文为 64 比特位,主要做了 32 轮变换,每轮变换中都涉及移位和变换。

识别方法为:TEA 算法中有一个固定的常数 0x9e3779b9 或者 0x61c88647

TEA 的源码如下:

void encrypt(uint32_t*v,unint32_t*k) {
    uint32_t v0 = v[0], v1 = v[1], sum = 0, i;
    uint32_t delta = 0x9e3779b9;
    uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
    for(i=0;i<32;i++) {
        sum += delta;
        v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
        v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
    }
    v[0] = v0;
    v[1] = v1;
}
void decrypt(uint32_t*v,unint32_t*k) {
    uint32_t v0 = v[0], v1 = v[1], sum = 0xC6EF3720, i;
    uint32_t delta = 0x9e3779b9;
    uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
    for(i=0;i<32;i++) {
        v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
        v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
        sum -= delta;
    }
    v[0] = v0;
    v[1] = v1;
}

AES

AES 也是常见的分组加密算法,AES 加解密流程如图所示:

其中,字节替代过程是通过 S 盒完成一个字节到另一个字节的映射。S 盒和逆 S 盒具体如下:

    0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
 0 63 7c 77 7b f2 6b 6f c5 30  1 67 2b fe d7 ab 76
 1 ca 82 c9 7d fa 59 47 f0 ad d4 a2 af 9c a4 72 c0
 2 b7 fd 93 26 36 3f f7 cc 34 a5 e5 f1 71 d8 31 15
 3  4 c7 23 c3 18 96  5 9a  7 12 80 e2 eb 27 b2 75
 4  9 83 2c 1a 1b 6e 5a a0 52 3b d6 b3 29 e3 2f 84
 5 53 d1  0 ed 20 fc b1 5b 6a cb be 39 4a 4c 58 cf
 6 d0 ef aa fb 43 4d 33 85 45 f9  2 7f 50 3c 9f a8
 7 51 a3 40 8f 92 9d 38 f5 bc b6 da 21 10 ff f3 d2
 8 cd  c 13 ec 5f 97 44 17 c4 a7 7e 3d 64 5d 19 73
 9 60 81 4f dc 22 2a 90 88 46 ee b8 14 de 5e  b db
 a e0 32 3a  a 49  6 24 5c c2 d3 ac 62 91 95 e4 79
 b e7 c8 37 6d 8d d5 4e a9 6c 56 f4 ea 65 7a ae  8
 c ba 78 25 2e 1c a6 b4 c6 e8 dd 74 1f 4b bd 8b 8a
 d 70 3e b5 66 48  3 f6  e 61 35 57 b9 86 c1 1d 9e
 e e1 f8 98 11 69 d9 8e 94 9b 1e 87 e9 ce 55 28 df
 f 8c a1 89  d bf e6 42 68 41 99 2d  f b0 54 bb 16
    0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
 0 52  9 6a d5 30 36 a5 38 bf 40 a3 9e 81 f3 d7 fb
 1 7c e3 39 82 9b 2f ff 87 34 8e 43 44 c4 de e9 cb
 2 54 7b 94 32 a6 c2 23 3d ee 4c 95  b 42 fa c3 4e
 3  8 2e a1 66 28 d9 24 b2 76 5b a2 49 6d 8b d1 25
 4 72 f8 f6 64 86 68 98 16 d4 a4 5c cc 5d 65 b6 92
 5 6c 70 48 50 fd ed b9 da 5e 15 46 57 a7 8d 9d 84
 6 90 d8 ab  0 8c bc d3  a f7 e4 58  5 b8 b3 45  6
 7 d0 2c 1e 8f ca 3f  f  2 c1 af bd  3  1 13 8a 6b
 8 3a 91 11 41 4f 67 dc ea 97 f2 cf ce f0 b4 e6 73
 9 96 ac 74 22 e7 ad 35 85 e2 f9 37 e8 1c 75 df 6e
 a 47 f1 1a 71 1d 29 c5 89 6f b7 62  e aa 18 be 1b
 b fc 56 3e 4b c6 d2 79 20 9a db c0 fe 78 cd 5a f4
 c 1f dd a8 33 88  7 c7 31 b1 12 10 59 27 80 ec 5f
 d 60 51 7f a9 19 b5 4a  d 2d e5 7a 9f 93 c9 9c ef
 e a0 e0 3b 4d ae 2a f5 b0 c8 eb bb 3c 83 53 99 61
 f 17 2b  4 7e ba 77 d6 26 e1 69 14 63 55 21  c 7d

如果发现程序中有 S 盒或者动态生成了 S 盒,那么就可以确定采用了 AES 加密

RC4

RC4 加密算法属于流加密算法,包括初始化函数和加解密函数,函数代码具体如下:

/*初始化函数*/
void rc4_init(unsigned char*s,unsigned char*key,unsigned long Len) {
    int i=0,j=0;
    //char k[256]={0};
    unsigned char tmp = 0;
    for(i=0;i<256;i++) {
        s[i]=i;
        k[i]=key[i%Len];
    }
    for(i=0;i<256;i++) {
        j=(j+s[i]+k[i])%256;
        tmp=s[i];
        s[i]=s[j];//交换s[i]和s[j]
        s[j]=tmp;
    }
}
/*加解密*/
void rc4_crypt(unsigned char*s,unsigned char*Data,unsigned Long Len) {
    int i=0,j=0,t=0;
    unsigned long k=0;
    unsigned long tmp;
    for(k=0;k<Len;k++){
        i=(i+1)%256;
        j=(j+s[i])%256;
        tmp=s[i];
        s[i]=s[j];//交换s[i]和s[j]
        s[j]=tmp;
        t=(s[i]+s[j])%256;
        Data[k]^=s[t];
    }
}

可以看出,初始化代码对字符数组 s 进行了初始化赋值,且赋值分别递增,之后又对 s 进行了 256 次变换操作。通过识别初始化代码,可以判断为 RC4 加密

MD5

MD5 消息摘要算法,是一种被广泛使用的密码散列函数,可以产生一个 128 位(16字节)的散列值,用于确保信息传输的完整性和一致性。MD5 加密的函数大致如下:

MD5_CTX md5c;
MD5Init(&md5c);
MD5UpdaterString(&md5c, plain);
MD5Final(digest,&md5c);

其中,MD5Init 会初始化四个称作 MD5 链接变量的整数参数。因此如果看到这四个常数 0x67452301、0xefcdab89、0x98badcfe、0x10325476,就可以怀疑该函数是否为 MD5 算法了

MD5Init 函数代码如下:

void MD5Init (MD5_CTX *context)
/*context*/
{
    context->count[0] = context->count[1] = 0;
    /* Load magic initialization constants. */
    context->state[0] = 0x67452301;
    context->state[1] = 0xefcdab89;
    context->state[2] = 0x98badcfe;
    context->state[3] = 0x10325476;
}

汇总

特征值识别

各算法运算过程中使用到的特征常量如下:

但是有时出题人会故意对这些常量进行修改,因此在利用这一手段做出判断后还需要通过动调等手段来对算法进行验证

特征运算识别

当特征值不足以识别出算法时,可以通过分析程序是否使用了某些特征运算来鉴别算法,常见算法的特征运算如下:

同理,也许经过动调或复现等手段确认才可下定论

posted @ 2021-07-13 09:17  Moominn  阅读(2540)  评论(0编辑  收藏  举报