View difference between Paste ID: x6qxstgx and yVhWeQ3X
SHOW: | | - or go back to the newest paste.
1-
/*
1+
/**
2
 * Source: https://stackoverflow.com/questions/17946282/whats-the-hash-in-hkcu-software-microsoft-windows-currentversion-explorer-filee
3
 * 
4
 * AssocHashGen - now you can set default browser in one click, just like on XP
5
 *
6
 * This is a crappy proof of concept tool to generate User Association hashes
7
 * in Windows 10 and 8.1.
8
 *
9
 * This should be all that's needed to solve the association problems that
10
 * Mozilla and Google have been complaining about. If microsoft still claims
11
 * this is a "security" measure and not just anti-competitive nonsense, it
12
 * defeats that "security" too.
13
 *
14
 * http://www.theverge.com/2015/7/30/9076445/mozilla-microsoft-windows-10-browser-default-apps-complaint
15
 * http://www.theverge.com/2015/10/18/9563927/microsoft-windows-10-default-apps-browser-prompt
16
 *
17
 * Technical details:
18
 * User choice hashes are pretty much just
19
 * MD5((protocol + sid + progid + exepath).toLower()) passed through some
20
 * custom scrambling functions. Dead simple. Not sure why no one else beat me
21
 * to it yet.
22
 *
23
 * Using Qt because I had it around and they have MD5 built in as well as
24
 * nice string manipulation functions.
25
 *
26
 * Sample Usage:
27
 * For URLs of http and https, provide SID to calculate this for any user on
28
 * any machine:
29
 * AssocHashGen -s "<SID>" -p "c:\program files (x86)\mozilla firefox\firefox.exe" http FirefoxURL
30
 * For all others (file extensions, non-http(s) URLs, etc) do NOT provide exe path:
31
 * AssocHashGen -s "<SID>" .htm ChromeHTML
32
 *
33
 * Tested on Windows 10 Enterprise and 8.1 Professional.
34
 * Algorithm has remained the same.
35
 *
36
 * WARNING:
37
 * This code lacks basic things like error handling, memory management and
38
 * buffer length checks. This is done "for clarity" but also "because lazy".
39
 * Do _not_ use it directly except for testing.
40
 */
41
42
#include <QCoreApplication>
43
44
#include <QCommandLineParser>
45
#include <iostream>
46
#include <Windows.h>
47
#include <sddl.h>
48
#include <vector>
49
#include <QDebug>
50
#include <QCryptographicHash>
51
52
void CS64_WordSwap(const unsigned int *data, unsigned int dataLength,
53
                   const unsigned int *md5Start, unsigned int *output)
54
{
55
    unsigned int v5; // er10@1
56
    const unsigned int *v6; // rdi@1
57
    unsigned int v7; // er11@3
58
    unsigned int v8; // ebx@3
59
    int v9; // er9@3
60
    int v10; // er11@3
61
    int v11; // ebx@3
62
    unsigned int v12; // er8@3
63
    __int64 v13; // rsi@3
64
    unsigned int v14; // er8@4
65
    unsigned int v15; // edx@4
66
    int v16; // er8@4
67
    int v17; // er9@4
68
    unsigned int v18; // edx@4
69
    char result; // al@6
70
    unsigned int v20; // er11@9
71
    unsigned int v21; // er8@9
72
    int v22; // er9@9
73
74
    v5 = dataLength;
75
    v6 = data;
76
    if (dataLength < 2 || dataLength & 1)
77
    {
78
        result = 0;
79
    }
80
    else
81
    {
82
        v7 = *md5Start | 1;
83
        v8 = md5Start[1] | 1;
84
        v9 = 0;
85
        v10 = v7 + 0x69FB0000;
86
        v11 = v8 + 0x13DB0000;
87
        v12 = 0;
88
        v13 = ((v5 - 2) >> 1) + 1;
89
        do
90
        {
91
            v14 = *v6 + v12;
92
            v6 += 2;
93
            v5 -= 2;
94
            v15 = 0x79F8A395 * (v14 * v10 - 0x10FA9605 * (v14 >> 16))
95
                + 0x689B6B9F * ((v14 * v10 - 0x10FA9605 * (v14 >> 16)) >> 16);
96
            v16 = 0xEA970001 * v15 - 0x3C101569 * (v15 >> 16);
97
            v17 = v16 + v9;
98
            v18 = (*(v6 - 1) + v16) * v11 - 0x3CE8EC25 * ((*(v6 - 1) + v16) >> 16);
99
            v12 = 0x1EC90001 * (0x59C3AF2D * v18 - 0x2232E0F1 * (v18 >> 16))
100
                + 0x35BD1EC9 * ((0x59C3AF2D * v18 - 0x2232E0F1 * (v18 >> 16)) >> 16);
101
            v9 = v12 + v17;
102
            --v13;
103
        } while (v13);
104
        if (v5 == 1)
105
        {
106
            v20 = (*v6 + v12) * v10 - 0x10FA9605 * ((*v6 + v12) >> 16);
107
            v21 = 0xEA970001 * (0x79F8A395 * v20 + 0x689B6B9F * (v20 >> 16))
108
                - 0x3C101569 * ((0x79F8A395 * v20 + 0x689B6B9F * (v20 >> 16)) >> 16);
109
            v22 = v21 + v9;
110
            v12 = 0x1EC90001
111
                * (0x59C3AF2D * (v21 * v11 - 0x3CE8EC25 * (v21 >> 16))
112
                    - 0x2232E0F1 * ((v21 * v11 - 0x3CE8EC25 * (v21 >> 16)) >> 16))
113
                + 901586633
114
                * ((0x59C3AF2D * (v21 * v11 - 0x3CE8EC25 * (v21 >> 16))
115
                    - 0x2232E0F1 * ((v21 * v11 - 0x3CE8EC25 * (v21 >> 16)) >> 16)) >> 16);
116
            v9 = v12 + v22;
117
        }
118
        result = 1;
119
        *output = v12;
120
        output[1] = v9;
121
    }
122
}
123
124
void CS64_Reversible(const unsigned int *data, unsigned int dataLength,
125
                     const unsigned int *md5, unsigned int *output)
126
{
127
    unsigned int v5; // er10@1
128
    const unsigned int *v6; // rdi@1
129
    unsigned int v7; // ebx@3
130
    int v8; // er11@3
131
    unsigned int v9; // er9@3
132
    int v10; // ebx@3
133
    unsigned int v11; // er8@3
134
    __int64 v12; // rsi@3
135
    unsigned int v13; // er8@4
136
    unsigned int v14; // er8@4
137
    unsigned int v15; // edx@4
138
    int v16; // er11@4
139
    unsigned int v17; // edx@4
140
    unsigned int v18; // edx@4
141
    char result; // al@6
142
    unsigned int v20; // edx@9
143
    unsigned int v21; // edx@9
144
    int v22; // er11@9
145
    unsigned int v23; // edx@9
146
    unsigned int v24; // eax@9
147
148
    v5 = dataLength;
149
    v6 = data;
150
    if (dataLength < 2 || dataLength & 1)
151
    {
152
        result = 0;
153
    }
154
    else
155
    {
156
        v7 = *md5;
157
        v8 = 0;
158
        v9 = md5[1] | 1;
159
        v10 = v7 | 1;
160
        v11 = 0;
161
        v12 = ((v5 - 2) >> 1) + 1;
162
        do
163
        {
164
            v5 -= 2;
165
            v13 = v10 * (*v6 + v11);
166
            v6 += 2;
167
            v14 = 0x5B9F0000 * (0xB1110000 * v13 - 0x30674EEF * (v13 >> 16))
168
                - 0x78F7A461
169
                * ((0xB1110000 * v13 - 0x30674EEF * (v13 >> 16)) >> 16);
170
            v15 = 0x1D830000 * (0x12CEB96D * (v14 >> 16) - 0x46930000 * v14)
171
                + 0x257E1D83
172
                * ((0x12CEB96D * (v14 >> 16) - 0x46930000 * v14) >> 16);
173
            v16 = v15 + v8;
174
            v17 = 0x16F50000 * v9 * (*(v6 - 1) + v15) - 0x5D8BE90B
175
                * (v9 * (*(v6 - 1) + v15) >> 16);
176
            v18 = 0x2B890000 * (0x96FF0000 * v17 - 0x2C7C6901 * (v17 >> 16))
177
                + 0x7C932B89
178
                * ((0x96FF0000 * v17 - 0x2C7C6901 * (v17 >> 16)) >> 16);
179
            v11 = 0x9F690000 * v18 - 0x405B6097 * (v18 >> 16);
180
            v8 = v11 + v16;
181
            --v12;
182
        } while (v12);
183
        if (v5 == 1)
184
        {
185
            v20 = 0xB1110000 * v10 * (v11 + *v6) - 0x30674EEF
186
                * (v10 * (v11 + *v6) >> 16);
187
            v21 = 0x1D830000
188
                * (0x12CEB96D * ((0x5B9F0000 * v20 - 0x78F7A461 * (v20 >> 16)) >> 16)
189
                    - 0x46930000 * (0x5B9F0000 * v20 - 0x78F7A461 * (v20 >> 16)))
190
                + 0x257E1D83
191
                * ((0x12CEB96D * ((0x5B9F0000 * v20 - 0x78F7A461 * (v20 >> 16)) >> 16)
192
                    - 0x46930000 * (0x5B9F0000 * v20 - 0x78F7A461 * (v20 >> 16))) >> 16);
193
            v22 = v21 + v8;
194
            v23 = 0x16F50000 * v9 * v21 - 0x5D8BE90B * (v9 * v21 >> 16);
195
            v24 = (0x96FF0000 * v23 - 0x2C7C6901 * (v23 >> 16)) >> 16;
196
            v11 = 0x9F690000 * (0x2B890000 * (0x96FF0000 * v23 - 0x2C7C6901 * (v23 >> 16)) + 0x7C932B89 * v24)
197
                - 0x405B6097 * ((0x2B890000 * (0x96FF0000 * v23 - 0x2C7C6901 * (v23 >> 16)) + 0x7C932B89 * v24) >> 16);
198
            v8 = v11 + v22;
199
        }
200
        result = 1;
201
        *output = v11;
202
        output[1] = v8;
203
    }
204
}
205
206
QString getSid()
207
{
208
    // shit code with no error handling. if we can't get the sid, just tank, lazy PoC
209
    HANDLE hToken = NULL;
210
    OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken);
