Browse Source

EQ2 Voice Recover RC4 key decryptor code for Independent and BOINC Project

Emagi 4 months ago
parent
commit
195f7bc84d

+ 26 - 0
EQ2/devtools/EQ2VoiceRecover/README.md

@@ -0,0 +1,26 @@
+# EQ2Voice Recovery Project BOINC Application - **PROTOTYPE BUILD**
+
+**LINUX/WINDOWS SUPPORT ONLY AT THIS TIME**
+
+This is released for the sake of being open about what our code is doing for the BOINC project and please keep in mind the adhoc process it was put together, back in 2020 by LethalEncounter and the new integration to BOINC by Image/Emagi in 2023.
+
+Visit http://boinc.eq2emu.com/cplan/ for more project details.  This BOINC Application is used inside the EQ2 Voice Recovery project in attempt to brute force RC4 64-bit encryption keys used on MP3 NPC Voices.
+
+### Building/Compiling
+
+Linux
+- apt-get install libboinc-app-dev
+- Obtain BOINC source, find more details here https://boinc.berkeley.edu/trac/wiki/SourceCodeGit
+- Edit compile.sh with nano/vi/other utility, -I./boinc-src/lib/ should point to the boinc source's lib folder pulled from the first step
+- bash -x compile.sh
+
+Windows
+- Visual Studio 2019+ and install without the boinc defines for now unless you really want to combine BOINC for windows.
+
+## Authors
+
+Project team site at [EQ2EMu](https://www.eq2emu.com) and [ZekLabs](https://www.zeklabs.com)
+
+## License
+
+This project is licensed under the GNU General Public License - see the [LICENSE.md](LICENSE.md) file for details

+ 1 - 0
EQ2/devtools/EQ2VoiceRecover/compile.sh

@@ -0,0 +1 @@
+g++ -O2 -o eq2_voice_recover main.cpp -DBOINC_APPLICATION -I./boincserver/boinc-src/api/ -I./boincserver/boinc-src/lib/ -lboinc_zip -lboinc_api -lboinc

+ 31 - 0
EQ2/devtools/EQ2VoiceRecover/eq2_voice_recover.sln

@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30011.22
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "eq2_voice_recover", "eq2_voice_recover.vcxproj", "{E3B38CEE-86C8-491A-8AC8-240FA47ED8F4}"
+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
+		{E3B38CEE-86C8-491A-8AC8-240FA47ED8F4}.Debug|x64.ActiveCfg = Debug|x64
+		{E3B38CEE-86C8-491A-8AC8-240FA47ED8F4}.Debug|x64.Build.0 = Debug|x64
+		{E3B38CEE-86C8-491A-8AC8-240FA47ED8F4}.Debug|x86.ActiveCfg = Debug|Win32
+		{E3B38CEE-86C8-491A-8AC8-240FA47ED8F4}.Debug|x86.Build.0 = Debug|Win32
+		{E3B38CEE-86C8-491A-8AC8-240FA47ED8F4}.Release|x64.ActiveCfg = Release|x64
+		{E3B38CEE-86C8-491A-8AC8-240FA47ED8F4}.Release|x64.Build.0 = Release|x64
+		{E3B38CEE-86C8-491A-8AC8-240FA47ED8F4}.Release|x86.ActiveCfg = Release|Win32
+		{E3B38CEE-86C8-491A-8AC8-240FA47ED8F4}.Release|x86.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {60B62D8A-1558-4686-8932-CDAA6B64E653}
+	EndGlobalSection
+EndGlobal

+ 155 - 0
EQ2/devtools/EQ2VoiceRecover/eq2_voice_recover.vcxproj

@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <VCProjectVersion>16.0</VCProjectVersion>
+    <ProjectGuid>{E3B38CEE-86C8-491A-8AC8-240FA47ED8F4}</ProjectGuid>
+    <RootNamespace>eq2voicerecover</RootNamespace>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+    <IncludePath>C:\eq2_data\boinc-master\boinc-master\api;C:\eq2_data\boinc-master\boinc-master\lib;$(IncludePath)</IncludePath>
+    <LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);C:\eq2_data\boinc-master\boinc-master\win_build\Build\x64\Release</LibraryPath>
+    <TargetName>eq2voice</TargetName>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>false</LinkIncremental>
+    <IncludePath>C:\eq2_data\boinc-master\boinc-master\api;C:\eq2_data\boinc-master\boinc-master\lib;$(IncludePath)</IncludePath>
+    <LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);C:\eq2_data\boinc-master\boinc-master\win_build\Build\x64\Release</LibraryPath>
+    <TargetName>eq2voice</TargetName>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions);BOINC_APPLICATION</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);libboincapi.lib;libboinc.lib</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions);BOINC_APPLICATION</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);libboincapi.lib;libboinc.lib</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="main.cpp" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 249 - 0
EQ2/devtools/EQ2VoiceRecover/main.cpp

