游戏安全实验室 首页 技术入门 查看内容

 阅读目录

【技术入门】加密算法识别和变异加密算法处理

发布于:2017-10-12 14:39   |    99416次阅读 作者: 管理员    |   原作者: loudy

现代软件技术中,对软件本身加密保护以防止逆向分析,已经成为软件技术中不可或缺的一部分,这给逆向分析带来了很大的难度,促使逆向分析人员必须去了解常规加密算法思想。

在实际应用中,碰到简单的加密算法有BASE64(也许只能算编码而不算加密吧),稍难点的有DES、RC6等对称加密算法和MD5、CRC32等摘要算法,再难的就是RSA、ECC等非对称加密算法。分析过程中可以借助密码学综合工具。

这些成熟算法都有规律可循,分析起来不难,例如BASE64、DES、MD5等都可以在程序中找到常量表,根据常量表就可以推测算法(这里可以借助百度或者google的力量),找到关键点后再结合流程分析就很容易将算法分析清楚。当然,这些算法也可以先通过PEID的kanal插件简单识别。

 

公钥算法虽然没那么简单,但熟悉算法原理后也不难,比如RSA,弄清原理加识别大数运算基本没太大问题;比如ECC,弄清原理加上识别大数点运算也没有太大问题。公钥密码算法推荐以下工具,具体使用方法可以问百度和google,此处不细说。

当然,如果要真正理解这些加密算法,仅仅通过这些工具是肯定不够的,必须看懂源码,理解源码,甚至自己手动编码实现算法,接下来就知道为什么了。

 

其实,如果仅仅只是使用标准算法,那么用上文提供的工具辅助就可以分析清楚了,但很多时候我们会碰到变异后的密码学算法。如果此时你还是硬套模板,那么你会发现你的分析已经进入了一个死胡同。这时,我们必须结合加解密源码,一步步分析对比待逆向的程序,找到每一个不同点,然后修改源码,保持源码和程序的行为完全一致,才能确保逆向分析正确可靠。

 

例如,根据先期分析已经确定是base64编码(加密),但其编码常量已经由“ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/”改变成“OPWvYny#Nopz0$HI34QRSG@dJKq7fghD9Zi*kAB8rsFu56L&Ca^2tTUVEewxlm+/”,如下图。

另外还在基本base64上加了异或操作。

所以,必须修改base64源码如下,常量改变,加上异或,以保证源码运行结果和程序一致。

const char * base64char = "OPWvYny#Nopz0$HI34QRSG@dJKq7fghD9Zi*kAB8rsFu56L&Ca^2tTUVEewxlm+/";

 

char * base64_encode( const unsigned char * bindata, char * base64, int binlength )

{

    int i, j;

    unsigned char current;

unsigned char k;

 

    for ( i = 0, j = 0 ; i < binlength ; i += 3 )

    {

        current = (bindata[i] >> 2) ;

        current &= (unsigned char)0x3F;

for(k=0;k<64;k++)

{

unsigned h = k>>4;

h = k^h;

if(h == current)

{

current = k;

break;

}

}

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

 

        current = ( (unsigned char)(bindata[i] << 4 ) ) & ( (unsigned char)0x30 ) ;

 

        if ( i + 1 >= binlength )

        {

            for(k=0;k<64;k++)

{

unsigned h = k>>4;

h = k^h;

if(h == current)

{

current = k;

break;

}

}

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

            base64[j++] = '=';

            base64[j++] = '=';

            break;

        }

        current |= ( (unsigned char)(bindata[i+1] >> 4) ) & ( (unsigned char) 0x0F );

for(k=0;k<64;k++)

{

unsigned h = k>>4;

h = k^h;

if(h == current)

{

current = k;

break;

}

}

 

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

 

        current = ( (unsigned char)(bindata[i+1] << 2) ) & ( (unsigned char)0x3C ) ;

        if ( i + 2 >= binlength )

        {

            for(k=0;k<64;k++)

{

unsigned h = k>>4;

h = k^h;

if(h == current)

{

current = k;

break;

}

}

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

            base64[j++] = '=';

            break;

        }

        current |= ( (unsigned char)(bindata[i+2] >> 6) ) & ( (unsigned char) 0x03 );

for(k=0;k<64;k++)

{

unsigned h = k>>4;

h = k^h;

if(h == current)

{

current = k;

break;

}

}

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

 

        current = ( (unsigned char)bindata[i+2] ) & ( (unsigned char)0x3F ) ;

for(k=0;k<64;k++)

{

unsigned h = k>>4;

h = k^h;

if(h == current)

{

current = k;

break;

}

}

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

    }

    base64[j] = '\0';

    return base64;

}

 

int base64_decode( const char * base64, unsigned char * bindata )

{

    int i, j;

    unsigned char k;

    unsigned char temp[4];

    for ( i = 0, j = 0; base64[i] != '\0' ; i += 4 )

    {

        memset( temp, 0xFF, sizeof(temp) );

        for ( k = 0 ; k < 64 ; k ++ )

        {

            if ( base64char[k] == base64[i] )

                temp[0]= k ^ (k>>4);

        }

        for ( k = 0 ; k < 64 ; k ++ )

        {

            if ( base64char[k] == base64[i+1] )

                temp[1]= k ^ (k>>4);

        }

        for ( k = 0 ; k < 64 ; k ++ )

        {

            if ( base64char[k] == base64[i+2] )

                temp[2]= k ^ (k>>4);

        }

        for ( k = 0 ; k < 64 ; k ++ )

        {

            if ( base64char[k] == base64[i+3] )

                temp[3]= k ^ (k>>4);

        }

 

        bindata[j++] = ((unsigned char)(((unsigned char)(temp[0] << 2))&0xFC)) |

                ((unsigned char)((unsigned char)(temp[1]>>4)&0x03));

        if ( base64[i+2] == '=' )

            break;

 

        bindata[j++] = ((unsigned char)(((unsigned char)(temp[1] << 4))&0xF0)) |

                ((unsigned char)((unsigned char)(temp[2]>>2)&0x0F));

        if ( base64[i+3] == '=' )

            break;

 

        bindata[j++] = ((unsigned char)(((unsigned char)(temp[2] << 6))&0xF0)) |

                ((unsigned char)(temp[3]&0x3F));

    }

    return j;

}

 

再如,通过百度搜索常量,发现了DES的置换表,再通过流程初步分析确定是使用了DES算法,但源码运行结果和程序(DES部分)运行结果不一致,考虑为DES变异算法。深入分析,发现4点不一致。

 

不同点1 ByteToBit该函数如下和标准DES有差异,其中已经注释。

故,修改标准DES中对应函数如下

不同点2 子秘钥使用顺序,该函数中,输入与子秘钥的异或操作从最后一个开始依次往前,而标准DES从第一个开始依次往后。

故修改标准DES加密操作中对应位置如下

相对的,修改解密操作代码

不同点3 ByteToBit1,也和标准DES不一致。

 

故修改标准DES中代码如下

不同点4 调整R、L顺序调试发现,最后的R和L顺序反了,故修改代码。在加密操作最后和解密操作最前均加上如下代码。

经过这四处修改后的DES算法加密结果和该函数一致,且能正常解密,证明逆向分析结果是正确的,可以进行下一步操作。


来源:loudy-投稿

*转载请注明来自游戏安全实验室(GSLAB.QQ.COM)

分享到:
踩0 赞1

收藏

上一篇:【技术入门】LuaJIT分析技巧

下一篇:【技术入门】Android平台下静态插入ShellCode实现ELF的注入

最新评论
B Color Image Link Quote Code Smilies

发表评论