Add DLL to modify PlayFab url
This commit is contained in:
@@ -47,13 +47,21 @@
|
|||||||
<PropertyGroup Label="UserMacros" />
|
<PropertyGroup Label="UserMacros" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
<LinkIncremental>true</LinkIncremental>
|
<LinkIncremental>true</LinkIncremental>
|
||||||
<OutDir>$(ProjectDir)bin\$(Platform)\$(Configuration)\</OutDir>
|
<OutDir>$(SolutionDir)Prospect.Launcher\Libs</OutDir>
|
||||||
<IntDir>$(ProjectDir)bin\intermediate\$(Platform)\$(Configuration)\</IntDir>
|
<IntDir>$(ProjectDir)bin\intermediate\$(Platform)\$(Configuration)\</IntDir>
|
||||||
|
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
<LinkIncremental>false</LinkIncremental>
|
<LinkIncremental>false</LinkIncremental>
|
||||||
<OutDir>$(ProjectDir)bin\$(Platform)\$(Configuration)\</OutDir>
|
<OutDir>$(SolutionDir)Prospect.Launcher\Libs</OutDir>
|
||||||
<IntDir>$(ProjectDir)bin\intermediate\$(Platform)\$(Configuration)\</IntDir>
|
<IntDir>$(ProjectDir)bin\intermediate\$(Platform)\$(Configuration)\</IntDir>
|
||||||
|
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<VcpkgUseStatic>true</VcpkgUseStatic>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<VcpkgUseStatic>true</VcpkgUseStatic>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
@@ -63,13 +71,13 @@
|
|||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)libs\detours\;$(UESDK);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<EnableUAC>false</EnableUAC>
|
<EnableUAC>false</EnableUAC>
|
||||||
<AdditionalDependencies>detours.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
@@ -82,7 +90,8 @@
|
|||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)libs\detours\;$(UESDK);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<Optimization>MinSpace</Optimization>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
@@ -90,12 +99,14 @@
|
|||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<EnableUAC>false</EnableUAC>
|
<EnableUAC>false</EnableUAC>
|
||||||
<AdditionalDependencies>detours.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="hooks.h" />
|
||||||
<ClInclude Include="logger.h" />
|
<ClInclude Include="logger.h" />
|
||||||
<ClInclude Include="main.h" />
|
<ClInclude Include="SDK.h" />
|
||||||
|
<ClInclude Include="SDK_Memory.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="logger.cpp" />
|
<ClCompile Include="logger.cpp" />
|
||||||
|
|||||||
@@ -15,10 +15,16 @@
|
|||||||
</Filter>
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="main.h">
|
<ClInclude Include="logger.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="logger.h">
|
<ClInclude Include="SDK.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="hooks.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="SDK_Memory.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -0,0 +1,96 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <locale>
|
||||||
|
#include <string>
|
||||||
|
#include "SDK_Memory.h"
|
||||||
|
|
||||||
|
namespace SDK
|
||||||
|
{
|
||||||
|
template<class T>
|
||||||
|
struct TArray
|
||||||
|
{
|
||||||
|
friend struct FString;
|
||||||
|
|
||||||
|
TArray()
|
||||||
|
{
|
||||||
|
Data = nullptr;
|
||||||
|
Count = Max = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Num() const
|
||||||
|
{
|
||||||
|
return Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
T& operator[](int i)
|
||||||
|
{
|
||||||
|
return Data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
const T& operator[](int i) const
|
||||||
|
{
|
||||||
|
return Data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsValidIndex(int i) const
|
||||||
|
{
|
||||||
|
return i < Num();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T* Data;
|
||||||
|
int32_t Count;
|
||||||
|
int32_t Max;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FString : private TArray<wchar_t>
|
||||||
|
{
|
||||||
|
FString(const wchar_t* other)
|
||||||
|
{
|
||||||
|
Max = Count = *other ? std::wcslen(other) + 1 : 0;
|
||||||
|
|
||||||
|
if (Count)
|
||||||
|
{
|
||||||
|
Data = static_cast<wchar_t*>(GMalloc->Malloc(Count));
|
||||||
|
|
||||||
|
wcscpy_s(Data, Count, other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FString(const std::wstring& other) : FString(other.c_str())
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsValid() const
|
||||||
|
{
|
||||||
|
return Data != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wchar_t* c_str() const
|
||||||
|
{
|
||||||
|
return Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ToString() const
|
||||||
|
{
|
||||||
|
const auto length = std::wcslen(Data);
|
||||||
|
|
||||||
|
std::string str(length, '\0');
|
||||||
|
std::use_facet<std::ctype<wchar_t>>(std::locale()).narrow(Data, Data + length, '?', &str[0]);
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UPlayFabAPISettings
|
||||||
|
{
|
||||||
|
FString VerticalName;
|
||||||
|
FString BaseServiceHost;
|
||||||
|
FString TitleId;
|
||||||
|
FString AdvertisingIdType;
|
||||||
|
FString AdvertisingIdValue;
|
||||||
|
bool DisableAdvertising = false;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#define DEFAULT_ALIGNMENT 0
|
||||||
|
|
||||||
|
namespace SDK
|
||||||
|
{
|
||||||
|
class FExec
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~FExec() = default;
|
||||||
|
private:
|
||||||
|
virtual bool Exec(void* world, void* cmd, void* ar) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FMalloc : FExec
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void* Malloc(SIZE_T Count, uint32_t Alignment = DEFAULT_ALIGNMENT) = 0;
|
||||||
|
|
||||||
|
virtual void* TryMalloc(SIZE_T Count, uint32_t Alignment = DEFAULT_ALIGNMENT) = 0;
|
||||||
|
|
||||||
|
virtual void* Realloc(void* Original, SIZE_T Count, uint32_t Alignment = DEFAULT_ALIGNMENT) = 0;
|
||||||
|
|
||||||
|
virtual void* TryRealloc(void* Original, SIZE_T Count, uint32_t Alignment = DEFAULT_ALIGNMENT) = 0;
|
||||||
|
|
||||||
|
virtual void Free(void* Original) = 0;
|
||||||
|
|
||||||
|
virtual SIZE_T QuantizeSize(SIZE_T Count, uint32_t Alignment)
|
||||||
|
{
|
||||||
|
return Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool GetAllocationSize(void* Original, SIZE_T& SizeOut)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Trim(bool bTrimThreadCaches)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void SetupTLSCachesOnCurrentThread()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void ClearAndDisableTLSCachesOnCurrentThread()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void InitializeStatsMetadata();
|
||||||
|
|
||||||
|
virtual bool Exec(void* InWorld, void* Cmd, void* Ar) override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void UpdateStats() = 0;
|
||||||
|
|
||||||
|
virtual void GetAllocatorStats(void* out_Stats) = 0;
|
||||||
|
|
||||||
|
virtual void DumpAllocatorStats(class FOutputDevice& Ar) = 0;
|
||||||
|
|
||||||
|
virtual bool IsInternallyThreadSafe() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool ValidateHeap()
|
||||||
|
{
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const TCHAR* GetDescriptiveName() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
FMalloc* GMalloc;
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SDK.h"
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
HANDLE h_out = nullptr, h_old_out = nullptr;
|
HANDLE h_out = nullptr, h_old_out = nullptr;
|
||||||
HANDLE h_err = nullptr, h_old_err = nullptr;
|
HANDLE h_err = nullptr, h_old_err = nullptr;
|
||||||
HANDLE h_in = nullptr, h_old_in = nullptr;
|
HANDLE h_in = nullptr, h_old_in = nullptr;
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <Windows.h>
|
|
||||||
|
|
||||||
namespace logger
|
namespace logger
|
||||||
{
|
{
|
||||||
void Attach();
|
void Attach();
|
||||||
@@ -12,4 +9,4 @@ namespace logger
|
|||||||
bool Print(const char* fmt, ...);
|
bool Print(const char* fmt, ...);
|
||||||
|
|
||||||
char ReadKey();
|
char ReadKey();
|
||||||
};
|
}
|
||||||
@@ -1,17 +1,71 @@
|
|||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <MinHook.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include "main.h"
|
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include <detours.h>
|
#include "SDK.h"
|
||||||
|
#include "SDK_Memory.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variable offset, find with "STOPMOVIECAPTURE", scroll up.
|
||||||
|
*/
|
||||||
|
constexpr uintptr_t OffsetGMalloc = 0x5C9A3F8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function offset, find with "?sdk=".
|
||||||
|
*/
|
||||||
|
constexpr uintptr_t OffsetPlayFabApiGetUrl = 0xCA5010;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function hooks.
|
||||||
|
*/
|
||||||
|
typedef SDK::FString(__fastcall* tPlayFabApiGetUrl)(SDK::UPlayFabAPISettings*, const SDK::FString&);
|
||||||
|
|
||||||
|
tPlayFabApiGetUrl OldPlayFabApiGetUrl;
|
||||||
|
|
||||||
|
SDK::FString __fastcall PlayFabApiGetUrlProxy(SDK::UPlayFabAPISettings* thiz, const SDK::FString& callPath)
|
||||||
|
{
|
||||||
|
logger::Print("[Agent] GetURL called with callPath %s\n", callPath.ToString().c_str());
|
||||||
|
|
||||||
|
return std::wstring(L"http://127.0.0.1:8888") + std::wstring(callPath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
DWORD WINAPI OnDllAttach(LPVOID base)
|
DWORD WINAPI OnDllAttach(LPVOID base)
|
||||||
{
|
{
|
||||||
logger::Attach();
|
|
||||||
logger::Print("[Agent] DLL Attached\n");
|
logger::Print("[Agent] DLL Attached\n");
|
||||||
|
|
||||||
// TODO: Patch.
|
const auto hModule = GetModuleHandleW(nullptr);
|
||||||
|
const auto hModulePtr = reinterpret_cast<uintptr_t>(hModule);
|
||||||
|
|
||||||
logger::Print("[Agent] DLL Exit\n");
|
// Initialize GMalloc.
|
||||||
FreeLibraryAndExitThread(static_cast<HMODULE>(base), 1);
|
SDK::GMalloc = *reinterpret_cast<SDK::FMalloc**>(hModulePtr + OffsetGMalloc);
|
||||||
|
|
||||||
|
// Initialize MinHook.
|
||||||
|
if (MH_Initialize() != MH_OK)
|
||||||
|
{
|
||||||
|
logger::Print("[Agent] Failed to initialize MinHook\n");
|
||||||
|
FreeLibraryAndExitThread(hModule, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hook UPlayFabAPISettings::GetUrl.
|
||||||
|
const auto pTarget = reinterpret_cast<LPVOID>(hModulePtr + OffsetPlayFabApiGetUrl);
|
||||||
|
const auto ppOriginal = reinterpret_cast<LPVOID*>(&OldPlayFabApiGetUrl);
|
||||||
|
const auto mhStatus = MH_CreateHook(pTarget, &PlayFabApiGetUrlProxy, ppOriginal);
|
||||||
|
|
||||||
|
if (mhStatus != MH_OK)
|
||||||
|
{
|
||||||
|
logger::Print("[Agent] Failed to create PlayFabAPIGetUrl hook (%d)\n", mhStatus);
|
||||||
|
FreeLibraryAndExitThread(hModule, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MH_EnableHook(pTarget) != MH_OK)
|
||||||
|
{
|
||||||
|
logger::Print("[Agent] Failed to enable PlayFabAPIGetUrl hook\n");
|
||||||
|
FreeLibraryAndExitThread(hModule, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger::Print("[Agent] DLL Initialized\n");
|
||||||
|
ExitThread(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI DllMain(
|
BOOL WINAPI DllMain(
|
||||||
@@ -27,10 +81,18 @@ BOOL WINAPI DllMain(
|
|||||||
// Allocate a console.
|
// Allocate a console.
|
||||||
AllocConsole();
|
AllocConsole();
|
||||||
freopen_s(reinterpret_cast<FILE**>(stdout), "CONOUT$", "w", stdout);
|
freopen_s(reinterpret_cast<FILE**>(stdout), "CONOUT$", "w", stdout);
|
||||||
|
|
||||||
|
// Attach logger.
|
||||||
|
logger::Attach();
|
||||||
|
|
||||||
// Spawn thread.
|
// Spawn thread.
|
||||||
CreateThread(nullptr, 0, OnDllAttach, hinstDll, 0, nullptr);
|
CreateThread(nullptr, 0, OnDllAttach, hinstDll, 0, nullptr);
|
||||||
}
|
}
|
||||||
|
else if (fdwReason == DLL_PROCESS_DETACH)
|
||||||
|
{
|
||||||
|
// Detach logger.
|
||||||
|
logger::Detach();
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#include <windows.h>
|
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using Prospect.Launcher.Invoke;
|
||||||
|
|
||||||
|
namespace Prospect.Launcher
|
||||||
|
{
|
||||||
|
public static class Inject
|
||||||
|
{
|
||||||
|
const int PROCESS_CREATE_THREAD = 0x0002;
|
||||||
|
const int PROCESS_QUERY_INFORMATION = 0x0400;
|
||||||
|
const int PROCESS_VM_OPERATION = 0x0008;
|
||||||
|
const int PROCESS_VM_WRITE = 0x0020;
|
||||||
|
const int PROCESS_VM_READ = 0x0010;
|
||||||
|
|
||||||
|
const uint MEM_COMMIT = 0x00001000;
|
||||||
|
const uint MEM_RESERVE = 0x00002000;
|
||||||
|
const uint PAGE_READWRITE = 4;
|
||||||
|
|
||||||
|
// https://codingvision.net/c-inject-a-dll-into-a-process-w-createremotethread
|
||||||
|
public static unsafe bool Library(uint processId, string path)
|
||||||
|
{
|
||||||
|
IntPtr procHandle = Kernel32.OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, (int)processId);
|
||||||
|
|
||||||
|
var loadLibraryAddr = Kernel32.GetProcAddress(Kernel32.GetModuleHandle("kernel32.dll"), "LoadLibraryA");
|
||||||
|
if (loadLibraryAddr == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Failed GetProcAddress.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var allocMemAddress = Kernel32.VirtualAllocEx(procHandle, IntPtr.Zero, (uint)((path.Length + 1) * Marshal.SizeOf(typeof(char))), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||||
|
if (allocMemAddress == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Failed VirtualAllocEx.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var libraryBytes = Encoding.Default.GetBytes(path);
|
||||||
|
|
||||||
|
fixed (byte* pLibraryBytes = libraryBytes)
|
||||||
|
{
|
||||||
|
Kernel32.WriteProcessMemory(procHandle, allocMemAddress, pLibraryBytes, libraryBytes.Length + 1, out _);
|
||||||
|
}
|
||||||
|
|
||||||
|
var threadHandle = Kernel32.CreateRemoteThread(procHandle, IntPtr.Zero, 0, loadLibraryAddr, allocMemAddress, 0, IntPtr.Zero);
|
||||||
|
if (threadHandle == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Failed CreateRemoteThread.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,5 +42,23 @@ namespace Prospect.Launcher.Invoke
|
|||||||
|
|
||||||
[DllImport("kernel32.dll", SetLastError = true)]
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
public static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, uint flNewProtect, out uint lpflOldProtect);
|
public static extern bool VirtualProtectEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, uint flNewProtect, out uint lpflOldProtect);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
|
||||||
|
public static extern IntPtr GetModuleHandle(string lpModuleName);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll")]
|
||||||
|
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
|
||||||
|
|
||||||
|
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
|
||||||
|
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
|
||||||
|
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll")]
|
||||||
|
public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
|
public static extern uint ResumeThread(IntPtr hThread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Binary file not shown.
@@ -44,10 +44,13 @@ namespace Prospect.Launcher
|
|||||||
Write(offset, data);
|
Write(offset, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe void Write(int offset, Span<byte> data)
|
public unsafe void Write(int offset, ReadOnlySpan<byte> data)
|
||||||
|
{
|
||||||
|
Write(_baseAddress + offset, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe void Write(IntPtr addr, ReadOnlySpan<byte> data)
|
||||||
{
|
{
|
||||||
var addr = _baseAddress + offset;
|
|
||||||
|
|
||||||
// Modify protection.
|
// Modify protection.
|
||||||
if (!Kernel32.VirtualProtectEx(_handle, addr, data.Length, 0x40, out var oldProtect))
|
if (!Kernel32.VirtualProtectEx(_handle, addr, data.Length, 0x40, out var oldProtect))
|
||||||
{
|
{
|
||||||
@@ -56,7 +59,7 @@ namespace Prospect.Launcher
|
|||||||
|
|
||||||
fixed (byte* pData = data)
|
fixed (byte* pData = data)
|
||||||
{
|
{
|
||||||
var write = Kernel32.WriteProcessMemory(_handle, _baseAddress + offset, pData, data.Length, out _);
|
var write = Kernel32.WriteProcessMemory(_handle, addr, pData, data.Length, out _);
|
||||||
|
|
||||||
// Restore protection.
|
// Restore protection.
|
||||||
Kernel32.VirtualProtectEx(_handle, addr, data.Length, oldProtect, out _);
|
Kernel32.VirtualProtectEx(_handle, addr, data.Length, oldProtect, out _);
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
|
||||||
using Prospect.Launcher.Invoke;
|
using Prospect.Launcher.Invoke;
|
||||||
using Prospect.Launcher.Invoke.Structs;
|
using Prospect.Launcher.Invoke.Structs;
|
||||||
|
|
||||||
@@ -33,6 +32,7 @@ namespace Prospect.Launcher
|
|||||||
|
|
||||||
// 2EA46 = Default
|
// 2EA46 = Default
|
||||||
// A22AB = The Cycle Playtest
|
// A22AB = The Cycle Playtest
|
||||||
|
gameArgs.Add("-empty");
|
||||||
gameArgs.Add("-log");
|
gameArgs.Add("-log");
|
||||||
gameArgs.Add("-windowed");
|
gameArgs.Add("-windowed");
|
||||||
gameArgs.Add("-noeac");
|
gameArgs.Add("-noeac");
|
||||||
@@ -51,7 +51,7 @@ namespace Prospect.Launcher
|
|||||||
// Spawn.
|
// Spawn.
|
||||||
var startupInfo = new StartupInfo();
|
var startupInfo = new StartupInfo();
|
||||||
|
|
||||||
if (!Kernel32.CreateProcess(gameBinary, string.Join(' ', gameArgs), ProcessCreationFlags.ZERO_FLAG, ref startupInfo, out var processInfo))
|
if (!Kernel32.CreateProcess(gameBinary, string.Join(' ', gameArgs), ProcessCreationFlags.CREATE_SUSPENDED, ref startupInfo, out var processInfo))
|
||||||
{
|
{
|
||||||
Console.WriteLine("Failed to spawn game.");
|
Console.WriteLine("Failed to spawn game.");
|
||||||
return;
|
return;
|
||||||
@@ -59,22 +59,21 @@ namespace Prospect.Launcher
|
|||||||
|
|
||||||
Console.WriteLine("Spawned.");
|
Console.WriteLine("Spawned.");
|
||||||
|
|
||||||
// Modify.
|
// Inject DLL.
|
||||||
MemoryHelper memory;
|
var agentPath = Path.Combine(AppContext.BaseDirectory, "Libs", "Prospect.Agent.dll");
|
||||||
|
|
||||||
while ((memory = MemoryHelper.CreateForHandle(processInfo.hProcess, gameBinary)) == null)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Failed to obtain MemoryHelper.");
|
|
||||||
Thread.Sleep(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Patches.ChangePlayFabUrl(memory, ".localhost"))
|
if (!Inject.Library(processInfo.dwProcessId, agentPath))
|
||||||
{
|
{
|
||||||
Console.WriteLine("Failed to patch playfab url.");
|
Console.WriteLine("Failed to inject library.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("Injected.");
|
||||||
|
|
||||||
|
// Resume.
|
||||||
|
Kernel32.ResumeThread(processInfo.hThread);
|
||||||
|
|
||||||
Console.WriteLine("Patched.");
|
Console.WriteLine("Resumed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14,4 +14,14 @@
|
|||||||
<PlatformTarget>x64</PlatformTarget>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Libs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="Libs\Prospect.Agent.dll">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Serilog;
|
||||||
|
using Serilog.Events;
|
||||||
|
|
||||||
|
namespace Prospect.Server.Api
|
||||||
|
{
|
||||||
|
public static class Program
|
||||||
|
{
|
||||||
|
public static int Main(string[] args)
|
||||||
|
{
|
||||||
|
Log.Logger = new LoggerConfiguration()
|
||||||
|
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
|
||||||
|
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
|
||||||
|
.Enrich.FromLogContext()
|
||||||
|
.WriteTo.Console()
|
||||||
|
.CreateLogger();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log.Information("Starting web host");
|
||||||
|
CreateHostBuilder(args).Build().Run();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Fatal(ex, "Host terminated unexpectedly");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Log.CloseAndFlush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||||
|
Host.CreateDefaultBuilder(args)
|
||||||
|
.UseSerilog()
|
||||||
|
.ConfigureWebHostDefaults(webBuilder =>
|
||||||
|
{
|
||||||
|
webBuilder.UseStartup<Startup>();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"Prospect.Server.Api": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"dotnetRunMessages": "true",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"applicationUrl": "https://A22AB.localhost:5555",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net5.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Prospect.Server.Api
|
||||||
|
{
|
||||||
|
public class Startup
|
||||||
|
{
|
||||||
|
public void ConfigureServices(IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddControllers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||||
|
{
|
||||||
|
if (env.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.UseDeveloperExceptionPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
app.UseSerilogRequestLogging();
|
||||||
|
|
||||||
|
app.UseRouting();
|
||||||
|
|
||||||
|
app.UseEndpoints(endpoints =>
|
||||||
|
{
|
||||||
|
endpoints.MapControllers();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
{
|
||||||
|
}
|
||||||
@@ -7,6 +7,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Prospect.Agent", "Prospect.
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Prospect.Launcher", "Prospect.Launcher\Prospect.Launcher.csproj", "{1C8F4637-9552-4726-818B-196ECE2AE966}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Prospect.Launcher", "Prospect.Launcher\Prospect.Launcher.csproj", "{1C8F4637-9552-4726-818B-196ECE2AE966}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Prospect.Server.Api", "Prospect.Server.Api\Prospect.Server.Api.csproj", "{A539B020-8BEC-497F-9176-DC2665D927A1}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|x64 = Debug|x64
|
Debug|x64 = Debug|x64
|
||||||
@@ -29,6 +31,14 @@ Global
|
|||||||
{1C8F4637-9552-4726-818B-196ECE2AE966}.Release|x64.Build.0 = Release|Any CPU
|
{1C8F4637-9552-4726-818B-196ECE2AE966}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{1C8F4637-9552-4726-818B-196ECE2AE966}.Release|x86.ActiveCfg = Release|Any CPU
|
{1C8F4637-9552-4726-818B-196ECE2AE966}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{1C8F4637-9552-4726-818B-196ECE2AE966}.Release|x86.Build.0 = Release|Any CPU
|
{1C8F4637-9552-4726-818B-196ECE2AE966}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{A539B020-8BEC-497F-9176-DC2665D927A1}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{A539B020-8BEC-497F-9176-DC2665D927A1}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{A539B020-8BEC-497F-9176-DC2665D927A1}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{A539B020-8BEC-497F-9176-DC2665D927A1}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{A539B020-8BEC-497F-9176-DC2665D927A1}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{A539B020-8BEC-497F-9176-DC2665D927A1}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{A539B020-8BEC-497F-9176-DC2665D927A1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{A539B020-8BEC-497F-9176-DC2665D927A1}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Abbreviations/=API/@EntryIndexedValue">API</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Abbreviations/=SDK/@EntryIndexedValue">SDK</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Rules/=Classes_0020and_0020structs/@EntryIndexedValue"><NamingElement Priority="1"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="__interface" /><type Name="class" /><type Name="struct" /></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></NamingElement></s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Rules/=Class_0020and_0020struct_0020methods/@EntryIndexedValue"><NamingElement Priority="10"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="member function" /></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></NamingElement></s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Rules/=Namespaces/@EntryIndexedValue"><NamingElement Priority="17"><Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"><type Name="namespace" /><type Name="namespace alias" /></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></NamingElement></s:String></wpf:ResourceDictionary>
|
||||||
Reference in New Issue
Block a user