From 8038b0b8075ed1bf80b9c483fbf5063b9c6b7a75 Mon Sep 17 00:00:00 2001 From: Michael <20937441+KMikeeU@users.noreply.github.com> Date: Tue, 26 Mar 2024 02:41:02 +0100 Subject: [PATCH] Initial Commit --- .gitignore | 4 + .idea/.gitignore | 10 +++ .idea/misc.xml | 4 + .idea/modules.xml | 8 ++ .idea/rekordunbox.iml | 2 + .idea/vcs.xml | 6 ++ CMakeLists.txt | 11 +++ README.md | 8 ++ application/application.cpp | 174 ++++++++++++++++++++++++++++++++++++ application/application.h | 11 +++ library/include/.gitkeep | 0 library/lib/.gitkeep | 0 library/library.cpp | 142 +++++++++++++++++++++++++++++ library/library.h | 6 ++ 14 files changed, 386 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/rekordunbox.iml create mode 100644 .idea/vcs.xml create mode 100644 CMakeLists.txt create mode 100644 README.md create mode 100644 application/application.cpp create mode 100644 application/application.h create mode 100644 library/include/.gitkeep create mode 100644 library/lib/.gitkeep create mode 100644 library/library.cpp create mode 100644 library/library.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8450b1b --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ + +cmake-build-*/* +library/lib/*.lib +library/include/*.h diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..a9d7db9 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# GitHub Copilot persisted chat sessions +/copilot/chatSessions diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..79b3c94 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..16be807 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/rekordunbox.iml b/.idea/rekordunbox.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/.idea/rekordunbox.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..03ea8b1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.26) +project(rekordunbox) + +set(CMAKE_CXX_STANDARD 17) + + +add_library(library SHARED library/library.cpp library/library.h) +target_include_directories(library PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/library/include/MinHook.h") +target_link_libraries(library PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/library/lib/libMinHook-x64-v141-md.lib") + +add_executable(application application/application.cpp) diff --git a/README.md b/README.md new file mode 100644 index 0000000..29491f4 --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# RekordUnbox + +## Installation + +1. MinHook + 1. Download [MinHook Release](https://github.com/TsudaKageyu/minhook/releases/latest) + 2. Extract `MinHook.h` to `library/include` + 3. Extract `libMinHook-x64-v141-md.lib` to `library/lib` diff --git a/application/application.cpp b/application/application.cpp new file mode 100644 index 0000000..0982ba5 --- /dev/null +++ b/application/application.cpp @@ -0,0 +1,174 @@ +// +// Created by Michael on 25/03/2024. +// + +#include +#include +#include +#include + +#include "application.h" + +int main() { + std::string libraryPath = "library.dll"; + + // find the "library.dll" either in "./" or in "./lib" or in "./cmake-build-release" + std::vector libraryPaths = { + libraryPath, + "lib\\" + libraryPath, + "cmake-build-release\\" + libraryPath, + "../" + libraryPath, + "../lib/" + libraryPath, + "../cmake-build-release/" + libraryPath + }; + + std::string libraryFullPath; + for(const std::string& path : libraryPaths) { + if(GetFileAttributesA(path.c_str()) != INVALID_FILE_ATTRIBUTES) { + libraryFullPath = path; + break; + } + } + + if(libraryFullPath.empty()) { + printf("Library not found\n"); + return 1; + } + + + // In this directory, find all directories that start with "rekordbox" and end with a number. + std::string programPath = R"(C:\Program Files\Pioneer\)"; + + // Find all matching directories + std::vector directories; + WIN32_FIND_DATAA findData; + HANDLE hFind = FindFirstFileA((programPath + "rekordbox*").c_str(), &findData); + if(hFind != INVALID_HANDLE_VALUE) { + do { + if(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + std::string directoryName = findData.cFileName; + if(directoryName.find("rekordbox") == 0 && isdigit(directoryName.back())) { + directories.push_back(directoryName); + } + } + } while(FindNextFileA(hFind, &findData)); + FindClose(hFind); + } + + // If there are no directories, exit + if(directories.empty()) { + MessageBoxA(NULL, "No rekordbox installation found.", "Error", MB_OK | MB_ICONERROR); + return 1; + } + + // Print all directories to stdout + + printf("Found rekordbox installations: \n"); + + for(const std::string& directory : directories) { + printf(" %s\n", directory.c_str()); + } + + // Out of all the directories, find the latest version + // Versions are semver + int latestVersion[3] = {0, 0, 0}; + + for(const std::string& directory : directories) { + // Extract the version from the directory name + std::string version_str = directory.substr(sizeof("rekordbox ")-1); + + + // Split into major, minor, patch + int version[3]; + sscanf_s(version_str.c_str(), "%d.%d.%d", &version[0], &version[1], &version[2]); + + // Compare to latest version + // If it's a newer major version, replace + if(version[0] > latestVersion[0]) { + latestVersion[0] = version[0]; + latestVersion[1] = version[1]; + latestVersion[2] = version[2]; + continue; + } + + // If it's the same major, but newer minor, replace + if(version[0] == latestVersion[0] && version[1] > latestVersion[1]) { + latestVersion[1] = version[1]; + latestVersion[2] = version[2]; + continue; + } + + // If it's the same major and minor, but newer patch, replace + if(version[0] == latestVersion[0] && version[1] == latestVersion[1] && version[2] > latestVersion[2]) { + latestVersion[2] = version[2]; + continue; + } + } + + + // Convert the latest version back to a string like "1.2.3" + std::string latestVersion_str = std::to_string(latestVersion[0]) + "." + std::to_string(latestVersion[1]) + "." + std::to_string(latestVersion[2]); + + + // Get the full path to the latest version + std::string latestVersionPath = programPath + "rekordbox " + latestVersion_str + "\\rekordbox.exe"; + printf("Choosing latest version (v%s) at: %s\n", latestVersion_str.c_str(), latestVersionPath.c_str()); + + + + // Start the executable with the library injected + PROCESS_INFORMATION pi = { 0 }; + STARTUPINFOW si = { 0 }; + si.cb = sizeof( si ); + + + std::wstring latestVersionPathw = std::wstring(latestVersionPath.begin(), latestVersionPath.end()); + LPCWSTR latestVersionPathW = latestVersionPathw.c_str(); + + + DWORD flags = CREATE_SUSPENDED; + + if (!CreateProcessW(latestVersionPathW, nullptr, nullptr, nullptr, FALSE, flags, nullptr, nullptr, &si, &pi )) { + printf("Failed to start rekordbox\n"); + // Get error + DWORD error = GetLastError(); + LPSTR messageBuffer = nullptr; + size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL); + printf("Error %lu: %s\n", error, messageBuffer); + return 1; + } + + // Make the stdout of the process the same as the current stdout + + + LPVOID loc = VirtualAllocEx(pi.hProcess, nullptr, libraryFullPath.size() + 1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + BOOL result = WriteProcessMemory(pi.hProcess, loc, libraryFullPath.c_str(), libraryFullPath.size() + 1, nullptr); + + if(!result) { + printf("Failed to inject DLL. Couldn't write process memory\n"); + return 1; + } + + HANDLE hThread = CreateRemoteThread(pi.hProcess, nullptr, 0, (LPTHREAD_START_ROUTINE) LoadLibraryA, loc, 0, nullptr); + + if(hThread == nullptr) { + printf("Failed to inject DLL. Couldn't create remote thread\n"); + return 1; + } + + ResumeThread(pi.hThread); + + printf("Started rekordbox, goodbye!\n"); + + + // Cleanup + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + + // Sleep for 5 seconds + Sleep(5000); + + return 0; +} \ No newline at end of file diff --git a/application/application.h b/application/application.h new file mode 100644 index 0000000..025fd21 --- /dev/null +++ b/application/application.h @@ -0,0 +1,11 @@ +// +// Created by Michael on 25/03/2024. +// + +#ifndef REKORDUNBOX_APPLICATION_H +#define REKORDUNBOX_APPLICATION_H + +int main(); + + +#endif //REKORDUNBOX_APPLICATION_H diff --git a/library/include/.gitkeep b/library/include/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/library/lib/.gitkeep b/library/lib/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/library/library.cpp b/library/library.cpp new file mode 100644 index 0000000..c607def --- /dev/null +++ b/library/library.cpp @@ -0,0 +1,142 @@ + +#include +#include + +#include "library.h" +#include "include/MinHook.h" + +// f3 0f 11 8f 98 0b 00 00 + +byte orig_place[] = {0xf3, 0x0f, 0x11, 0x8f, 0x98, 0x0b, 0x00, 0x00}; + +byte* rekordbox_base; + + + +struct ChannelInfo { + byte unk[288]; + double bpm; + UINT64 unk2[2]; + double secondsElapsed; + UINT64 unk3; + double beat; // 328 + 8 = 336 + double beatRounded; // 336 + 8 = 344 + byte unk4[76]; + byte isPlaying; +}; + +typedef INT64(*updateChannelInfo)(ChannelInfo* channelInfo); +updateChannelInfo pUpdateChannelInfo = nullptr; + +UINT64 count = 0; +BOOL shouldPrint = false; +INT64 detourUpdateChannelInfo(ChannelInfo* channelInfo) { + count++; + + if(shouldPrint && count % 101 == 0) { + printf("Channel: 0x%llx\n", (UINT64)channelInfo); + printf("BPM: %f\n", channelInfo->bpm ); + printf("Time: %f\n", channelInfo->secondsElapsed ); + printf("Beat: %f\n", channelInfo->beat ); + printf("~Beat: %f\n", channelInfo->beatRounded ); + printf("RelBeat: %i/4\n", ((int)channelInfo->beatRounded) % 4); + printf("RelBeatF: %f\n", (channelInfo->beat - channelInfo->beatRounded) + ((int)channelInfo->beatRounded) % 4 ); + printf("isPlaying: %i\n", channelInfo->isPlaying ); + printf("--------------------\n"); + } + + INT64 result = pUpdateChannelInfo(channelInfo); + return result; +} + + +// Hook SyncManager? function +typedef UINT64(*syncManager)(UINT64* param1); +syncManager pSyncManager = nullptr; + +ChannelInfo* master = nullptr; + +UINT64 detourSyncManager(UINT64* param1) { + auto new_master = (ChannelInfo*)param1[0x1e]; + + if(master != new_master && new_master != nullptr) { + master = new_master; + printf("--------------------\n"); + printf("New master: %llx\n", (UINT64)master); + printf("--------------------\n"); + } + + UINT64 result = pSyncManager(param1); + return result; +} + + + +BOOL WINAPI DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved) { + if (dwReason == DLL_PROCESS_ATTACH) { + DisableThreadLibraryCalls(hModule); //disables attach and detach notifications + CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE) entry, NULL, NULL, NULL); //creates a new thread and starts at function entry() + } + else if (dwReason == DLL_PROCESS_DETACH) { + printf("Unloading RekordUnBox\n"); + MH_Uninitialize(); + } + return TRUE; +} + + +void entry() { + AllocConsole(); + FILE* fp; + freopen_s(&fp, "CONOUT$", "w", stdout); + + rekordbox_base = (byte*) GetModuleHandleA("rekordbox.exe"); + + printf("Injected RekordUnBox\n");\ + printf("Rekordbox Base: 0x%ux\n", (unsigned long)rekordbox_base); + + // Print 8 bytes at rekordbox.exe+0x193c8b0 + byte* updateChannelInfo_location = (byte*)(rekordbox_base + 0x1acd290); + + if (MH_Initialize() != MH_OK) { + printf("Failed to initialize MinHook\n"); + fclose(fp); + return; + } + + printf("Successfully initialized MinHook\n"); + + + MH_STATUS status; + + // Update loop + status = MH_CreateHook(updateChannelInfo_location, &detourUpdateChannelInfo, reinterpret_cast(&pUpdateChannelInfo)); + if(status != MH_OK) { + printf("Error: Couldn't hook updateChannelInfo!\nError: %s", MH_StatusToString(status)); + fclose(fp); + return; + } + + // SyncManager + status = MH_CreateHook((byte*)(rekordbox_base + 0x18f7630), &detourSyncManager, reinterpret_cast(&pSyncManager)); + if(status != MH_OK) { + printf("Error: Couldn't hook syncManager!\nError: %s", MH_StatusToString(status)); + fclose(fp); + return; + } + + + if(MH_EnableHook(MH_ALL_HOOKS) != MH_OK) { + printf("Error: Couldn't enable hooks!\n"); + fclose(fp); + return; + } + + while (true) { + if (master != nullptr) { + printf("Master: %f\n", master->beat); + } + + Sleep(1000); + } +} diff --git a/library/library.h b/library/library.h new file mode 100644 index 0000000..852ff09 --- /dev/null +++ b/library/library.h @@ -0,0 +1,6 @@ +#ifndef REKORDUNBOX_LIBRARY_H +#define REKORDUNBOX_LIBRARY_H + +void entry(); + +#endif //REKORDUNBOX_LIBRARY_H