211
    DWORD dwBufferSize = 0;
212
    GetTokenInformation(hToken, TokenUser, NULL, 0, &dwBufferSize);
213
    std::vector<BYTE> buffer;
214
    buffer.resize(dwBufferSize);
215
    PTOKEN_USER pTokenUser = reinterpret_cast<PTOKEN_USER>(&buffer[0]);
216
217
    GetTokenInformation(
218
        hToken,
219
        TokenUser,
220
        pTokenUser,
221
        dwBufferSize,
222
        &dwBufferSize);
223
224
    LPWSTR output;
225
    ConvertSidToStringSidW(pTokenUser->User.Sid, &output);
226
227
    CloseHandle(hToken);
228
    hToken = NULL;
229
230
    return QString::fromWCharArray(output);
231
}
232
233
234
QString genHash(QString protocol, QString exepath, QString sid, QString progid)
235
{
236
    // start out zero'd because towchararray doesn't append 0s and laziness
237
    wchar_t* data = (wchar_t*)calloc(1024, 1);
238
    QString((protocol + sid + progid + exepath).toLower()).toWCharArray(data);
239
    QCryptographicHash hash(QCryptographicHash::Md5);
240
    int dataLength = wcslen(data)*2+2;
241
    hash.addData((char *)data, dataLength);
242
    int v6 = dataLength >> 2;
243
    if ((dataLength >> 2) & 1)
244
        --v6;
245
246
    // result of the aforementioned md5 operation
247
    unsigned int* md5 = (unsigned int*)hash.result().data();
248
    unsigned int out[2];
249
    unsigned int out2[2];
250
    CS64_WordSwap((unsigned int *)data, v6, md5, out);
251
    CS64_Reversible((unsigned int *)data, v6, md5, out2);
252
253
    unsigned int finalResult[2] = { out[0] ^ out2[0], out[1] ^ out2[1] };
254
    return QByteArray((char*)finalResult, sizeof(finalResult)).toBase64();
255
}
256
257
int main(int argc, char *argv[])
258
{
259
260
    QCoreApplication a(argc, argv);
261
    QCommandLineParser parser;
262
    parser.setApplicationDescription("Crack windows user association hashes");
263
    parser.addHelpOption();
264
    parser.addVersionOption();
265
    parser.addPositionalArgument("protocol", "Protocol string");
266
    parser.addPositionalArgument("progid", "Program ID to associate");
267
    parser.addOption(QCommandLineOption("s",
268
                                        "Security Identifier (SID) token",
269
                                        "sid", getSid()));
270
    parser.addOption(QCommandLineOption("p",
271
                                        "Path to executable for ProgId (only "
272
                                        "needed for browsers http/https "
273
                                        "protocol)", "path"));
274
    parser.process(a);
275
276
    if (parser.positionalArguments().size() < 2)
277
        parser.showHelp();
278
    QTextStream ts( stdout );
279
    ts << genHash(parser.positionalArguments().first(), parser.value("p"),
280
                  parser.value("s"), parser.positionalArguments().last())
281
       << endl;
282
}