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 0000000..959edf8
Binary files /dev/null and b/ModKey2Key.rc differ
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 0000000..9ced016
Binary files /dev/null and b/icon.ico differ
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 0000000..6e4cf62
Binary files /dev/null and b/libModKey2Key/libModKey2Key.aps differ
diff --git a/libModKey2Key/libModKey2Key.rc b/libModKey2Key/libModKey2Key.rc
new file mode 100644
index 0000000..78ef135
Binary files /dev/null and b/libModKey2Key/libModKey2Key.rc differ
diff --git a/libModKey2Key/libModKey2Key.vcxproj b/libModKey2Key/libModKey2Key.vcxproj
new file mode 100644
index 0000000..1e84fa8
--- /dev/null
+++ b/libModKey2Key/libModKey2Key.vcxproj
@@ -0,0 +1,155 @@
+
+
+
+
+ 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