首页
社区
课程
招聘
[原创]第八题 惊天阴谋 by k1ee
2020-12-7 20:46 5543

[原创]第八题 惊天阴谋 by k1ee

2020-12-7 20:46
5543

惊天阴谋

去花,修复各种干扰后,取得程序逻辑如下

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
const char* username = "141E8F96636898EF";
const char* serial = "dd8c5dd5bff047cb86c51fc808254c0950ebd2d9c7e6b34679a6cda7f96ea0f46d105248c68b6534546d34c26534546d34c26534542538d289a28b2d14d06534546614d225146289a28b6614d249a7096d10522538d22538d289a28b48a21b2d14d041a69b2d14d06614d289a28b25146250a28948a21b48c68b48c68b49829948a21b6d105249a7092c345289a28b6534542c34522d14d050a2896d105225146289a28b6d105249a7092d14d049a7096d34c26d10522d14d049a70948a21b2d14d048c68b48a21b49a70925146248c68b41a69b08a69948c68b48c68b498299";
 
uint8_t username_md5[16] = { 0 };
md5((uint8_t*)username, strlen(username), username_md5);
uint8_t username_md5_1[16] = { 0 };
md5(username_md5, 8, username_md5_1);
uint8_t username_md5_2[16] = { 0 };
md5(username_md5 + 8, 8, username_md5_2);
 
uint8_t serial_hex[224] = { 0 };
char* sp = (char*)serial;
for (int i = 0; i < 224; ++i)
{
    sscanf_s(sp, "%2hhx", &serial_hex[i]);
    sp += 2;
}
uint8_t* serial_1 = serial_hex;
uint8_t* serial_2 = serial_hex + 32;
 
uint8_t result1_1[32] = { 0 };
uint32_t* pi = (uint32_t*)serial_1;
uint32_t* po = (uint32_t*)result1_1;
for (int i = 0; i < 8; ++i)
{
    *po++ = transform1_1(*pi++);
}
 
uint8_t result1_2[32] = { 0 };
memcpy(result1_2, result1_1, 32);
HCRYPTPROV ctx;
CryptAcquireContextA(&ctx, 0, 0, 24, 0xF0000000);
HCRYPTHASH hash;
CryptCreateHash(ctx, 0x800C, 0, 0, &hash);
unsigned char hashData[20] = { 0x31, 0x5F, 0x4C, 0x30, 0x56, 0x33, 0x5F, 0x42, 0x58, 0x53, 0x5F, 0x46, 0x30, 0x52, 0x45, 0x56, 0x45, 0x52, 0x21, 0x00 };
CryptHashData(hash, hashData, 19, 0);
HCRYPTKEY key;
CryptDeriveKey(ctx, 0x6610, hash, 0, &key);
DWORD len = 32;
CryptEncrypt(key, 0, 0, 0, result1_2, &len, 32);
 
uint8_t result1_2_trans[16] = { 0 };
for (int i = 0; i < 16; ++i)
{
    result1_2_trans[i] = result1_2[2 * i];
}
 
transform1_2(result1_2_trans);
 
//Equals MD5 Part1
 
uint8_t result2_1[32] = { 0 };
transform2_1(serial_2, result2_1);
 
uint8_t result2_2[16] = { 0 };
transform2_2(result2_1, result2_2);
 
transform2_3(result2_2, username_md5_2);

注册码分为两部分

1.3

魔改的AES,动调取得sbox,手算rsbox,解密。

1
2
3
4
5
6
7
8
9
10
11
12
AES_ctx actx;
int akey[8] = { 0 };
akey[0] = 0x59206F57;
akey[1] = 0x59676E6F;
akey[2] = 0x206E6175;
akey[3] = 0x75486958;
akey[4] = 0x4B206E61;
akey[5] = 0x75586E61;
akey[6] = 0x754C206E;
akey[7] = 0x6E61546E;
AES_init_ctx(&actx, (uint8_t*)akey);
AES_ECB_decrypt(&actx, username_md5_1);

每一位+0x7F得到第二位

1
2
3
4
5
6
uint8_t part1_1[32] = { 0 };
for (int i = 0; i < 16; ++i)
{
    part1_1[i * 2] = username_md5_1[i];
    part1_1[i * 2 + 1] = username_md5_1[i] + 0x7F;
}

1.2

调用API进行解密即可

