From 96754a4daae995b500f7492b297889dfd8ef77f1 Mon Sep 17 00:00:00 2001 From: Mike Date: Thu, 26 Feb 2026 08:18:02 +0200 Subject: [PATCH] UPLOAD --- LICENSE | 21 +++ ModKey2Key.rc | Bin 0 -> 5164 bytes ModKey2Key.sln | 41 ++++++ ModKey2Key.vcxproj | 146 ++++++++++++++++++ ModKey2Key.vcxproj.filters | 37 +++++ ModKey2Key.vcxproj.user | 4 + README.md | 35 ++++- icon.ico | Bin 0 -> 238142 bytes libModKey2Key/dllmain.cpp | 140 ++++++++++++++++++ libModKey2Key/dllmain.h | 24 +++ libModKey2Key/framework.h | 5 + libModKey2Key/libModKey2Key.aps | Bin 0 -> 2680 bytes libModKey2Key/libModKey2Key.rc | Bin 0 -> 4648 bytes libModKey2Key/libModKey2Key.vcxproj | 155 ++++++++++++++++++++ libModKey2Key/libModKey2Key.vcxproj.filters | 38 +++++ libModKey2Key/libModKey2Key.vcxproj.user | 4 + libModKey2Key/resource.h | 14 ++ main.cpp | 155 ++++++++++++++++++++ resource.h | 16 ++ 19 files changed, 834 insertions(+), 1 deletion(-) create mode 100644 LICENSE create mode 100644 ModKey2Key.rc create mode 100644 ModKey2Key.sln create mode 100644 ModKey2Key.vcxproj create mode 100644 ModKey2Key.vcxproj.filters create mode 100644 ModKey2Key.vcxproj.user create mode 100644 icon.ico create mode 100644 libModKey2Key/dllmain.cpp create mode 100644 libModKey2Key/dllmain.h create mode 100644 libModKey2Key/framework.h create mode 100644 libModKey2Key/libModKey2Key.aps create mode 100644 libModKey2Key/libModKey2Key.rc create mode 100644 libModKey2Key/libModKey2Key.vcxproj create mode 100644 libModKey2Key/libModKey2Key.vcxproj.filters create mode 100644 libModKey2Key/libModKey2Key.vcxproj.user create mode 100644 libModKey2Key/resource.h create mode 100644 main.cpp create mode 100644 resource.h diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..17907d8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 rlaphoenix + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ModKey2Key.rc b/ModKey2Key.rc new file mode 100644 index 0000000000000000000000000000000000000000..959edf8bb26c002df2781972b3227c9097a17574 GIT binary patch literal 5164 zcmdUzOK%%D5Xa|Spx=R&F9{m>l^oJzEX%H7*)pOBTEKviSdSWzB}0-M2k2*S`}>m` zX;)gMv66#|#V*O=%y8Z$_n*HH?7)Iu+MV6n#Ktz|?b{4k8`#ty?Sl;&mF;JqU<2#f zh<5^fM%x88p%vXDy<7T$k+|L2133Hkqy4}t2eI7)I%0MRb~oad*68=`4=Y7%QSL>& zexwuccXn+JYg)@rt!j1a*n6u0J*9tTHTxY%gYTuC0IAXU^(DjZJuaQM!OpSEs*U?t zX>9lCKf^k*Lldok<6A}RGJ47$72wCbs~-7pAAE}TO>}wt@1Dh6q7)sE*h-PqNAK-o z!!7T8cdK>j0^S{we?vSqB?f}Mz~>`Io`)CFhXbskNO@Th2h&Ve-9?N2l*_IzJm1+F zah0;FK?b$RuQF?Qh_4!t`2NKcHc~d>@t!E|Ky^j?GOk(!s!@yfJVvTR9Ir+!H|$q? z1@8uUC#;reRxvuvUaaV{IR=y=Z8W)H)zkl7H7L$=j|#PVkFZ%WW{C4A=zbn+g|Nf? zDXzUYb~vxU@?Wx;s8m_DS)-`tmu$V_lc5n7lSHq#l<2wZ?8S=QCBIZ< z(xWO-RB_g$&3&|6btNl}B-Gej?f%;1r)WIJ9}ag-+T>>koCG-e;{660^}LzWEUne# zM01UVc^Q`Tsb1!>eC6WYS9PspS6QZn1T*}tv)KR--Jw|zKaG%eypoN@+&nAtTo3In z+WZnV`p7q**GrnB+T^p|w(+A*IkG_sxwXeVa0(sSXX5SyqaJYW9jaqXM8_yB|$z9edQxg)rX6> z*s8^v$)`FmOlWnoU$tD3PW#|L@jhpr8u){_f;{zrg%n)_JTik%^3wW@&NStC!Z=31 zW3p9e*>Ce@eZI0{TN=A>HOj`!_tN~D^%NJ6+;V1LW#8x6HP3zf=veOT9w+ONd@i@K z*JNS6ZE8b4gPU+u_D-XJXGDi~niLzV)TwePQjUlORmD^_le|l5mp#qv&F*Zw)pzN< z4b<4%sJBDZdVe_^;%P}Yzks#Ij8vC&ORutT1^Y8b_9M_ht|?!157*sX_h#+m!ks}G zfXn8(s|#CIQWU!X>qeiv5aKwy^QSxIJvhpvDU?ZWoe;!bT(yR1#C6D{{{Wxov-h;= z7AlFW@w8B8|GA1MSC7G>wn{}1UeR0;thA7Qf8I;^C97^e$9=E6)o#UGRvM2iZ`1kb zOLyn>lWdmXZuLE9y#3a{C~4=(|JTa@MR7asmL0OvNW#q#KO$F^vFra#*8MI{{{pF> BX$JrR literal 0 HcmV?d00001 diff --git a/ModKey2Key.sln b/ModKey2Key.sln new file mode 100644 index 0000000..6305764 --- /dev/null +++ b/ModKey2Key.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33627.172 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ModKey2Key", "ModKey2Key.vcxproj", "{6CCE5275-E7BB-4334-968F-10F65BDC1D42}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libModKey2Key", "libModKey2Key\libModKey2Key.vcxproj", "{AED2C517-BB61-4CA0-9364-D1245F281878}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6CCE5275-E7BB-4334-968F-10F65BDC1D42}.Debug|x64.ActiveCfg = Debug|x64 + {6CCE5275-E7BB-4334-968F-10F65BDC1D42}.Debug|x64.Build.0 = Debug|x64 + {6CCE5275-E7BB-4334-968F-10F65BDC1D42}.Debug|x86.ActiveCfg = Debug|Win32 + {6CCE5275-E7BB-4334-968F-10F65BDC1D42}.Debug|x86.Build.0 = Debug|Win32 + {6CCE5275-E7BB-4334-968F-10F65BDC1D42}.Release|x64.ActiveCfg = Release|x64 + {6CCE5275-E7BB-4334-968F-10F65BDC1D42}.Release|x64.Build.0 = Release|x64 + {6CCE5275-E7BB-4334-968F-10F65BDC1D42}.Release|x86.ActiveCfg = Release|Win32 + {6CCE5275-E7BB-4334-968F-10F65BDC1D42}.Release|x86.Build.0 = Release|Win32 + {AED2C517-BB61-4CA0-9364-D1245F281878}.Debug|x64.ActiveCfg = Debug|x64 + {AED2C517-BB61-4CA0-9364-D1245F281878}.Debug|x64.Build.0 = Debug|x64 + {AED2C517-BB61-4CA0-9364-D1245F281878}.Debug|x86.ActiveCfg = Debug|Win32 + {AED2C517-BB61-4CA0-9364-D1245F281878}.Debug|x86.Build.0 = Debug|Win32 + {AED2C517-BB61-4CA0-9364-D1245F281878}.Release|x64.ActiveCfg = Release|x64 + {AED2C517-BB61-4CA0-9364-D1245F281878}.Release|x64.Build.0 = Release|x64 + {AED2C517-BB61-4CA0-9364-D1245F281878}.Release|x86.ActiveCfg = Release|Win32 + {AED2C517-BB61-4CA0-9364-D1245F281878}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {7C32F601-D49F-4A02-AE5C-34E0340B1338} + EndGlobalSection +EndGlobal diff --git a/ModKey2Key.vcxproj b/ModKey2Key.vcxproj new file mode 100644 index 0000000..9befbb7 --- /dev/null +++ b/ModKey2Key.vcxproj @@ -0,0 +1,146 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {6cce5275-e7bb-4334-968f-10f65bdc1d42} + ModKey2Key + 10.0 + ModKey2Key + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ModKey2Key.vcxproj.filters b/ModKey2Key.vcxproj.filters new file mode 100644 index 0000000..05d0e2a --- /dev/null +++ b/ModKey2Key.vcxproj.filters @@ -0,0 +1,37 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Header Files + + + + + Resource Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/ModKey2Key.vcxproj.user b/ModKey2Key.vcxproj.user new file mode 100644 index 0000000..0f14913 --- /dev/null +++ b/ModKey2Key.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/README.md b/README.md index 4674018..2f928fe 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,35 @@ -# Streamfab +# ModKey2Key +Simple C++ library to decrypt ModKey values used to authorize StreamFab API requests. + +## Background + +The team behind DVDFab, a software that does everything you could imagine with DVDs and Blu-rays, later released a new tool called StreamFab. +StreamFab lets you download online videos that are protected by DRM from places like Netflix, Prime Video, Disney+, Hulu, and more. + +It worked by sending video and audio decryption jobs to an API they control. Their API would internally send a Widevine license request to the +relevant streaming platform to obtain the video and audio decryption keys. These keys would then be sent back by the API to the StreamFab client +for decryption. + +The DVDFab team did not want to allow their API to be used by other software or groups, understandably so it cannot be abused, overused, or re-sold. +The API would ask for a certain key to be provided during API calls as authorization. + +## So, how was the API authorized? + +I don't fully remember anymore, as this project was written years before I created this README. +However, generally from what I remember, at a high level, it would send you a relatively large amount of data. +This data contained various information including an 'encrypted' key. These were referred to as 'modkeys'. + +## How was it reversed? + +This was relatively trivial to reverse engineer, thanks to the DVDFab team making a large mistake in one of the +StreamFab releases. One of them had way less obfuscation then it typically has, including no virtualization or +any kind of anti-debugging tricks. It had some obfuscation, but very very little. + +Because the encryption/decryption algorithm used is a typicall memory jumping bitwise operation, translating the code to another language was not possible. +This is why I made it as a DLL that could be easily imported and used by other software, even Python 64-bit. +Simply pass the ModKey to the `modkey2key` function, and voila it returns the real key you can use to authorize StreamFab API requests and decrypt responses. + +I simply took the function from the StreamFab.exe client, looked for the relevant function, had ghidra generate pseudocode, and made small changes to rework +it as a new project in Visual Studio as a library. I also had to make some small changes to do with memory addressing to operate correctly when compiled as +a 64-bit library. diff --git a/icon.ico b/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..9ced0162a02e1e32921697c387a4bee963fae01b GIT binary patch literal 238142 zcmeEP1)x+#7hW0_knZjd>5`5Iyrw&(6+}f$FhELd6cw!BKtTm5Q4mp(?i3JE0qO2K z|M$)AJnr7@c#nPY^l~@u-aB*Vd~UW7Al2+-FgTdXIlZB;`n)s-Br|exZWbuGh6uk zl)n@Tq);F}D3BUAE$~X2i26TQ8PI21nV9E>=BxWj=bV+7cFJCPLv*%sN29WpI~|$5 z+_~_a<*tY4E`K{BZ$*j7$D@+-1K;yHUeDk0_q-49$NLV+SNGHRN=HAxv`YWpBa1a_ z$mio=J5v5qD3C${*A&PcQ@CpL8D(Oh8CIzNSM76G-ihN%Ozuh&Z9DinCU<4qap!aW zeIRF7_vYtpN5|Y%cCuYF%658cSmEZ)(2e_DcO~VU6bdA93fyO@{6@*h5km^p`ynb< z#gnmlDhm%{(2Awt;xiCzo7)s)Yine#il>Jbs6TgVnGVCDg;z@ABbL&=WK4krr5`Ul zu|%7Z{qooRJv?WHTkU}X%F;k_<@EQtDoV7g!zRm}{?5JRMDm%|5&kaTT8YS zeLJx-ax!Xn)_IkBcO6o&{`{!il`ayqzG5IMM+J#UTTki7YwK#aT9ZOdq zP~U$)Z>_rii?4o`8TkF=7v5I)<9!F>{+&xV0H&?a<@4DNwkIN8Nn!hZ=@V@M+66dY zpsld5;zOOl580CuPo#7;v?-8oSFI=70<+(ON6-1B6GO+1ystE5Uv`DjCcsG>90OW( zmeIpsl6PMFM828*n=D$kOIB_>ChPt@E1M5qm92+v$&RCm&DcI*VVD< z;C0z_@LD_`*5~kfTQC>!`D%_pd)ThkyH3lG%XY{opZp*%jT|psi#3SrOB+jOVgJ0L zgQiy(&~Hq!7L%7$8Cp7Na!N|CLWu&4EB1@(nYa2%tBvOcW^*A9o2s~yR}FyIj+XK= zVf0%v`}^Nz<(6ZRmDdzTC=a(Bx|u*2^%wtEY;Q$7iEAEg|BB5=W!87gW&E>mpnnyG z{iJ-3NK?WmEceY@`}c1u^@<3k@lI(=(xAYXWxG7oK2MdSS_gC|W1_N`hcBq0l1t>} zAuYPfr=QN3-!~kR?Z7GJnbK9E&&IDT^%tkU{0^8#KiD57rw`wf^VYaf44$5?7bknPg?C$@_FLNt7mMppW6^>#3{?GHUp_j`OT_2IwpbO

