Advertisement
Guest User

AssocHashGen.cpp

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