1
2
3
4
5
6
7
8
9
10
HCRYPTPROV ctx;
CryptAcquireContextA(&ctx, 0, 0, 24, 0xF0000000);
HCRYPTHASH hash;
CryptCreateHash(ctx, 0x800C, 0, 0, &hash);
unsigned char hashData[20] = { 0x31, 0x5F, 0x4C, 0x30, 0x56, 0x33, 0x5F, 0x42, 0x58, 0x53, 0x5F, 0x46, 0x30, 0x52, 0x45, 0x56, 0x45, 0x52, 0x21, 0x00 };
CryptHashData(hash, hashData, 19, 0);
HCRYPTKEY key;
CryptDeriveKey(ctx, 0x6610, hash, 0, &key);
DWORD len = 32;
CryptDecrypt(key, 0, 0, 0, part1_1, &len);

1.1

六种运算的虚拟机,把所有指令打出来,然后分析可以看出有很多重复的部分,懒得写程序提炼,于是手动提炼了一部分,12万行缩小到1.2万行,编译爆破程序求解,16线程106分钟解得所有逆向关系

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
uint32_t* ansbuf = new uint32_t[0x10000000];
for (int i = 0; i < 16; ++i)
{
    uint32_t val = i * 0x10000000;
    char filename[128] = { 0 };
    sprintf_s(filename, "E:/Ctf/KCTF2020Q4/KCTF-KeyME/Solver/Solver/Release/%08X_%08X.bin", val, val + 0xFFFFFFF);
    FILE* fp;
    fopen_s(&fp, filename, "rb"); 
    int ret = fread(ansbuf, 4, 0x10000000, fp);
    fclose(fp);
    for (int k = 0; k < 0x10000000; ++k)
    {
        uint32_t input = val++;
        uint32_t output = ansbuf[k];
        for (int t = 0; t < 8; ++t)
        {
            if (pi[t] == output)
            {
                po[t] = input;
                //pos[t].push_back(input);
            }
        }
    }
}
delete[] ansbuf;
 
printf("Serial Part 1\n");
for (int i = 0; i < 32; ++i)
{
    printf("%02x", part1_2[i]);
}
1
83bde72e2806ce3c8f424e242559a66314bb37008d62a69bfd1a960f8e4102c8

2.3

一个可逆算法,直接算出输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int buf1[8] = { 0x18111C1A, 0x1190C08, 0x10070B20, 0x151D0217, 0x12161B14, 0xA1E05, 0xD130309, 0x1F0E0604 };
int buf2[8] = { 0x14161715, 0x12040C13, 0xE100603, 0xF1C180A, 0x50B001F, 0x200D1A08, 0x9111D1E, 0x1B010219 };
int buf3[8] = { 0x11ECEE03, 0xC050E14, 0x5F7ED03, 0xE700F600, 0xBEFE800, 0xFF0403F5, 0xF4061600, 0xF90918EF }; 
uint8_t* p1 = (uint8_t*)buf1;
uint8_t* p2 = (uint8_t*)buf2;
uint8_t* p3 = (uint8_t*)buf3;
 
uint8_t target_m[16] = { 0x15, 0x09, 0x0c, 0x1f, 0x1c, 0x13, 0x16, 0x19, 0x1d, 0x03, 0x10, 0x0f, 0x01, 0x02, 0x1e, 0x06 };
 
for (int i = 0; i < 16; ++i)
    uint8_t mid = target_m[i] - p3[i] + md5c[i];
    cal[i] = __ROL__(mid, p1[i] & 7) ^ p2[i];
}

2.2

最令人头痛的算法,我记录了所有和输入有关的运算,发现还是可逆的,也就三处需要记录

 

image-20201207204140227

 

image-20201207204152042

 

每一处输入输出关系也就65423个,因此爆破即可,从后往前还原数据

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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
uint16_t r2_r1(uint64_t res, uint64_t v3, uint64_t v2)
{
    std::vector<int> ret;
    for (int i = 65422; i >= 0; --i)
    {
        if (res == (i * (v3 * v3 % 65423 * v2 % 65423) % 65423))
        {
            ret.push_back(i);
        }
    }
    if (ret.size() != 1)
    {
        _CrtDbgBreak();
    }
    return ret[0];
}
 
