Xetrill

FTA UserChoise Hash (Reverse^2)

Dec 20th, 2021
336
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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. }
Add Comment
Please, Sign In to add comment