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