uint16_t r2_r2(uint64_t res, uint64_t val, uint64_t bp)
{
    std::vector<int> ret;
    for (int i = 65422; i >= 0; --i)
    {
        uint64_t r = ((int64_t)(i - val * bp) % 65423 + 65423) % 65423;
        if (res == r)
        {
            ret.push_back(i);
        }
    }
    if (ret.size() != 1)
    {
        _CrtDbgBreak();
    }
    return ret[0];
}
 
uint16_t r2_r3(uint64_t res, uint64_t v1, uint64_t v2, uint64_t v3)
{
    std::vector<int> ret;
    for (int i = 65422; i >= 0; --i)
    {
        uint64_t r = ((int64_t)(i * v1 - v2 * v3) % 65423 + 65423) % 65423;
        if (res == r)
        {
            ret.push_back(i);
        }
    }
    if (ret.size() != 1)
    {
        _CrtDbgBreak();
    }
    return ret[0];
}
 
struct re2_op
{
    int bufptr_res;
    int bufptr_another;
    uint64_t mul_val1;
    uint64_t min_val3;
};
 
void reverse2_2(uint16_t* input, uint8_t* output)
{
    uint8_t buf1[0x370 * 16] = { 0 };
    int64_t* b1ptr1 = (int64_t*)buf1;
    int32_t* t1ptr = (int32_t*)table_trans2;
    for (int i = 0; i < 16; ++i)
    {
        int64_t val1 = *t1ptr++;
        for (int k = 15; k >= 0; --k)
        {
            int64_t val2 = 0;
            if (k > 0)
            {
                int64_t val3 = transform2_calc1(val1, k >> 1);
                val2 = val3 * val3 % 65423;
                if (k & 1)
                    val2 = val2 * val1 % 65423;
            }
            else
            {
                val2 = 1;
            }
            *b1ptr1++ = val2;
        }
        b1ptr1 = (int64_t*)(buf1 + 0x370 * (i + 1));
    }
 
    for (int i = 0; i < 16; ++i)
    {
        uint64_t* b1ptr2 = (uint64_t*)(buf1 + 0x80 + i * 0x370);
        *b1ptr2 = 0xDEAD;
    }
 
    std::vector<re2_op> ops;
    uint64_t* b1ptr3 = (uint64_t*)buf1;
    for (int i = 1; i <= 15; ++i)
    {
        uint64_t* b1ptr7 = (uint64_t*)(buf1 + 0x370 * i + 8 * (i - 1));
        for (int a1 = 16 - i; a1 >= 1; --a1)
        {
            uint64_t val3 = *b1ptr7;
            uint64_t* b1ptr8 = b1ptr3;
            uint64_t* b1ptr9 = b1ptr7;
            for (int a2 = 18 - i; a2 >= 1; --a2)
            {
                uintptr_t diff3 = ((uintptr_t)b1ptr3 - (uintptr_t)buf1);
                uintptr_t diff7 = ((uintptr_t)b1ptr7 - (uintptr_t)buf1);
                uintptr_t diff8 = ((uintptr_t)b1ptr8 - (uintptr_t)buf1);
                uintptr_t diff9 = ((uintptr_t)b1ptr9 - (uintptr_t)buf1);
 
                if (diff9 % 0x370 == 0x80)
                {
                    re2_op op;
                    op.bufptr_res = diff9 / 0x370;
                    op.bufptr_another = diff8 / 0x370;
                    op.mul_val1 = *b1ptr3;
                    op.min_val3 = val3;
                    ops.push_back(op);
                }
 
                *b1ptr9++ = ((int64_t)(*b1ptr9 * *b1ptr3 - val3 * *b1ptr8++) % 65423 + 65423) % 65423;
            }
            b1ptr7 += 110;
        }
        b1ptr3 += 111;
    }
 
    uint16_t* op = (uint16_t*)output;
    uint64_t bufrec_1[16] = { 0 };
    int64_t* b1p2 = (int64_t*)buf1;
    for (int k = 0; k < 16; ++k)
    {
        int64_t v2 = *b1p2;
        int64_t v3 = transform2_calc1(*b1p2, 0x7FC6);
 
        uint16_t ret = r2_r1(input[k], v3, v2);
 
        for (int t = 15; t > k; --t)
        {
            ret = r2_r2(ret, input[t], *(uint64_t*)(buf1 + k * 0x370 + t * 8));
        }
 
        bufrec_1[k] = ret;
        b1p2 += 111;
    }
 
    for (int i = ops.size() - 1; i >= 0; --i)
    {
        re2_op op = ops[i];
        bufrec_1[op.bufptr_res] = r2_r3(bufrec_1[op.bufptr_res], op.mul_val1, op.min_val3, bufrec_1[op.bufptr_another]);
    }
 
    for (int i = 0; i < 16; ++i)
    {
        op[i] = bufrec_1[i];
    }
}

2.1

似乎是个矩阵,不过当时太累了,爆破也不是很难

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
82
83
84
85
86
bool reverse2_1(uint8_t* input, uint8_t* output)
{
    uint8_t buf[0x200] = { 0 };
    int8_t* kptr = (int8_t*)&buf[511];
    int* tptr = (int*)table_check2;
    uint8_t* iptr = input + 7;
    for (int i = 0; i < 8; ++i)
    {
        for (int p = 0; p < 8; ++p)
        {
            bool solved = false;
            int8_t sb_solved[8] = { 0 };
            const int smax = 4;
            for (int s1 = -4; s1 <= smax; s1 += 2)
            {
                for (int s2 = -4; s2 <= smax; s2 += 2)
                {
                    for (int s3 = -4; s3 <= smax; s3 += 2)
                    {
                        for (int s4 = -4; s4 <= smax; s4 += 2)
                        {
                            for (int s5 = -4; s5 <= smax; s5 += 2)
                            {
                                for (int s6 = -4; s6 <= smax; s6 += 2)
                                {
                                    for (int s7 = -4; s7 <= smax; s7 += 2)
                                    {
                                        for (int s8 = -4; s8 <= smax; s8 += 2)
                                        {
                                            int8_t sb[8] = { s1, s2, s3, s4, s5, s6, s7, s8 };
                                            int a1 = ((iptr[0] >> p) & 1) == 1 ? 8 : -8;
                                            int a2 = ((iptr[8] >> p) & 1) == 1 ? 8 : -8;
                                            int a3 = ((iptr[16] >> p) & 1) == 1 ? 8 : -8;
                                            int a4 = ((iptr[24] >> p) & 1) == 1 ? 8 : -8;
                                            for (int k = 7; k >= 0; --k)
                                            {
                                                int c = sb[k];
                                                a1 -= c * tptr[24 + k];
                                                a2 -= c * tptr[16 + k];
                                                a3 -= c * tptr[8 + k];
                                                a4 -= c * tptr[k];
                                            }
                                            if (a1 == 0 && a2 == 0 && a3 == 0 && a4 == 0)
                                            {
                                                solved = true;
                                                memcpy(sb_solved, sb, 8);
                                                goto solved;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        solved:
            if (!solved)
                return false;
            for (int k = 7; k >= 0; --k)
            {
                *kptr-- = sb_solved[k];
            }
        }
        iptr--;
    }
 
    uint8_t* optr = output;
    int8_t* bptr = (int8_t*)buf;
    for (int i = 0; i < 64; ++i)
    {
        for (int k = 0; k < 8; ++k)
        {
            bptr[k] /= 2;
            bptr[k] += 2;
        }
 
        optr[0] = (bptr[0] << 5) | (bptr[1] << 2) | (bptr[2] >> 1);
        optr[1] = (bptr[2] << 7) | (bptr[3] << 4) | (bptr[4] << 1) | (bptr[5] >> 2);
        optr[2] = (bptr[5] << 6) | (bptr[6] << 3) | (bptr[7]);
 
        optr += 3;
        bptr += 8;
    }
    return true;
}

此题应该多解,我没求出预期解

结束

1
83bde72e2806ce3c8f424e242559a66314bb37008d62a69bfd1a960f8e4102c81001040041040241004a20844a20840201040200000201040241001241041200040040000208041200040008000241001001040200000208040000041001040001244a20840041041001040201040208044a20840200000041040200004a20844a20840208040000040001240041040041040001240241000009040208040040000009040208040240044a20840000040240040009040041040201041200041001041200040241000041041200040008000208044a2084100104020804000100

杂记

https://docs.microsoft.com/en-us/windows/win32/debug/pe-format

 

image-20201204150243977

 

实际上是从KernelBase和advapi32里找函数

 

image-20201204151820844


[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
点赞1
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回