首页
论坛
课程
招聘
[原创]IdaPro6.6安装程序密钥算法还原
2020-9-14 18:04 1172

[原创]IdaPro6.6安装程序密钥算法还原

2020-9-14 18:04
1172

ida是一款常用的静态分析工具,但是需要安装后才能使用,网上可以找到安装后的绿色版或者密钥进行安装,但是没有找到破解版安装包。作为逆向工程初级从业人员,业余分析该工具的密钥算法练练手是不错的选项,对于入门学习者,可以通过复现破解还原过程积累逆向工程经验(萌新第一次发帖,希望各位带佬嘴下留情)。

 

文章中所有的材料均存放于链接:https://pan.baidu.com/s/16bdMjrWxsP2KfA1MqzE3dQ

 

提取码:71tr

 

第一步:

 

多数安装包都可以通过压缩文件解压,因此首先尝试是否可以解压,选中安装包右键用压缩工具打开发现不能解压,说明该安装包必须在运行时解压内部文件。

 

图片描述

 

第二步:

 

将安装包拖入到od中进行调试,安装包程序正常运行,猜测可能未进行反调试操作。持续点击下一步直至输入密钥,随机输入密钥单机下一步,弹出密钥错误提示框。在弹窗函数下断点,仍然弹出窗口,如下图所示。

 

图片描述

 

此时保持安装包窗口状态,不要单击确定按钮,回到od,单击k进入堆栈调用窗口,发现程序并没有调用弹窗函数,且也没有调用窗口创建函数,猜测该安装程序并非单一进程。

 

图片描述

 

第三步:

 

未验证安装程序为多进程的猜想,使用od重新载入该安装程序,在creatfile函数处下断点,监控到进程往系统的临时文件夹创建了一个文件,如下图所示。

 

图片描述

 

为证明该文件即为安装子进程,给创建进程的函数下一个断点,如下图所示。

 

图片描述

 

od按下F8运行,此时出现安装程序。表明:主进程在系统临时文件夹创建一个临时安装进程,并将自身地址作为命令行参数启动,安装进程进行密钥检测并解压主进程进行安装。

 

第四步:

 

在了解程序的框架之后对安装程序进程密钥相关算法进行逆向还原,ida打开该文件,如下图所示。

 

图片描述

 

入口函数接口较为复杂,无法直接定位到算法函数,因此先使用od附加调试(调试时进入线程窗口激活所有线程)定位至算法函数再进行代码还原,如下图进行附加调试。

 

选中对应的进程
选中对应的进程
程序在弹窗函数断点
程序在弹窗函数断点
栈回溯找到调用源
栈回溯找到调用源

 

并在函数478FFC处发现疑似密钥计算函数(此处在条件跳转指令进行比较的内存处下内存写入断点可以定位,这里就不演示了),如下图所示。

 

图片描述

 

第五步:

 

对密钥校验算法进行还原,使用ida打开安装子进程文件,F5反编译,如下图所示:
图片描述
原始idb文件
图片描述
根据自己的理解和动态调试结果修改的idb文件

 

第六步:

 

还原idb文件为源代码,如下:

#include<stdio.h>
#include<Windows.h>


int GetSeedEnd(unsigned int a1)
{
    return (a1 >> 24) | ((a1 & 0xFF0000) >> 8) | ((unsigned __int16)(a1 & 0xFF00) << 8) | (a1 << 24);
}
int GetSeedFirst(unsigned char * a1, int a2, int a3)
{
    unsigned char * Local1 = a1;
    /*此处位运算无法根据idb还原*/
    a3 = a3 & 0xFFFF00FF;
    a3 |= ((a3 & 0xFF) << 8);
    /**/
    unsigned int Local3 = a3 << 16;
    /*此处位运算无法根据idb还原*/
    Local3 = Local3 & 0xFFFF0000;
    Local3 |= a3 & 0xFFFF;
    /**/
    int Local2 = a2 >> 2;
    if (a2 >> 2 >= 0)
    {
        memset(Local1, Local3, Local2);
        memset(&Local1[4 * Local2], Local3, a2 & 3);
    }
    return Local3;
}

unsigned int * CalculateSeedEnd(unsigned int * a1, unsigned int * a2, unsigned int * a3)
{
    unsigned int * Local1 = a1;
    unsigned int * Local2 = a2;
    unsigned int * Local3 = a3;

    unsigned int LocalFlag1[5] = { 0 };
    unsigned int * LocalFlag3 = Local3;
    unsigned int * LocalFlag4 = Local3 + 13;
    unsigned int * LocalFlag5 = Local3;
    int LocalFlag6;
    unsigned int * LocalFlag7 = Local3 + 20;
    unsigned int * LocalFlag8 = Local3 + 40;
    int LocalFlag9;
    int LocalFlag10;
    unsigned int * LocalFlag11 = Local3 + 40;
    int LocalFlag12;

    unsigned int * result;
    int count = 16;
    do
    {
        *LocalFlag3 = (*Local2 >> 24) | ((*Local2 & 0xFF0000u) >> 8) | ((*Local2 & 0xFF00) << 8) | (*Local2 << 24);
        ++LocalFlag3;
        ++Local2;
        --count;
    } while (count);

    count = 64;
    do
    {
        LocalFlag4[3] = ((*(LocalFlag4 - 13) ^ *(LocalFlag4 - 11) ^ (unsigned int)(*(LocalFlag4 - 5) ^ *LocalFlag4)) >> 31) | 2 * (*(LocalFlag4 - 13) ^ *(LocalFlag4 - 11) ^ *(LocalFlag4 - 5) ^ *LocalFlag4);
        ++LocalFlag4;
        --count;
    } while (count);

    LocalFlag1[0] = *Local1;
    LocalFlag1[1] = Local1[1];
    LocalFlag1[2] = Local1[2];
    LocalFlag1[3] = Local1[3];
    LocalFlag1[4] = Local1[4];

    count = 20;
    do
    {
        LocalFlag6 = *LocalFlag5
            + LocalFlag1[4]
            + (LocalFlag1[3] ^ LocalFlag1[1] & (LocalFlag1[3] ^ LocalFlag1[2]))
            + ((LocalFlag1[0] >> 27) | 32 * LocalFlag1[0])
            + 1518500249;
        LocalFlag1[4] = LocalFlag1[3];
        LocalFlag1[3] = LocalFlag1[2];
        LocalFlag1[2] = (LocalFlag1[1] >> 2) | (LocalFlag1[1] << 30);
        LocalFlag1[1] = LocalFlag1[0];
        LocalFlag1[0] = LocalFlag6;
        ++LocalFlag5;
        --count;
    } while (count);

    count = 20;
    LocalFlag7 = Local3 + 20;
    do
    {
        LocalFlag9 = *LocalFlag7
            + LocalFlag1[4]
            + (LocalFlag1[3] ^ LocalFlag1[1] ^ LocalFlag1[2])
            + ((LocalFlag1[0] >> 27) | 32 * LocalFlag1[0])
            + 1859775393;
        LocalFlag1[4] = LocalFlag1[3];
        LocalFlag1[3] = LocalFlag1[2];
        LocalFlag1[2] = (LocalFlag1[1] >> 2) | (LocalFlag1[1] << 30);
        LocalFlag1[1] = LocalFlag1[0];
        LocalFlag1[0] = LocalFlag9;
        ++LocalFlag7;
        --count;
    } while (count);
    count = 20;
    LocalFlag8 = Local3 + 40;
    do
    {
        LocalFlag10 = *LocalFlag8
            + LocalFlag1[4]
            + (LocalFlag1[3] & LocalFlag1[2] | LocalFlag1[1] & LocalFlag1[3] | LocalFlag1[1] & LocalFlag1[2])
            + ((LocalFlag1[0] >> 27) | 32 * LocalFlag1[0])
            - 1894007588;
        LocalFlag1[4] = LocalFlag1[3];
        LocalFlag1[3] = LocalFlag1[2];
        LocalFlag1[2] = (LocalFlag1[1] >> 2) | (LocalFlag1[1] << 30);
        LocalFlag1[1] = LocalFlag1[0];
        LocalFlag1[0] = LocalFlag10;
        ++LocalFlag8;
        --count;
    } while (count);

    count = 20;
    LocalFlag11 = Local3 + 60;
    do
    {
        LocalFlag12 = *LocalFlag11
            + LocalFlag1[4]
            + (LocalFlag1[3] ^ LocalFlag1[1] ^ LocalFlag1[2])
            + ((LocalFlag1[0] >> 27) | 32 * LocalFlag1[0])
            - 899497514;
        LocalFlag1[4] = LocalFlag1[3];
        LocalFlag1[3] = LocalFlag1[2];
        LocalFlag1[2] = (LocalFlag1[1] >> 2) | (LocalFlag1[1] << 30);
        LocalFlag1[1] = LocalFlag1[0];
        LocalFlag1[0] = LocalFlag12;
        ++LocalFlag11;
        --count;
    } while (count);
    *Local1 += LocalFlag12;
    Local1[1] += LocalFlag1[1];
    Local1[2] += LocalF
lag1[2];
    Local1[3] += LocalFlag1[3];
    result = Local1;
    result[4] += LocalFlag1[4];
    return result;
}