@@ -0,0 +1,249 @@
+#include <fstream>
+#include <iostream>
+#include <vector>
+#include <map>
+#include <cstring>
+
+#ifdef BOINC_APPLICATION
+#include "boinc_api.h"
+#endif
+
+using namespace std;
+typedef unsigned char           int8;
+typedef unsigned short          int16;
+typedef unsigned int            int32;
+
+typedef unsigned char           uint8;
+typedef  signed  char           sint8;
+typedef unsigned short          uint16;
+typedef  signed  short          sint16;
+typedef unsigned int            uint32;
+typedef  signed  int            sint32;
+typedef unsigned char           uchar;
+
+int processBlock(int8* alldata, int8 key1, int8 key2, int8 key3, int8 key4, int8 key5, int8 key6, FILE* outFile);
+
+int entries = 0;
+std::map<int32, std::string> filenames;
+int main(int argc, char** argv)
+{
+    std::string outputKey("");
+
+#ifdef BOINC_APPLICATION
+    boinc_init();
+#endif
+
+    FILE* file = fopen("testbin.dat", "r+b");
+    fread(&entries, sizeof(int32), 1, file);
+    if(entries < 1) {
+	return 0;
+    }
+    
+    string resolved_name("");
+    FILE* outFile = NULL;
+
+#ifdef BOINC_APPLICATION
+	int retval = boinc_resolve_filename_s("out", resolved_name);
+	if (!retval) {
+		outFile = boinc_fopen(resolved_name.c_str(), "w+");
+	}
+#endif
+
+	//printf("Entries found %u\n",entries);
+    int8* mp3s = new int8[entries*10];
+	int offset = 0;
+	for(int i=0;i<entries;i++) {
+		int filenamelength = 0;
+		fread(&filenamelength, sizeof(int32), 1, file);
+		char filename[256];
+		fread(filename, sizeof(char), filenamelength, file);
+		filename[filenamelength] = '\0';
+		std::string fileNameStr = std::string(filename);
+	//	printf("Entry adding (%u) %s\n",filenamelength,fileNameStr.c_str());
+		filenames.insert(make_pair(i, fileNameStr));
+		fread(&mp3s[offset], sizeof(unsigned char), 10, file);
+		offset += 10;
+	}
+	
+	fclose(file);
+
+    int8 key[8];
+    key[0] = 0xff;
+    key[1] = 0xff;
+    key[2] = 0xfF;
+    key[3] = 0xff;
+    key[4] = 0xFF;
+    key[5] = 0xFF;
+    key[6] = 0xFF;
+    key[7] = 0xFF;
+    bool bigtask = false;
+    if (argc > 5) {
+        for (int8 i = 0; i < 7; i++) {
+            if (i >= argc - 1)
+                break;
+            key[i] = strtol(argv[i + 1], NULL, 16);
+        }
+        int total_found = processBlock(mp3s, key[0], key[1], key[2], key[3], key[4], key[5], outFile);
+	if(outFile) {
+		if(total_found > 0) {
+			// do nothing
+		}
+		else {
+                fwrite("0", sizeof(char), 1, outFile);
+		}
+		fclose(outFile);
+	}
+
+#ifdef BOINC_APPLICATION
+	boinc_finish(0);
+#endif
+
+    return 0;
+    }
+    else{
+	cout << "Usage: eq2_voice_recover [key1] [key2] [key3] [key4] [key5] [key6]\n";
+	cout << "Example: eq2_voice_recover 91 CD E3 8F A6 93\n\n";
+	cout << "NOTE: If you want to test it, rename all_data.bin to something else and rename all_data.bin.TEST to all_data.bin.\nOnce that is done the above example should find a match very quickly.\n";
+    }
+	if(outFile) {
+		fwrite("0", sizeof(char), 1, outFile);
+		fclose(outFile);
+	}
+
+#ifdef BOINC_APPLICATION
+	boinc_finish(0);
+#endif
+
+    return 0;    
+}
+
+int processBlock(int8* alldata, int8 key1, int8 key2, int8 key3, int8 key4, int8 key5, int8 key6, FILE* outFile) {
+    int total_found = 0;
+    int8 key[8];
+    key[0] = key1;
+    key[1] = key2;
+    key[2] = key3;
+    key[3] = key4;
+    key[4] = key5;
+    key[5] = key6;
+    key[6] = 255;
+    key[7] = 255;
+    int8 S[256];
+    int8 keyinit[256];
+    int8 expected_result[8] = { 0x49, 0x44, 0x33, 0x03, 0x00, 0x00, 0x00, 0x00 };
+    map<int8, map<int8, map<int8, vector<int32>>>> expected_result_lookup;
+    int32 pos = 0;
+    int8 test_byte = 0;
+    int8 test_byte2 = 0;
+    int8 test_byte3 = 0;
+    int8* data = 0;
+	int32 keys_tried = 0;
+    for (int16 z = 0; z < entries; z++) {
+        pos = z * 10;
+        data = alldata + pos;
+        test_byte = data[0] ^ expected_result[0];
+        test_byte2 = data[1] ^ expected_result[1];
+        test_byte3 = data[2] ^ expected_result[2];
+        expected_result_lookup[test_byte][test_byte2][test_byte3].push_back(pos);
+    }
+    for (int i = 0; i < 256; i++)
+        keyinit[i] = i;
+    int16 total_work = 255 * 15;
+    if (key6 != 255)
+        total_work -= (255 - key6);
+    int16 current_work = 0;
+    int8 loop_count = 15;
+    if (key[4] == 15)
+        loop_count = 16; //we need to work on 0 as well, we start at 255
+    for (int e = 0; e < loop_count;e++) {
+        //cout << "key6: " << (int)key6 << ", key5: " << (int)key[4] << endl;
+        for (sint16 f = key6; f >= 0; f--) {
+            key[5] = f;
+            for (sint16 g = 255; g >= 0; g--) {
+                key[6] = g;
+                for (sint16 h = 255; h >= 0; h--) {
+					keys_tried++;
+                    key[7] = h;
+                    memcpy(S, keyinit, 256);
+                    int16 j = 0;
+                    int8 tmp = 0;
+                    for (int i = 0; i < 256; i++) {
+                        j = (j + S[i] + key[i % 8]) % 256;
+                        tmp = S[j];
+                        S[j] = S[i];
+                        S[i] = tmp;
+                    }
+                    int16 i = 0;
+                    j = 0;
+                    tmp = 0;
+                    int8 test_bytes[8];
+                    bool success = false;
+                    bool first_pass = false;
+                    for (int x = 0; x < 8; x++) {
+                        i = (i + 1);
+                        j = (j + S[i]) % 256;
+                        tmp = S[j];
+                        S[j] = S[i];
+                        S[i] = tmp;
+                        test_bytes[x] = S[(S[i] + S[j]) % 256];
+                        if (x < 3) {
+                            if (x == 0 && expected_result_lookup.count(test_bytes[x]) == 0)
+                                break;
+                            if (x == 1 && expected_result_lookup[test_bytes[0]].count(test_bytes[x]) == 0)
+                                break;
+                            if (x == 2) {
+                                if (expected_result_lookup[test_bytes[0]][test_bytes[1]].count(test_bytes[x]) == 0)
+                                    break;
+                                else
+                                    first_pass = true;
+                            }
+                        }
+                    }
+					int whichKey = 0;
+                    if (first_pass) {
+                        vector<int32>::iterator data_itr;
+                        for (data_itr = expected_result_lookup[test_bytes[0]][test_bytes[1]][test_bytes[2]].begin(); data_itr != expected_result_lookup[test_bytes[0]][test_bytes[1]][test_bytes[2]].end(); data_itr++) {
+                            whichKey = *data_itr / 10;
+							int8* data = alldata + *data_itr;
+                            for (int8 x = 3; x < 8; x++) {
+                                if ((test_bytes[x] ^ data[x]) != expected_result[x])
+                                    break;
+                                if (x == 7)
+                                    success = true;
+                            }
+                        }
+                    }
+                    if (success) {			
+                        string foundkey = "";
+                        char output[4];
+                        for (int o = 0; o < 8; o++) {
+                            snprintf(output, 3, "%02X", (unsigned char)key[o]);
+                            foundkey.append(output);
+                        }
+			if(outFile) {
+	                        std::string data("FOUND KEY: " + foundkey + " based on key " + filenames[whichKey]);
+				fwrite(data.c_str(),sizeof(char),data.size(),outFile);
+			}
+                        cout << "FOUND KEY: " << foundkey.c_str() << " based on key " << filenames[whichKey] << endl;
+                        total_found += 1;
+                    }
+                }
+            }
+            current_work++;
+        }
+	double fraction = ((double)(current_work)) / ((double)total_work);
+	if(fraction > 1.0) {
+		fraction = 1.0;
+	}
+
+#ifdef BOINC_APPLICATION
+	boinc_fraction_done(fraction);
+#endif
+
+       cout << "percent done: " << ((double)(current_work)) / ((double)total_work) << " keys tried " << keys_tried << endl;
+        key6 = 255;
+        if(key[4] > 0)
+            key[4]--;
+    }
+    return total_found;
+}

BIN
EQ2/devtools/EQ2VoiceRecover/testbin.dat