• 010 Editor v8.0.1(32


    010 Editor 的逆向分析整体算下来还是比较简单的,将程序拖入OD,通过字符串搜索定位到核心代码,经过分析,主要是如下图所示的两个关键函数,返回正确的值,才算是注册成功。

    00409C9B 这个函数返回DB 才是正确的,看下面的关键跳转,这个很好判断。

    进入00409C9B 后发现该函数也调用了0040A826的函数,而且这个函数必须返回2D,00409C9B才能返回DB。

    所以主要分析0040A826函数让其返回2D就可以了。

    进入0040A826函数以后如下图所示

    这里有两个关键的函数需要详细的分析:

    00407644处函数:

    004083C8处函数:

    分析到这里,我们就可以根据以上分析出来的算法,定位k[3]、k[0]、k[6]、k[1]、k[7]、k[2]、k[5]的值(k[10]就是密码数组)

    k[3] = 9C 或 FC 或 AC(010Editor 是有3种注册码的 这里我们只分析k[3] = 9C的情况 这种情况其实密钥只有8位)

    AL = (k[0] ^ k[6] ^ 0x18 + 0x3D) ^ A7

    ESI = (0X100 * (k1 ^ k7 & 0xFF) + k2 ^ k5 & 0XFF) & 0XFFFF

    EAX = (((ESI ^ 0x7892) + 0x4d30) ^ 0x3421) & 0xffff

    下面是用c++写的小程序得到上面的值

     1 #include <stdio.h>
     2 #include <time.h>
     3 #include <windows.h>
     4 
     5 int main()
     6 {
     7     srand(time(NULL));
     8     byte K[10] = { 0x00, 0x11, 0x22, 0x9C, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 };
     9 
    10     while (true)
    11     {
    12         byte k0 = rand() % 0xFF;
    13         byte k6 = rand() % 0xFF;
    14         byte al = (k0 ^ k6 ^ 0X18 + 0X3D) ^ 0XA7;
    15         if (al >= 0)
    16         {
    17             K[0] = k0;
    18             K[6] = k6;
    19             break;
    20         }
    21     }
    22     // ESI = ((k[1] ^ k[7] & 0xFF) * 0x100 + k[2] ^ k[5] & 0xFF) & 0xFFFF
    23     // EAX = ((EAX ^ 0x7892 + 0x4D30) ^ 0x3421) & 0xFFFF / 0xB
    24     // 判断余数,如果余数不为零,返回零,如果余数为零,返回商
    25     while (true)
    26     {
    27         byte k1 = rand() % 0xFF;
    28         byte k7 = rand() % 0xFF;
    29         byte k2 = rand() % 0xFF;
    30         byte k5 = rand() % 0xFF;
    31 
    32         DWORD ESI = (0X100 * (k1 ^ k7 & 0xFF) + k2 ^ k5 & 0XFF) & 0XFFFF;
    33         DWORD EAX = (((ESI ^ 0x7892) + 0x4d30) ^ 0x3421) & 0xffff;
    34         if (EAX % 0XB == 0 && EAX/0XB <= 0x3E8)
    35         {
    36             K[1] = k1;
    37             K[7] = k7;
    38             K[2] = k2;
    39             K[5] = k5;
    40             break;
    41         }
    42     }
    43 
    44     printf("%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X
    ", K[0], K[1], K[2], K[3], K[4], K[5], K[6], K[7], K[8], K[9]);
    45     getchar();
    46     return 0;
    47 }

    上面程序算出来的值输入后,程序可以断在下面代码处,我们继续分析

    这里有个关键函数 00402E50,这个函数传入用户名字符串,返回一个类似哈希值的数据,然后跟密钥产生关系。

    我们的做法是直接将程序拖入到IDA,找到00402E50函数,直接F5反编译 ,然后把代码抠出来直接用。

    该函数里面有个数组,在OD里面找到这个地址,直接把数组抠出来也可以直接用的。

    下面就是完整的注册机代码。

    #include <stdio.h>
    #include <time.h>
    #include <windows.h>
    
    DWORD g_EcodeArray[] = 
    {
        0x39cb44b8, 0x23754f67, 0x5f017211, 0x3ebb24da, 0x351707c6, 0x63f9774b, 0x17827288, 0x0fe74821, 0x5b5f670f, 0x48315ae8, 0x785b7769, 0x2b7a1547, 0x38d11292, 0x42a11b32, 0x35332244, 0x77437b60,
        0x1eab3b10, 0x53810000, 0x1d0212ae, 0x6f0377a8, 0x43c03092, 0x2d3c0a8e, 0x62950cbf, 0x30f06ffa, 0x34f710e0, 0x28f417fb, 0x350d2f95, 0x5a361d5a, 0x15cc060b, 0x0afd13cc, 0x28603bcf, 0x3371066b,
        0x30cd14e4, 0x175d3a67, 0x6dd66a13, 0x2d3409f9, 0x581e7b82, 0x76526b99, 0x5c8d5188, 0x2c857971, 0x15f51fc0, 0x68cc0d11, 0x49f55e5c, 0x275e4364, 0x2d1e0dbc, 0x4cee7ce3, 0x32555840, 0x112e2e08,
        0x6978065a, 0x72921406, 0x314578e7, 0x175621b7, 0x40771dbf, 0x3fc238d6, 0x4a31128a, 0x2dad036e, 0x41a069d6, 0x25400192, 0x00dd4667, 0x6afc1f4f, 0x571040ce, 0x62fe66df, 0x41db4b3e, 0x3582231f,
        0x55f6079a, 0x1ca70644, 0x1b1643d2, 0x3f7228c9, 0x5f141070, 0x3e1474ab, 0x444b256e, 0x537050d9, 0x0f42094b, 0x2fd820e6, 0x778b2e5e, 0x71176d02, 0x7fea7a69, 0x5bb54628, 0x19ba6c71, 0x39763a99,
        0x178d54cd, 0x01246e88, 0x3313537e, 0x2b8e2d17, 0x2a3d10be, 0x59d10582, 0x37a163db, 0x30d6489a, 0x6a215c46, 0x0e1c7a76, 0x1fc760e7, 0x79b80c65, 0x27f459b4, 0x799a7326, 0x50ba1782, 0x2a116d5c,
        0x63866e1b, 0x3f920e3c, 0x55023490, 0x55b56089, 0x2c391fd1, 0x2f8035c2, 0x64fd2b7a, 0x4ce8759a, 0x518504f0, 0x799501a8, 0x3f5b2cad, 0x38e60160, 0x637641d8, 0x33352a42, 0x51a22c19, 0x085c5851,
        0x032917ab, 0x2b770ac7, 0x30ac77b3, 0x2bec1907, 0x035202d0, 0x0fa933d3, 0x61255df3, 0x22ad06bf, 0x58b86971, 0x5fca0de5, 0x700d6456, 0x56a973db, 0x5ab759fd, 0x330e0be2, 0x5b3c0ddd, 0x495d3c60,
        0x53bd59a6, 0x4c5e6d91, 0x49d9318d, 0x103d5079, 0x61ce42e3, 0x7ed5121d, 0x14e160ed, 0x212d4ef2, 0x270133f0, 0x62435a96, 0x1fa75e8b, 0x6f092fbe, 0x4a000d49, 0x57ae1c70, 0x004e2477, 0x561e7e72,
        0x468c0033, 0x5dcc2402, 0x78507ac6, 0x58af24c7, 0x0df62d34, 0x358a4708, 0x3cfb1e11, 0x2b71451c, 0x77a75295, 0x56890721, 0x0fef75f3, 0x120f24f1, 0x01990ae7, 0x339c4452, 0x27a15b8e, 0x0ba7276d,
        0x60dc1b7b, 0x4f4b7f82, 0x67db7007, 0x4f4a57d9, 0x621252e8, 0x20532cfc, 0x6a390306, 0x18800423, 0x19f3778a, 0x462316f0, 0x56ae0937, 0x43c2675c, 0x65ca45fd, 0x0d604ff2, 0x0bfd22cb, 0x3afe643b,
        0x3bf67fa6, 0x44623579, 0x184031f8, 0x32174f97, 0x4c6a092a, 0x5fb50261, 0x01650174, 0x33634af1, 0x712d18f4, 0x6e997169, 0x5dab7afe, 0x7c2b2ee8, 0x6edb75b4, 0x5f836fb6, 0x3c2a6dd6, 0x292d05c2,
        0x052244db, 0x149a5f4f, 0x5d486540, 0x331d15ea, 0x4f456920, 0x483a699f, 0x3b450f05, 0x3b207c6c, 0x749d70fe, 0x417461f6, 0x62b031f1, 0x2750577b, 0x29131533, 0x588c3808, 0x1aef3456, 0x0f3c00ec,
        0x7da74742, 0x4b797a6c, 0x5ebb3287, 0x786558b8, 0x00ed4ff2, 0x6269691e, 0x24a2255f, 0x62c11f7e, 0x2f8a7dcd, 0x643b17fe, 0x778318b8, 0x253b60fe, 0x34bb63a3, 0x5b03214f, 0x5f1571f4, 0x1a316e9f,
        0x7acf2704, 0x28896838, 0x18614677, 0x1bf569eb, 0x0ba85ec9, 0x6aca6b46, 0x1e43422a, 0x514d5f0e, 0x413e018c, 0x307626e9, 0x01ed1dfa, 0x49f46f5a, 0x461b642b, 0x7d7007f2, 0x13652657, 0x6b160bc5,
        0x65e04849, 0x1f526e1c, 0x5a0251b6, 0x2bd73f69, 0x2dbf7acd, 0x51e63e80, 0x5cf2670f, 0x21cd0a03, 0x5cff0261, 0x33ae061e, 0x3bb6345f, 0x5d814a75, 0x257b5df4, 0x0a5c2c5b, 0x16a45527, 0x16f23945 };
    
    
    int __cdecl EncodeUsername(const char *pszUserName, int a2, char a3, short a4)
    {
        const char *v4; // edx@1
        signed int v5; // esi@1
        signed int v6; // edi@1
        unsigned __int8 v7; // bl@2
        int v8; // eax@3
        int v9; // ecx@3
        int v10; // ecx@4
        int result; // eax@4
        int v12; // ecx@5
        unsigned __int8 v13; // [sp+8h] [bp-10h]@2
        unsigned __int8 v14; // [sp+Ch] [bp-Ch]@2
        unsigned __int8 v15; // [sp+10h] [bp-8h]@2
        int v16; // [sp+14h] [bp-4h]@1
    
        v4 = pszUserName;
        v16 = 0;
        v5 = strlen(pszUserName);
        v6 = 0;
        if (v5 <= 0)
        {
            result = 0;
        }
        else
        {
            v13 = 0;
            v14 = 0;
            v7 = 15 * a4;
            v15 = 17 * a3;
            do
            {
                v8 = toupper(v4[v6]);
                v9 = v16 + g_EcodeArray[v8];
                if (a2)
                {
                    v10 = g_EcodeArray[v7]
                        + g_EcodeArray[v15]
                        + g_EcodeArray[(unsigned __int8)(v8 + 47)] * (g_EcodeArray[(unsigned __int8)(v8 + 13)] ^ v9);
                    result = g_EcodeArray[v14] + v10;
                    v16 = g_EcodeArray[v14] + v10;
                }
                else
                {
                    v12 = g_EcodeArray[v7]
                        + g_EcodeArray[v15]
                        + g_EcodeArray[(unsigned __int8)(v8 + 23)] * (g_EcodeArray[(unsigned __int8)(v8 + 63)] ^ v9);
                    result = g_EcodeArray[v13] + v12;
                    v16 = g_EcodeArray[v13] + v12;
                }
                v14 += 19;
                ++v6;
                v15 += 9;
                v7 += 13;
                v13 += 7;
                v4 = pszUserName;
            } while (v6 < v5);
        }
        return result;
    }
    
    int main()
    {
        srand(time(NULL));
        byte K[10] = { 0x00, 0x11, 0x22, 0x9C, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99 };
        int dwRet = rand() % 0x3E8;
        // 用户名 加密
        char szName[100] = {0};
        printf("请输入用户名:");
        scanf_s("%s", szName, 100);
        DWORD dwKey = EncodeUsername(szName, 1, 0, dwRet);
        // cmp K[4], retValue & 0xFF
        // cmp K[5], retValue >> 8 & 0xFF
        // cmp K[6], retValue >> 16 & 0xFF
        // cmp K[7], retValue >> 24 & 0xFF
        K[4] = dwKey & 0xFF;
        K[5] = dwKey >> 8 & 0xFF;
        K[6] = dwKey >> 16 & 0xFF;
        K[7] = dwKey >> 24 & 0xFF;
    
        while (true)
        {
            byte k0 = rand() % 0xFF;
            byte k6 = K[6];
            byte al = (k0 ^ k6 ^ 0X18 + 0X3D) ^ 0XA7;
            if (al >= 9)
            {
                K[0] = k0;
                K[6] = k6;
                break;
            }
        }
        // ESI = ((k[1] ^ k[7] & 0xFF) * 0x100 + k[2] ^ k[5] & 0xFF) & 0xFFFF
        // EAX = ((EAX ^ 0x7892 + 0x4D30) ^ 0x3421) & 0xFFFF / 0xB
        // 判断余数,如果余数不为零,返回零,如果余数为零,返回商
        while (true)
        {
            byte k1 = rand() % 0xFF;
            byte k7 = K[7];
            byte k2 = rand() % 0xFF;
            byte k5 = K[5];
    
            DWORD ESI = (0X100 * (k1 ^ k7 & 0xFF) + k2 ^ k5 & 0XFF) & 0XFFFF;
            DWORD EAX = (((ESI ^ 0x7892) + 0x4d30) ^ 0x3421) & 0xffff;
            if (EAX % 0XB == 0 && EAX/0XB == dwRet)
            {
                K[1] = k1;
                K[7] = k7;
                K[2] = k2;
                K[5] = k5;
                break;
            }
        }
    
        printf("%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X
    ", K[0], K[1], K[2], K[3], K[4], K[5], K[6], K[7], K[8], K[9]);
        getchar();
        return 0;
    }

    文章写的比较粗糙,主要是把核心算法和代码写出来了,剩下的就比较简单了。大家有什么问题可以留言,互相交流。

  • 相关阅读:
    第一篇博文
    重拾javascript系列-JS声明详解之var
    重拾Javascript系列
    AtCoder DP Contest 26题
    DP题
    一众数论
    字符编码
    C# DateTime类型和sqlserver DateTime精度不同
    vs2015中的数据库架构对比工具(New Schema Comparison)
    SqlServer常用语句
  • 原文地址:https://www.cnblogs.com/duxie/p/9852670.html
Copyright © 2020-2023  润新知