int CalculateSeedFirst(unsigned char * Seed, unsigned char * InitSeed, unsigned int Length)
{
    unsigned char * LocalFlag1 = Seed;
    unsigned char * LocalFlag2;
    unsigned char * LocalFlag3;
    int LocalFlag4;
    int LocalFlag5;
    BYTE * LocalFlag6;
    BYTE * LocalFlag7;
    int result = Length;
        /*此处指针比较代码存在漏洞,在建议直接走else分支/
    if ((signed int)InitSeed > (signed int)LocalFlag1)
    {
        LocalFlag2 = &LocalFlag1[Length - 4];
        LocalFlag3 = &InitSeed[Length - 4];
        LocalFlag4 = Length >> 2;
        if (LocalFlag4 >= 0)
        {
            while (LocalFlag4)
            {
                *(DWORD *)LocalFlag3 = *(DWORD *)LocalFlag2;
                LocalFlag2 -= 4;
                LocalFlag3 -= 4;
                --LocalFlag4;
            }
            LocalFlag5 = result & 3;
            LocalFlag6 = LocalFlag2 + 3;
            LocalFlag7 = LocalFlag3 + 3;
            while (LocalFlag5)
            {
                *LocalFlag7-- = *LocalFlag6--;
                --LocalFlag5;
            }
        }
    }else if (InitSeed != LocalFlag1)
    {
        int p = Length >> 2;
        if (p >= 0)
            memcpy(InitSeed, LocalFlag1, 4 * p + (result & 3));
    }
    return result;
}

int GetHashCode(unsigned int * HashCode, unsigned char * MyHashCode)
{
    unsigned int * LocalHashCode = HashCode;
    unsigned char * LocalMyHashCode = MyHashCode;
    unsigned int LocalFlag1 = HashCode[5] & 0x3F;
    BYTE * LocalFlag2 = (unsigned char *)LocalHashCode + LocalFlag1 + 28;
    *LocalFlag2 = 0x80;
    unsigned char * LocalFlag3 = LocalFlag2 + 1;
    int LocalFlag4 = 55 - LocalFlag1;
    int LocalFlag5 = 5;
    unsigned int * LocalFlag6 = LocalHashCode;

    if (LocalFlag4 < 0)
    {
        GetSeedFirst(LocalFlag3, LocalFlag4 + 8, 0);
        CalculateSeedEnd(LocalHashCode, LocalHashCode + 7, LocalHashCode + 23);
        LocalFlag3 = (unsigned char *)(LocalHashCode + 7);
        LocalFlag4 = 56;
    }
    GetSeedFirst(LocalFlag3, LocalFlag4, 0);
    LocalHashCode[22] = GetSeedEnd(8 * LocalHashCode[5]);
    LocalHashCode[21] = GetSeedEnd(LocalHashCode[5] >> 29);////check
    CalculateSeedEnd(LocalHashCode, LocalHashCode + 7, LocalHashCode + 23);
    do
    {
        *LocalFlag6 = GetSeedEnd(*LocalFlag6);
        ++LocalFlag6;
        --LocalFlag5;
    } while (LocalFlag5);
    CalculateSeedFirst((unsigned char *)LocalHashCode, LocalMyHashCode, 20);
    return GetSeedFirst((unsigned char *)LocalHashCode, 412, 0);
}



int CalculateHashCode(unsigned int * HashCode, unsigned char * Seed, unsigned int SeedLength)
{
    unsigned int LocalSeedLength = SeedLength;
    unsigned int * LocalHashCode = HashCode;
    unsigned char * LocalSeed = Seed;
    unsigned int LocalFlag1 = HashCode[5];
    unsigned int LocalFlag2;
    unsigned char * LocalSeedforCalculate;
    unsigned int i;
    LocalHashCode[5] += LocalSeedLength;
    if (HashCode[5] < LocalFlag1)
        ++HashCode[6];
    LocalFlag2 = 64 - (LocalFlag1 & 0x3F);
    if (LocalFlag2 > SeedLength)
        return CalculateSeedFirst(Seed, (unsigned char *)HashCode - LocalFlag2 + 92, SeedLength);
    CalculateSeedFirst(Seed, (unsigned char *)HashCode - LocalFlag2 + 92, LocalFlag2);
    CalculateSeedEnd(LocalHashCode, LocalHashCode + 7, LocalHashCode + 23);
    LocalSeedforCalculate = &LocalSeed[LocalFlag2];
    for (i = LocalSeedLength - LocalFlag2; i >= 0x40; i -= 64)
    {
        CalculateSeedFirst(LocalSeedforCalculate, (unsigned char *)LocalHashCode + 28, 64);
        CalculateSeedEnd(LocalHashCode, LocalHashCode + 7, LocalHashCode + 23);
        LocalSeedforCalculate += 64;
    }
    return CalculateSeedFirst(LocalSeedforCalculate, (unsigned char *)LocalHashCode + 28, i);
}

void *    InitHashCode(unsigned int *    InitHashCode)
{
    InitHashCode[0] = 0x67452301;
    InitHashCode[1] = 0xEFCDAB89;
    InitHashCode[2] = 0x98BADCFE;
    InitHashCode[3] = 0x10325476;
    InitHashCode[4] = 0xC3D2E1F0;
    InitHashCode[5] = 0;
    InitHashCode[6] = 0;

    return InitHashCode;
}

int GetValidPassword(unsigned char * Password)
{
    unsigned char * LocalPassword = Password;
    unsigned char * LocalSeed1 = (unsigned char *)"PasswordCheckHash";
    unsigned char LocalSeed2[8] = { 0x58 ,0x72 ,0x44 ,0xF1 ,0xB0 ,0x7B ,0x1B ,0x32};

    unsigned int LengthOfPassword = strlen((const char *)LocalPassword);
    unsigned int LocalInitHashCode[28] = { 0 };
    unsigned char MyHashCode[32] = { 0 };

    if (LengthOfPassword == 0)return 0;

    InitHashCode(LocalInitHashCode);
    CalculateHashCode(LocalInitHashCode, LocalSeed1, 0x11);
    CalculateHashCode(LocalInitHashCode, LocalSeed2, 0x8);
    CalculateHashCode(LocalInitHashCode, LocalPassword, LengthOfPassword);

    unsigned int * p = (unsigned int *)malloc(1024 * 4);
    memcpy(p, LocalInitHashCode, 28 * 4);
    GetHashCode(p, MyHashCode);//LocalInitHashCode作为具部变量容易堆栈崩溃
    free(p);
    return 1;
}

int main()
{
    char *    Password = "123456";
    GetValidPassword((unsigned char *)Password);//合法的hashcode为73 4D 89 77 37 77 82 3E 11 C1 E6 25 51 B3 D3 51 00 CF 9C C7
    return 0;
}

编译并于源程序比对测试,如下图所示:
图片描述
还原代码计算的hashcode
图片描述
安装子进程计算的hashcode

 

通过代码计算的hashcode与源程序计算的hashcode相同,算法还原成功(待完全待验证,欢迎补充)。合法hashcode为“73 4D 89 77 37 77 82 3E 11 C1 E6 25 51 B3 D3 51 00 CF 9C C7”,可通过计算碰撞还原合法密钥(欢迎尝试)。


《0day安全 软件漏洞分析技术(第二版)》第三次再版印刷预售开始!

收藏
点赞3
打赏
分享
最新回复 (5)
雪    币: 586
活跃值: 活跃值 (160)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
arab 活跃值 2020-9-14 22:48
2
1
少年,SHA1了解一下 
雪    币: 681
活跃值: 活跃值 (165)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lucktiger 活跃值 2020-9-15 08:31
3
0
学习一下。
雪    币: 1226
活跃值: 活跃值 (26)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zhuhelin1997 活跃值 2020-9-15 09:01
4
1
二楼说的对,密钥参考了sha1,但是不完全一样的呢
雪    币: 55
活跃值: 活跃值 (154)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
killpy 活跃值 2 2020-9-16 18:04
5
0
厉害
雪    币: 12103
活跃值: 活跃值 (118)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
FlashK 活跃值 2020-9-17 12:47
6
0
有进步。思路好。
游客
登录 | 注册 方可回帖
返回