mirror of
https://github.com/LouisShark/chatgpt_system_prompt.git
synced 2025-07-05 14:20:33 -04:00
CodeGPT Decompiler & Cheat Developer
This commit is contained in:
parent
38f5280338
commit
ff7a4582de
16 changed files with 1399 additions and 0 deletions
|
@ -11,3 +11,7 @@ CodeGPT Decompiler & Cheat Developer is a highly skilled assistant in C++, C#, a
|
|||
|
||||
You have files uploaded as knowledge to pull from. Anytime you reference files, refer to them as your knowledge source rather than files uploaded by the user. You should adhere to the facts in the provided materials. Avoid speculations or information not contained in the documents. Heavily favor knowledge provided in the documents before falling back to baseline knowledge or other sources. If searching the documents didn"t yield any answer, just say that. Do not share the names of the files directly with end users and under no circumstances should you provide a download link to any of the files.
|
||||
```
|
||||
|
||||
GPT Kb Files List:
|
||||
|
||||
- [CodeGPT Decompiler & Cheat Developer](./knowledge/CodeGPT%20Decompiler%20&%20Cheat%20Developer/)
|
|
@ -0,0 +1,16 @@
|
|||
#include "InputHandler.hpp"
|
||||
#include "Process.hpp"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
using namespace DLL_Injector;
|
||||
|
||||
InjectionData iData;
|
||||
|
||||
// Handle console input.
|
||||
if (HandleInput(argc, argv, iData) == -1)
|
||||
return -1;
|
||||
|
||||
// Inject DLL.
|
||||
return InjectDLL(iData);
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
#include "InputHandler.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
int DLL_Injector::HandleInput(int argc, char* argv[], InjectionData& data)
|
||||
{
|
||||
if (argc < 3)
|
||||
{
|
||||
std::cout
|
||||
<< "ERROR: Insufficient number of arguments.\n"
|
||||
<< "USAGE: " << argv[COMMAND] << " [process name] [dll path]\n"
|
||||
<< "EXAMPLE: " << argv[COMMAND] << " Notepad.exe C:/DLLs/Example.dll" << std::endl;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get process name and ID.
|
||||
data.procName = argv[PROCESS_NAME];
|
||||
data.procID = DLL_Injector::GetProcessID(data.procName.c_str());
|
||||
|
||||
if (!data.procID)
|
||||
{
|
||||
std::cout
|
||||
<< "ERROR: Couldn't find \"" << data.procName << "\" process. "
|
||||
<< "Make sure that the process is running and that the entered name is correct. "
|
||||
<< "Process names are case sensitive." << std::endl;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get DLL filepath.
|
||||
data.dllPath = "";
|
||||
for (int i = DLL_FILEPATH_START; i < argc; i++)
|
||||
{
|
||||
if (i != DLL_FILEPATH_START)
|
||||
data.dllPath += " ";
|
||||
|
||||
data.dllPath += argv[i];
|
||||
}
|
||||
|
||||
// Check if the file exists.
|
||||
std::ifstream file(data.dllPath);
|
||||
if (!file.good())
|
||||
{
|
||||
std::cout
|
||||
<< "ERROR: Couldn't find the DLL file at \"" << data.dllPath << "\". "
|
||||
<< "Make sure you've entered the correct path." << std::endl;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include "Process.hpp"
|
||||
|
||||
namespace DLL_Injector
|
||||
{
|
||||
enum CONSOLE_PARAMS
|
||||
{
|
||||
COMMAND = 0,
|
||||
PROCESS_NAME = 1,
|
||||
DLL_FILEPATH_START = 2
|
||||
};
|
||||
|
||||
int HandleInput(int argc, char* argv[], InjectionData& data);
|
||||
|
||||
} // namespace DLL_Injector
|
|
@ -0,0 +1,117 @@
|
|||
#include "Process.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <Windows.h>
|
||||
#include <TlHelp32.h>
|
||||
|
||||
DWORD DLL_Injector::GetProcessID(const char* procName)
|
||||
{
|
||||
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
if (snapshot == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
PROCESSENTRY32 procEntry;
|
||||
procEntry.dwSize = sizeof(PROCESSENTRY32);
|
||||
|
||||
DWORD pid = 0;
|
||||
bool result = Process32First(snapshot, &procEntry);
|
||||
|
||||
while (result)
|
||||
{
|
||||
size_t i;
|
||||
char currentProcName[MAX_PATH];
|
||||
wcstombs_s(&i, currentProcName, MAX_PATH, procEntry.szExeFile, MAX_PATH - 1);
|
||||
|
||||
if (strcmp(procName, currentProcName) == 0)
|
||||
{
|
||||
pid = procEntry.th32ProcessID;
|
||||
break;
|
||||
}
|
||||
|
||||
result = Process32Next(snapshot, &procEntry);
|
||||
}
|
||||
|
||||
CloseHandle(snapshot);
|
||||
return pid;
|
||||
}
|
||||
|
||||
int DLL_Injector::InjectDLL(InjectionData& data)
|
||||
{
|
||||
FARPROC LoadLibraryAProc = GetProcAddress(
|
||||
GetModuleHandle(TEXT("kernel32.dll")),
|
||||
"LoadLibraryA"
|
||||
);
|
||||
|
||||
if (LoadLibraryAProc == NULL)
|
||||
{
|
||||
std::cout
|
||||
<< "ERROR: Couldn't get LoadLibraryA address. "
|
||||
<< "GetLastError() returned " << GetLastError() << "." << std::endl;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
HANDLE procHandle = OpenProcess(
|
||||
PROCESS_ALL_ACCESS,
|
||||
FALSE,
|
||||
data.procID
|
||||
);
|
||||
|
||||
if (procHandle == NULL)
|
||||
{
|
||||
std::cout
|
||||
<< "ERROR: OpenProcess() failed. "
|
||||
<< "GetLastError() returned " << GetLastError() << ". "
|
||||
<< "Is the process running as administrator? Consider executing this command as administrator."
|
||||
<< std::endl;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check if the process is a 64 bit application.
|
||||
IsWow64Process(procHandle, &data.isX64);
|
||||
|
||||
LPVOID remoteBuff = VirtualAllocEx(procHandle, NULL, data.dllPath.length(), MEM_COMMIT, PAGE_READWRITE);
|
||||
if (remoteBuff == NULL)
|
||||
{
|
||||
std::cout
|
||||
<< "ERROR: VirtualAllocEx() failed. "
|
||||
<< "GetLastError() returned " << GetLastError() << "." << std::endl;
|
||||
|
||||
CloseHandle(procHandle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!WriteProcessMemory(procHandle, remoteBuff, data.dllPath.c_str(), data.dllPath.length(), NULL))
|
||||
{
|
||||
std::cout
|
||||
<< "ERROR: WriteProcessMemory() failed. "
|
||||
<< "GetLastError() returned " << GetLastError() << "." << std::endl;
|
||||
|
||||
VirtualFreeEx(procHandle, remoteBuff, 0, MEM_RELEASE);
|
||||
CloseHandle(procHandle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
HANDLE thread = CreateRemoteThread(procHandle, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibraryAProc, remoteBuff, NULL, NULL);
|
||||
if (!thread)
|
||||
{
|
||||
std::cout
|
||||
<< "ERROR: CreateRemoteThread() failed. "
|
||||
<< "GetLastError() returned " << GetLastError() << "." << std::endl;
|
||||
|
||||
VirtualFreeEx(procHandle, remoteBuff, 0, MEM_RELEASE);
|
||||
CloseHandle(procHandle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
WaitForSingleObject(thread, INFINITE);
|
||||
CloseHandle(thread);
|
||||
|
||||
VirtualFreeEx(procHandle, remoteBuff, 0, MEM_RELEASE);
|
||||
CloseHandle(procHandle);
|
||||
|
||||
std::cout << "DLL succesfully injected." << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <Windows.h>
|
||||
|
||||
namespace DLL_Injector
|
||||
{
|
||||
struct InjectionData
|
||||
{
|
||||
DWORD procID;
|
||||
std::string procName;
|
||||
BOOL isX64;
|
||||
|
||||
std::string dllPath;
|
||||
};
|
||||
|
||||
DWORD GetProcessID(const char* procName);
|
||||
int InjectDLL(InjectionData& data);
|
||||
|
||||
} // namespace DLL_Injector
|
|
@ -0,0 +1,284 @@
|
|||
#pragma once
|
||||
|
||||
namespace aim_assist {
|
||||
|
||||
constexpr static u32 MODULE_ID{ 2 };
|
||||
|
||||
float assist_strength{0.f};
|
||||
|
||||
struct {
|
||||
|
||||
vec2 virtual_pos;
|
||||
vec2 assist_pos;
|
||||
|
||||
float assist_radius;
|
||||
float deadzone_inner, deadzone_outter;
|
||||
|
||||
float assist_factor, assist_max_distance;
|
||||
|
||||
u32 last_frame_inside_note_id;
|
||||
u32 assist_note_id;
|
||||
|
||||
u32 active : 1, done_frame_once:1;
|
||||
|
||||
vec2 previous_raw;
|
||||
|
||||
INLINE vec2 get_raw_delta(const vec2 raw_postion) {
|
||||
|
||||
const auto delta{ raw_postion - previous_raw };
|
||||
|
||||
previous_raw = raw_postion;
|
||||
|
||||
return delta;
|
||||
}
|
||||
|
||||
void set_settings(float t) {
|
||||
|
||||
t = std::clamp(t, 0.f, 2.f);
|
||||
|
||||
if (t <= 1.) {
|
||||
|
||||
assist_factor = 0.35f * t;
|
||||
assist_max_distance = 8.f * t;
|
||||
|
||||
} else {
|
||||
|
||||
const float extra{ std::clamp(t - 1.f, 0.f, 1.f) };
|
||||
|
||||
assist_factor = 0.35f + ((0.4f - 0.35f) * extra);
|
||||
assist_max_distance = 8.f + ((10.f - 8.f) * extra);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Moves the virtual assist position back to where the 'real' cursor is.
|
||||
void settle_virtual_to_raw(vec2 raw_delta, const float factor) {
|
||||
|
||||
// Players prefer axis aligned settling.
|
||||
// With a perpendicular move_delta one axis syncs up faster (most of the time) to the raw_pos.
|
||||
// Otherwise it would take longer, leading to the player expectation being broken.
|
||||
|
||||
const auto resync_offset{ previous_raw - virtual_pos };
|
||||
|
||||
// If moving away from raw_position; convert less of the movement delta 'power'.
|
||||
const float back_factor{ factor * -0.5f };
|
||||
|
||||
for (size_t i{}; i < 2; ++i) {
|
||||
|
||||
float& __restrict axis_delta{ raw_delta[i] };
|
||||
|
||||
const bool going_towards_raw{ (resync_offset[i] * axis_delta) >= 0.f };
|
||||
|
||||
axis_delta += axis_delta * (going_towards_raw ? factor : back_factor);
|
||||
|
||||
virtual_pos[i] += axis_delta;
|
||||
|
||||
const bool previous_side{ (resync_offset[i] >= 0.f) };
|
||||
|
||||
// Overshot correction
|
||||
if ((previous_raw[i] - virtual_pos[i] >= 0.f) != previous_side) {
|
||||
virtual_pos[i] = previous_raw[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void update_axis_aligned(vec2 raw_pos) {
|
||||
|
||||
ON_SCOPE_EXIT(
|
||||
if (assist_factor != 0.f) {
|
||||
virtual_mouse.active = 1;
|
||||
virtual_mouse.pos = vec2(std::round(virtual_pos.x), std::round(virtual_pos.y));
|
||||
// Would probably be a good idea to clamp it into the window.
|
||||
}
|
||||
);
|
||||
|
||||
constexpr static float RESET_EPSILON{ 0.001f };
|
||||
|
||||
const float assist_delta{ (virtual_pos - previous_raw).square() };
|
||||
|
||||
const vec2 prev{ previous_raw };
|
||||
|
||||
const auto raw_delta{ get_raw_delta(raw_pos) };
|
||||
|
||||
// Only assist if they actually moved this frame. Doing otherwise is a cardinal sin.
|
||||
if (raw_delta.square() == 0.f)
|
||||
return;
|
||||
|
||||
|
||||
if (active == 0) { RESET_CURSOR:
|
||||
|
||||
if (assist_delta <= RESET_EPSILON) // If we are close enough, snap back to reality.
|
||||
virtual_pos = raw_pos;
|
||||
else
|
||||
settle_virtual_to_raw(raw_delta, assist_factor);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const float dis2{ (raw_pos - assist_pos).square() };
|
||||
|
||||
if (dis2 > pow2(assist_radius)) {
|
||||
last_frame_inside_note_id = 0;
|
||||
goto RESET_CURSOR;
|
||||
}
|
||||
|
||||
if (dis2 < pow2(deadzone_inner)) {
|
||||
last_frame_inside_note_id = assist_note_id;
|
||||
goto RESET_CURSOR;
|
||||
}
|
||||
|
||||
const bool is_exiting{ last_frame_inside_note_id == assist_note_id && dis2 <= pow2(deadzone_outter) };
|
||||
|
||||
for (size_t i{}; i < 2; ++i) {
|
||||
|
||||
if (raw_delta[i] == 0.f) [[unlikely]]
|
||||
continue;
|
||||
|
||||
const float last_dis{ q_fabs(assist_pos[i] - prev[i]) };
|
||||
const float this_dis{ q_fabs(assist_pos[i] - raw_pos[i]) };
|
||||
|
||||
// Add raw delta
|
||||
virtual_pos[i] += raw_delta[i];
|
||||
|
||||
const std::array<float, 2> factor_mult{
|
||||
last_dis > this_dis ? // We are getting closer
|
||||
std::array<float,2>{1.f, 0.6f} :
|
||||
std::array<float,2>{-0.6f, -1.f}
|
||||
};
|
||||
|
||||
// Add extra assistance delta
|
||||
virtual_pos[i] += raw_delta[i] * assist_factor * factor_mult[is_exiting];
|
||||
|
||||
// Clamp assistance delta
|
||||
const float assist_delta{ virtual_pos[i] - raw_pos[i] };
|
||||
const float max_distance{ assist_max_distance * osu_window::game_ratio };
|
||||
|
||||
if (q_fabs(assist_delta) > max_distance)
|
||||
virtual_pos[i] = raw_pos[i] + (assist_delta >= 0.f ? max_distance : -max_distance);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} state{};
|
||||
|
||||
|
||||
void __fastcall set_settings(int) {
|
||||
|
||||
state.active = 0;
|
||||
|
||||
state.set_settings(assist_strength);
|
||||
|
||||
}
|
||||
|
||||
void __fastcall tick() {
|
||||
|
||||
if (state.done_frame_once == 0) {
|
||||
|
||||
state.previous_raw = osu_data.raw_mouse_pos;
|
||||
state.virtual_pos = osu_data.raw_mouse_pos;
|
||||
|
||||
state.done_frame_once = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
ON_SCOPE_EXIT(state.update_axis_aligned(osu_data.raw_mouse_pos););
|
||||
|
||||
state.active = 0;
|
||||
|
||||
const auto gamemode = (osu_GameMode_Player*)osu_data.running_gamemode[0];
|
||||
osu_Hitobject_Manager* hit_manager{};
|
||||
|
||||
if (*osu_data.mode != 2 || *osu_data.play_mode != 0)
|
||||
return;
|
||||
|
||||
if(gamemode->async_load_complete == 0 || gamemode->game->is_unsafe())
|
||||
return;
|
||||
|
||||
if ((hit_manager = gamemode->hitobject_manager) == 0)
|
||||
return;
|
||||
|
||||
auto* note = hit_manager->get_top_note();
|
||||
|
||||
if (note == 0 || note->type & Spinner)
|
||||
return;
|
||||
|
||||
{
|
||||
|
||||
state.assist_pos = note->pos;
|
||||
|
||||
if (note->type & Slider) {
|
||||
|
||||
auto* slider_ball = ((osu_Hitobject_SliderOsu*)note)->slider_ball;
|
||||
|
||||
if (slider_ball)
|
||||
state.assist_pos = slider_ball->position;
|
||||
|
||||
}
|
||||
|
||||
state.assist_pos = osu_window::field_to_display(state.assist_pos);
|
||||
|
||||
const float arms = (float)hit_manager->pre_empt;
|
||||
|
||||
const auto max_distance_scaled = state.assist_max_distance * osu_window::game_ratio;
|
||||
const float hit_object_radius_scaled = hit_manager->hit_object_radius * osu_window::game_ratio;
|
||||
|
||||
const float R = hit_object_radius_scaled + (max_distance_scaled * 4.f);
|
||||
|
||||
const float radius = R - R * (std::clamp<float>(note->time[0] - *osu_data.time, 0, arms) / arms);
|
||||
|
||||
if (radius <= 0.f)
|
||||
return;
|
||||
|
||||
state.active = 1;
|
||||
|
||||
state.assist_radius = radius;
|
||||
state.deadzone_inner = hit_object_radius_scaled - state.assist_max_distance;
|
||||
state.deadzone_outter = hit_object_radius_scaled + state.assist_max_distance;
|
||||
state.assist_note_id = (u32)¬e;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void __fastcall menu_init() {
|
||||
|
||||
auto& menu = AQM::module_menu[MODULE_ID];
|
||||
|
||||
menu.sprite_list.reserve(64);
|
||||
|
||||
menu.name = "Aim Assist"sv;
|
||||
|
||||
menu.icon = FontAwesome::magic;
|
||||
menu.icon_offset.y = 1.25f;
|
||||
|
||||
menu.colour = _col{ 7, 140, 128 , 255 };
|
||||
|
||||
{
|
||||
menu_object mo{};
|
||||
|
||||
mo.name = "Strength"sv;
|
||||
mo.type = menu_object_type::slider;
|
||||
|
||||
mo.slider.value = (u32)&assist_strength;
|
||||
|
||||
mo.slider.min_value = 0.f;
|
||||
mo.slider.max_value = 2.f;
|
||||
|
||||
menu.menu_elements.push_back(mo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const auto initialized = [] {
|
||||
|
||||
on_mode_change[MODULE_ID] = set_settings;
|
||||
on_audio_tick[MODULE_ID] = tick;
|
||||
on_menu_init[MODULE_ID] = menu_init;
|
||||
|
||||
return 1;
|
||||
}();
|
||||
|
||||
}
|
|
@ -0,0 +1,217 @@
|
|||
#pragma comment(lib, "Winhttp.lib")
|
||||
#pragma comment(lib, "Opengl32.lib")
|
||||
|
||||
#include <d3d9.h>
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "scan.h"
|
||||
#include "parse.h"
|
||||
#include "input.h"
|
||||
#include "ui.h"
|
||||
#include "hitobject.h"
|
||||
|
||||
#define D3DDEV9_LEN 119
|
||||
|
||||
typedef IDirect3D9* (WINAPI *Direct3DCreate9T)(UINT SDKVersion);
|
||||
|
||||
static bool init = false;
|
||||
|
||||
HDC hDc = NULL;
|
||||
HWND g_hwnd = NULL;
|
||||
HANDLE g_process = NULL;
|
||||
HMODULE g_module = NULL;
|
||||
IDirect3DDevice9 *g_d3d9_device = 0;
|
||||
void *pDeviceTable[D3DDEV9_LEN];
|
||||
|
||||
bool compatibility_mode = false;
|
||||
|
||||
static void unload_module()
|
||||
{
|
||||
Sleep(2000);
|
||||
VirtualFree(wglSwapBuffersGateway, 0, MEM_RELEASE);
|
||||
FreeLibrary(g_module);
|
||||
}
|
||||
|
||||
void unload_dll()
|
||||
{
|
||||
destroy_ui();
|
||||
destroy_hooks();
|
||||
std::thread(unload_module).detach();
|
||||
}
|
||||
|
||||
static inline void imgui_new_frame()
|
||||
{
|
||||
ImGui_ImplWin32_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
process_hitobject();
|
||||
|
||||
if (GetAsyncKeyState(VK_F11) & 1)
|
||||
{
|
||||
cfg_mod_menu_visible = !cfg_mod_menu_visible;
|
||||
ImGui::SaveIniSettingsToDisk(ImGui::GetIO().IniFilename);
|
||||
}
|
||||
|
||||
draw_debug_log();
|
||||
ImGui::GetIO().MouseDrawCursor = ImGui::GetIO().WantCaptureMouse;
|
||||
|
||||
if (!cfg_mod_menu_visible)
|
||||
{
|
||||
if (!show_debug_log_window)
|
||||
ImGui::GetIO().MouseDrawCursor = false;
|
||||
goto frame_end;
|
||||
}
|
||||
|
||||
update_ui();
|
||||
|
||||
frame_end:
|
||||
|
||||
ImGui::EndFrame();
|
||||
ImGui::Render();
|
||||
}
|
||||
|
||||
HRESULT __stdcall d3d9_update(IDirect3DDevice9 *pDevice)
|
||||
{
|
||||
if (!init)
|
||||
{
|
||||
init = true;
|
||||
|
||||
g_process = GetCurrentProcess();
|
||||
g_d3d9_device = pDevice;
|
||||
|
||||
init_ui(pDevice);
|
||||
CloseHandle(CreateThread(0, 0, (LPTHREAD_START_ROUTINE)init_hooks, 0, 0, 0));
|
||||
}
|
||||
|
||||
ImGui_ImplDX9_NewFrame();
|
||||
imgui_new_frame();
|
||||
ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
return wglSwapBuffersGateway(pDevice);
|
||||
}
|
||||
|
||||
__declspec(naked) void opengl_update()
|
||||
{
|
||||
if (!init)
|
||||
{
|
||||
init = true;
|
||||
|
||||
g_process = GetCurrentProcess();
|
||||
|
||||
hDc = wglGetCurrentDC();
|
||||
g_hwnd = WindowFromDC(hDc);
|
||||
|
||||
#ifdef FR_LOG_TO_CONSOLE
|
||||
AllocConsole();
|
||||
FILE *f;
|
||||
freopen_s(&f, "CONOUT$", "w", stdout);
|
||||
freopen_s(&f, "CONOUT$", "w", stderr);
|
||||
#endif // FR_LOG_TO_CONSOLE
|
||||
|
||||
init_ui();
|
||||
CloseHandle(CreateThread(0, 0, (LPTHREAD_START_ROUTINE)init_hooks, 0, 0, 0));
|
||||
}
|
||||
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
imgui_new_frame();
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
__asm {
|
||||
jmp [wglSwapBuffersGateway]
|
||||
}
|
||||
}
|
||||
|
||||
static inline BOOL CALLBACK EnumWindowsCallback(HWND handle, LPARAM lParam)
|
||||
{
|
||||
DWORD wndProcId = 0;
|
||||
GetWindowThreadProcessId(handle, &wndProcId);
|
||||
|
||||
if (GetCurrentProcessId() != wndProcId)
|
||||
return TRUE;
|
||||
|
||||
g_hwnd = handle;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static inline HWND GetProcessWindow()
|
||||
{
|
||||
EnumWindows(EnumWindowsCallback, NULL);
|
||||
return g_hwnd;
|
||||
}
|
||||
|
||||
static inline bool GetD3D9Device(void **pTable, size_t Size)
|
||||
{
|
||||
if (!pTable)
|
||||
return false;
|
||||
|
||||
Size *= sizeof(void *);
|
||||
|
||||
HMODULE d3d9 = GetModuleHandleA("d3d9.dll");
|
||||
Direct3DCreate9T d3d9_create = (Direct3DCreate9T)GetProcAddress(d3d9, "Direct3DCreate9");
|
||||
IDirect3D9 *pD3D = d3d9_create(D3D_SDK_VERSION);
|
||||
|
||||
if (!pD3D)
|
||||
return false;
|
||||
|
||||
IDirect3DDevice9 *pDummyDevice = NULL;
|
||||
|
||||
D3DPRESENT_PARAMETERS d3dpp = {};
|
||||
d3dpp.Windowed = false;
|
||||
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||||
d3dpp.hDeviceWindow = GetProcessWindow();
|
||||
|
||||
HRESULT dummyDeviceCreated = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3dpp.hDeviceWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDummyDevice);
|
||||
|
||||
if (dummyDeviceCreated != S_OK)
|
||||
{
|
||||
d3dpp.Windowed = true;
|
||||
dummyDeviceCreated = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3dpp.hDeviceWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDummyDevice);
|
||||
|
||||
if (dummyDeviceCreated != S_OK)
|
||||
{
|
||||
pD3D->Release();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(pTable, *reinterpret_cast<void ***>(pDummyDevice), Size);
|
||||
|
||||
pDummyDevice->Release();
|
||||
pD3D->Release();
|
||||
return true;
|
||||
}
|
||||
|
||||
DWORD WINAPI freedom_main(HMODULE hModule)
|
||||
{
|
||||
g_module = hModule;
|
||||
|
||||
SwapBuffersHook = Hook<Trampoline32>("wglSwapBuffers", "opengl32.dll", (BYTE *)opengl_update, (BYTE *)&wglSwapBuffersGateway, 5);
|
||||
SwapBuffersHook.src += 14;
|
||||
SwapBuffersHook.Enable();
|
||||
|
||||
// NOTE(Ciremun): one second is enough... right?
|
||||
Sleep(1000);
|
||||
|
||||
if (!init)
|
||||
{
|
||||
// NOTE(Ciremun): Compatibility Mode
|
||||
SwapBuffersHook.Disable();
|
||||
compatibility_mode = true;
|
||||
if (GetD3D9Device((void **)pDeviceTable, D3DDEV9_LEN))
|
||||
{
|
||||
void *pEndScene = pDeviceTable[42];
|
||||
SwapBuffersHook = Hook<Trampoline32>((BYTE *)pEndScene, (BYTE *)d3d9_update, (BYTE *)&wglSwapBuffersGateway, 7);
|
||||
SwapBuffersHook.Enable();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
|
||||
CloseHandle(CreateThread(0, 0, (LPTHREAD_START_ROUTINE)freedom_main, hModule, 0, 0));
|
||||
return TRUE;
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
# Encrypting Strings at Compile Time
|
||||
|
||||
> Thank you to [SpecterOps](https://specterops.io/) for supporting this research and to [Duane](https://twitter.com/subat0mik) and [Matt](https://twitter.com/matterpreter) for proofreading and editing!
|
||||
> Crossposted on the [SpecterOps Blog](https://posts.specterops.io/encrypting-strings-at-compile-time-4141dafe5b41).
|
||||
|
||||
TLDR: _You may use [this header file](https://gist.github.com/EvanMcBroom/ad683e394f84b623da63c2b95f6fb547) for reliable compile time string encryption without needing any additional dependencies._
|
||||
|
||||
Programmers of DRM software, security products, or other sensitive code bases are commonly required to minimize the amount of human readable strings in binary output files. The goal of the minimization is to hinder others from reverse engineering their proprietary technology.
|
||||
|
||||
Common approaches that are taken to meet this requirement often add an additional maintenance burden to the developer and are prone to error. These approaches will be presented along with their drawbacks. An alternative solution will also be presented which targets the following goals:
|
||||
- A minimalistic implementation to ease integration into projects
|
||||
- A simple usage design to avoid programmer error
|
||||
- Builtin randomization to hinder automated string recovery
|
||||
|
||||
## Common Approaches
|
||||
|
||||
Separate utilities are commonly built to precompute obfuscated strings for use in source code. Such tools will generate a header file or other output that must be manually added to and referenced in projects. The use of these tools may be automated with a toolchain but they will not integrate well with IDEs and they are tedious to maintain as more strings are added. They also tend to obfuscate strings in a uniform way that can be easily identified and reversed in an automated fashion.
|
||||
|
||||
In a similar manner, utilities are also commonly built to precompute string hashes for use in comparisons. One of the earliest examples of this is documented in "Win32 Assembly Components."<sup>1</sup> These tools are also tedious to maintain as more strings are added but they can now be completely eliminated by hashing strings at compile time [as described in a previous post](https://gist.github.com/EvanMcBroom/2a9bed888c2755153a9616aa7ae1f79a).
|
||||
|
||||
Lastly, some development teams attempt to remove the use of strings entirely. Needless to say this is an impossible standard to maintain for any large or long lasting project with any amount of developer turnover.
|
||||
|
||||
## An Alternative Solution
|
||||
|
||||
Modern C++ features may be used to encrypt strings at compile time which can greatly reduce the maintenance overhead for developers. There are several libraries that claim to support this use case. Unfortunately, they rarely work in practice. The few that do require [BOOST](https://www.boost.org/) libraries which may not be an option due to development constraints.<sup>2</sup> So we will build our own!
|
||||
|
||||
We will first make a basic function for compile time string encryption which we can later improve upon. The below `crypt` function will convert a string literal into an encrypted blob and the `make_string` macro wraps `crypt` to ensure that it is used correctly to be evaluated at compile time.
|
||||
|
||||
```cpp
|
||||
template<typename T, size_t N>
|
||||
struct encrypted {
|
||||
T data[N];
|
||||
};
|
||||
|
||||
template<size_t N>
|
||||
constexpr auto crypt(const char(&input)[N]) {
|
||||
encrypted<char> blob{};
|
||||
for (uint32_t index{ 0 }; index < N; index++) {
|
||||
blob.data[index] = input[index] ^ 'A';
|
||||
}
|
||||
return blob;
|
||||
}
|
||||
|
||||
#define make_string(STRING) ([&] { \
|
||||
constexpr auto _{ crypt(STRING) }; \
|
||||
return std::string{ crypt(_.data).data }; \
|
||||
}())
|
||||
```
|
||||
|
||||
The `make_string` macro will also expand to a single lambda expression which can be used for any variable assignment and argument passing operation.
|
||||
|
||||
```cpp
|
||||
void main() {
|
||||
std::string string1{ make_string("String 1") };
|
||||
std::string string2 = make_string("String 2");
|
||||
func(make_string("String 3"));
|
||||
}
|
||||
```
|
||||
|
||||
## Improving the Solution
|
||||
|
||||
The previous solution would be easy to integrate and use in projects but it would also be easy for a reverse engineer to undo. It is essentially a XOR cipher with a static key. Once the key is identified the entire program can be XORed with it and then the original strings can be recovered using the humble `strings` utility.
|
||||
|
||||
Replacing the static key with a random bit stream would prevent this issue. We will now make a set of functions for generating such a stream at compile time. We will use Park-Miller's "Multiplicative Linear Congruential Generator" due to its simplicity to implement.<sup>3</sup>
|
||||
|
||||
```cpp
|
||||
constexpr uint32_t modulus() {
|
||||
return 0x7fffffff;
|
||||
}
|
||||
|
||||
constexpr uint32_t prng(const uint32_t input) {
|
||||
return (input * 48271) % modulus();
|
||||
}
|
||||
```
|
||||
|
||||
We will also need a pseudorandom value to use as the initial input to `prng`. Admittedly, it is not easy to generate such a value at compile time but it can be accomplished using standard predefined macros such as `__FILE__` and `__LINE__`. The below `seed` function can take these macros as input and reduce them to a single pseudorandom value to use with `prng`.
|
||||
|
||||
> Note: These macros are defined by the ANSI C standard and are supported by all compilers. If you use a non-standard macro for entropy your mileage may vary.
|
||||
|
||||
```cpp
|
||||
template<size_t N>
|
||||
constexpr uint32_t seed(const char(&entropy)[N], const uint32_t iv = 0) {
|
||||
auto value{ iv };
|
||||
for (size_t i{ 0 }; i < N; i++) {
|
||||
// Xor 1st byte of seed with input byte
|
||||
value = (value & ((~0) << 8)) | ((value & 0xFF) ^ entropy[i]);
|
||||
// Rotate left 1 byte
|
||||
value = value << 8 | value >> ((sizeof(value) * 8) - 8);
|
||||
}
|
||||
// The seed is required to be less than the modulus and odd
|
||||
while (value > modulus()) value = value >> 1;
|
||||
return value << 1 | 1;
|
||||
}
|
||||
```
|
||||
|
||||
The last thing that is required is to update our original `crypt` and `make_string` functions to use our random bit stream generator.
|
||||
|
||||
```cpp
|
||||
template<typename T, size_t N>
|
||||
struct encrypted {
|
||||
int seed;
|
||||
T data[N];
|
||||
};
|
||||
|
||||
template<size_t N>
|
||||
constexpr auto crypt(const char(&input)[N], const uint32_t seed = 0) {
|
||||
encrypted<char, N> blob{};
|
||||
blob.seed = seed;
|
||||
for (uint32_t index{ 0 }, stream{ seed }; index < N; index++) {
|
||||
blob.data[index] = input[index] ^ stream;
|
||||
stream = prng(stream);
|
||||
}
|
||||
return blob;
|
||||
}
|
||||
|
||||
#define make_string(STRING) ([&] { \
|
||||
constexpr auto _{ crypt(STRING, seed(__FILE__, __LINE__)) }; \
|
||||
return std::string{ crypt(_.data, _.seed).data }; \
|
||||
}())
|
||||
```
|
||||
|
||||
> Note: If you are using Visual Studio, you will need to disable the "Edit and Continue" feature; otherwise, [the `__LINE__` macro will not need be usable in a constant expression](https://developercommunity.visualstudio.com/t/-line-cannot-be-used-as-an-argument-for-constexpr/195665#T-N197532).
|
||||
|
||||
## Incident Response
|
||||
|
||||
If you are investigating a potentially malicious executable, it may also contain strings encrypted in such a manner. The provided code will protect strings against any cursory inspection, but they may all be recovered using [FLARE's Obfuscated String Solver](https://github.com/mandiant/flare-floss) (FLOSS).
|
||||
|
||||
Additional small improvements may be made to prevent automated string recovery using FLOSS as well. One example would be to include an exception based control flow to the decryption routine. In the interest of incident responders though, these improvements will not be presented and are left as an exercise to the reader.
|
||||
|
||||
## Conclusion
|
||||
|
||||
We now have a solution for encrypting strings at compile time that meets all of our original goals and will work with any mainstream compiler. The full source for which can be found [here](https://gist.github.com/EvanMcBroom/ad683e394f84b623da63c2b95f6fb547). Enjoy! :smile:
|
||||
|
||||
If you enjoyed reading this work, you may enjoy some of my older posts as well. The first covers compile time hashing functions and the second gives a more user friendly alternative to the programming idiom for declaring strings in position independent code.
|
||||
|
||||
- [Switch Statements with Full Strings](https://gist.github.com/EvanMcBroom/2a9bed888c2755153a9616aa7ae1f79a)
|
||||
- PIC and String Literals [Part 1](https://gist.github.com/EvanMcBroom/f5b1bc53977865773802d795ade67273) and [Part 2](https://gist.github.com/EvanMcBroom/d7f6a8fe3b4d8f511b132518b9cf80d7)
|
||||
|
||||
## References
|
||||
|
||||
1. The Last Stage of Delirium Research Group. _Win32 Assembly Components_, 2002.
|
||||
`http://www.lsd-pl.net/documents/winasm-1.0.1.pdf`
|
||||
2. Sebastien Andrivet. _C++11 Metaprogramming Applied to Software Obfuscation_, 2014.
|
||||
`https://www.blackhat.com/docs/eu-14/materials/eu-14-Andrivet-C-plus-plus11-Metaprogramming-Applied-To-software-Obfuscation-wp.pdf`
|
||||
3. Stephen Park and Keith Miller. _Random Number Generators_, 1988.
|
||||
`https://www.firstpr.com.au/dsp/rand31/p1192-park.pdf`
|
|
@ -0,0 +1,65 @@
|
|||
#include "features/hidden_remover.h"
|
||||
|
||||
Hook<Trampoline32> HiddenHook;
|
||||
tHiddenHook o_hom_update_vars_hidden;
|
||||
uintptr_t hom_update_vars_code_start = 0;
|
||||
uintptr_t hom_update_vars_hidden_loc = 0;
|
||||
int32_t hom_mods_original_value = 0;
|
||||
|
||||
void init_unmod_hidden()
|
||||
{
|
||||
if (hom_update_vars_hidden_loc)
|
||||
{
|
||||
HiddenHook = Hook<Trampoline32>(hom_update_vars_hidden_loc + 0x7, (BYTE *)hk_hom_update_vars_hidden, (BYTE *)&o_hom_update_vars_hidden, 6);
|
||||
if (cfg_hidden_remover_enabled)
|
||||
HiddenHook.Enable();
|
||||
}
|
||||
}
|
||||
|
||||
void unmod_hidden_on_beatmap_load()
|
||||
{
|
||||
if (cfg_hidden_remover_enabled && osu_manager_ptr)
|
||||
{
|
||||
uintptr_t osu_manager = *(uintptr_t *)(osu_manager_ptr);
|
||||
if (osu_manager)
|
||||
{
|
||||
uintptr_t hit_manager_ptr = *(uintptr_t *)(osu_manager + OSU_MANAGER_HIT_MANAGER_OFFSET);
|
||||
uintptr_t mods_ptr = *(uintptr_t *)(hit_manager_ptr + OSU_HIT_MANAGER_MODS_OFFSET);
|
||||
*(int32_t *)(mods_ptr + 0x0C) = hom_mods_original_value;
|
||||
hom_mods_original_value = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void enable_hidden_remover_hooks()
|
||||
{
|
||||
enable_notify_hooks();
|
||||
HiddenHook.Enable();
|
||||
}
|
||||
|
||||
void disable_hidden_remover_hooks()
|
||||
{
|
||||
disable_notify_hooks();
|
||||
HiddenHook.Disable();
|
||||
}
|
||||
|
||||
__declspec(naked) void hk_hom_update_vars_hidden()
|
||||
{
|
||||
__asm {
|
||||
push eax
|
||||
push ebx
|
||||
push edx
|
||||
mov eax, [ecx+OSU_HIT_MANAGER_MODS_OFFSET]
|
||||
mov ebx, [eax+0x8]
|
||||
mov edx, [eax+0xC]
|
||||
mov hom_mods_original_value, edx
|
||||
xor edx, ebx
|
||||
and edx, -0x9
|
||||
xor edx, ebx
|
||||
mov [eax+0xC], edx
|
||||
pop edx
|
||||
pop ebx
|
||||
pop eax
|
||||
jmp o_hom_update_vars_hidden
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
#include "hook.h"
|
||||
|
||||
bool detour_32(BYTE *src, BYTE *dst, const uintptr_t len)
|
||||
{
|
||||
if (len < 5)
|
||||
return false;
|
||||
|
||||
DWORD curProtection;
|
||||
VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &curProtection);
|
||||
|
||||
memset(src, 0x90, len);
|
||||
|
||||
uintptr_t relativeAddress = dst - src - 5;
|
||||
*src = 0xE9;
|
||||
*(uintptr_t *)(src + 1) = relativeAddress;
|
||||
|
||||
VirtualProtect(src, len, curProtection, &curProtection);
|
||||
return true;
|
||||
}
|
||||
|
||||
BYTE *trampoline_32(BYTE *src, BYTE *dst, const uintptr_t len)
|
||||
{
|
||||
if (len < 5)
|
||||
return 0;
|
||||
|
||||
BYTE *gateway = (BYTE *)VirtualAlloc(0, len, MEM_COMMIT | MEM_RESERVE,
|
||||
PAGE_EXECUTE_READWRITE);
|
||||
|
||||
memcpy_s(gateway, len, src, len);
|
||||
|
||||
uintptr_t gatewayRelativeAddr = src - gateway - 5;
|
||||
*(gateway + len) = 0xE9;
|
||||
*(uintptr_t *)((uintptr_t)gateway + len + 1) = gatewayRelativeAddr;
|
||||
|
||||
detour_32(src, dst, len);
|
||||
|
||||
return gateway;
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
#include "features/relax.h"
|
||||
#include "window.h"
|
||||
|
||||
float od_window = 5.f;
|
||||
float od_window_left_offset = .0f;
|
||||
float od_window_right_offset = .0f;
|
||||
float od_check_ms = .0f;
|
||||
|
||||
float jumping_window_offset = .0f;
|
||||
|
||||
int wait_hitobjects_min = 10;
|
||||
int wait_hitobjects_max = 25;
|
||||
|
||||
bool debug_relax = false;
|
||||
|
||||
static char current_click = cfg_relax_style == 'a' ? right_click[0] : left_click[0];
|
||||
|
||||
void calc_od_timing()
|
||||
{
|
||||
static const auto rand_range_f = [](float f_min, float f_max) -> float
|
||||
{
|
||||
float scale = rand() / (float)RAND_MAX;
|
||||
return f_min + scale * (f_max - f_min);
|
||||
};
|
||||
static const auto rand_range_i = [](int i_min, int i_max) -> int
|
||||
{
|
||||
return rand() % (i_max + 1 - i_min) + i_min;
|
||||
};
|
||||
if (cfg_relax_checks_od && (od_check_ms == .0f))
|
||||
{
|
||||
od_check_ms = rand_range_f(od_window_left_offset, od_window_right_offset);
|
||||
if (cfg_jumping_window)
|
||||
{
|
||||
static uint32_t hit_objects_passed = current_beatmap.hit_object_idx;
|
||||
static int wait_hitojects_count = rand_range_i(wait_hitobjects_min, wait_hitobjects_max);
|
||||
if (current_beatmap.hit_object_idx - hit_objects_passed >= wait_hitojects_count)
|
||||
{
|
||||
// NOTE(Ciremun): move od window to the left
|
||||
if (rand_range_i(0, 1) >= 1)
|
||||
jumping_window_offset = rand_range_f(.1337f, od_window - od_window_left_offset);
|
||||
else
|
||||
jumping_window_offset = -rand_range_f(.1337f, od_window_right_offset);
|
||||
hit_objects_passed = current_beatmap.hit_object_idx;
|
||||
wait_hitojects_count = rand_range_i(wait_hitobjects_min, wait_hitobjects_max);
|
||||
}
|
||||
od_check_ms += jumping_window_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector2<float> mouse_position()
|
||||
{
|
||||
Vector2<float> mouse_pos;
|
||||
uintptr_t osu_manager = *(uintptr_t *)(osu_manager_ptr);
|
||||
uintptr_t osu_ruleset_ptr = *(uintptr_t *)(osu_manager + OSU_MANAGER_RULESET_PTR_OFFSET);
|
||||
mouse_pos.x = *(float *)(osu_ruleset_ptr + OSU_RULESET_MOUSE_X_OFFSET);
|
||||
mouse_pos.y = *(float *)(osu_ruleset_ptr + OSU_RULESET_MOUSE_Y_OFFSET);
|
||||
|
||||
return mouse_pos;
|
||||
}
|
||||
|
||||
void update_relax(Circle &circle, const int32_t audio_time)
|
||||
{
|
||||
static double keydown_time = 0.0;
|
||||
static double keyup_delay = 0.0;
|
||||
|
||||
if (cfg_relax_lock)
|
||||
{
|
||||
calc_od_timing();
|
||||
|
||||
auto current_time = audio_time + od_check_ms;
|
||||
auto valid_timing = current_time >= circle.start_time;
|
||||
auto mouse_pos = mouse_position();
|
||||
Vector2 screen_pos = playfield_to_screen(circle.position);
|
||||
auto scalar_dist = sqrt((mouse_pos.x - screen_pos.x) * (mouse_pos.x - screen_pos.x) + (mouse_pos.y - screen_pos.y) * (mouse_pos.y - screen_pos.y));
|
||||
auto valid_position = scalar_dist <= current_beatmap.scaled_hit_object_radius;
|
||||
|
||||
if (debug_relax)
|
||||
{
|
||||
ImGui::GetBackgroundDrawList()->AddCircleFilled(
|
||||
ImVec2(screen_pos.x, screen_pos.y),
|
||||
current_beatmap.scaled_hit_object_radius,
|
||||
ImColor( 0, 255, 255, 100 ) );
|
||||
}
|
||||
|
||||
if (valid_timing /* && valid_position */)
|
||||
{
|
||||
if (!circle.clicked)
|
||||
{
|
||||
if (cfg_relax_style == 'a')
|
||||
current_click = current_click == left_click[0] ? right_click[0] : left_click[0];
|
||||
|
||||
send_keyboard_input(current_click, 0);
|
||||
FR_INFO_FMT("Relax hit %d!, %d %d", current_beatmap.hit_object_idx, circle.start_time, circle.end_time);
|
||||
keyup_delay = circle.end_time ? circle.end_time - circle.start_time : 0.5;
|
||||
|
||||
if (cfg_timewarp_enabled)
|
||||
{
|
||||
double timewarp_playback_rate_div_100 = cfg_timewarp_playback_rate / 100.0;
|
||||
keyup_delay /= timewarp_playback_rate_div_100;
|
||||
}
|
||||
else if (circle.type == HitObjectType::Slider || circle.type == HitObjectType::Spinner)
|
||||
{
|
||||
if (current_beatmap.mods & Mods::DoubleTime)
|
||||
keyup_delay /= 1.5;
|
||||
else if (current_beatmap.mods & Mods::HalfTime)
|
||||
keyup_delay /= 0.75;
|
||||
}
|
||||
keydown_time = ImGui::GetTime();
|
||||
circle.clicked = true;
|
||||
od_check_ms = .0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cfg_relax_lock && keydown_time && ((ImGui::GetTime() - keydown_time) * 1000.0 > keyup_delay))
|
||||
{
|
||||
keydown_time = 0.0;
|
||||
send_keyboard_input(current_click, KEYEVENTF_KEYUP);
|
||||
}
|
||||
}
|
||||
|
||||
void relax_on_beatmap_load()
|
||||
{
|
||||
current_click = cfg_relax_style == 'a' ? right_click[0] : left_click[0];
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
|
||||
extern float od_window;
|
||||
extern float od_window_left_offset;
|
||||
extern float od_window_right_offset;
|
||||
extern float od_check_ms;
|
||||
|
||||
extern float jumping_window_offset;
|
||||
|
||||
extern int wait_hitobjects_min;
|
||||
extern int wait_hitobjects_max;
|
||||
|
||||
extern bool debug_relax;
|
||||
|
||||
void relax_on_beatmap_load();
|
||||
void update_relax(Circle &circle, const int32_t audio_time);
|
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "pattern.h"
|
||||
|
||||
constexpr auto parse_beatmap_func_sig { pattern::build<"55 8B EC 57 56 53 81 EC 58 01 00 00 8B F1 8D BD B8 FE FF FF B9 4E 00 00 00 33 C0 F3 AB 8B CE 89 8D B0 FE FF FF"> };
|
||||
constexpr auto current_scene_func_sig { pattern::build<"55 8B EC 57 56 53 50 8B D9 83 3D"> };
|
||||
constexpr auto beatmap_onload_func_sig { pattern::build<"55 8B EC 57 56 53 83 EC 44 8B F1 B9"> };
|
||||
constexpr auto selected_song_func_sig { pattern::build<"55 8B EC 83 E4 F8 57 56 83 EC 38 83 3D"> };
|
||||
constexpr auto audio_time_func_sig { pattern::build<"55 8B EC 83 E4 F8 57 56 83 EC 38 83 3D"> };
|
||||
constexpr auto osu_manager_func_sig { pattern::build<"55 8B EC 57 56 53 83 EC 14 80 3D"> };
|
||||
constexpr auto binding_manager_func_sig { pattern::build<"55 8B EC 57 56 83 EC 58 8B F1 8D 7D A0"> };
|
||||
constexpr auto selected_replay_func_sig { pattern::build<"55 8B EC 57 56 53 81 EC A0 00 00 00 8B F1 8D BD 68 FF FF FF B9 22 00 00 00 33 C0 F3 AB 8B CE 8B F1 8D 7D E0"> };
|
||||
constexpr auto window_manager_func_sig { pattern::build<"57 56 53 83 EC 6C 8B F1 8D 7D A8 B9 12 00 00 00 33 C0 F3 AB 8B CE 89 4D 94"> };
|
||||
constexpr auto update_timing_func_sig { pattern::build<"55 8B EC 83 E4 F8 57 56 83 EC 18 8B F9 8B 0D"> };
|
||||
constexpr auto check_timewarp_func_sig { pattern::build<"55 8B EC 57 56 53 81 EC B0 01 00 00 8B F1 8D BD 50 FE FF FF B9 68 00 00 00 33 C0"> };
|
||||
constexpr auto osu_client_id_func_sig { pattern::build<"8B F1 8D 7D C4 B9 0C 00 00 00 33 C0 F3 AB 8B CE 89 4D C0 8B 15"> };
|
||||
constexpr auto username_func_sig { pattern::build<"55 8B EC 57 56 53 83 EC 08 33 C0 89 45 EC 89 45 F0 8B F2 8B CE 8B 01 8B 40 30"> };
|
||||
constexpr auto update_flashlight_func_sig { pattern::build<"55 8B EC 56 83 EC 14 8B F1 8B 56 5C"> };
|
||||
constexpr auto check_flashlight_func_sig { pattern::build<"55 8B EC 57 56 53 83 EC 18 8B F9 80"> };
|
||||
constexpr auto hom_update_vars_func_sig { pattern::build<"55 8B EC 57 56 53 83 EC . 8B F1 8B DA 8B 7E . 85 FF 75 . 8D 65 . 5B 5E 5F 5D C2 08 00 8B CF BA"> };
|
||||
|
||||
constexpr auto approach_rate_sig { pattern::build<"8B 85 B0 FE FF FF D9 58 2C"> };
|
||||
constexpr auto approach_rate_sig_2 { pattern::build<"8B 85 B0 FE FF FF D9 40 38 D9 58 2C"> };
|
||||
constexpr auto circle_size_sig { pattern::build<"8B 85 B0 FE FF FF D9 58 30"> };
|
||||
constexpr auto overall_difficulty_sig { pattern::build<"8B 85 B0 FE FF FF D9 58 38"> };
|
||||
constexpr auto beatmap_onload_sig { pattern::build<"0F 94 C2"> };
|
||||
constexpr auto current_scene_sig { pattern::build<"A1....A3....A1....A3"> };
|
||||
constexpr auto selected_song_sig { pattern::build<"D9 EE DD 5C 24 10 83 3D"> };
|
||||
constexpr auto audio_time_sig { pattern::build<"F7 DA 3B C2"> };
|
||||
constexpr auto osu_manager_sig { pattern::build<"85 C9"> };
|
||||
constexpr auto binding_manager_sig { pattern::build<"8D 45 D8 50 8B 0D"> };
|
||||
constexpr auto selected_replay_sig { pattern::build<"8B 46 38 83 78 30 00"> };
|
||||
constexpr auto osu_username_sig { pattern::build<"8B 01 8B 40 28 FF 50 18 8B 15"> };
|
||||
constexpr auto window_manager_sig { pattern::build<"83 C2 04 8B 0D"> };
|
||||
constexpr auto score_multiplier_sig { pattern::build<"8B F1 D9 E8 83 FA 04 0F 83"> };
|
||||
constexpr auto update_timing_sig { pattern::build<"D9 C0 DD 05"> };
|
||||
constexpr auto update_timing_sig_2 { pattern::build<"DE E9 DD 1D"> };
|
||||
constexpr auto check_timewarp_sig { pattern::build<"D9 E8 DE F1 DE C9"> };
|
||||
constexpr auto hom_update_vars_hidden_sig { pattern::build<"DD 1C 24 8B CE 8B 01 8B 40 . FF 50 . DD 5E . 8B 7E ."> };
|
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
#define OSU_MANAGER_HIT_MANAGER_OFFSET 0x48
|
||||
#define OSU_MANAGER_RULESET_PTR_OFFSET 0x68
|
||||
#define OSU_MANAGER_BEATMAP_OFFSET 0xDC
|
||||
#define OSU_MANAGER_IS_REPLAY_MODE_OFFSET 0x17B
|
||||
|
||||
#define OSU_RULESET_MOUSE_X_OFFSET 0x80
|
||||
#define OSU_RULESET_MOUSE_Y_OFFSET 0x84
|
||||
#define OSU_RULESET_FLASHLIGHT_SPRITE_MANAGER_OFFSET 0x54
|
||||
|
||||
#define OSU_FLASHLIGHT_SPRITE_MANAGER_ALPHA_OFFSET 0x28
|
||||
#define OSU_AUDIO_TIME_IS_PLAYING_OFFSET 0x30
|
||||
|
||||
#define OSU_BEATMAP_AR_OFFSET 0x2C
|
||||
#define OSU_BEATMAP_CS_OFFSET 0x30
|
||||
#define OSU_BEATMAP_OD_OFFSET 0x38
|
||||
#define OSU_BEATMAP_SONG_STR_OFFSET 0x80
|
||||
|
||||
#define OSU_HIT_MANAGER_MODS_OFFSET 0x34
|
||||
#define OSU_HIT_MANAGER_HIT_OBJECTS_LIST_OFFSET 0x48
|
||||
#define OSU_HIT_MANAGER_HIT_OBJECTS_COUNT_OFFSET 0x90
|
||||
#define OSU_HIT_MANAGER_HIT_OBJECT_RADIUS_OFFSET 0x18
|
||||
|
||||
#define OSU_HIT_OBJECT_START_TIME_OFFSET 0x10
|
||||
#define OSU_HIT_OBJECT_END_TIME_OFFSET 0x14
|
||||
#define OSU_HIT_OBJECT_CIRCLE_TYPE_OFFSET 0x18
|
||||
#define OSU_HIT_OBJECT_POSITION_X_OFFSET 0x38
|
||||
#define OSU_HIT_OBJECT_POSITION_Y_OFFSET 0x3C
|
||||
#define OSU_HIT_OBJECT_ANIMATION_OFFSET 0xB8
|
||||
|
||||
#define OSU_ANIMATION_SLIDER_BALL_X_OFFSET 0x4C
|
||||
#define OSU_ANIMATION_SLIDER_BALL_Y_OFFSET 0x50
|
||||
|
||||
#define OSU_REPLAY_AUTHOR_OFFSET 0x28
|
||||
#define OSU_REPLAY_300_COUNT_OFFSET 0x8A
|
||||
#define OSU_REPLAY_100_COUNT_OFFSET 0x88
|
||||
#define OSU_REPLAY_50_COUNT_OFFSET 0x8C
|
||||
#define OSU_REPLAY_MISS_COUNT_OFFSET 0x92
|
||||
#define OSU_REPLAY_COMBO_OFFSET 0x68
|
||||
#define OSU_REPLAY_MODS_OFFSET 0x1C
|
||||
#define OSU_REPLAY_COMPRESSED_DATA_OFFSET 0x30
|
|
@ -0,0 +1,196 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
namespace timewarp {
|
||||
|
||||
constexpr static u32 MODULE_ID{ 0 };
|
||||
|
||||
u8 timewarp_active{ 0 };
|
||||
|
||||
double timewarp_rate{ 100.f };
|
||||
|
||||
double dummy{};
|
||||
|
||||
float* ac_ratio_check = (float*)&dummy;
|
||||
double* osu_FrameAimTime = &dummy;
|
||||
float ctb_movement_ratio{ 1.f };
|
||||
|
||||
void __fastcall AudioEngine_set_CurrentPlaybackRate(double* CurrentPlaybackRate) {
|
||||
|
||||
const auto original = *CurrentPlaybackRate;
|
||||
|
||||
osu_data.mod_play_speed = original;
|
||||
|
||||
if (timewarp_active) {
|
||||
if(*osu_data.mode == 2)
|
||||
*CurrentPlaybackRate = timewarp_rate;
|
||||
} else timewarp_rate = original;
|
||||
|
||||
*osu_FrameAimTime = (1000. / 60.) * (original / *CurrentPlaybackRate);
|
||||
|
||||
*ac_ratio_check = float(*CurrentPlaybackRate) * 0.01f;
|
||||
ctb_movement_ratio = *ac_ratio_check;
|
||||
|
||||
}
|
||||
|
||||
u8 timewarp_loaded{}, ac_patched{}, ctb_loaded{};
|
||||
|
||||
void __fastcall patch_ac() {
|
||||
|
||||
if (timewarp_loaded == 0)
|
||||
return;
|
||||
|
||||
if (ctb_loaded == 0 && *osu_data.play_mode == 2) {
|
||||
|
||||
constexpr static auto aob{
|
||||
TO_AOB("89 46 6C 8B 46 38 8B 50 1C")
|
||||
};
|
||||
|
||||
auto t = mem::find_ERWP_cached(0, aob);
|
||||
|
||||
if (t) {
|
||||
|
||||
ctb_loaded = 1;
|
||||
osu_data.force_restart |= 1;
|
||||
|
||||
t += 0x21;
|
||||
|
||||
*(u8*)t = 0xeb;
|
||||
|
||||
t += (*(u8*)++t) + 5;
|
||||
|
||||
*(u32*)t = (u32)&ctb_movement_ratio;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (ac_patched)
|
||||
return;
|
||||
|
||||
constexpr static auto aob{
|
||||
TO_AOB("85 c0 7e 0c c7 85 ? ff ff ff 00 00 c0 3f eb")
|
||||
};
|
||||
|
||||
const auto t = mem::find_ERWP_cached(0, aob);
|
||||
|
||||
if (t == 0)
|
||||
return;
|
||||
|
||||
ac_patched = 1;
|
||||
|
||||
*(u16*)(t + 2) = 0x9090;
|
||||
|
||||
ac_ratio_check = (float*)(t + 10);
|
||||
|
||||
osu_data.force_restart |= 1;
|
||||
|
||||
}
|
||||
|
||||
void __fastcall load(const int mode) {
|
||||
|
||||
if (timewarp_loaded || timewarp_active == 0)
|
||||
return;
|
||||
|
||||
constexpr static auto aob{
|
||||
TO_AOB("55 8b ec 56 8b 35 ? ? ? ? 85 f6")
|
||||
};
|
||||
|
||||
const auto t = mem::find_ERWP_cached(0, aob);
|
||||
|
||||
if (t == 0)
|
||||
return;
|
||||
|
||||
timewarp_loaded = 1;
|
||||
|
||||
{
|
||||
constexpr static auto UpdateTiming_aob{
|
||||
TO_AOB("dc 25 ? ? ? ? de e9 dd 1d")
|
||||
};
|
||||
|
||||
const auto t2 = mem::find_ERWP_cached(0, UpdateTiming_aob);
|
||||
|
||||
osu_FrameAimTime = t2 ? *(double**)(t2 + 2) : osu_FrameAimTime;
|
||||
|
||||
}
|
||||
|
||||
std::array<u8, 24> inter{
|
||||
0x8d, 0x4c, 0x24, 0x4, // LEA ECX, [ESP + 0x4]
|
||||
0xe8, 0,0,0,0, // CALL AudioEngine_set_CurrentPlaybackRate
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0xe9, 0,0,0,0 // JMP back
|
||||
};
|
||||
|
||||
*(std::array<u8, 10>*)(inter.data() + 9) = *(std::array<u8, 10>*)t;
|
||||
|
||||
const auto loc = erw_memory.allocate_chunk(inter.size());
|
||||
|
||||
*(int*)(inter.data() + 5) = int(AudioEngine_set_CurrentPlaybackRate) - int(loc + 9);
|
||||
*(int*)(inter.data() + 20) = int(t + 10) - int(loc + 24);
|
||||
|
||||
*(std::array<u8, 24>*)loc = inter;
|
||||
|
||||
{
|
||||
std::array<u8, 10> inter{
|
||||
0xe9,0,0,0,0,
|
||||
0x90,0x90,0x90,0x90,0x90
|
||||
};
|
||||
|
||||
*(int*)(inter.data() + 1) = int(loc) - int(t + 5);
|
||||
|
||||
*(std::array<u8, 10>*)t = inter;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void __fastcall menu_init() {
|
||||
|
||||
auto& menu = AQM::module_menu[MODULE_ID];
|
||||
|
||||
menu.sprite_list.reserve(64);
|
||||
|
||||
menu.name = "Timewarp"sv;
|
||||
|
||||
menu.icon = FontAwesome::clock_o;
|
||||
menu.icon_offset.y = 1.f;
|
||||
|
||||
menu.colour = _col{ 117, 7, 140 , 255 };
|
||||
|
||||
{
|
||||
menu_object mo{};
|
||||
|
||||
mo.name = "Enabled"sv;
|
||||
mo.type = menu_object_type::clicker_bool;
|
||||
mo.clicker_bool.value = &timewarp_active;
|
||||
|
||||
menu.menu_elements.push_back(mo);
|
||||
}
|
||||
|
||||
{
|
||||
menu_object mo{};
|
||||
|
||||
mo.name = "Play Speed"sv;
|
||||
mo.type = menu_object_type::slider;
|
||||
mo.slider.is_double = 1;
|
||||
mo.slider.snap_to_int = 1;
|
||||
mo.slider.value = (u32)&timewarp_rate;
|
||||
|
||||
mo.slider.min_value = 50.f;
|
||||
mo.slider.max_value = 150.f;
|
||||
|
||||
menu.menu_elements.push_back(mo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const auto initialized = [] {
|
||||
|
||||
on_mode_change[MODULE_ID] = load;
|
||||
on_audio_tick_ingame[MODULE_ID] = patch_ac;
|
||||
on_menu_init[MODULE_ID] = menu_init;
|
||||
|
||||
return 1;
|
||||
}();
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue