mirror of
https://github.com/ApfelTeeSaft/Starfall.git
synced 2026-08-26 19:33:39 +00:00
Init
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
x64/
|
||||
*/x64
|
||||
Starfall/Starfall
|
||||
*/*.vcxproj.user
|
||||
.vs
|
||||
*/Release
|
||||
*/Debug
|
||||
@@ -0,0 +1,28 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2024, Starfall
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -0,0 +1,22 @@
|
||||
# Starfall
|
||||
Starfall is a universal SSL bypass / redirect for native UE HTTP games, made for Fortnite. <br>
|
||||
|
||||
# Configuring Starfall
|
||||
|
||||
## Changing Starfall's Backend URL.
|
||||
To change Starfall's backend URL to your's go to ``Starfall/opts.h`` and change the ``Backend`` variable to your Backend URL.
|
||||
|
||||
## Build for a Hybrid
|
||||
Go to ``Starfall/opts.h`` and change ``UrlSet`` to Hybrid.
|
||||
|
||||
## Build for a Dev
|
||||
Go to ``Starfall/opts.h`` and change ``UrlSet`` to Dev.
|
||||
|
||||
## Redirecting every URL
|
||||
Go to ``Starfall/opts.h`` and change ``UrlSet`` to All.
|
||||
|
||||
## Enabling Console for debugging
|
||||
Go to ``Starfall/opts.h`` and change ``Console`` to true.
|
||||
|
||||
# Other
|
||||
If you use Starfall for a project please credit me.
|
||||
@@ -0,0 +1,34 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.9.34616.47
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "plooshfinder", "plooshfinder\plooshfinder.vcxproj", "{1EFDB154-D3B5-43BC-8733-F3D6941C9E36}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Starfall", "Starfall\Starfall.vcxproj", "{9C02D0A1-F786-4B04-B466-8D58C5B74FD1}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{1EFDB154-D3B5-43BC-8733-F3D6941C9E36} = {1EFDB154-D3B5-43BC-8733-F3D6941C9E36}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{1EFDB154-D3B5-43BC-8733-F3D6941C9E36}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1EFDB154-D3B5-43BC-8733-F3D6941C9E36}.Debug|x64.Build.0 = Debug|x64
|
||||
{1EFDB154-D3B5-43BC-8733-F3D6941C9E36}.Release|x64.ActiveCfg = Release|x64
|
||||
{1EFDB154-D3B5-43BC-8733-F3D6941C9E36}.Release|x64.Build.0 = Release|x64
|
||||
{9C02D0A1-F786-4B04-B466-8D58C5B74FD1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9C02D0A1-F786-4B04-B466-8D58C5B74FD1}.Debug|x64.Build.0 = Debug|x64
|
||||
{9C02D0A1-F786-4B04-B466-8D58C5B74FD1}.Release|x64.ActiveCfg = Release|x64
|
||||
{9C02D0A1-F786-4B04-B466-8D58C5B74FD1}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {2BE449DA-BD65-4FB2-9582-A7FCB41F1393}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,118 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{9c02d0a1-f786-4b04-b466-8d58c5b74fd1}</ProjectGuid>
|
||||
<RootNamespace>Starfall</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;STARFALL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalDependencies>$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;STARFALL_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
|
||||
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
|
||||
<IntelJCCErratum>false</IntelJCCErratum>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalDependencies>$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<EntryPointSymbol>
|
||||
</EntryPointSymbol>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="base.h" />
|
||||
<ClInclude Include="exit.h" />
|
||||
<ClInclude Include="hooking.h" />
|
||||
<ClInclude Include="opts.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
<ClInclude Include="redirection.h" />
|
||||
<ClInclude Include="request.h" />
|
||||
<ClInclude Include="ue.h" />
|
||||
<ClInclude Include="url.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="base.cpp" />
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="exit.cpp" />
|
||||
<ClCompile Include="hooking.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="redirection.cpp" />
|
||||
<ClCompile Include="request.cpp" />
|
||||
<ClCompile Include="ue.cpp" />
|
||||
<ClCompile Include="url.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="opts.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="redirection.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="url.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="hooking.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ue.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="exit.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="base.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="request.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="exit.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="base.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="hooking.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="redirection.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ue.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="url.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="request.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,14 @@
|
||||
#include "pch.h"
|
||||
#include "base.h"
|
||||
|
||||
namespace Starfall {
|
||||
namespace Globals {
|
||||
void* buf;
|
||||
|
||||
void* tbuf;
|
||||
size_t tsize;
|
||||
|
||||
void* rbuf;
|
||||
size_t rsize;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include "opts.h"
|
||||
#include "pch.h"
|
||||
|
||||
namespace Starfall {
|
||||
namespace Globals {
|
||||
extern void* buf;
|
||||
//extern size_t size;
|
||||
|
||||
extern void* tbuf;
|
||||
extern size_t tsize;
|
||||
|
||||
extern void* rbuf;
|
||||
extern size_t rsize;
|
||||
}
|
||||
using namespace Globals;
|
||||
};
|
||||
using namespace Starfall;
|
||||
|
||||
#define Log(type, ...) if (Console) printf("LogStarfall: " #type ": " __VA_ARGS__)
|
||||
@@ -0,0 +1,54 @@
|
||||
#include "pch.h"
|
||||
#include "base.h"
|
||||
#include "request.h"
|
||||
#include "exit.h"
|
||||
#include "opts.h"
|
||||
|
||||
namespace Starfall {
|
||||
void Init() {
|
||||
if (Console) {
|
||||
AllocConsole();
|
||||
|
||||
FILE* fptr;
|
||||
freopen_s(&fptr, "CONOUT$", "w+", stdout);
|
||||
SetConsoleTitleA("Starfall - https://github.com/ParadiseFN/Starfall");
|
||||
}
|
||||
|
||||
if (UseBackendParam) {
|
||||
FString cmd = GetCommandLineW();
|
||||
auto pos = cmd.find(L"-backend=");
|
||||
if (pos != std::wstring::npos) {
|
||||
backend = cmd.substr(pos + 9);
|
||||
}
|
||||
else {
|
||||
backend = Backend;
|
||||
}
|
||||
}
|
||||
|
||||
buf = *(void**)(__readgsqword(0x60) + 0x10);
|
||||
|
||||
auto section = pe_get_section((char*)buf, ".text");
|
||||
auto rsection = pe_get_section((char*)buf, ".rdata");
|
||||
|
||||
tbuf = (void*)(__int64(buf) + section->virtualAddress);
|
||||
tsize = section->virtualSize;
|
||||
|
||||
rbuf = (void*)(__int64(buf) + rsection->virtualAddress);
|
||||
rsize = rsection->virtualSize;
|
||||
|
||||
FindProcessRequest();
|
||||
if (Game == Fortnite) FindPushWidget();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL APIENTRY DllMain( HMODULE dllBase,
|
||||
DWORD callReason,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
if (callReason == 1) ManualMapping ? Init() : (void) CreateThread(0, 0, (LPTHREAD_START_ROUTINE)Init, 0, 0, 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
#include "pch.h"
|
||||
#include "hooking.h"
|
||||
#include "base.h"
|
||||
#include "exit.h"
|
||||
|
||||
namespace Starfall {
|
||||
int dontExit = 0;
|
||||
namespace Hooks {
|
||||
void RequestExitWithStatusHook(bool Force, unsigned char Code)
|
||||
{
|
||||
if (dontExit == 0) {
|
||||
TerminateProcess(GetCurrentProcess(), Code);
|
||||
}
|
||||
else {
|
||||
dontExit--;
|
||||
}
|
||||
}
|
||||
|
||||
void UnsafeEnvironmentPopupHook(wchar_t** unknown1, unsigned __int8 _case, __int64 unknown2, char unknown3)
|
||||
{
|
||||
dontExit++;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Callbacks {
|
||||
bool RequestExitWithStatusCallback(struct pf_patch_t* patch, void* stream) {
|
||||
AsmHook(stream, Hooks::RequestExitWithStatusHook);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UnsafeEnvironmentPopupCallback(struct pf_patch_t* patch, void* stream) {
|
||||
AsmHook(stream, Hooks::UnsafeEnvironmentPopupHook);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PushWidgetCallback(struct pf_patch_t* patch, void* stream) {
|
||||
FindExit();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Finders {
|
||||
void FindExit() {
|
||||
constexpr static struct pf_patch_t patch = pf_construct_patch_sig("48 89 5C 24 ? 57 48 83 EC 40 41 B9 ? ? ? ? 0F B6 F9 44 38 0D ? ? ? ? 0F B6 DA 72 24 89 5C 24 30 48 8D 05 ? ? ? ? 89 7C 24 28 4C 8D 05 ? ? ? ? 33 D2 48 89 44 24 ? 33 C9 E8 ? ? ? ?", RequestExitWithStatusCallback);
|
||||
constexpr static struct pf_patch_t patch2 = pf_construct_patch_sig("48 8B C4 48 89 58 18 88 50 10 88 48 08 57 48 83 EC 30", RequestExitWithStatusCallback);
|
||||
constexpr static struct pf_patch_t patch3 = pf_construct_patch_sig("4C 8B DC 49 89 5B 08 49 89 6B 10 49 89 73 18 49 89 7B 20 41 56 48 83 EC 30 80 3D ? ? ? ? ? 49 8B", RequestExitWithStatusCallback);
|
||||
|
||||
constexpr static struct pf_patch_t patch4 = pf_construct_patch_sig("4C 8B DC 55 49 8D AB ? ? ? ? 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 85 ? ? ? ? 49 89 73 F0 49 89 7B E8 48 8B F9 4D 89 63 E0 4D 8B E0 4D 89 6B D8", Ret0Callback); // 17.30
|
||||
constexpr static struct pf_patch_t patch5 = pf_construct_patch_sig("4C 8B DC 55 49 8D AB ? ? ? ? 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 85 ? ? ? ? 49 89 5B 20 48 8B D9 4D 89 63 E0 4D 89 6B D8", Ret0Callback); // 19.10
|
||||
constexpr static struct pf_patch_t patch6 = pf_construct_patch_sig("48 89 5C 24 ? 55 56 57 41 54 41 55 41 56 41 57 48 8D AC 24 ? ? ? ? 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 85 ? ? ? ? 80 B9 ? ? ? ? ? 48 8B DA 48 8B F1", Ret0Callback); // 28.00
|
||||
constexpr static struct pf_patch_t patch7 = pf_construct_patch_sig("40 55 53 56 57 41 54 41 56 41 57 48 8D AC 24 ? ? ? ? 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 85 ? ? ? ? ? 0F B6 ?", Ret0Callback); // 29.00/22.40
|
||||
constexpr static struct pf_patch_t patch8 = pf_construct_patch_sig("48 89 5C 24 ? 55 56 57 41 54 41 55 41 56 41 57 48 8D AC 24 ? ? ? ? 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 85 ? ? ? ? ? 0F B6 ? 44 88 44 24 ?", Ret0Callback); // 30.00
|
||||
|
||||
|
||||
constexpr static struct pf_patch_t patches2[] = {
|
||||
patch,
|
||||
patch2,
|
||||
patch3,
|
||||
patch4,
|
||||
patch5,
|
||||
patch6,
|
||||
patch7,
|
||||
patch8
|
||||
};
|
||||
|
||||
constexpr static struct pf_patchset_t patchset2 = pf_construct_patchset(patches2, sizeof(patches2) / sizeof(struct pf_patch_t), (bool (*)(void*, size_t, pf_patchset_t))pf_find_maskmatch);
|
||||
|
||||
pf_patchset_emit(tbuf, tsize, patchset2);
|
||||
}
|
||||
|
||||
void FindPushWidget()
|
||||
{
|
||||
constexpr static auto patch = pf_construct_patch_sig("48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC 30 48 8B E9 49 8B D9 48 8D 0D ? ? ? ? 49 8B F8 48 8B F2 E8 ? ? ? ? 4C 8B CF 48 89 5C 24 ? 4C 8B C6 48 8B D5 48 8B 48 78", PushWidgetCallback);
|
||||
constexpr static auto patch2 = pf_construct_patch_sig("48 8B C4 4C 89 40 18 48 89 50 10 48 89 48 08 55 53 56 57 41 54 41 55 41 56 41 57 48 8D 68 B8 48 81 EC ? ? ? ? 65 48 8B 04 25", PushWidgetCallback); // 26.00
|
||||
constexpr static auto patch3 = pf_construct_patch_sig("48 8B C4 48 89 58 10 48 89 70 18 48 89 78 20 55 41 56 41 57 48 8D 68 A1 48 81 EC ? ? ? ? 65 48 8B 04 25 ? ? ? ? 48 8B F9 B9 ? ? ? ? 49", PushWidgetCallback); // 28.00
|
||||
constexpr static auto patch4 = pf_construct_patch_sig("48 8B C4 48 89 58 08 48 89 70 10 48 89 78 18 55 41 56 41 57 48 8D 68 A1 48 81 EC ? ? ? ? 65 48 8B 04 25 ? ? ? ? 48 8B F9 B9 ? ? ? ? 48", PushWidgetCallback); // 30.00
|
||||
|
||||
constexpr static struct pf_patch_t patches[] = {
|
||||
patch,
|
||||
patch2,
|
||||
patch3,
|
||||
patch4
|
||||
};
|
||||
|
||||
constexpr static struct pf_patchset_t patchset = pf_construct_patchset(patches, sizeof(patches) / sizeof(struct pf_patch_t), (bool (*)(void*, size_t, pf_patchset_t))pf_find_maskmatch);
|
||||
|
||||
pf_patchset_emit(tbuf, tsize, patchset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
#include "pch.h"
|
||||
|
||||
namespace Starfall {
|
||||
namespace Callbacks {
|
||||
bool RequestExitWithStatusCallback(struct pf_patch_t* patch, void* stream);
|
||||
|
||||
bool PushWidgetCallback(struct pf_patch_t* patch, void* stream);
|
||||
}
|
||||
using namespace Callbacks;
|
||||
|
||||
namespace Finders {
|
||||
void FindExit();
|
||||
|
||||
void FindPushWidget();
|
||||
}
|
||||
using namespace Finders;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include "pch.h"
|
||||
#include "hooking.h"
|
||||
|
||||
namespace Starfall {
|
||||
namespace Hooking {
|
||||
__forceinline void AsmHook(uint64_t ptr, void* detour) {
|
||||
AsmHook((void*)ptr, detour);
|
||||
}
|
||||
|
||||
bool Ret0Callback(struct pf_patch_t* patch, void* stream) {
|
||||
DWORD og;
|
||||
VirtualProtect(stream, 1, PAGE_EXECUTE_READWRITE, &og);
|
||||
*(uint8_t*)stream = (uint8_t)0xC3;
|
||||
VirtualProtect(stream, 1, og, &og);
|
||||
return true;
|
||||
}
|
||||
|
||||
void VTHook(void** addr, void* detour, void** orig) {
|
||||
DWORD oldProt;
|
||||
|
||||
VirtualProtect(addr, sizeof(void*), PAGE_EXECUTE_READWRITE, &oldProt);
|
||||
|
||||
if (orig) *orig = *addr;
|
||||
|
||||
*addr = detour;
|
||||
|
||||
VirtualProtect(addr, sizeof(void*), oldProt, &oldProt);
|
||||
}
|
||||
}
|
||||
|
||||
__declspec(noinline) bool InternalCheckBytes(void* base, int ind, const uint8_t* bytes, size_t sz, bool upwards) {
|
||||
auto offBase = (uint8_t*)(upwards ? __int64(base) - ind : __int64(base) + ind);
|
||||
for (int i = 0; i < sz; i++) {
|
||||
if (*(offBase + i) != bytes[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
#include "pch.h"
|
||||
|
||||
|
||||
namespace Starfall {
|
||||
namespace Hooking {
|
||||
__forceinline void AsmHook(void* ptr, void* detour) {
|
||||
if (!ptr || !detour) return;
|
||||
|
||||
uint8_t data[] = {
|
||||
0x41, 0x52, // push r10
|
||||
0x49, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov r10, detour
|
||||
0x41, 0xFF, 0xD2, // call r10
|
||||
0x41, 0x5A, // pop r10
|
||||
0xC3 // ret
|
||||
};
|
||||
|
||||
DWORD oldProt;
|
||||
VirtualProtect(ptr, sizeof(data), PAGE_EXECUTE_READWRITE, &oldProt);
|
||||
|
||||
memcpy(ptr, data, sizeof(data));
|
||||
*(uint64_t*)(__int64(ptr) + 4) = (uint64_t)detour;
|
||||
|
||||
VirtualProtect(ptr, sizeof(data), oldProt, &oldProt);
|
||||
}
|
||||
|
||||
__forceinline void AsmHook(uint64_t ptr, void* detour);
|
||||
|
||||
bool Ret0Callback(struct pf_patch_t* patch, void* stream);
|
||||
|
||||
void VTHook(void** addr, void* detour, void** orig = nullptr);
|
||||
}
|
||||
using namespace Hooking;
|
||||
|
||||
bool InternalCheckBytes(void* base, int ind, const uint8_t* bytes, size_t sz, bool upwards = false);
|
||||
template <uint8_t... Data>
|
||||
class CheckBytes {
|
||||
public:
|
||||
constexpr static uint8_t bytes[sizeof...(Data)] = { Data... };
|
||||
void* Base;
|
||||
int Ind;
|
||||
bool Upwards;
|
||||
|
||||
CheckBytes(void* base, int ind, bool upwards = false) {
|
||||
Base = base;
|
||||
Ind = ind;
|
||||
Upwards = upwards;
|
||||
}
|
||||
|
||||
operator bool() {
|
||||
return InternalCheckBytes(Base, Ind, bytes, sizeof...(Data), Upwards);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//#define CheckBytes(base, ind, bytes, upwards) CheckBytesInternal(base, ind, bytes.data(), bytes.size(), upwards)
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "ue.h"
|
||||
|
||||
constexpr bool Console = false; // if the console window should be created
|
||||
constexpr StarfallURLSet URLSet = Default;
|
||||
constexpr inline FString Backend = L"http://127.0.0.1:3551"; // your backend url
|
||||
constexpr UEGame Game = Fortnite; // use Generic for any UE game other than fortnite
|
||||
|
||||
// misc options, don't change unless you know what you're doing
|
||||
constexpr bool UseBackendParam = false; // for phoenix/paradise launcher
|
||||
constexpr bool ManualMapping = false; // if you're using EAC & a manual mapper, then enable this for the dll to work
|
||||
constexpr bool FixMemLeak = true; // memory leak fix
|
||||
@@ -0,0 +1 @@
|
||||
#include "pch.h"
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef PCH_H
|
||||
#define PCH_H
|
||||
|
||||
#undef UNICODE
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <Windows.h>
|
||||
#include <array>
|
||||
#include <psapi.h>
|
||||
#include <string_view>
|
||||
|
||||
namespace Plooshfinder {
|
||||
#include "../plooshfinder/include/plooshfinder_sig.h"
|
||||
#include "../plooshfinder/include/plooshfinder.h"
|
||||
#include "../plooshfinder/include/formats/pe.h"
|
||||
};
|
||||
using namespace Plooshfinder;
|
||||
|
||||
namespace Starfall {
|
||||
namespace Types {
|
||||
enum StarfallURLSet {
|
||||
Default, // default, private server
|
||||
Hybrid, // redirect profile, version, and content pages to private server, otherwise use official
|
||||
Dev, // redirect profile & content pages to private server, otherwise use official
|
||||
All, // redirect every single request to private server
|
||||
};
|
||||
enum UEGame {
|
||||
Generic,
|
||||
Fortnite
|
||||
};
|
||||
}
|
||||
using namespace Types;
|
||||
}
|
||||
using namespace Starfall;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,58 @@
|
||||
#include "pch.h"
|
||||
#include "redirection.h"
|
||||
#include "opts.h"
|
||||
|
||||
namespace Starfall {
|
||||
namespace Redirection {
|
||||
bool shouldRedirect(URL* uri) {
|
||||
switch (URLSet) {
|
||||
case ::Hybrid: {
|
||||
constexpr static const wchar_t* redirectedPaths[] = {
|
||||
L"/fortnite/api/v2/versioncheck/",
|
||||
L"/fortnite/api/game/v2/profile/",
|
||||
L"/content/api/pages/",
|
||||
L"/affiliate/api/public/affiliates/slug",
|
||||
L"/socialban/api/public/v1",
|
||||
L"/fortnite/api/cloudstorage/system"
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(redirectedPaths) / sizeof(wchar_t*); i++) {
|
||||
if (uri->Path.starts_with(redirectedPaths[i])) return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ::Dev: {
|
||||
constexpr static const wchar_t* redirectedPathsDev[] = {
|
||||
L"/fortnite/api/game/v2/profile/",
|
||||
L"/affiliate/api/public/affiliates/slug",
|
||||
L"/content/api/pages/"
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(redirectedPathsDev) / sizeof(wchar_t*); i++) {
|
||||
if (uri->Path.starts_with(redirectedPathsDev[i])) return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ::Default: {
|
||||
static constexpr const wchar_t *redirectedUrls[] = {
|
||||
L"ol.epicgames.com",
|
||||
L"ol.epicgames.net",
|
||||
//L".akamaized.net", // if you have your own blurl
|
||||
L"on.epicgames.com",
|
||||
L"game-social.epicgames.com",
|
||||
L"ak.epicgames.com",
|
||||
//L"cdn2.unrealengine.com" // only needed if you have fixed friend images in friends list
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(redirectedUrls) / sizeof(wchar_t *); i++) {
|
||||
if (uri->Domain.ends_with(redirectedUrls[i])) return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ::All:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include "pch.h"
|
||||
#include "url.h"
|
||||
|
||||
namespace Starfall {
|
||||
namespace Redirection {
|
||||
bool shouldRedirect(URL* uri);
|
||||
}
|
||||
using namespace Redirection;
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
#include "pch.h"
|
||||
#include "base.h"
|
||||
#include "hooking.h"
|
||||
#include "url.h"
|
||||
#include "request.h"
|
||||
#include "redirection.h"
|
||||
#include <array>
|
||||
#include "opts.h"
|
||||
#include <time.h>
|
||||
#include <sys/timeb.h>
|
||||
|
||||
#define CallVirt(T, vt, offset, ...) ((T) vt[offset])(__VA_ARGS__)
|
||||
|
||||
namespace Unreal {
|
||||
FString FCurlHttpRequest::GetURL()
|
||||
{
|
||||
return GetURLFunc(this, FString());
|
||||
}
|
||||
|
||||
void FCurlHttpRequest::SetURL(URL& URL)
|
||||
{
|
||||
FString str = URL;
|
||||
SetURLFunc(this, str);
|
||||
free(str.String);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Starfall {
|
||||
bool setupMemLeak = false;
|
||||
void SetupRequest(FCurlHttpRequest* Request) {
|
||||
if (FCurlHttpRequest::SetURLFunc == nullptr) {
|
||||
void* GetFunc = *Request->VTable;
|
||||
FCurlHttpRequest::GetURLFunc = (decltype(FCurlHttpRequest::GetURLFunc)) *Request->VTable;
|
||||
uint32_t URLOffset = 0;
|
||||
for (int i = 0; i < 100; i++) {
|
||||
// this is only needed for latest
|
||||
if (CheckBytes<0x48, 0x8D, 0x91>(GetFunc, i)) {
|
||||
URLOffset = *(uint32_t*)(__int64(GetFunc) + i + 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (URLOffset == 0) goto def;
|
||||
for (int64_t i = 0; i < ((__int64(FCurlHttpRequest::ProcessRequestVT) - __int64(Request->VTable)) / 8) /* search radius */; i++) {
|
||||
auto func = Request->VTable[i];
|
||||
for (int j = 0; j < 100; j++) {
|
||||
if (CheckBytes<0x48, 0x81, 0xC1>(func, j)) {
|
||||
if (*(uint32_t*)(__int64(func) + j + 3) == URLOffset) {
|
||||
FCurlHttpRequest::SetURLFunc = (void (*)(FCurlHttpRequest*, FString)) Request->VTable[i];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
def:
|
||||
FCurlHttpRequest::SetURLFunc = (void (*)(FCurlHttpRequest*, FString)) Request->VTable[10];
|
||||
}
|
||||
// this works bc the first request is a datarouter request, and the second request should be after engine init
|
||||
else if (!setupMemLeak && Game == Fortnite) {
|
||||
constexpr static struct pf_patch_t ml_patch = pf_construct_patch_sig("4C 8B DC 55 57 41 56 49 8D AB ? ? ? ? 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 85 ? ? ? ? 48 8B 01 41 B6", Ret0Callback);
|
||||
|
||||
constexpr static struct pf_patch_t patches[] = {
|
||||
ml_patch
|
||||
};
|
||||
|
||||
constexpr static struct pf_patchset_t patchset = pf_construct_patchset(patches, sizeof(patches) / sizeof(struct pf_patch_t), (bool (*)(void*, size_t, pf_patchset_t))pf_find_maskmatch);
|
||||
|
||||
pf_patchset_emit(tbuf, tsize, patchset);
|
||||
setupMemLeak = true;
|
||||
}
|
||||
}
|
||||
|
||||
FString backend;
|
||||
|
||||
namespace Hooks {
|
||||
bool (*ProcessRequestOG)(FCurlHttpRequest* Request);
|
||||
bool ProcessRequestHook(FCurlHttpRequest* Request) {
|
||||
SetupRequest(Request);
|
||||
auto urlS = Request->GetURL();
|
||||
auto url = (URL *) malloc(sizeof(URL));
|
||||
if (!url) return false;
|
||||
__stosb((uint8_t*)url, 0, sizeof(URL));
|
||||
url->Construct(urlS);
|
||||
|
||||
Log(Display, "URL: %ls\n", static_cast<wchar_t *>(urlS));
|
||||
if (shouldRedirect(url)) {
|
||||
Request->SetURL(UseBackendParam ? url->SetHost(backend) : url->SetHost<Backend>());
|
||||
|
||||
UseBackendParam ? url->Dealloc() : url->DeallocPathQuery();
|
||||
}
|
||||
else {
|
||||
url->Dealloc();
|
||||
}
|
||||
|
||||
free(url);
|
||||
return ProcessRequestOG(Request);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Callbacks {
|
||||
bool PtrCallback(struct pf_patch_t* patch, void* stream) {
|
||||
FCurlHttpRequest::ProcessRequestVT = (void**)stream;
|
||||
|
||||
VTHook((void**)stream, ProcessRequestHook, (void **) &ProcessRequestOG);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StringCallback(struct pf_patch_t* patch, void* stream) {
|
||||
void* saddr = (void*)((__int64(stream) + 7) + *(int32_t*)(__int64(stream) + 3));
|
||||
if (__int64(saddr) >= __int64(rbuf) && __int64(saddr) < (__int64(rbuf) + (int64_t)rsize)) {
|
||||
if (wcscmp((wchar_t*)saddr, L"Could not set libcurl options for easy handle, processing HTTP request failed. Increase verbosity for additional information.") == 0) {
|
||||
for (int i = 0; i < 2048; i++) {
|
||||
if (CheckBytes<0x48, 0x81, 0xEC>(stream, i, true)) {
|
||||
for (int x = 0; x < 50; x++) {
|
||||
if (CheckBytes<0x40>(stream, i + x, true)) {
|
||||
Log(Display, "Found using 4.24 & lower method\n");
|
||||
stream = (uint8_t*)stream - i - x;
|
||||
goto HookVT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (wcscmp((wchar_t*)saddr, L"STAT_FCurlHttpRequest_ProcessRequest") == 0) {
|
||||
for (int i = 0; i < 2048; i++) {
|
||||
if (CheckBytes<0x4C, 0x8B, 0xDC>(stream, i, true)) {
|
||||
Log(Display, "Found using 4.25 & 4.26 method\n");
|
||||
goto setStream;
|
||||
}
|
||||
else if (CheckBytes<0x48, 0x8B, 0xC4>(stream, i, true)) {
|
||||
Log(Display, "Found using UE 4.27 - 5.3 method\n");
|
||||
setStream:
|
||||
stream = (uint8_t*)stream - i;
|
||||
goto HookVT;
|
||||
}
|
||||
else if (CheckBytes<0x48, 0x81, 0xEC>(stream, i, true) || CheckBytes<0x48, 0x83, 0xEC>(stream, i, true)) {
|
||||
for (int x = 0; x < 50; x++) {
|
||||
if (CheckBytes<0x40>(stream, i + x, true)) {
|
||||
Log(Display, "Found using UE 4.25, 4.26 & 5.4+ method\n");
|
||||
stream = (uint8_t*)stream - i - x;
|
||||
goto HookVT;
|
||||
} else if (CheckBytes<0x4C, 0x8B, 0xDC>(stream, i + x, true) || CheckBytes<0x4C, 0x8B, 0xC4>(stream, i + x, true)) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
HookVT:
|
||||
Log(Display, "ProcessRequest: 0x%llx\n", __int64(stream) - __int64(buf));
|
||||
char* ptrMatches = (char*)&stream;
|
||||
|
||||
#ifndef _DEBUG
|
||||
constexpr static char ptrMasks[] = {
|
||||
(char)0xff,
|
||||
(char)0xff,
|
||||
(char)0xff,
|
||||
(char)0xff,
|
||||
(char)0xff,
|
||||
(char)0xff,
|
||||
(char)0xff,
|
||||
(char)0xff
|
||||
};
|
||||
|
||||
constexpr static auto patch2 = pf_construct_patch_dynmatch((void*)ptrMasks, 8, PtrCallback);
|
||||
|
||||
constexpr static struct pf_patch_t patches2[] = {
|
||||
patch2
|
||||
};
|
||||
|
||||
constexpr static struct pf_patchset_t patchset2 = pf_construct_patchset(patches2, sizeof(patches2) / sizeof(struct pf_patch_t), (bool (*)(void*, size_t, pf_patchset_t))pf_find_maskmatch);
|
||||
|
||||
auto& patchToMod = (pf_patch_t &) patch2;
|
||||
DWORD og;
|
||||
VirtualProtect((void*)&(patchToMod.matches), sizeof(void*), PAGE_READWRITE, &og);
|
||||
patchToMod.matches = ptrMatches;
|
||||
VirtualProtect((void*)&(patchToMod.matches), sizeof(void*), og, &og);
|
||||
#else
|
||||
char ptrMasks[] = {
|
||||
(char)0xff,
|
||||
(char)0xff,
|
||||
(char)0xff,
|
||||
(char)0xff,
|
||||
(char)0xff,
|
||||
(char)0xff,
|
||||
(char)0xff,
|
||||
(char)0xff
|
||||
};
|
||||
|
||||
auto patch2 = pf_construct_patch(ptrMatches, (void*)ptrMasks, 8, PtrCallback);
|
||||
|
||||
struct pf_patch_t patches2[] = {
|
||||
patch2
|
||||
};
|
||||
|
||||
struct pf_patchset_t patchset2 = pf_construct_patchset(patches2, sizeof(patches2) / sizeof(struct pf_patch_t), (bool (*)(void*, size_t, pf_patchset_t))pf_find_maskmatch);
|
||||
#endif
|
||||
while (!pf_patchset_emit(rbuf, rsize, patchset2));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
namespace Finders {
|
||||
void FindProcessRequest() {
|
||||
constexpr static std::array<uint8_t, 2> matches = {
|
||||
0x48,
|
||||
0x8d
|
||||
};
|
||||
constexpr static std::array<uint8_t, 2> masks = {
|
||||
0xfb,
|
||||
0xff
|
||||
};
|
||||
|
||||
constexpr static auto patch = pf_construct_patch((void*)matches.data(), (void*)masks.data(), 2, StringCallback);
|
||||
|
||||
constexpr static pf_patch_t patches[] = {
|
||||
patch
|
||||
};
|
||||
|
||||
constexpr static struct pf_patchset_t patchset = pf_construct_patchset(patches, sizeof(patches) / sizeof(struct pf_patch_t), pf_find_maskmatch);
|
||||
|
||||
while (!pf_patchset_emit(tbuf, tsize, patchset));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
#include "pch.h"
|
||||
#include "ue.h"
|
||||
#include "url.h"
|
||||
|
||||
#define CallVirt(T, vt, offset, ...) ((T) vt[offset])(__VA_ARGS__)
|
||||
|
||||
namespace Unreal {
|
||||
class FCurlHttpRequest
|
||||
{
|
||||
public:
|
||||
void** VTable;
|
||||
static inline FString& (*GetURLFunc)(FCurlHttpRequest*, FString) = nullptr;
|
||||
static inline void (*SetURLFunc)(FCurlHttpRequest*, FString) = nullptr;
|
||||
static inline void** ProcessRequestVT = nullptr;
|
||||
|
||||
FString GetURL();
|
||||
void SetURL(URL& URL);
|
||||
};
|
||||
}
|
||||
|
||||
namespace Starfall {
|
||||
extern FString backend; // for phoenix/paradise launcher
|
||||
void SetupRequest(FCurlHttpRequest* Request);
|
||||
|
||||
namespace Hooks {
|
||||
bool ProcessRequestHook(FCurlHttpRequest* Request);
|
||||
}
|
||||
using namespace Hooks;
|
||||
|
||||
namespace Callbacks {
|
||||
bool PtrCallback(struct pf_patch_t* patch, void* stream);
|
||||
|
||||
bool StringCallback(struct pf_patch_t* patch, void* stream);
|
||||
}
|
||||
using namespace Callbacks;
|
||||
|
||||
namespace Finders {
|
||||
void FindProcessRequest();
|
||||
}
|
||||
using namespace Finders;
|
||||
}
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
#include "pch.h"
|
||||
#include "base.h"
|
||||
#include "ue.h"
|
||||
namespace Starfall {
|
||||
template <typename T>
|
||||
__forceinline T* Alloc(size_t sz) {
|
||||
return (T*)malloc(sz);
|
||||
}
|
||||
}
|
||||
|
||||
namespace Unreal {
|
||||
FString::FString()
|
||||
{
|
||||
String = nullptr;
|
||||
Length = MaxSize = 0;
|
||||
}
|
||||
|
||||
FString::FString(const char* Other)
|
||||
{
|
||||
if (Other)
|
||||
{
|
||||
MaxSize = Length = (int)strlen(Other) + 1;
|
||||
|
||||
AllocString();
|
||||
|
||||
size_t ConvertedChars = 0;
|
||||
mbstowcs_s(&ConvertedChars, String, Length, Other, _TRUNCATE);
|
||||
}
|
||||
}
|
||||
|
||||
FString::FString(wchar_t* Other)
|
||||
{
|
||||
if (Other) {
|
||||
MaxSize = Length = (int)wcslen(Other) + 1;
|
||||
|
||||
AllocString();
|
||||
|
||||
__movsb((PBYTE)String, (const PBYTE)Other, Length * sizeof(wchar_t));
|
||||
}
|
||||
}
|
||||
|
||||
FString::FString(uint32_t len) {
|
||||
MaxSize = Length = len + 1;
|
||||
AllocString();
|
||||
}
|
||||
|
||||
__declspec(noinline) FString FString::operator+(FString other) {
|
||||
if (!String || !other.String) return *this;
|
||||
auto sLen = Length - 1;
|
||||
auto oLen = other.Length - 1;
|
||||
FString nStr((uint32_t)(sLen + oLen));
|
||||
__movsb((PBYTE)nStr.String, (const PBYTE)String, sLen * sizeof(wchar_t));
|
||||
__movsb((PBYTE)nStr.String + sLen * sizeof(wchar_t), (const PBYTE)other.String, oLen * sizeof(wchar_t));
|
||||
nStr.String[nStr.Length - 1] = 0;
|
||||
return nStr;
|
||||
}
|
||||
|
||||
__declspec(noinline) void FString::operator+=(FString other) {
|
||||
if (!String || !other.String) return;
|
||||
auto sLen = Length - 1;
|
||||
auto oLen = other.Length - 1;
|
||||
Length = (uint32_t)(sLen + oLen + 1);
|
||||
auto os = String;
|
||||
AllocString();
|
||||
__movsb((PBYTE)String, (const PBYTE)os, sLen * sizeof(wchar_t));
|
||||
__movsb((PBYTE)String + sLen * sizeof(wchar_t), (const PBYTE)other.String, oLen * sizeof(wchar_t));
|
||||
String[Length - 1] = 0;
|
||||
free(os);
|
||||
}
|
||||
|
||||
__declspec(noinline) FString FString::substr(size_t off, size_t count) {
|
||||
if (count == -1) count = Length - off - 1;
|
||||
else if (count > Length) return *this;
|
||||
FString nStr((uint32_t)count);
|
||||
|
||||
__movsb((PBYTE) nStr.String, (const PBYTE) (String + off), count * sizeof(wchar_t));
|
||||
nStr.String[count] = 0;
|
||||
return nStr;
|
||||
}
|
||||
|
||||
__declspec(noinline) size_t FString::find(wchar_t c) {
|
||||
for (uint32_t i = 0; i < Length; i++) {
|
||||
if (String[i] == c) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t FString::find(char c) {
|
||||
return find((wchar_t)c);
|
||||
}
|
||||
|
||||
size_t FString::find(const wchar_t* c) {
|
||||
for (uint32_t i = 0; i < Length; i++) {
|
||||
bool found = true;
|
||||
for (int x = 0; x < wcslen(c); x++) {
|
||||
if (String[i + x] != c[x]) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool FString::contains(wchar_t c) {
|
||||
for (uint32_t i = 0; i < Length; i++) {
|
||||
if (String[i] == c) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FString::contains(const wchar_t* c) {
|
||||
for (uint32_t i = 0; i < Length; i++) {
|
||||
bool found = true;
|
||||
for (int x = 0; x < wcslen(c); x++) {
|
||||
if (String[i + x] != c[x]) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FString::starts_with(const wchar_t* c) {
|
||||
for (int x = 0; x < wcslen(c); x++) {
|
||||
if (String[x] != c[x]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FString::ends_with(const wchar_t* c) {
|
||||
auto cLen = wcslen(c);
|
||||
auto start = ((size_t) Length - 1) - cLen;
|
||||
for (size_t x = 0; x < cLen; x++) {
|
||||
if (String[start + x] != c[x]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t FString::find_first_of(char c) {
|
||||
return find(c);
|
||||
}
|
||||
|
||||
size_t FString::find_first_of(wchar_t c) {
|
||||
return find(c);
|
||||
}
|
||||
|
||||
wchar_t* FString::c_str() {
|
||||
return String;
|
||||
}
|
||||
|
||||
FString::operator wchar_t* () {
|
||||
return String;
|
||||
}
|
||||
|
||||
__declspec(noinline) void FString::Dealloc() {
|
||||
free(String);
|
||||
String = nullptr;
|
||||
MaxSize = Length = 0;
|
||||
}
|
||||
|
||||
inline void FString::AllocString() {
|
||||
String = Alloc<wchar_t>(Length * sizeof(wchar_t));
|
||||
}
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
#pragma once
|
||||
#include "pch.h"
|
||||
|
||||
namespace Unreal {
|
||||
class FString
|
||||
{
|
||||
public:
|
||||
wchar_t* String;
|
||||
uint32_t Length;
|
||||
uint32_t MaxSize;
|
||||
inline static const size_t npos = -1;
|
||||
FString();
|
||||
|
||||
FString(const char* Other);
|
||||
|
||||
FString(wchar_t* Other);
|
||||
|
||||
consteval FString(const wchar_t* Other) {
|
||||
if (Other) {
|
||||
MaxSize = Length = (int)std::wstring_view(Other).size() + 1;
|
||||
String = (wchar_t*)Other;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
consteval FString(const wchar_t* Other, size_t len) {
|
||||
if (Other) {
|
||||
MaxSize = Length = (uint32_t) len;
|
||||
String = (wchar_t*)Other;
|
||||
}
|
||||
}
|
||||
|
||||
FString(uint32_t len);
|
||||
|
||||
FString operator+(FString other);
|
||||
|
||||
void operator+=(FString other);
|
||||
|
||||
FString substr(size_t off, size_t count = -1);
|
||||
|
||||
size_t find(wchar_t c);
|
||||
|
||||
size_t find(char c);
|
||||
|
||||
size_t find(const wchar_t* c);
|
||||
|
||||
bool contains(wchar_t c);
|
||||
|
||||
bool contains(const wchar_t* c);
|
||||
|
||||
bool starts_with(const wchar_t* c);
|
||||
|
||||
bool ends_with(const wchar_t* c);
|
||||
|
||||
size_t find_first_of(char c);
|
||||
|
||||
size_t find_first_of(wchar_t c);
|
||||
|
||||
wchar_t* c_str();
|
||||
|
||||
operator wchar_t* ();
|
||||
|
||||
void Dealloc();
|
||||
private:
|
||||
inline void AllocString();
|
||||
};
|
||||
|
||||
class FStringUtil {
|
||||
public:
|
||||
consteval static size_t find_const(const FString s, const wchar_t c) {
|
||||
for (uint32_t i = 0; i < s.Length; i++) {
|
||||
if (s.String[i] == c) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
template<FString s, size_t off, size_t count = -1>
|
||||
consteval static std::array<wchar_t, count == -1 ? s.Length - off : count + 1> substr() {
|
||||
std::array<wchar_t, count == -1 ? s.Length - off : count + 1> arr;
|
||||
|
||||
for (size_t i = 0; i < (count == -1 ? (s.Length - off) : count + 1); i++) {
|
||||
arr[i] = (s.String + off)[i];
|
||||
}
|
||||
arr[(count == -1 ? s.Length - off - 1 : count)] = 0;
|
||||
return arr;
|
||||
}
|
||||
};
|
||||
|
||||
class CPPArrayUtil {
|
||||
public:
|
||||
template<size_t S, std::array<wchar_t, S> s, size_t off, size_t count = -1>
|
||||
consteval static std::array<wchar_t, count == -1 ? S - off : count + 1> substr() {
|
||||
if (off == FString::npos) return {};
|
||||
std::array<wchar_t, count == -1 ? S - off : count + 1> arr;
|
||||
|
||||
for (size_t i = 0; i < (count == -1 ? (S - off) : count + 1); i++) {
|
||||
arr[i] = (s.data() + off)[i];
|
||||
}
|
||||
arr[(count == -1 ? S - off - 1 : count)] = 0;
|
||||
return arr;
|
||||
}
|
||||
|
||||
|
||||
template<size_t S, std::array<wchar_t, S> a>
|
||||
consteval static size_t find(const wchar_t c) {
|
||||
for (uint32_t i = 0; i < a.size(); i++) {
|
||||
if (a[i] == c) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
}
|
||||
using namespace Unreal;
|
||||
@@ -0,0 +1,32 @@
|
||||
#include "pch.h"
|
||||
#include "url.h"
|
||||
|
||||
namespace Starfall {
|
||||
URL::StrType URL::GetUrl() {
|
||||
StrType v1 = Protocol.substr(0, Protocol.Length - 1);
|
||||
v1 += Seperator;
|
||||
v1 += Domain;
|
||||
v1 += Port;
|
||||
v1 += Path;
|
||||
v1 += Query;
|
||||
return v1;
|
||||
}
|
||||
|
||||
URL::operator StrType() {
|
||||
return GetUrl();
|
||||
}
|
||||
|
||||
void URL::DeallocPathQuery() {
|
||||
Path.Dealloc();
|
||||
Query.Dealloc();
|
||||
}
|
||||
|
||||
void URL::Dealloc() {
|
||||
Protocol.Dealloc();
|
||||
Seperator.Dealloc();
|
||||
Domain.Dealloc();
|
||||
Port.Dealloc();
|
||||
Path.Dealloc();
|
||||
Query.Dealloc();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
#include "pch.h"
|
||||
#include "ue.h"
|
||||
|
||||
namespace Starfall {
|
||||
class URL {
|
||||
public:
|
||||
using StrType = FString;
|
||||
StrType Protocol, Seperator, Domain, Port, Path, Query;
|
||||
|
||||
void Construct(StrType& url) {
|
||||
auto ProtoEnd = url.find(':');
|
||||
Protocol = url.substr(0, ProtoEnd);
|
||||
auto ProtoSize = (url[ProtoEnd + 1] == '/' && url[ProtoEnd + 2] == '/') ? 3 : 1;
|
||||
Seperator = url.substr(ProtoEnd, ProtoSize);
|
||||
auto DomainAndPortStart = url.substr(ProtoEnd + ProtoSize);
|
||||
auto PathEnd = DomainAndPortStart.find_first_of('/');
|
||||
auto DomainAndPort = DomainAndPortStart.substr(0, PathEnd);
|
||||
auto PathStart = DomainAndPortStart.substr(PathEnd);
|
||||
DomainAndPortStart.Dealloc();
|
||||
auto PortOff = DomainAndPort.find_first_of(':');
|
||||
Domain = DomainAndPort.substr(0, PortOff);
|
||||
if (PortOff != StrType::npos) Port = DomainAndPort.substr(PortOff);
|
||||
DomainAndPort.Dealloc();
|
||||
auto QueryOff = PathStart.find_first_of('?');
|
||||
Path = PathStart.substr(0, QueryOff);
|
||||
if (QueryOff != StrType::npos) Query = PathStart.substr(QueryOff);
|
||||
PathStart.Dealloc();
|
||||
}
|
||||
|
||||
URL& SetHost(FString host) {
|
||||
auto ProtoEnd = host.find(':');
|
||||
Protocol = host.substr(0, ProtoEnd);
|
||||
auto ProtoSize = (host[ProtoEnd + 1] == '/' && host[ProtoEnd + 2] == '/') ? 3 : 1;
|
||||
Seperator.Dealloc();
|
||||
Seperator = host.substr(ProtoEnd, ProtoSize);
|
||||
auto DomainAndPortStart = host.substr(ProtoEnd + ProtoSize);
|
||||
auto PathEnd = DomainAndPortStart.find_first_of('/');
|
||||
auto DomainAndPort = DomainAndPortStart.substr(0, PathEnd);
|
||||
DomainAndPortStart.Dealloc();
|
||||
auto PortOff = DomainAndPort.find_first_of(':');
|
||||
Domain.Dealloc();
|
||||
Domain = DomainAndPort.substr(0, PortOff);
|
||||
if (PortOff != StrType::npos) {
|
||||
Port.Dealloc();
|
||||
Port = DomainAndPort.substr(PortOff);
|
||||
}
|
||||
DomainAndPort.Dealloc();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <FString host>
|
||||
URL& SetHost() {
|
||||
constexpr auto ProtoEnd = FStringUtil::find_const(host, ':');
|
||||
Protocol.Dealloc();
|
||||
constexpr static auto ProtocolS = FStringUtil::substr<host, 0, ProtoEnd>();
|
||||
constexpr static FString ProtocolV = ProtocolS.data();
|
||||
Protocol = ProtocolV;
|
||||
constexpr auto ProtoSize = (host.String[ProtoEnd + 1] == '/' && host.String[ProtoEnd + 2] == '/') ? 3 : 1;
|
||||
Seperator.Dealloc();
|
||||
constexpr static auto SeperatorS = FStringUtil::substr<host, ProtoEnd, ProtoSize>();
|
||||
constexpr static FString SeperatorV = SeperatorS.data();
|
||||
Seperator = SeperatorV;
|
||||
constexpr auto DomainAndPortStart = FStringUtil::substr<host, ProtoEnd + ProtoSize>();
|
||||
constexpr auto PathEnd = CPPArrayUtil::find<DomainAndPortStart.size(), DomainAndPortStart>('/');
|
||||
constexpr auto DomainAndPort = CPPArrayUtil::substr<DomainAndPortStart.size(), DomainAndPortStart, 0, PathEnd>();
|
||||
constexpr auto PortOff = CPPArrayUtil::find<DomainAndPort.size(), DomainAndPort>(':');
|
||||
Domain.Dealloc();
|
||||
constexpr static auto DomainS = CPPArrayUtil::substr<DomainAndPort.size(), DomainAndPort, 0, PortOff>();
|
||||
constexpr static FString DomainV = DomainS.data();
|
||||
Domain = DomainV;
|
||||
if (PortOff != FString::npos) {
|
||||
Port.Dealloc();
|
||||
constexpr static auto PortS = CPPArrayUtil::substr<DomainAndPort.size(), DomainAndPort, PortOff>();
|
||||
constexpr static FString PortV = PortS.data();
|
||||
Port = PortV;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
StrType GetUrl();
|
||||
|
||||
operator StrType();
|
||||
|
||||
void Dealloc();
|
||||
void DeallocPathQuery();
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// Hint files help the Visual Studio IDE interpret Visual C++ identifiers
|
||||
// such as names of functions and macros.
|
||||
// For more information see https://go.microsoft.com/fwlink/?linkid=865984
|
||||
#define PF_C
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define PF_C extern "C"
|
||||
#else
|
||||
#define PF_C
|
||||
#endif
|
||||
|
||||
PF_C uint32_t arm64_branch(void *caller, void *target, bool link);
|
||||
@@ -0,0 +1,69 @@
|
||||
#ifndef _ELF_DEFS_H
|
||||
#define _ELF_DEFS_H
|
||||
#include <stdint.h>
|
||||
|
||||
#define SHT_SYMTAB 0x2
|
||||
#define SHT_DYNSYM 0xb
|
||||
#define PT_LOAD 0x1
|
||||
|
||||
struct elf_ident_64 {
|
||||
char signature[4];
|
||||
uint8_t file_class;
|
||||
uint8_t encoding;
|
||||
uint8_t version;
|
||||
uint8_t os;
|
||||
uint8_t abi_version;
|
||||
char pad[7];
|
||||
};
|
||||
|
||||
struct elf_header_64 {
|
||||
struct elf_ident_64 ident;
|
||||
uint16_t type;
|
||||
uint16_t machine;
|
||||
uint32_t version;
|
||||
uint64_t entry;
|
||||
uint64_t ph_off;
|
||||
uint64_t sh_off;
|
||||
uint32_t flags;
|
||||
uint16_t head_size;
|
||||
uint16_t ph_size;
|
||||
uint16_t ph_count;
|
||||
uint16_t sh_size;
|
||||
uint16_t sh_count;
|
||||
uint16_t sect_table_index;
|
||||
};
|
||||
|
||||
struct elf_pheader_64 {
|
||||
uint32_t type;
|
||||
uint32_t flags;
|
||||
uint64_t offset;
|
||||
uint64_t virtual_address;
|
||||
uint64_t physical_address;
|
||||
uint64_t file_size;
|
||||
uint64_t memory_size;
|
||||
uint64_t align;
|
||||
};
|
||||
|
||||
struct elf_sheader_64 {
|
||||
uint32_t name_off;
|
||||
uint32_t type;
|
||||
uint64_t flags;
|
||||
uint64_t address;
|
||||
uint64_t offset;
|
||||
uint64_t size;
|
||||
uint32_t link;
|
||||
uint32_t info;
|
||||
uint64_t align;
|
||||
uint64_t entry_count;
|
||||
};
|
||||
|
||||
struct elf_symbol_64 {
|
||||
uint32_t name;
|
||||
unsigned char info;
|
||||
unsigned char other;
|
||||
uint16_t sh_index;
|
||||
uint64_t offset;
|
||||
uint64_t size;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,129 @@
|
||||
#ifndef _MACHO_DEFS_H
|
||||
#define _MACHO_DEFS_H
|
||||
#include <stdint.h>
|
||||
|
||||
#define LC_SEGMENT_64 0x19
|
||||
#define LC_BUILD_VERSION 0x32
|
||||
#define LC_SYMTAB 0x2
|
||||
#define CPU_TYPE_ARM64 0xc000001
|
||||
#define LC_FILESET_ENTRY 0x80000035
|
||||
|
||||
struct mach_header_64 {
|
||||
uint32_t magic;
|
||||
uint32_t cputype;
|
||||
uint32_t cpusubtype;
|
||||
uint32_t filetype;
|
||||
uint32_t ncmds;
|
||||
uint32_t sizeofcmds;
|
||||
uint32_t flags;
|
||||
uint32_t reserved;
|
||||
};
|
||||
|
||||
struct fat_header {
|
||||
uint32_t magic;
|
||||
uint32_t nfat_arch;
|
||||
};
|
||||
|
||||
struct fat_arch {
|
||||
uint32_t cputype;
|
||||
uint32_t cpusubtype;
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
uint32_t align;
|
||||
};
|
||||
|
||||
struct section_64 {
|
||||
char sectname[16];
|
||||
char segname[16];
|
||||
|
||||
uint64_t addr;
|
||||
uint64_t size;
|
||||
uint32_t offset;
|
||||
uint32_t align;
|
||||
uint32_t reloff;
|
||||
uint32_t nreloc;
|
||||
uint32_t flags;
|
||||
uint32_t reserved1;
|
||||
uint32_t reserved2;
|
||||
uint32_t reserved3;
|
||||
};
|
||||
|
||||
struct segment_command_64 {
|
||||
uint32_t cmd;
|
||||
uint32_t cmdsize;
|
||||
|
||||
char segname[16];
|
||||
uint64_t vmaddr;
|
||||
uint64_t vmsize;
|
||||
uint64_t fileoff;
|
||||
uint64_t filesize;
|
||||
uint32_t maxprot;
|
||||
uint32_t initprot;
|
||||
uint32_t nsects;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
struct load_command_64 {
|
||||
uint32_t cmd;
|
||||
uint32_t cmdsize;
|
||||
};
|
||||
|
||||
struct build_version_command {
|
||||
uint32_t cmd;
|
||||
uint32_t cmdsize;
|
||||
|
||||
uint32_t platform;
|
||||
uint32_t minos;
|
||||
uint32_t sdk;
|
||||
uint32_t ntools;
|
||||
};
|
||||
|
||||
struct symtab_command {
|
||||
uint32_t cmd;
|
||||
uint32_t cmdsize;
|
||||
uint32_t symoff;
|
||||
uint32_t nsyms;
|
||||
uint32_t stroff;
|
||||
uint32_t strsize;
|
||||
};
|
||||
|
||||
struct nlist_64 {
|
||||
union {
|
||||
uint32_t str_index;
|
||||
} un;
|
||||
uint8_t type;
|
||||
uint8_t nsect;
|
||||
uint16_t desc;
|
||||
uint64_t offset;
|
||||
};
|
||||
|
||||
struct kmod_info {
|
||||
struct kmod_info *next;
|
||||
int32_t info_version;
|
||||
uint32_t id;
|
||||
char name[64];
|
||||
char version[64];
|
||||
int32_t reference_count;
|
||||
struct kmod_reference *reference_list;
|
||||
uint64_t address;
|
||||
uint64_t size;
|
||||
uint64_t hdr_size;
|
||||
void *start;
|
||||
void *stop;
|
||||
};
|
||||
|
||||
struct kmod_reference {
|
||||
struct kmod_reference *next;
|
||||
struct kmod_info *info;
|
||||
};
|
||||
|
||||
struct fileset_entry_command {
|
||||
uint32_t cmd;
|
||||
uint32_t cmdsize;
|
||||
uint64_t vmaddr;
|
||||
uint64_t fileoff;
|
||||
uint32_t entry_id;
|
||||
uint32_t reserved;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,119 @@
|
||||
#ifndef _PE_DEFS_H
|
||||
#define _PE_DEFS_H
|
||||
#include <stdint.h>
|
||||
|
||||
struct DOS_Header {
|
||||
char e_magic[0x2];
|
||||
uint16_t e_cblp;
|
||||
uint16_t e_cp;
|
||||
uint16_t e_crlc;
|
||||
uint16_t e_cparhdr;
|
||||
uint16_t e_minalloc;
|
||||
uint16_t e_maxalloc;
|
||||
uint16_t e_ss;
|
||||
uint16_t e_sp;
|
||||
uint16_t e_csum;
|
||||
uint16_t e_ip;
|
||||
uint16_t e_cs;
|
||||
uint16_t e_lfarlc;
|
||||
uint16_t e_ovno;
|
||||
char e_res1[0x8];
|
||||
uint16_t e_oemid;
|
||||
uint16_t e_oeminfo;
|
||||
char e_res2[0x14];
|
||||
uint32_t e_lfanew;
|
||||
};
|
||||
|
||||
struct COFF_Header {
|
||||
char magic[0x4];
|
||||
uint16_t machine;
|
||||
uint16_t numberOfSections;
|
||||
uint32_t timeDateStamp;
|
||||
uint32_t pointerToSymbolTable;
|
||||
uint32_t numberOfSymbols;
|
||||
uint16_t sizeOfOptionalHeader;
|
||||
uint16_t characteristics;
|
||||
};
|
||||
|
||||
struct Section_Header {
|
||||
char name[0x8];
|
||||
uint32_t virtualSize;
|
||||
uint32_t virtualAddress;
|
||||
uint32_t sizeOfRawData;
|
||||
uint32_t pointerToRawData;
|
||||
uint32_t pointerToRelocations;
|
||||
uint32_t pointerToLineNumbers;
|
||||
uint16_t numberOfRelocations;
|
||||
uint16_t numberOfLineNumbers;
|
||||
uint32_t characteristics;
|
||||
};
|
||||
|
||||
struct Symbol_Header {
|
||||
union {
|
||||
char name[0x8];
|
||||
struct {
|
||||
uint32_t zeros;
|
||||
uint32_t strtab_off;
|
||||
} over_8b;
|
||||
} name;
|
||||
uint32_t value;
|
||||
int16_t nsect;
|
||||
uint16_t type;
|
||||
uint8_t s_class;
|
||||
uint8_t n_aux;
|
||||
};
|
||||
|
||||
struct PE_Data_Directory_Entry {
|
||||
uint32_t virtualAddress;
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
struct PE64_Optional_Header {
|
||||
uint16_t magic;
|
||||
uint8_t majorLinkerVersion;
|
||||
uint8_t minorLinkerVersion;
|
||||
uint32_t sizeOfCode;
|
||||
uint32_t sizeOfInitializedData;
|
||||
uint32_t sizeOfUninitializedData;
|
||||
uint32_t addressOfEntryPoint;
|
||||
uint32_t baseOfCode;
|
||||
uint64_t imageBase;
|
||||
uint32_t sectionAlignment;
|
||||
uint32_t fileAlignment;
|
||||
uint16_t majorOperatingSystemVersion;
|
||||
uint16_t minorOperatingSystemVersion;
|
||||
uint16_t majorImageVersion;
|
||||
uint16_t minorImageVersion;
|
||||
uint16_t majorSubsystemVersion;
|
||||
uint16_t minorSubsystemVersion;
|
||||
uint32_t win32VersionValue;
|
||||
uint32_t sizeOfImage;
|
||||
uint32_t sizeOfHeaders;
|
||||
uint32_t checkSum;
|
||||
uint16_t subsystem;
|
||||
uint16_t dllCharacteristics;
|
||||
uint64_t sizeOfStackReserve;
|
||||
uint64_t sizeOfStackCommit;
|
||||
uint64_t sizeOfHeapReserve;
|
||||
uint64_t sizeOfHeapCommit;
|
||||
uint32_t loaderFlags;
|
||||
uint32_t numberOfRvaAndSizes;
|
||||
struct PE_Data_Directory_Entry exportTableEntry;
|
||||
struct PE_Data_Directory_Entry importTableEntry;
|
||||
struct PE_Data_Directory_Entry resourceTableEntry;
|
||||
struct PE_Data_Directory_Entry exceptionTableEntry;
|
||||
struct PE_Data_Directory_Entry certificateTableEntry;
|
||||
struct PE_Data_Directory_Entry baseRelocationTableEntry;
|
||||
struct PE_Data_Directory_Entry debugEntry;
|
||||
struct PE_Data_Directory_Entry architectureEntry;
|
||||
struct PE_Data_Directory_Entry globalPtrEntry;
|
||||
struct PE_Data_Directory_Entry tlsTableEntry;
|
||||
struct PE_Data_Directory_Entry loadConfigTableEntry;
|
||||
struct PE_Data_Directory_Entry boundImportEntry;
|
||||
struct PE_Data_Directory_Entry iatEntry;
|
||||
struct PE_Data_Directory_Entry delayImportDescriptorEntry;
|
||||
struct PE_Data_Directory_Entry clrRuntimeHeaderEntry;
|
||||
struct PE_Data_Directory_Entry reservedEntry;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef _ELF_H
|
||||
#define _ELF_H
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "defs/elf_defs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define PF_C extern "C"
|
||||
#else
|
||||
#define PF_C
|
||||
#endif
|
||||
|
||||
PF_C bool elf_check(char *buf);
|
||||
PF_C bool is_elf(char *buf);
|
||||
PF_C struct elf_sheader_64 *elf_get_section(char *buf, char *name);
|
||||
PF_C char *elf_va_to_ptr(char *buf, uint64_t addr);
|
||||
PF_C uint64_t elf_ptr_to_va(char *buf, char *ptr);
|
||||
PF_C struct elf_symbol_64 *elf_find_symbol_stype(char *buf, char *name, uint32_t type);
|
||||
PF_C struct elf_symbol_64 *elf_find_symbol(char *buf, char *name);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef _MACHO_H
|
||||
#define _MACHO_H
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "defs/macho_defs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define PF_C extern "C"
|
||||
#else
|
||||
#define PF_C
|
||||
#endif
|
||||
|
||||
PF_C uint32_t macho_get_magic(char *buf);
|
||||
PF_C bool macho_check(char *buf);
|
||||
PF_C char *macho_find_arch(char *buf, uint32_t arch);
|
||||
PF_C uint32_t macho_get_platform(char *buf);
|
||||
PF_C struct segment_command_64 *macho_get_segment(char *buf, char *name);
|
||||
PF_C struct section_64 *macho_get_section(char *buf, struct segment_command_64 *segment, char *name);
|
||||
PF_C struct section_64 *macho_get_last_section(struct segment_command_64 *segment);
|
||||
PF_C struct section_64 *macho_find_section(char *buf, char *segment_name, char *section_name);
|
||||
PF_C struct fileset_entry_command *macho_get_fileset(char *buf, char *name);
|
||||
PF_C struct segment_command_64 *macho_get_segment_for_va(char *buf, uint64_t addr);
|
||||
PF_C struct section_64 *macho_get_section_for_va(struct segment_command_64 *segment, uint64_t addr);
|
||||
PF_C struct section_64 *macho_find_section_for_va(char *buf, uint64_t addr);
|
||||
PF_C char *macho_va_to_ptr(char *buf, uint64_t addr);
|
||||
PF_C struct segment_command_64 *macho_get_segment_for_ptr(char *buf, char *ptr);
|
||||
PF_C struct section_64 *macho_get_section_for_ptr(struct segment_command_64 *segment, char *buf, char *ptr);
|
||||
PF_C struct section_64 *macho_find_section_for_ptr(char *buf, char *ptr);
|
||||
PF_C uint64_t macho_ptr_to_va(char *buf, char *ptr);
|
||||
PF_C struct nlist_64 *macho_find_symbol(char *buf, char *name);
|
||||
PF_C uint64_t macho_get_symbol_size(struct nlist_64 *symbol);
|
||||
PF_C uint64_t macho_parse_plist_integer(char *key);
|
||||
PF_C struct mach_header_64 *macho_parse_prelink_info(char *buf, struct section_64 *kmod_info, char *bundle_name);
|
||||
PF_C uint64_t macho_xnu_untag_va(uint64_t addr);
|
||||
PF_C struct mach_header_64 *macho_parse_kmod_info(char *buf, struct section_64 *kmod_info, struct section_64 *kmod_start, char *bundle_name);
|
||||
PF_C struct mach_header_64 *macho_find_kext(char *buf, char *name);
|
||||
PF_C void macho_run_each_kext(char *buf, void (*function)(char *real_buf, char *kextbuf, uint64_t kext_size));
|
||||
PF_C char *fileset_va_to_ptr(char *buf, char *kext, uint64_t addr);
|
||||
PF_C struct segment_command_64 *fileset_get_segment_for_ptr(char *buf, char *kext, char *ptr);
|
||||
PF_C struct section_64 *fileset_find_section_for_ptr(char *buf, char *kext, char *ptr);
|
||||
PF_C uint64_t fileset_ptr_to_va(char *buf, char *kext, char *ptr);
|
||||
PF_C struct nlist_64 *fileset_find_symbol(char *buf, char *kext, char *name);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef _MULTI_H
|
||||
#define _MULTI_H
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define PF_C extern "C"
|
||||
#else
|
||||
#define PF_C
|
||||
#endif
|
||||
|
||||
PF_C void *pf_va_to_ptr(void *buf, uint64_t addr);
|
||||
PF_C uint64_t pf_ptr_to_va(void *buf, void *ptr);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef _PE_H
|
||||
#define _PE_H
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "defs/pe_defs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define PF_C extern "C"
|
||||
#else
|
||||
#define PF_C
|
||||
#endif
|
||||
|
||||
PF_C bool dos_check(char *buf);
|
||||
PF_C struct COFF_Header *get_pe_header(char *buf);
|
||||
PF_C bool pe_check(char *buf);
|
||||
PF_C bool is_pe(char *buf);
|
||||
PF_C struct PE64_Optional_Header *get_pe_opt_header(char *buf);
|
||||
PF_C struct Symbol_Header *pe_get_symtab(char *buf);
|
||||
PF_C char *pe_get_strtab(char *buf);
|
||||
PF_C struct Section_Header *pe_get_section(char *buf, const char *name);
|
||||
PF_C char *pe_va_to_ptr(char *buf, uint64_t addr);
|
||||
PF_C uint64_t pe_ptr_to_va(char *buf, char *ptr);
|
||||
PF_C struct Symbol_Header *pe_find_symbol(char *buf, char *name);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,89 @@
|
||||
#ifndef _PLOOSHFINDER_H
|
||||
#define _PLOOSHFINDER_H
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifndef _DEBUG
|
||||
#pragma comment(lib, "../x64/Release/plooshfinder.lib")
|
||||
#else
|
||||
#pragma comment(lib, "../x64/Debug/plooshfinder.lib")
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define PF_C extern "C"
|
||||
#else
|
||||
#define PF_C
|
||||
#endif
|
||||
|
||||
#pragma pack(push, 0x1)
|
||||
struct pf_patch_t {
|
||||
void *matches;
|
||||
void *masks;
|
||||
bool disabled;
|
||||
uint32_t count;
|
||||
bool (*callback)(struct pf_patch_t *patch, void *stream);
|
||||
};
|
||||
|
||||
struct pf_patchset_t {
|
||||
struct pf_patch_t *patches;
|
||||
uint32_t count;
|
||||
bool (*handler)(void *buf, size_t size, struct pf_patchset_t patch);
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
// patch utils
|
||||
#ifdef __cplusplus
|
||||
constexpr pf_patch_t pf_construct_patch(void* matches, void* masks, uint32_t count, bool (*callback)(struct pf_patch_t* patch, void* stream)) {
|
||||
struct pf_patch_t patch;
|
||||
|
||||
// construct the patch
|
||||
patch.matches = matches;
|
||||
patch.masks = masks;
|
||||
patch.disabled = false;
|
||||
patch.count = count;
|
||||
patch.callback = callback;
|
||||
|
||||
return patch;
|
||||
}
|
||||
|
||||
constexpr pf_patch_t pf_construct_patch_dynmatch(void* masks, uint32_t count, bool (*callback)(struct pf_patch_t* patch, void* stream)) {
|
||||
struct pf_patch_t patch;
|
||||
|
||||
// construct the patch
|
||||
patch.matches = nullptr;
|
||||
patch.masks = masks;
|
||||
patch.disabled = false;
|
||||
patch.count = count;
|
||||
patch.callback = callback;
|
||||
|
||||
return patch;
|
||||
}
|
||||
|
||||
constexpr struct pf_patchset_t pf_construct_patchset(struct pf_patch_t* patches, uint32_t count, bool (*handler)(void *buf, size_t size, struct pf_patchset_t patchset)) {
|
||||
struct pf_patchset_t patchset;
|
||||
|
||||
patchset.patches = patches;
|
||||
patchset.count = count;
|
||||
patchset.handler = handler;
|
||||
|
||||
return patchset;
|
||||
}
|
||||
|
||||
__forceinline constexpr struct pf_patchset_t pf_construct_patchset(const struct pf_patch_t* patches, uint32_t count, bool (*handler)(void* buf, size_t size, struct pf_patchset_t patchset)) {
|
||||
return pf_construct_patchset((struct pf_patch_t*)patches, count, handler);
|
||||
}
|
||||
#else
|
||||
PF_C struct pf_patch_t pf_construct_patch(void *matches, void *masks, uint32_t count, bool (*callback)(struct pf_patch_t *patch, void *stream));
|
||||
PF_C struct pf_patchset_t pf_construct_patchset(struct pf_patch_t* patches, uint32_t count, bool (*handler)(void* buf, size_t size, struct pf_patchset_t patchset));
|
||||
#endif
|
||||
PF_C bool pf_patchset_emit(void *buf, size_t size, struct pf_patchset_t patchset);
|
||||
PF_C void pf_disable_patch(struct pf_patch_t *patch);
|
||||
|
||||
// utils for finding
|
||||
PF_C uint8_t *pf_find_next(uint8_t *stream, uint32_t count, uint8_t match, uint8_t mask);
|
||||
PF_C uint8_t *pf_find_prev(uint8_t *stream, uint32_t count, uint8_t match, uint8_t mask);
|
||||
PF_C uint8_t* pf_find_next_multiple(uint8_t* stream, uint32_t count, uint8_t* matches, uint8_t* masks, uint32_t mmc);
|
||||
PF_C uint8_t* pf_find_prev_multiple(uint8_t* stream, uint32_t count, uint8_t* matches, uint8_t* masks, uint32_t mmc);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef _PLOOSHFINDER8_H
|
||||
#define _PLOOSHFINDER8_H
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define PF_C extern "C"
|
||||
#else
|
||||
#define PF_C
|
||||
#endif
|
||||
|
||||
#pragma pack(push, 0x1)
|
||||
struct pf_patch8_t {
|
||||
uint8_t *matches;
|
||||
uint8_t *masks;
|
||||
bool disabled;
|
||||
uint32_t count;
|
||||
bool (*callback)(struct pf_patch8_t *patch, void *stream);
|
||||
};
|
||||
|
||||
struct pf_patchset8_t {
|
||||
struct pf_patch8_t *patches;
|
||||
uint32_t count;
|
||||
bool (*handler)(void *buf, size_t size, struct pf_patchset8_t patch);
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
// patch utils
|
||||
PF_C bool pf_maskmatch(uint8_t insn, uint8_t match, uint8_t mask);
|
||||
PF_C bool pf_find_maskmatch(void *buf, size_t size, struct pf_patchset_t patchset);
|
||||
|
||||
// utils for finding
|
||||
PF_C int8_t pf_signextend(int8_t val, uint8_t bits);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,86 @@
|
||||
#ifndef _PLOOSHFINDER_SIG_H
|
||||
#define _PLOOSHFINDER_SIG_H
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include "plooshfinder8.h"
|
||||
#include "plooshfinder.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define PF_C extern "C"
|
||||
#else
|
||||
#define PF_C
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
// compile-time processed implementation of sig patch
|
||||
constexpr int PatternCount(std::string_view s) {
|
||||
int c = 0;
|
||||
for (int i = 0; i < s.size(); i++) {
|
||||
if (s[i] == ' ') c++;
|
||||
}
|
||||
return c + 1; // last i think
|
||||
}
|
||||
|
||||
constexpr uint32_t parsePatternPart(std::string_view s) {
|
||||
uint32_t val = 0;
|
||||
for (int i = 0; i < s.size(); i++) {
|
||||
uint8_t byte = s[i];
|
||||
if (byte >= '0' && byte <= '9') byte = byte - '0';
|
||||
else if (byte >= 'a' && byte <= 'f') byte = byte - 'a' + 10;
|
||||
else if (byte >= 'A' && byte <= 'F') byte = byte - 'A' + 10;
|
||||
else if (byte == '?') byte = 0;
|
||||
val = (val << 4) | (byte & 0xF);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
constexpr uint32_t parsePatternMask(std::string_view s) {
|
||||
uint32_t val = 0;
|
||||
for (int i = 0; i < s.size(); i++) {
|
||||
uint8_t byte = s[i];
|
||||
if (byte >= '0' && byte <= '9' || byte >= 'a' && byte <= 'f' || byte >= 'A' && byte <= 'F') byte = 0xf;
|
||||
else if (byte == '?') byte = 0x0;
|
||||
val = (val << 4) | (byte & 0xF);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
template <size_t sz, std::array<uint8_t, sz> match, std::array<uint8_t, sz> mask, bool (*call)(struct pf_patch_t* patch, void* stream)>
|
||||
class pf_constexpr_patch_data_t {
|
||||
public:
|
||||
static constexpr std::array<uint8_t, sz> matches = match;
|
||||
static constexpr std::array<uint8_t, sz> masks = mask;
|
||||
static constexpr size_t arrsz = sz;
|
||||
static constexpr bool (*cb)(struct pf_patch_t* patch, void* stream) = call;
|
||||
};
|
||||
#define pf_construct_patch_sig(sig, callback) []() consteval { \
|
||||
constexpr pf_constexpr_patch_data_t<PatternCount(sig), ([]() consteval { \
|
||||
constexpr auto st = std::string_view(sig); \
|
||||
constexpr auto arrsz = PatternCount(st); \
|
||||
std::array<uint8_t, arrsz> matches = { 0 }; \
|
||||
size_t cInd = 0; \
|
||||
for (int i = 0; i < arrsz; i++) { \
|
||||
auto part = st.substr(cInd, st.find_first_of(' ', cInd) == std::string_view::npos ? st.size() - cInd : (st.find_first_of(' ', cInd) + 1) - cInd - 1); \
|
||||
matches[i] = parsePatternPart(part); \
|
||||
cInd = st.find_first_of(' ', cInd) + 1; \
|
||||
} \
|
||||
return matches; \
|
||||
})(), ([]() consteval { \
|
||||
constexpr auto st = std::string_view(sig); \
|
||||
constexpr auto arrsz = PatternCount(st); \
|
||||
std::array<uint8_t, arrsz> masks = { 0 }; \
|
||||
size_t cInd = 0; \
|
||||
for (int i = 0; i < arrsz; i++) { \
|
||||
auto part = st.substr(cInd, st.find_first_of(' ', cInd) == std::string_view::npos ? st.size() - cInd : (st.find_first_of(' ', cInd) + 1) - cInd - 1); \
|
||||
masks[i] = parsePatternMask(part); \
|
||||
cInd = st.find_first_of(' ', cInd) + 1; \
|
||||
} \
|
||||
return masks; \
|
||||
})(), callback> d; \
|
||||
return pf_construct_patch((void *) d.matches.data(), (void *) d.masks.data(), d.arrsz, d.cb); \
|
||||
}()
|
||||
#else
|
||||
PF_C struct pf_patch_t pf_construct_patch_sig(const char *sig, bool (*callback)(struct pf_patch_t *patch, void *stream));
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef _UTILS_H
|
||||
#define _UTILS_H
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define PF_C extern "C"
|
||||
#else
|
||||
#define PF_C
|
||||
#endif
|
||||
|
||||
PF_C uint32_t convert_endianness32(uint32_t val);
|
||||
#define Cast(T, expr) (T) (expr)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,111 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\formats\elf.c" />
|
||||
<ClCompile Include="src\formats\macho.c" />
|
||||
<ClCompile Include="src\formats\multi.c" />
|
||||
<ClCompile Include="src\formats\pe.c" />
|
||||
<ClCompile Include="src\plooshfinder.c" />
|
||||
<ClCompile Include="src\plooshfinder8.c" />
|
||||
<ClCompile Include="src\plooshfinder_sig.c" />
|
||||
<ClCompile Include="src\utils.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\formats\defs\elf_defs.h" />
|
||||
<ClInclude Include="include\formats\defs\macho_defs.h" />
|
||||
<ClInclude Include="include\formats\defs\pe_defs.h" />
|
||||
<ClInclude Include="include\formats\elf.h" />
|
||||
<ClInclude Include="include\formats\macho.h" />
|
||||
<ClInclude Include="include\formats\multi.h" />
|
||||
<ClInclude Include="include\formats\pe.h" />
|
||||
<ClInclude Include="include\plooshfinder.h" />
|
||||
<ClInclude Include="include\plooshfinder8.h" />
|
||||
<ClInclude Include="include\plooshfinder_sig.h" />
|
||||
<ClInclude Include="include\utils.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="cpp.hint" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{1efdb154-d3b5-43bc-8733-f3d6941c9e36}</ProjectGuid>
|
||||
<RootNamespace>plooshfinder</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>
|
||||
</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NOLOG;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
|
||||
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>
|
||||
</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Source">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Headers">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Source\Formats">
|
||||
<UniqueIdentifier>{49b1533c-7528-46c5-840c-71827da7395a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Headers\Formats">
|
||||
<UniqueIdentifier>{358939c8-87b9-480a-a5c2-4510332a1f55}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Headers\Formats\Defs">
|
||||
<UniqueIdentifier>{a89650b4-9dcb-4857-9a4c-c85711680efc}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\plooshfinder.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\plooshfinder_sig.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\plooshfinder8.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\utils.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\formats\multi.c">
|
||||
<Filter>Source\Formats</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\formats\pe.c">
|
||||
<Filter>Source\Formats</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\formats\elf.c">
|
||||
<Filter>Source\Formats</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\formats\macho.c">
|
||||
<Filter>Source\Formats</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\plooshfinder.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\plooshfinder8.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\utils.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\formats\elf.h">
|
||||
<Filter>Headers\Formats</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\formats\macho.h">
|
||||
<Filter>Headers\Formats</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\formats\multi.h">
|
||||
<Filter>Headers\Formats</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\formats\pe.h">
|
||||
<Filter>Headers\Formats</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\formats\defs\elf_defs.h">
|
||||
<Filter>Headers\Formats\Defs</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\formats\defs\macho_defs.h">
|
||||
<Filter>Headers\Formats\Defs</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\formats\defs\pe_defs.h">
|
||||
<Filter>Headers\Formats\Defs</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\plooshfinder_sig.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="cpp.hint" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,162 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../../include/formats/elf.h"
|
||||
#include "../../include/utils.h"
|
||||
|
||||
bool elf_check(char *buf) {
|
||||
struct elf_header_64 *hdr = (struct elf_header_64 *) buf;
|
||||
char elf_magic[5] = { 0x7f, 'E', 'L', 'F' };
|
||||
|
||||
if (strncmp(hdr->ident.signature, elf_magic, 4) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_elf(char *buf) {
|
||||
bool elf = elf_check(buf);
|
||||
|
||||
if (!elf) {
|
||||
printf("%s: Not an ELF!\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
return elf;
|
||||
}
|
||||
|
||||
|
||||
struct elf_sheader_64 *elf_get_section(char *buf, char *name) {
|
||||
if (!elf_check(buf)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct elf_header_64 *hdr = (struct elf_header_64 *) buf;
|
||||
struct elf_sheader_64 *section_hdr = Cast(struct elf_sheader_64*, buf + hdr->sh_off);
|
||||
|
||||
struct elf_sheader_64 *sname_hdr = section_hdr + hdr->sect_table_index;
|
||||
char *sname_tbl = buf + sname_hdr->offset;
|
||||
|
||||
|
||||
for (uint16_t i = 0; i < hdr->sh_count; i++) {
|
||||
struct elf_sheader_64 *section = section_hdr + i;
|
||||
char *sect_name = sname_tbl + section->name_off;
|
||||
|
||||
if (strcmp(sect_name, name) == 0) {
|
||||
return section;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *elf_va_to_ptr(char *buf, uint64_t addr) {
|
||||
if (!elf_check(buf)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct elf_header_64 *hdr = (struct elf_header_64 *) buf;
|
||||
struct elf_pheader_64 *program_hdr = Cast(struct elf_pheader_64*, buf + hdr->ph_off);
|
||||
|
||||
for (int i = 0; i < hdr->ph_count; i++) {
|
||||
struct elf_pheader_64 *phdr = program_hdr + i;
|
||||
|
||||
if (phdr->type == PT_LOAD) {
|
||||
uint64_t segment_start = phdr->virtual_address;
|
||||
uint64_t segment_end = segment_start + phdr->file_size;
|
||||
if (segment_start <= addr && segment_end > addr) {
|
||||
uint64_t offset = addr - segment_start;
|
||||
return buf + phdr->offset + offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t elf_ptr_to_va(char *buf, char *ptr) {
|
||||
if (!elf_check(buf)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct elf_header_64 *hdr = (struct elf_header_64 *) buf;
|
||||
struct elf_pheader_64 *program_hdr = Cast(struct elf_pheader_64*, buf + hdr->ph_off);
|
||||
uint64_t ptr_addr = (uint64_t) ptr;
|
||||
|
||||
for (int i = 0; i < hdr->ph_count; i++) {
|
||||
struct elf_pheader_64 *phdr = program_hdr + i;
|
||||
|
||||
if (phdr->type == PT_LOAD) {
|
||||
uint64_t segment_start = (uint64_t) buf + phdr->offset;
|
||||
uint64_t segment_end = segment_start + phdr->file_size;
|
||||
uint64_t segment_va = phdr->virtual_address;
|
||||
|
||||
if (segment_start <= ptr_addr && segment_end > ptr_addr) {
|
||||
uint64_t offset = ptr_addr - segment_start;
|
||||
|
||||
return segment_va + offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct elf_symbol_64 *elf_find_symbol_stype(char *buf, char *name, uint32_t type) {
|
||||
if (!elf_check(buf)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct elf_header_64 *hdr = (struct elf_header_64 *) buf;
|
||||
struct elf_sheader_64* section_hdr = Cast(struct elf_sheader_64*, buf + hdr->sh_off);
|
||||
struct elf_sheader_64 *sect = NULL;
|
||||
struct elf_sheader_64 *strtab_sect;
|
||||
|
||||
for (uint16_t i = 0; i < hdr->sh_count; i++) {
|
||||
struct elf_sheader_64 *section = section_hdr + i;
|
||||
|
||||
if (section->type == type) {
|
||||
sect = section;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sect) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strtab_sect = section_hdr + sect->link;
|
||||
|
||||
struct elf_symbol_64 *symtab = Cast(struct elf_symbol_64*, buf + sect->offset);
|
||||
char *strtab = buf + strtab_sect->offset;
|
||||
uint64_t count = sect->size / sizeof(struct elf_symbol_64);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
struct elf_symbol_64 *symbol = symtab + i;
|
||||
char *sym_name = strtab + symbol->name;
|
||||
|
||||
if (strcmp(sym_name, name) == 0) {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct elf_symbol_64 *elf_find_symbol(char *buf, char *name) {
|
||||
if (!elf_check(buf)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct elf_symbol_64 *symbol = elf_find_symbol_stype(buf, name, SHT_SYMTAB);
|
||||
|
||||
if (!symbol) {
|
||||
symbol = elf_find_symbol_stype(buf, name, SHT_DYNSYM);
|
||||
}
|
||||
|
||||
if (!symbol) {
|
||||
printf("%s: Failed to find symbol %s!\n", __FUNCTION__, name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return symbol;
|
||||
}
|
||||
@@ -0,0 +1,658 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "../../include/formats/macho.h"
|
||||
#include "../../include/utils.h"
|
||||
|
||||
uint32_t macho_get_magic(char *buf) {
|
||||
uint32_t *buf_ptr = (uint32_t *) buf;
|
||||
uint32_t magic = buf_ptr[0];
|
||||
|
||||
if (magic == 0xfeedfacf || magic == 0xbebafeca) {
|
||||
return magic;
|
||||
} else {
|
||||
printf("%s: Not a mach-o!\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool macho_check(char *buf) {
|
||||
uint32_t magic = macho_get_magic(buf);
|
||||
|
||||
if (magic == 0xfeedfacf || magic == 0xbebafeca) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
char *macho_find_arch(char *buf, uint32_t arch) {
|
||||
uint32_t magic = macho_get_magic(buf);
|
||||
|
||||
if (magic == 0xbebafeca) {
|
||||
struct fat_header *header = (struct fat_header *) buf;
|
||||
struct fat_arch *farch = (struct fat_arch *) ((char *) buf + sizeof(struct fat_header));
|
||||
|
||||
for (uint32_t i = 0; i < convert_endianness32(header->nfat_arch); i++) {
|
||||
if (farch->cputype == arch) {
|
||||
return buf + convert_endianness32(farch->offset);
|
||||
}
|
||||
|
||||
farch = (struct fat_arch *) ((char *) farch + sizeof(struct fat_arch));
|
||||
}
|
||||
|
||||
printf("%s: Universal mach-o does not contain a slice for the arch requested!\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
uint32_t macho_get_platform(char *buf) {
|
||||
if (!macho_check(buf)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct load_command_64 *after_header = Cast(struct load_command_64*, buf + sizeof(struct mach_header_64));
|
||||
struct mach_header_64 *header = Cast(struct mach_header_64*, buf);
|
||||
|
||||
for (uint32_t i = 0; i < header->ncmds; i++) {
|
||||
if (after_header->cmd == LC_BUILD_VERSION) {
|
||||
struct build_version_command *cmd = (struct build_version_command *) after_header;
|
||||
|
||||
if (cmd->platform > 5) {
|
||||
printf("%s: Invalid platform!\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return cmd->platform;
|
||||
}
|
||||
|
||||
after_header = (struct load_command_64 *) ((char *) after_header + after_header->cmdsize);
|
||||
}
|
||||
|
||||
printf("%s: Unable to get platform!\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct segment_command_64 *macho_get_segment(char *buf, char *name) {
|
||||
if (!macho_check(buf)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct load_command_64* after_header = Cast(struct load_command_64*, buf + sizeof(struct mach_header_64));
|
||||
struct mach_header_64* header = Cast(struct mach_header_64*, buf);
|
||||
|
||||
for (uint32_t i = 0; i < header->ncmds; i++) {
|
||||
if (after_header->cmd == LC_SEGMENT_64) {
|
||||
struct segment_command_64 *segment = (struct segment_command_64 *) after_header;
|
||||
if (strcmp(segment->segname, name) == 0) {
|
||||
return segment;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
after_header = (struct load_command_64 *) ((char *) after_header + after_header->cmdsize);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct section_64 *macho_get_section(char *buf, struct segment_command_64 *segment, char *name) {
|
||||
if (!segment || !macho_check(buf)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct section_64 *section = (struct section_64 *) ((char *) segment + sizeof(struct segment_command_64));
|
||||
|
||||
for (uint32_t i = 0; i < segment->nsects; i++) {
|
||||
if (strcmp(section->sectname, name) == 0) {
|
||||
return section;
|
||||
}
|
||||
|
||||
section = (struct section_64 *) ((char *) section + sizeof(struct section_64));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct section_64 *macho_get_last_section(struct segment_command_64 *segment) {
|
||||
uint32_t index = segment->nsects - 1;
|
||||
struct section_64 *sections = (struct section_64 *) ((char *) segment + sizeof(struct segment_command_64));
|
||||
|
||||
return sections + index;
|
||||
}
|
||||
|
||||
struct section_64 *macho_find_section(char *buf, char *segment_name, char *section_name) {
|
||||
if (!macho_check(buf)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct segment_command_64 *segment = macho_get_segment(buf, segment_name);
|
||||
if (!segment) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct section_64 *section = macho_get_section(buf, segment, section_name);
|
||||
if (!section) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return section;
|
||||
}
|
||||
|
||||
struct fileset_entry_command *macho_get_fileset(char *buf, char *name) {
|
||||
if (!macho_check(buf)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct load_command_64* after_header = Cast(struct load_command_64*, buf + sizeof(struct mach_header_64));
|
||||
struct mach_header_64* header = Cast(struct mach_header_64*, buf);
|
||||
|
||||
for (uint32_t i = 0; i < header->ncmds; i++) {
|
||||
if (after_header->cmd == LC_FILESET_ENTRY) {
|
||||
struct fileset_entry_command *entry = (struct fileset_entry_command *) after_header;
|
||||
char *entry_name = (char *) entry + entry->entry_id;
|
||||
|
||||
if (strcmp(entry_name, name) == 0) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
after_header = (struct load_command_64 *) ((char *) after_header + after_header->cmdsize);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct segment_command_64 *macho_get_segment_for_va(char *buf, uint64_t addr) {
|
||||
if (!macho_check(buf)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct load_command_64* after_header = Cast(struct load_command_64*, buf + sizeof(struct mach_header_64));
|
||||
struct mach_header_64* header = Cast(struct mach_header_64*, buf);
|
||||
struct segment_command_64 *segment = NULL;
|
||||
|
||||
for (uint32_t i = 0; i < header->ncmds; i++) {
|
||||
if (after_header->cmd == LC_SEGMENT_64) {
|
||||
segment = (struct segment_command_64 *) after_header;
|
||||
uint64_t segment_start = segment->vmaddr;
|
||||
uint64_t segment_end = segment_start + segment->vmsize;
|
||||
|
||||
if (segment_start <= addr && segment_end > addr) {
|
||||
// segment's range contains the addr
|
||||
return segment;
|
||||
}
|
||||
}
|
||||
|
||||
after_header = (struct load_command_64 *) ((char *) after_header + after_header->cmdsize);
|
||||
}
|
||||
|
||||
printf("%s: Unable to find segment containing 0x%llx!\n", __FUNCTION__, addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct section_64 *macho_get_section_for_va(struct segment_command_64 *segment, uint64_t addr) {
|
||||
struct section_64 *section = (struct section_64 *) ((char *) segment + sizeof(struct segment_command_64));
|
||||
|
||||
for (uint32_t i = 0; i < segment->nsects; i++) {
|
||||
uint64_t section_start = section->addr;
|
||||
uint64_t section_end = section_start + section->size;
|
||||
|
||||
if (section_start <= addr && section_end > addr) {
|
||||
// section's range contains the addr
|
||||
return section;
|
||||
}
|
||||
|
||||
section = (struct section_64 *) ((char *) section + sizeof(struct section_64));
|
||||
}
|
||||
|
||||
printf("%s: Unable to find section containing 0x%llx?\n", __FUNCTION__, addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct section_64 *macho_find_section_for_va(char *buf, uint64_t addr) {
|
||||
if (!macho_check(buf)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct segment_command_64 *segment = macho_get_segment_for_va(buf, addr);
|
||||
if (!segment) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct section_64 *section = macho_get_section_for_va(segment, addr);
|
||||
if (!section) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return section;
|
||||
}
|
||||
|
||||
char *macho_va_to_ptr(char *buf, uint64_t addr) {
|
||||
if (!macho_check(buf)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct segment_command_64 *segment = macho_get_segment_for_va(buf, addr);
|
||||
if (!segment) {
|
||||
return NULL;
|
||||
} else if (segment->vmaddr == addr) {
|
||||
return buf + segment->fileoff;
|
||||
}
|
||||
|
||||
struct section_64 *section = macho_get_section_for_va(segment, addr);
|
||||
|
||||
uint64_t offset = addr - section->addr;
|
||||
|
||||
return buf + section->offset + offset;
|
||||
}
|
||||
|
||||
struct segment_command_64 *macho_get_segment_for_ptr(char *buf, char *ptr) {
|
||||
if (!macho_check(buf)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct load_command_64* after_header = Cast(struct load_command_64*, buf + sizeof(struct mach_header_64));
|
||||
struct mach_header_64* header = Cast(struct mach_header_64*, buf);
|
||||
struct segment_command_64 *segment = NULL;
|
||||
uint64_t ptr_addr = (uint64_t) ptr;
|
||||
|
||||
for (uint32_t i = 0; i < header->ncmds; i++) {
|
||||
if (after_header->cmd == LC_SEGMENT_64) {
|
||||
segment = (struct segment_command_64 *) after_header;
|
||||
uint64_t segment_start = (uint64_t) buf + segment->fileoff;
|
||||
uint64_t segment_end = segment_start + segment->filesize;
|
||||
|
||||
if (segment_start <= ptr_addr && segment_end > ptr_addr) {
|
||||
// segment's range contains the ptr
|
||||
return segment;
|
||||
}
|
||||
}
|
||||
|
||||
after_header = (struct load_command_64 *) ((char *) after_header + after_header->cmdsize);
|
||||
}
|
||||
|
||||
printf("%s: Unable to find segment containing ptr %p!\n", __FUNCTION__, ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct section_64 *macho_get_section_for_ptr(struct segment_command_64 *segment, char *buf, char *ptr) {
|
||||
struct section_64 *section = (struct section_64 *) ((char *) segment + sizeof(struct segment_command_64));
|
||||
uint64_t ptr_addr = (uint64_t) ptr;
|
||||
|
||||
for (uint32_t i = 0; i < segment->nsects; i++) {
|
||||
uint64_t section_start = (uint64_t) buf + section->offset;
|
||||
uint64_t section_end = section_start + section->size;
|
||||
|
||||
if (section_start <= ptr_addr && section_end > ptr_addr) {
|
||||
// section's range contains the ptr
|
||||
return section;
|
||||
}
|
||||
|
||||
section = (struct section_64 *) ((char *) section + sizeof(struct section_64));
|
||||
}
|
||||
|
||||
printf("%s: Unable to find section containing %p?\n", __FUNCTION__, ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct section_64 *macho_find_section_for_ptr(char *buf, char *ptr) {
|
||||
if (!macho_check(buf)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct segment_command_64 *segment = macho_get_segment_for_ptr(buf, ptr);
|
||||
if (!segment) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct section_64 *section = macho_get_section_for_ptr(segment, buf, ptr);
|
||||
if (!section) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return section;
|
||||
}
|
||||
|
||||
uint64_t macho_ptr_to_va(char *buf, char *ptr) {
|
||||
if (!macho_check(buf)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct section_64 *section = macho_find_section_for_ptr(buf, ptr);
|
||||
|
||||
uint64_t offset = ptr - buf - section->offset;
|
||||
|
||||
return section->addr + offset;
|
||||
}
|
||||
|
||||
struct nlist_64 *macho_find_symbol(char *buf, char *name) {
|
||||
if (!macho_check(buf)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct load_command_64* after_header = Cast(struct load_command_64*, buf + sizeof(struct mach_header_64));
|
||||
struct mach_header_64* header = Cast(struct mach_header_64*, buf);
|
||||
struct symtab_command *symtab_cmd = NULL;
|
||||
|
||||
for (uint32_t i = 0; i < header->ncmds; i++) {
|
||||
if (after_header->cmd == LC_SYMTAB) {
|
||||
symtab_cmd = (struct symtab_command *) after_header;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
after_header = (struct load_command_64 *) ((char *) after_header + after_header->cmdsize);
|
||||
}
|
||||
|
||||
if (!symtab_cmd) {
|
||||
printf("%s: Unable to find symbol table!\n", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct nlist_64 *symtab = Cast(struct nlist_64 *, buf + symtab_cmd->symoff);
|
||||
char *strtab = buf + symtab_cmd->stroff;
|
||||
|
||||
for (uint32_t i = 0; i < symtab_cmd->nsyms; i++) {
|
||||
struct nlist_64 *symbol_nlist = symtab + i;
|
||||
char *sym_name = strtab + symbol_nlist->un.str_index;
|
||||
|
||||
if (strcmp(sym_name, name) == 0) {
|
||||
return symbol_nlist;
|
||||
}
|
||||
}
|
||||
|
||||
//printf("%s: Unable to find symbol %s!\n", __FUNCTION__, name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint64_t macho_get_symbol_size(struct nlist_64 *symbol) {
|
||||
// this is not very reliable, as symtab doesn't include stripped symbols and can be in a weird order.
|
||||
|
||||
struct nlist_64 *next_symbol = symbol + 1;
|
||||
|
||||
if (next_symbol->offset < symbol->offset) {
|
||||
// symtab is in a weird order. can't really do anything about this, return 0.
|
||||
|
||||
printf("%s: Symtab is in a weird order!\n", __FUNCTION__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return next_symbol->offset - symbol->offset;
|
||||
}
|
||||
|
||||
uint64_t macho_parse_plist_integer(char *key) {
|
||||
char *key_value = strstr(key, "<integer");
|
||||
|
||||
if (key_value) {
|
||||
key_value = strstr(key_value, ">");
|
||||
|
||||
if (key_value) {
|
||||
return strtoull(key_value + 1, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mach_header_64 *macho_parse_prelink_info(char *buf, struct section_64 *kmod_info, char *bundle_name) {
|
||||
if (!macho_check(buf)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char kext_name[256];
|
||||
struct mach_header_64 *kext = NULL;
|
||||
|
||||
char *start = buf + kmod_info->offset;
|
||||
|
||||
char *info_dict = strstr(start, "PrelinkInfoDictionary");
|
||||
char *last_dict = strstr(info_dict, "<array>") + 7;
|
||||
|
||||
while (last_dict) {
|
||||
char *dict_end = strstr(last_dict, "</dict>");
|
||||
if (!dict_end) break;
|
||||
|
||||
char *dict2 = strstr(last_dict + 1, "<dict>");
|
||||
while (dict2) {
|
||||
if (dict2 > dict_end) break;
|
||||
|
||||
dict2 = strstr(dict2 + 1, "<dict>");
|
||||
dict_end = strstr(dict_end + 1, "</dict>");
|
||||
}
|
||||
|
||||
char *identifier = strstr(last_dict, "CFBundleIdentifier");
|
||||
|
||||
if (identifier) {
|
||||
char *value_key = strstr(identifier, "<string>");
|
||||
|
||||
if (value_key) {
|
||||
value_key += strlen("<string>");
|
||||
char *key_end = strstr(value_key, "</string>");
|
||||
|
||||
if (key_end) {
|
||||
__int64 key_len = key_end - value_key;
|
||||
|
||||
memcpy(kext_name, value_key, key_len);
|
||||
kext_name[key_len] = 0;
|
||||
|
||||
if (strcmp(kext_name, bundle_name) == 0) {
|
||||
char *addr_key = strstr(last_dict, "_PrelinkExecutableLoadAddr");
|
||||
|
||||
if (addr_key) {
|
||||
kext = (struct mach_header_64 *) macho_va_to_ptr(buf, macho_parse_plist_integer(addr_key));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
last_dict = strstr(dict_end, "<dict>");
|
||||
}
|
||||
|
||||
return kext;
|
||||
}
|
||||
|
||||
uint64_t macho_xnu_untag_va(uint64_t addr) {
|
||||
if (((addr >> 32) & 0xffff) == 0xfff0) {
|
||||
return (0xffffULL << 48) | addr;
|
||||
} else {
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
|
||||
struct mach_header_64 *macho_parse_kmod_info(char *buf, struct section_64 *kmod_info, struct section_64 *kmod_start, char *bundle_name) {\
|
||||
if (!macho_check(buf)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mach_header_64 *kext = NULL;
|
||||
|
||||
uint64_t kmod_count = kmod_info->size >> 3;
|
||||
uint64_t *info_start = Cast(uint64_t *, buf + kmod_info->offset);
|
||||
uint64_t *start = Cast(uint64_t*, buf + kmod_start->offset);
|
||||
|
||||
for (uint64_t i = 0; i < kmod_count; i++) {
|
||||
struct kmod_info *info = Cast(struct kmod_info *, macho_va_to_ptr(buf, macho_xnu_untag_va(info_start[i])));
|
||||
|
||||
if (strcmp(info->name, bundle_name) == 0) {
|
||||
kext = (struct mach_header_64 *) macho_va_to_ptr(buf, macho_xnu_untag_va(start[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return kext;
|
||||
}
|
||||
|
||||
struct mach_header_64 *macho_find_kext(char *buf, char *name) {
|
||||
struct mach_header_64 *kext = NULL;
|
||||
|
||||
struct segment_command_64 *prelink_info = macho_get_segment(buf, "__PRELINK_INFO");
|
||||
if (!prelink_info) return NULL;
|
||||
|
||||
struct section_64 *kmod_info = macho_get_section(buf, prelink_info, "__kmod_info");
|
||||
|
||||
if (!kmod_info) {
|
||||
struct section_64 *info = macho_get_section(buf, prelink_info, "__info");
|
||||
if (!info) return NULL;
|
||||
|
||||
kext = macho_parse_prelink_info(buf, info, name);
|
||||
} else {
|
||||
struct section_64 *kmod_start = macho_get_section(buf, prelink_info, "__kmod_start");
|
||||
if (!kmod_start) return NULL;
|
||||
|
||||
kext = macho_parse_kmod_info(buf, kmod_info, kmod_start, name);
|
||||
}
|
||||
|
||||
return kext;
|
||||
}
|
||||
|
||||
|
||||
void macho_run_each_kext(char *buf, void (*function)(char *real_buf, char *kextbuf, uint64_t kext_size)) {
|
||||
struct segment_command_64 *prelink_info = macho_get_segment(buf, "__PRELINK_INFO");
|
||||
if (!prelink_info) return;
|
||||
|
||||
struct section_64 *kmod_start = macho_get_section(buf, prelink_info, "__kmod_start");
|
||||
|
||||
if (!kmod_start) {
|
||||
struct section_64 *kexts_text = macho_find_section(buf, "__PLK_TEXT_EXEC", "__text");
|
||||
if (!kexts_text) return;
|
||||
|
||||
function(buf, buf + kexts_text->offset, kexts_text->size);
|
||||
} else {
|
||||
uint64_t kmod_count = kmod_start->size >> 3;
|
||||
uint64_t *start = Cast(uint64_t*, buf + kmod_start->offset);
|
||||
|
||||
for (uint32_t i = 0; i < kmod_count; i++) {
|
||||
struct mach_header_64 *kext = Cast(struct mach_header_64*, macho_va_to_ptr(buf, macho_xnu_untag_va(start[i])));
|
||||
|
||||
struct section_64 *kext_text = macho_find_section(Cast(char *, kext), "__TEXT_EXEC", "__text");
|
||||
|
||||
function(buf, macho_va_to_ptr(buf, macho_xnu_untag_va(kext_text->addr)), kext_text->size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *fileset_va_to_ptr(char *buf, char *kext, uint64_t addr) {
|
||||
if (!macho_check(buf)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct segment_command_64 *segment = macho_get_segment_for_va(kext, addr);
|
||||
if (!segment) {
|
||||
return NULL;
|
||||
} else if (segment->vmaddr == addr) {
|
||||
return buf + segment->fileoff;
|
||||
}
|
||||
|
||||
struct section_64 *section = macho_get_section_for_va(segment, addr);
|
||||
|
||||
uint64_t offset = addr - section->addr;
|
||||
|
||||
return buf + section->offset + offset;
|
||||
}
|
||||
|
||||
struct segment_command_64 *fileset_get_segment_for_ptr(char *buf, char *kext, char *ptr) {
|
||||
if (!macho_check(buf)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct load_command_64 *after_header = Cast(struct load_command_64 *, kext + sizeof(struct mach_header_64));
|
||||
struct mach_header_64 *header = Cast(struct mach_header_64*, kext);
|
||||
struct segment_command_64 *segment = NULL;
|
||||
uint64_t ptr_addr = (uint64_t) ptr;
|
||||
|
||||
for (uint32_t i = 0; i < header->ncmds; i++) {
|
||||
if (after_header->cmd == LC_SEGMENT_64) {
|
||||
segment = (struct segment_command_64 *) after_header;
|
||||
uint64_t segment_start = (uint64_t) buf + segment->fileoff;
|
||||
uint64_t segment_end = segment_start + segment->filesize;
|
||||
|
||||
if (segment_start <= ptr_addr && segment_end > ptr_addr) {
|
||||
// segment's range contains the ptr
|
||||
return segment;
|
||||
}
|
||||
}
|
||||
|
||||
after_header = (struct load_command_64 *) ((char *) after_header + after_header->cmdsize);
|
||||
}
|
||||
|
||||
printf("%s: Unable to find segment containing ptr %p!\n", __FUNCTION__, ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct section_64 *fileset_find_section_for_ptr(char *buf, char *kext, char *ptr) {
|
||||
if (!macho_check(buf)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct segment_command_64 *segment = fileset_get_segment_for_ptr(buf, kext, ptr);
|
||||
if (!segment) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct section_64 *section = macho_get_section_for_ptr(segment, buf, ptr);
|
||||
if (!section) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return section;
|
||||
}
|
||||
|
||||
|
||||
uint64_t fileset_ptr_to_va(char *buf, char *kext, char *ptr) {
|
||||
if (!macho_check(buf)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct section_64 *section = fileset_find_section_for_ptr(buf, kext, ptr);
|
||||
|
||||
uint64_t offset = ptr - buf - section->offset;
|
||||
|
||||
return section->addr + offset;
|
||||
}
|
||||
|
||||
struct nlist_64 *fileset_find_symbol(char *buf, char *kext, char *name) {
|
||||
if (!macho_check(buf)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct load_command_64 *after_header = Cast(struct load_command_64*, kext + sizeof(struct mach_header_64));
|
||||
struct mach_header_64 *header = Cast(struct mach_header_64*, kext);
|
||||
struct symtab_command *symtab_cmd = NULL;
|
||||
|
||||
for (uint32_t i = 0; i < header->ncmds; i++) {
|
||||
if (after_header->cmd == LC_SYMTAB) {
|
||||
symtab_cmd = (struct symtab_command *) after_header;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
after_header = (struct load_command_64 *) ((char *) after_header + after_header->cmdsize);
|
||||
}
|
||||
|
||||
if (!symtab_cmd) {
|
||||
printf("%s: Unable to find symbol table!\n", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct nlist_64 *symtab = Cast(struct nlist_64*, buf + symtab_cmd->symoff);
|
||||
char *strtab = buf + symtab_cmd->stroff;
|
||||
|
||||
for (uint32_t i = 0; i < symtab_cmd->nsyms; i++) {
|
||||
struct nlist_64 *symbol_nlist = symtab + i;
|
||||
char *sym_name = strtab + symbol_nlist->un.str_index;
|
||||
|
||||
if (strcmp(sym_name, name) == 0) {
|
||||
return symbol_nlist;
|
||||
}
|
||||
}
|
||||
|
||||
//printf("%s: Unable to find symbol %s!\n", __FUNCTION__, name);
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "../../include/formats/macho.h"
|
||||
#include "../../include/formats/elf.h"
|
||||
#include "../../include/formats/pe.h"
|
||||
#include "../../include/utils.h"
|
||||
// right now this is just ptr & virtual address conversion
|
||||
|
||||
char *pf_va_to_ptr(char *buf, uint64_t addr) {
|
||||
char *ptr = NULL;
|
||||
|
||||
if (macho_check(buf)) {
|
||||
ptr = macho_va_to_ptr(buf, addr);
|
||||
} else if (elf_check(buf)) {
|
||||
ptr = elf_va_to_ptr(buf, addr);
|
||||
} else if (pe_check(buf)) {
|
||||
ptr = pe_va_to_ptr(buf, addr);
|
||||
} else {
|
||||
printf("%s: Unknown binary format!\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
uint64_t pf_ptr_to_va(char *buf, char *ptr) {
|
||||
uint64_t va = 0;
|
||||
|
||||
if (macho_check(buf)) {
|
||||
va = macho_ptr_to_va(buf, ptr);
|
||||
} else if (elf_check(buf)) {
|
||||
va = elf_ptr_to_va(buf, ptr);
|
||||
} else if (pe_check(buf)) {
|
||||
va = pe_ptr_to_va(buf, ptr);
|
||||
} else {
|
||||
printf("%s: Unknown binary format!\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
return va;
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "../../include/formats/pe.h"
|
||||
#include "../../include/utils.h"
|
||||
|
||||
bool dos_check(char *buf) {
|
||||
/*struct DOS_Header* dos_hdr = Cast(struct DOS_Header*, buf);
|
||||
|
||||
if (strncmp(dos_hdr->e_magic, "MZ", 2) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;*/
|
||||
return true;
|
||||
}
|
||||
|
||||
struct COFF_Header *get_pe_header(char *buf) {
|
||||
if (!dos_check(buf)) {
|
||||
#ifndef NOLOG
|
||||
printf("No DOS stub!\n");
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct DOS_Header *dos_hdr = Cast(struct DOS_Header*, buf);
|
||||
|
||||
return Cast(struct COFF_Header *, buf + dos_hdr->e_lfanew);
|
||||
}
|
||||
|
||||
bool pe_check(char *buf) {
|
||||
/*struct COFF_Header* pe_hdr = get_pe_header(buf);
|
||||
|
||||
if (!pe_hdr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(pe_hdr->magic, "PE") == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;*/
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_pe(char *buf) {
|
||||
bool pe = pe_check(buf);
|
||||
|
||||
if (!pe) {
|
||||
#ifndef NOLOG
|
||||
printf("%s: Not a PE!\n", __FUNCTION__);
|
||||
#endif
|
||||
}
|
||||
|
||||
return pe;
|
||||
}
|
||||
|
||||
struct PE64_Optional_Header *get_pe_opt_header(char *buf) {
|
||||
if (!dos_check(buf)) {
|
||||
#ifndef NOLOG
|
||||
printf("No DOS stub!\n");
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!pe_check(buf)) return NULL;
|
||||
|
||||
struct COFF_Header *pe_hdr = get_pe_header(buf);
|
||||
|
||||
return Cast(struct PE64_Optional_Header*, (char *) pe_hdr + sizeof(struct COFF_Header));
|
||||
}
|
||||
|
||||
struct Symbol_Header *pe_get_symtab(char *buf) {
|
||||
if (!pe_check(buf)) return NULL;
|
||||
|
||||
struct COFF_Header *pe_hdr = get_pe_header(buf);
|
||||
|
||||
return Cast(struct Symbol_Header*, buf + pe_hdr->pointerToSymbolTable);
|
||||
}
|
||||
|
||||
char *pe_get_strtab(char *buf) {
|
||||
if (!pe_check(buf)) return NULL;
|
||||
|
||||
struct COFF_Header *pe_hdr = get_pe_header(buf);
|
||||
char *symtab = Cast(char *, pe_get_symtab(buf));
|
||||
|
||||
return symtab + (pe_hdr->numberOfSymbols * 18); // 18 is the correct size, but struct alignment makes it 20.
|
||||
}
|
||||
|
||||
struct Section_Header *pe_get_section(char *buf, const char *name) {
|
||||
if (!pe_check(buf)) return NULL;
|
||||
|
||||
struct COFF_Header *pe_hdr = get_pe_header(buf);
|
||||
struct Section_Header *sects_start = Cast(struct Section_Header *, (char *) pe_hdr + sizeof(struct COFF_Header) + pe_hdr->sizeOfOptionalHeader);
|
||||
char *strtab = pe_get_strtab(buf);
|
||||
|
||||
for (int i = 0; i < pe_hdr->numberOfSections; i++) {
|
||||
struct Section_Header *section = sects_start + i;
|
||||
char *real_name = section->name;
|
||||
|
||||
if (real_name[0] == '/') {
|
||||
real_name = strtab + strtoul(real_name + 1, 0, 0);
|
||||
}
|
||||
|
||||
if (strncmp(real_name, name, 8) == 0) {
|
||||
return section;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *pe_va_to_ptr(char *buf, uint64_t addr) {
|
||||
if (!pe_check(buf)) return NULL;
|
||||
|
||||
struct COFF_Header *pe_hdr = get_pe_header(buf);
|
||||
struct PE64_Optional_Header *opt_hdr = get_pe_opt_header(buf);
|
||||
struct Section_Header *sects_start = Cast(struct Section_Header*, (char *) opt_hdr + pe_hdr->sizeOfOptionalHeader);
|
||||
|
||||
for (int i = 0; i < pe_hdr->numberOfSections; i++) {
|
||||
struct Section_Header *section = sects_start + i;
|
||||
|
||||
uint64_t section_start = opt_hdr->imageBase + section->virtualAddress;
|
||||
uint64_t section_end = section_start + section->virtualSize;
|
||||
|
||||
if (section_start <= addr && section_end > addr) {
|
||||
uint64_t offset = addr - section_start;
|
||||
return buf + section->pointerToRawData + offset;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint64_t pe_ptr_to_va(char *buf, char *ptr) {
|
||||
if (!pe_check(buf)) return 0;
|
||||
|
||||
struct COFF_Header *pe_hdr = get_pe_header(buf);
|
||||
struct PE64_Optional_Header *opt_hdr = get_pe_opt_header(buf);
|
||||
struct Section_Header *sects_start = Cast(struct Section_Header*, (char*)opt_hdr + pe_hdr->sizeOfOptionalHeader);
|
||||
uint64_t ptr_addr = (uint64_t) ptr;
|
||||
|
||||
for (int i = 0; i < pe_hdr->numberOfSections; i++) {
|
||||
struct Section_Header *section = sects_start + i;
|
||||
|
||||
uint64_t section_start = (uint64_t) buf + section->pointerToRawData;
|
||||
uint64_t section_end = section_start + section->sizeOfRawData;
|
||||
|
||||
if (section_start <= ptr_addr && section_end > ptr_addr) {
|
||||
uint64_t offset = ptr_addr - section_start;
|
||||
return opt_hdr->imageBase + section->virtualAddress + offset;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct Symbol_Header *pe_find_symbol(char *buf, char *name) {
|
||||
if (!pe_check(buf)) return 0;
|
||||
|
||||
struct COFF_Header *pe_hdr = get_pe_header(buf);
|
||||
char *symtab = Cast(char *, pe_get_symtab(buf));
|
||||
char *strtab = pe_get_strtab(buf);
|
||||
|
||||
for (uint32_t i = 0; i < pe_hdr->numberOfSymbols; i++) {
|
||||
struct Symbol_Header *symbol = Cast(struct Symbol_Header *, symtab + (i * 18)); // 18 is the correct size, but struct alignment makes it 20.
|
||||
char *real_name = symbol->name.name;
|
||||
|
||||
if (symbol->name.over_8b.zeros == 0 && symbol->name.over_8b.strtab_off != 0) {
|
||||
real_name = strtab + symbol->name.over_8b.strtab_off;
|
||||
}
|
||||
|
||||
if (strcmp(real_name, name) == 0) {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
// plooshfinder
|
||||
// WIP patchfinder
|
||||
// Made by Ploosh
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "../include/plooshfinder.h"
|
||||
#include "../include/plooshfinder_sig.h"
|
||||
#include "../include/formats/pe.h"
|
||||
|
||||
void *pf_zero_buf;
|
||||
|
||||
struct pf_patch_t pf_construct_patch(void *matches, void *masks, uint32_t count, bool (*callback)(struct pf_patch_t *patch, void *stream)) {
|
||||
struct pf_patch_t patch;
|
||||
|
||||
// construct the patch
|
||||
patch.matches = matches;
|
||||
patch.masks = masks;
|
||||
patch.disabled = false;
|
||||
patch.count = count;
|
||||
patch.callback = callback;
|
||||
|
||||
return patch;
|
||||
}
|
||||
|
||||
struct pf_patchset_t pf_construct_patchset(struct pf_patch_t *patches, uint32_t count, bool (*handler)(void *buf, size_t size, struct pf_patchset_t patchset)) {
|
||||
struct pf_patchset_t patchset;
|
||||
|
||||
patchset.patches = patches;
|
||||
patchset.count = count;
|
||||
patchset.handler = handler;
|
||||
|
||||
return patchset;
|
||||
}
|
||||
|
||||
bool pf_patchset_emit(void *buf, size_t size, struct pf_patchset_t patchset) {
|
||||
return patchset.handler(buf, size, patchset);
|
||||
}
|
||||
|
||||
void pf_disable_patch(struct pf_patch_t *patch) {
|
||||
patch->disabled = true;
|
||||
}
|
||||
|
||||
uint8_t *pf_find_next(uint8_t *stream, uint32_t count, uint8_t match, uint8_t mask) {
|
||||
uint8_t *find_stream = 0;
|
||||
|
||||
for (int i = 0; (uint32_t) i < count; i++) {
|
||||
if (pf_maskmatch(stream[i], match, mask)) {
|
||||
find_stream = stream + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return find_stream;
|
||||
}
|
||||
|
||||
uint8_t *pf_find_prev(uint8_t *stream, uint32_t count, uint8_t match, uint8_t mask) {
|
||||
uint8_t *find_stream = 0;
|
||||
|
||||
for (int neg_count = -(int)count; count > 0; count--) {
|
||||
int ind = neg_count + count;
|
||||
if (pf_maskmatch(stream[ind], match, mask)) {
|
||||
find_stream = stream + ind;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return find_stream;
|
||||
}
|
||||
|
||||
uint8_t* pf_find_next_multiple(uint8_t* stream, uint32_t count, uint8_t* matches, uint8_t* masks, uint32_t mmc) {
|
||||
uint8_t* find_stream = 0;
|
||||
|
||||
for (int i = 0; (uint32_t)i < count; i++) {
|
||||
bool cont = false;
|
||||
for (uint32_t i2 = 0; i2 < mmc; i2++) {
|
||||
if (!pf_maskmatch(stream[i + i2], matches[i2], masks[i2])) {
|
||||
cont = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cont) continue;
|
||||
|
||||
find_stream = stream + i;
|
||||
break;
|
||||
}
|
||||
|
||||
return find_stream;
|
||||
}
|
||||
|
||||
uint8_t* pf_find_prev_multiple(uint8_t* stream, uint32_t count, uint8_t *matches, uint8_t *masks, uint32_t mmc) {
|
||||
uint8_t* find_stream = 0;
|
||||
|
||||
for (int neg_count = -(int)count; count > 0; count--) {
|
||||
int ind = neg_count + count;
|
||||
bool cont = false;
|
||||
for (uint32_t i = 0; i < mmc; i++) {
|
||||
if (!pf_maskmatch(stream[ind], matches[i], masks[i])) {
|
||||
cont = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cont) continue;
|
||||
find_stream = stream + ind;
|
||||
break;
|
||||
}
|
||||
|
||||
return find_stream;
|
||||
}
|
||||
|
||||
bool pf_set_zero_buf(struct pf_patch_t *patch, uint8_t *stream) {
|
||||
pf_zero_buf = stream;
|
||||
|
||||
pf_disable_patch(patch);
|
||||
return true;
|
||||
}
|
||||
|
||||
void *pf_find_zero_buf(void *buf, size_t size, size_t shc_count) {
|
||||
pf_zero_buf = NULL;
|
||||
|
||||
uint8_t *matches = (uint8_t *) malloc(shc_count);
|
||||
uint8_t *masks = (uint8_t *) malloc(shc_count);
|
||||
|
||||
for (size_t i = 0; i < shc_count; i++) {
|
||||
matches[i] = 0;
|
||||
masks[i] = 0xff;
|
||||
}
|
||||
|
||||
struct pf_patch_t patch = pf_construct_patch(matches, masks, sizeof(matches) / sizeof(uint8_t), (bool (*)(struct pf_patch_t *, void *stream)) pf_set_zero_buf);
|
||||
|
||||
struct pf_patch_t patches[] = {
|
||||
patch
|
||||
};
|
||||
|
||||
struct pf_patchset_t patchset = pf_construct_patchset(patches, sizeof(patches) / sizeof(struct pf_patch_t), (bool (*)(void *, size_t, struct pf_patchset_t)) pf_find_maskmatch);
|
||||
|
||||
pf_patchset_emit(buf, size, patchset);
|
||||
|
||||
#ifndef NOLOG
|
||||
if (!pf_zero_buf) {
|
||||
printf("%s: Unable to find zero buf!\n", __FUNCTION__);
|
||||
}
|
||||
#endif
|
||||
return pf_zero_buf;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include "../include/plooshfinder.h"
|
||||
#include "../include/plooshfinder8.h"
|
||||
#include <Windows.h>
|
||||
|
||||
bool pf_maskmatch(uint8_t insn, uint8_t match, uint8_t mask) {
|
||||
return (insn & mask) == match;
|
||||
}
|
||||
|
||||
bool pf_find_maskmatch(void *buf, size_t size, struct pf_patchset_t patchset) {
|
||||
uint8_t *stream = buf;
|
||||
|
||||
for (uint64_t i = 0; i < size; i++) {
|
||||
for (uint32_t p = 0; p < patchset.count; p++) {
|
||||
struct pf_patch8_t *patch = (struct pf_patch8_t *) patchset.patches + p;
|
||||
if (patch->disabled) continue;
|
||||
|
||||
uint32_t x;
|
||||
for (x = 0; x < patch->count; x++) {
|
||||
if (!pf_maskmatch(stream[i + x], patch->matches[x], patch->masks[x])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (x == patch->count) {
|
||||
if (patch->callback(patch, stream + i)) {
|
||||
uint32_t disabled = 0;
|
||||
for (uint32_t p = 0; p < patchset.count; p++) {
|
||||
struct pf_patch8_t* pt = (struct pf_patch8_t *) patchset.patches + p;
|
||||
if (pt->disabled) {
|
||||
disabled++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (patch->callback == pt->callback) {
|
||||
DWORD og;
|
||||
VirtualProtect(pt + offsetof(struct pf_patch8_t, disabled), sizeof(bool), PAGE_READWRITE, &og); // this is only needed bc constexpr lmao
|
||||
pt->disabled = true; // disable patches that have already been found
|
||||
VirtualProtect(pt + offsetof(struct pf_patch8_t, disabled), sizeof(bool), og, &og);
|
||||
disabled++;
|
||||
}
|
||||
}
|
||||
if (disabled == patchset.count) return true; // if all are done, return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int8_t pf_signextend(int8_t val, uint8_t bits) {
|
||||
val = (uint8_t) val << (8 - bits);
|
||||
val >>= 8 - bits;
|
||||
|
||||
return val;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "../include/plooshfinder.h"
|
||||
#include "../include/plooshfinder8.h"
|
||||
#include <stdio.h>
|
||||
|
||||
struct pf_patch_t pf_construct_patch_sig(const char *sig, bool (*callback)(struct pf_patch_t *patch, void *stream)) {
|
||||
struct pf_patch_t patch;
|
||||
char *temp_sig = malloc(strlen(sig) + 1);
|
||||
strcpy_s(temp_sig, strlen(sig) + 1, sig);
|
||||
void *orig_ts = temp_sig;
|
||||
uint8_t temp_match, temp_mask;
|
||||
char *part;
|
||||
uint32_t count = 0;
|
||||
|
||||
part = strtok(temp_sig, " ");
|
||||
while (part != NULL) {
|
||||
count++;
|
||||
part = strtok(NULL, " ");
|
||||
}
|
||||
|
||||
strcpy_s((char *) orig_ts, strlen(sig) + 1, sig);
|
||||
temp_sig = orig_ts;
|
||||
uint8_t *matches = malloc(count);
|
||||
uint8_t *masks = malloc(count);
|
||||
uint32_t index = 0;
|
||||
|
||||
part = strtok(temp_sig, " ");
|
||||
while (part != NULL) {
|
||||
size_t len = strlen(part);
|
||||
temp_match = 0x0;
|
||||
temp_mask = 0x0;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (part[i] != '?') {
|
||||
char hc[2] = {
|
||||
part[i],
|
||||
0
|
||||
};
|
||||
uint8_t hex = (uint8_t) strtoul(hc, NULL, 16);
|
||||
uint8_t shift = (uint8_t) ((len - i - 1) * 4);
|
||||
|
||||
temp_match |= hex << shift;
|
||||
temp_mask |= 0xf << shift;
|
||||
}
|
||||
}
|
||||
|
||||
matches[index] = temp_match;
|
||||
masks[index] = temp_mask;
|
||||
index++;
|
||||
part = strtok(NULL, " ");
|
||||
}
|
||||
free(orig_ts);
|
||||
|
||||
// construct the patch
|
||||
patch.matches = matches;
|
||||
patch.masks = masks;
|
||||
patch.disabled = false;
|
||||
patch.count = count;
|
||||
patch.callback = callback;
|
||||
|
||||
return patch;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "../include/utils.h"
|
||||
|
||||
// the compiler will just use a bswap (optimizations) if possible
|
||||
// but it's here if it's needed (i.e. there's no intrinsic)
|
||||
uint32_t convert_endianness32(uint32_t val) {
|
||||
uint32_t swapped = 0;
|
||||
for (uint32_t i = 0; i < 4; i++) {
|
||||
uint32_t sh = i << 3;
|
||||
swapped |= ((val >> sh) & 0xff) << (sh ^ 24);
|
||||
}
|
||||
|
||||
return swapped;
|
||||
}
|
||||
Reference in New Issue
Block a user