Ey`| 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 LCW7&{=Jfvp#T<$8 literal 0 HcmV?d00001 diff --git a/libModKey2Key/dllmain.cpp b/libModKey2Key/dllmain.cpp new file mode 100644 index 0000000..0a67f76 --- /dev/null +++ b/libModKey2Key/dllmain.cpp @@ -0,0 +1,140 @@ +#define _CRT_SECURE_NO_WARNINGS +#include +#include +#include "dllmain.h" + + +typedef unsigned long long undefined8; +typedef unsigned long undefined4; +typedef unsigned char undefined; +typedef unsigned char byte; +typedef unsigned long ulong; +typedef unsigned int uint; + + +void hex_to_bytes(char* input, char* output, ulong buffer_size) { + /* + Hex to Bytes -- Returned as char* (0-255) + + Parameters: + input: Input hex string data + output: Output bytes buffer + buffer_size: Output buffer size + */ + size_t len; + ulong i; + + len = strlen(input); + if (len + 1 >> 1 <= buffer_size) { + for (i = 0; i < len; i = i + 2) { + sscanf(input + i, "%2hhx", output + (i >> 1)); + } + } + return; +} + +void bytes_to_hex(char* input, char* output, ulong buffer_size) { + ulong i; + + for (i = 0; i < buffer_size; i = i + 1) { + sprintf((char*)(output + i * 2), "%02x", (ulong) * (byte*)(input + i)); + } + + return; +} + +void _modkey2key(uint* mod, uint* tok) { + /* Secure function to undo modifications to "mod" key (In-place). */ + // - when doing pointer arithmetic, make sure to use (long long) and not (long) as we + // are compiling for a 64-bit platform, not 32-bit. + long local_50; + long local_48; + byte local_31; + byte local_30; + byte local_2f; + short local_2e; + uint local_28; + uint local_24; + int local_20; + int local_1c; + short local_18; + byte local_15; + + int i; + uint tok_xor = *tok ^ 0x2a2e3706; + uint mod_deref = *mod; + + for (i = 1; i <= 3; i = i + 1) { + tok_xor = tok_xor ^ mod_deref; + + local_2e = (short)(tok_xor >> 0x10); + local_18 = (short)tok_xor; + local_2f = (byte)(tok_xor >> 0x10); + local_30 = (byte)(local_2e >> 5) & 0x1f; + local_31 = (byte)((int)tok_xor >> 0x1a); + + tok[i] = tok[i] << (-local_31 & 0x1f) | tok[i] >> (local_31 & 0x1f); + tok_xor = (int)(local_2e >> 0xf) ^ + (tok_xor >> (local_2f & 0x1f) | tok_xor << (-local_2f & 0x1f)) ^ + tok[i]; + + byte t_l = *(byte*)((long long)&tok_xor + (tok[i] - i & 3)) >> 3; + byte t_r = -(*(byte*)((long long)&tok_xor + (tok[i] - i & 3)) >> 3) & 0x1f; + mod[i] = mod[i] << t_l | mod[i] >> t_r; + + for (local_20 = 0; local_20 < 4; local_20 = local_20 + 1) { + local_15 = 0; + for (local_1c = 0; local_1c < 4; local_1c = local_1c + 1) { + if ((int)((int)local_18 & 3U) < local_1c) { + local_24 = 0xff; + } + else { + local_24 = (uint) * (byte*)((long long)&tok_xor + (ulong)(local_1c + local_20 & 3)); + } + local_15 = local_15 ^ (byte)local_24; + } + for (local_1c = 0; local_1c < 4; local_1c = local_1c + 1) { + if ((int)((int)(local_18 >> 2) & 3U) < local_1c) { + local_28 = 0xff; + } + else { + local_28 = (uint)local_15; + } + *(byte*)((long long)mod + (int)(i * 4 + (local_1c + local_20 & 3U))) = + *(byte*)((long long)mod + (int)(i * 4 + (local_1c + local_20 & 3U))) ^ + (byte)local_28; + } + local_18 = local_18 >> 4; + } + mod_deref = mod[i]; + local_50 = (long)i; + mod[i] = mod[i] << local_30 | mod[i] >> (-local_30 & 0x1f); + } + + return; +} + +char* modkey2key(char* mod, char* tok) { + size_t key_len; + char key[32]; + char mod_bytes[16]; + char tok_bytes[16]; + char* key_buffer; + + hex_to_bytes(mod, mod_bytes, 0x10); + hex_to_bytes(tok, tok_bytes, 0x10); + + _modkey2key((uint*)&mod_bytes, (uint*)&tok_bytes); + + bytes_to_hex(mod_bytes, key, 0x10); + + // copy key to new buffer as `key` is allocated on the func stack + // it would get cleared on return if we don't do this + key_len = strlen(key); + key_buffer = (char*)malloc(key_len + 1); // +1 for null terminator + strcpy(key_buffer, key); + + //std::cout << key << std::endl; + + return key; +} diff --git a/libModKey2Key/dllmain.h b/libModKey2Key/dllmain.h new file mode 100644 index 0000000..30ab15d --- /dev/null +++ b/libModKey2Key/dllmain.h @@ -0,0 +1,24 @@ +#ifndef MY_LIBRARY_H +#define MY_LIBRARY_H +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include + +typedef unsigned long long undefined8; +typedef unsigned long undefined4; +typedef unsigned char undefined; +typedef unsigned char byte; +typedef unsigned long ulong; +typedef unsigned int uint; + +void hex_to_bytes(char* input, char* output, ulong buffer_size); + +void bytes_to_hex(char* input, char* output, ulong buffer_size); + +void _modkey2key(uint* mod, uint* tok); + +extern "C" __declspec(dllexport) char* modkey2key(char* mod, char* tok); + +#endif diff --git a/libModKey2Key/framework.h b/libModKey2Key/framework.h new file mode 100644 index 0000000..a9744f8 --- /dev/null +++ b/libModKey2Key/framework.h @@ -0,0 +1,5 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files +#include diff --git a/libModKey2Key/libModKey2Key.aps b/libModKey2Key/libModKey2Key.aps new file mode 100644 index 0000000000000000000000000000000000000000..6e4cf623edd1754ae4bfbd3e07788494dc765936 GIT binary patch literal 2680 zcmb7G-HzHu6#i(a#5QRg^`gp6Ba-GKxmapQnm<*lSleWsHTKFjBr74&0M0HE3o8TK z<~{Ntxy(f?^|I<)M16q1LFsqKfNi{NRHGTsoc}p<&SwCi%&}O+gUihGjJrD=`*?vp zz88zalD|`0F7O9e`qNHp8b;I3^Z9f(9Cr?*$(yi0n|7L$!9n=8#?cuKd)s!Es1JOk z!K|-8l?x4tuUm?83sE?o%%gr-IROLe)(`!zW4;W!p6Ryv*q&G(O*=1N_xUjtS#oe#$hOGQ*@``xzb`IhT+EvMn4 zif>S`487|I^}y0`cei>EyC^7Kng8YmET0D7**yHEIO#kDJgnvDcFW))755JBCQYqf zNWH(Niac^Zi7OwKEuqKpRZjFfyCckwG8<00kAdn zfL6|Ft4zPcWjs}AzU(vCVq@}N2brTDiz1Yqj;s;u5U8mio9>yhj=3EOWTi0 zN%))HlVR#^uJtzf`QD{Ks;hQYF4(U;6Eh7HFF9LqSV=Z3*dQgruyjAA@C4s}Qa`@w zwEp+Qaep))gyq{S6uA8*aRpaCX-g#7Zz+ru#S+P7(ie;CYs^jeWa)~Wuniww&L%vr zEVw*rSDm-PwLHHU|M?ekM`{Q~*1*qd1`DK!RoyO0I3b}xdoy;NbolYQTE-G zcVGEGQ#doBtUPg4p|aTE++&t5LYp%0ThK-@BVr8lXegz8wCO|8Y{*Dr+tno+#HheC z3T7+Rm?_yYZH-c=*^XxwBFu#&{&N$IQZvGI^TdnodkBD_p9v zUCY$CD08-o(Oue;+maYpd6eBLeS@@Z*qg-q6TV`sG1?A@fr94gyW4I<`b~11)!oc+ zKEG0DZN?a_BTgzz@UO_o19GK~rt19i%~{>oPU(H|9m_e3lSwtNR`MUl;JEBR%t!Ly zXJqpKJ>jQPR;n#mEtGRIi literal 0 HcmV?d00001 diff --git a/libModKey2Key/libModKey2Key.rc b/libModKey2Key/libModKey2Key.rc new file mode 100644 index 0000000000000000000000000000000000000000..78ef135ad199be860e83229a4b6fa1f6a54b708a GIT binary patch literal 4648 zcmdUzTTdE66vxkVlYWOSzSOkwf?_b-tZIP9%XSX)8p^bSuHUZWEHnw}awmz#Pd&h{ZYi%3wjDSy= zTfj!lqPyqqmiLI2xb^G~oGp88uaL6s<_(|&cKcwr9BwW}zhz%7=deY&;qW?+PP`AS zVpXeI-Hz?d%GR_?D*!#_{lbd&1xS_Ok{tpm@*d<%hxHplyD&#~ieKh^+`&sj`-c4! zydyu4n+2rm=9QmIy`qV?BWe&%4S9$jAK>Ra~^w>sIC?~5A1}z@>Nx( zg6h=Q5we@)SCJvUKN-Jtd7tEVZY7wYbb>>r-sR0u3isW+DKG}PCSHU|( znx~n^XtH}gXUpOoP=z$Gk~ zwErr8-eaOtXIVu?R?p8_y5r>Riq3UKPW$dZ({hnUdn;(y7{+DJpK!>rR^XZ#q8hr}bmgCz~>vk6XtI>Wq9?AUm6T z@W3(D@w=?Ah9JfJtnFl<@Oy*o5)xbZw2fBz=^UYVk6qoFN5Hea@U$k$dJG!ua=YGn ze3s#>*y`ReV%80R-h;Yj++N+`!+Z{eou62pe1U^1y=^fp0j@*4C zkCl09S2x?|MYcSZtW1~PA<|mKGw5aQuOL-p{KbO!l6Q4jY$MOm{;R;XY4e(Lp|X*+w<{^B$IrS8@7 z6Lr1bWq + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {aed2c517-bb61-4ca0-9364-d1245f281878} + libModKey2Key + 10.0 + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;LIBMODKEY2KEY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + false + + + + + Level3 + true + true + true + WIN32;NDEBUG;LIBMODKEY2KEY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + true + true + false + + + + + Level3 + true + _DEBUG;LIBMODKEY2KEY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + pch.h + + + Windows + true + false + + + + + Level3 + true + true + true + NDEBUG;LIBMODKEY2KEY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + NotUsing + pch.h + + + Windows + true + true + true + false + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libModKey2Key/libModKey2Key.vcxproj.filters b/libModKey2Key/libModKey2Key.vcxproj.filters new file mode 100644 index 0000000..0776eb1 --- /dev/null +++ b/libModKey2Key/libModKey2Key.vcxproj.filters @@ -0,0 +1,38 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/libModKey2Key/libModKey2Key.vcxproj.user b/libModKey2Key/libModKey2Key.vcxproj.user new file mode 100644 index 0000000..0f14913 --- /dev/null +++ b/libModKey2Key/libModKey2Key.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/libModKey2Key/resource.h b/libModKey2Key/resource.h new file mode 100644 index 0000000..bd329b1 --- /dev/null +++ b/libModKey2Key/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by libModKey2Key.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..63b2012 --- /dev/null +++ b/main.cpp @@ -0,0 +1,155 @@ +// Online C++ compiler to run C++ program online +#define _CRT_SECURE_NO_WARNINGS +#include +#include + + +typedef unsigned long long undefined8; +typedef unsigned long undefined4; +typedef unsigned char undefined; +typedef unsigned char byte; +typedef unsigned long ulong; +typedef unsigned int uint; + + +void hex_to_bytes(char* input, char* output, ulong buffer_size) { + /* + Hex to Bytes -- Returned as char* (0-255) + + Parameters: + input: Input hex string data + output: Output bytes buffer + buffer_size: Output buffer size + */ + size_t len; + ulong i; + + len = strlen(input); + if (len + 1 >> 1 <= buffer_size) { + for (i = 0; i < len; i = i + 2) { + sscanf(input + i, "%2hhx", output + (i >> 1)); + } + } + return; +} + +void bytes_to_hex(char* input, char* output, ulong buffer_size) { + ulong i; + + for (i = 0; i < buffer_size; i = i + 1) { + sprintf((char*)(output + i * 2), "%02x", (ulong) * (byte*)(input + i)); + } + + return; +} + +void _modkey2key(uint* mod, uint* tok) { + /* Secure function to undo modifications to "mod" key (In-place). */ + // - when doing pointer arithmetic, make sure to use (long long) and not (long) as we + // are compiling for a 64-bit platform, not 32-bit. + long local_50; + long local_48; + byte local_31; + byte local_30; + byte local_2f; + short local_2e; + uint local_28; + uint local_24; + int local_20; + int local_1c; + short local_18; + byte local_15; + + int i; + uint tok_xor = *tok ^ 0x2a2e3706; + uint mod_deref = *mod; + + for (i = 1; i <= 3; i = i + 1) { + tok_xor = tok_xor ^ mod_deref; + + local_2e = (short)(tok_xor >> 0x10); + local_18 = (short)tok_xor; + local_2f = (byte)(tok_xor >> 0x10); + local_30 = (byte)(local_2e >> 5) & 0x1f; + local_31 = (byte)((int)tok_xor >> 0x1a); + + tok[i] = tok[i] << (-local_31 & 0x1f) | tok[i] >> (local_31 & 0x1f); + tok_xor = (int)(local_2e >> 0xf) ^ + (tok_xor >> (local_2f & 0x1f) | tok_xor << (-local_2f & 0x1f)) ^ + tok[i]; + + byte t_l = *(byte*)((long long)&tok_xor + (tok[i] - i & 3)) >> 3; + byte t_r = -(*(byte*)((long long)&tok_xor + (tok[i] - i & 3)) >> 3) & 0x1f; + mod[i] = mod[i] << t_l | mod[i] >> t_r; + + for (local_20 = 0; local_20 < 4; local_20 = local_20 + 1) { + local_15 = 0; + for (local_1c = 0; local_1c < 4; local_1c = local_1c + 1) { + if ((int)((int)local_18 & 3U) < local_1c) { + local_24 = 0xff; + } + else { + local_24 = (uint) * (byte*)((long long)&tok_xor + (ulong)(local_1c + local_20 & 3)); + } + local_15 = local_15 ^ (byte)local_24; + } + for (local_1c = 0; local_1c < 4; local_1c = local_1c + 1) { + if ((int)((int)(local_18 >> 2) & 3U) < local_1c) { + local_28 = 0xff; + } + else { + local_28 = (uint)local_15; + } + *(byte*)((long long)mod + (int)(i * 4 + (local_1c + local_20 & 3U))) = + *(byte*)((long long)mod + (int)(i * 4 + (local_1c + local_20 & 3U))) ^ + (byte)local_28; + } + local_18 = local_18 >> 4; + } + mod_deref = mod[i]; + local_50 = (long)i; + mod[i] = mod[i] << local_30 | mod[i] >> (-local_30 & 0x1f); + } + + return; +} + +char* modkey2key(char* mod, char* tok) { + size_t key_len; + char key[32]; + char mod_bytes[16]; + char tok_bytes[16]; + char* key_buffer; + + hex_to_bytes(mod, mod_bytes, 0x10); + hex_to_bytes(tok, tok_bytes, 0x10); + + _modkey2key((uint*)&mod_bytes, (uint*)&tok_bytes); + + bytes_to_hex(mod_bytes, key, 0x10); + + // copy key to new buffer as `key` is allocated on the func stack + // it would get cleared on return if we don't do this + key_len = strlen(key); + key_buffer = (char*)malloc(key_len + 1); // +1 for null terminator + strcpy(key_buffer, key); + + return key_buffer; +} + +int main(int argc, char* argv[]) { + //char mod[] = "dadcf4783dd85c97bcf1d7b90cc55d51"; + //char tok[] = "cab66d47305016a723586c4778c0b521"; + char* mod = argv[1]; + char* tok = argv[2]; + + //std::cout << "mod: " << mod << std::endl; + //std::cout << "tok: " << tok << std::endl; + + char* key = modkey2key(mod, tok); + + std::cout << key << std::endl; + // key == "dadcf478e4a50085f22bb673864b0ae9" + + return 0; +} diff --git a/resource.h b/resource.h new file mode 100644 index 0000000..dd3ce37 --- /dev/null +++ b/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ModKey2Key.rc +// +#define IDI_ICON1 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif