Skip to content

Commit

Permalink
feat: Patch 4
Browse files Browse the repository at this point in the history
  • Loading branch information
gottyduke committed Aug 17, 2023
1 parent cf7a965 commit b17efb1
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 65 deletions.
21 changes: 21 additions & 0 deletions .github/workflows/clang-format.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
on: [push]

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: DoozyX/clang-format-lint-action@v0.16.2
with:
source: '.'
exclude: './docs'
extensions: 'c,cc,cpp,cxx,h,hpp,hxx,inl,inc,ixx'
clangFormatVersion: 16
inplace: True
- uses: EndBug/add-and-commit@v9
with:
author_name: clang-format
message: 'chore: style formatting'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
46 changes: 46 additions & 0 deletions include/RE/Noesis.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#pragma once

#define is_at(M, O, C) static_assert(offsetof(C, M) == O)
namespace RE
{
namespace ls
{
// placeholder type
struct UIWidget
{};
}

namespace Noesis
{
// because MSVC compiles std::string differently in debug mode lol
struct string
{
std::uint32_t length;
std::uint16_t flag04;
std::uint8_t unk06;
bool unk07;
char buffer[16]; // possible union with small string optimization

constexpr auto string_view() const noexcept { return std::string_view{ buffer, length }; }
};
static_assert(sizeof(string) == 0x18);

struct XamlLoadRequest
{
void* vtbl;
std::uint32_t unk08;
std::uint32_t unk0C;
string file; // "SomeWidget.xaml"
std::uint64_t unk28;
string stack; // "HUD" / "Notification" / ""
void* callable;
string category; // "None"
// skipped
};
is_at(file, 0x10, XamlLoadRequest);
is_at(stack, 0x30, XamlLoadRequest);
is_at(category, 0x50, XamlLoadRequest);

static inline std::add_pointer_t<void(RE::ls::UIWidget*, bool)> _SetVisiblityMask{ nullptr };
} // namespace Noesis
} // namespace RE
243 changes: 179 additions & 64 deletions src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,83 +1,196 @@
#include "RE/Noesis.h"

using namespace DKUtil::Alias;

namespace Patches
{
static constexpr auto TestAlByte = dku::Hook::Assembly::make_pattern<"84 C0">();
static constexpr dku::Hook::OpCode Xor = 0x33;
using patch_entry = std::tuple<void*, std::ptrdiff_t, dku::Hook::OpCode>;

using patch_entry = std::pair<void*, std::ptrdiff_t>;
// 4.1.1.3648072
namespace IsAddonLoaded
{
void Commit()
{
patch_entry Patches[] = {
{ dku::Hook::Assembly::search_pattern<
"40 57 "
"48 83 EC 30 "
"48 8B 0D ?? ?? ?? ?? "
"48 8B FA "
"48 81 C1 D0 00 00 00 "
"E8 ?? ?? ?? ?? "
"48 8B C8 "
"E8 ?? ?? ?? ?? "
"84 C0">(),
0x24, 0x33 },
{ dku::Hook::Assembly::search_pattern<
"40 53 "
"56 "
"57 "
"48 81 EC D0 04 00 00 "
"48 8B 05 ?? ?? ?? ?? "
"48 33 C4 "
"48 89 84 24 C0 04 00 00 "
"48 8B D9 "
"49 8B F8 "
"48 8B 0D ?? ?? ?? ?? "
"48 8B F2 "
"48 81 C1 D0 00 00 00 "
"E8 ?? ?? ?? ?? "
"48 8B C8 "
"E8 ?? ?? ?? ?? "
"84 C0">(),
0x41, 0x33 },
{ dku::Hook::Assembly::search_pattern<
"40 53 "
"55 "
"56 "
"57 "
"41 56 "
"41 57 "
"48 81 EC ?? ?? ?? ?? "
"48 8B 05 ?? ?? ?? ?? "
"48 33 C4 "
"48 89 84 24 ?? ?? ?? ?? "
"48 8B D9 "
"45 0F B7 F9 "
"48 8B 0D ?? ?? ?? ?? "
"49 8B F8 "
"48 81 C1 ?? ?? ?? ?? "
"48 8B EA "
"E8 ?? ?? ?? ?? "
"48 8B C8 "
"E8 ?? ?? ?? ?? "
"84 C0">(),
0x4A, 0x33 },
{ dku::Hook::Assembly::search_pattern<
"48 89 5C 24 08 "
"8B 59 14 "
"45 33 DB "
"48 85 DB "
"74 ?? "
"4C 8B 51 08 "
"8B 0D ?? ?? ?? ?? "
"8B 05 ?? ?? ?? ?? "
"8B 15 ?? ?? ?? ??">(),
0xC, 0x31 },
};

for (auto i = 0; i < std::extent_v<decltype(Patches)>; ++i) {
auto& [entry, offset, patch] = Patches[i];

if (entry) {
auto addr = AsAddress(dku::Hook::adjust_pointer(entry, offset));

dku::Hook::WriteImm(addr, patch);
INFO("IsAddonLoaded patch {} installed at {:X}", i + 1, addr);
} else {
WARN("IsAddonLoaded patch {} cannot be found", i + 1);
}
}
}
} // namespace IsAddonLoaded

// 4.1.1.3624901
void Commit()

class UiWidgetCreator
{
patch_entry Patches[3] = {
{ dku::Hook::Assembly::search_pattern<
"40 57 "
"48 83 EC 30 "
"48 8B 0D ?? ?? ?? ?? "
"48 8B FA "
"48 81 C1 D0 00 00 00 "
"E8 ?? ?? ?? ?? "
"48 8B C8 "
"E8 ?? ?? ?? ??">(),
0x24 },
{ dku::Hook::Assembly::search_pattern<
"40 53 "
"56 "
"57 "
"48 81 EC D0 04 00 00 "
"48 8B 05 ?? ?? ?? ?? "
"48 33 C4 "
"48 89 84 24 C0 04 00 00 "
"48 8B D9 "
"49 8B F8 "
"48 8B 0D ?? ?? ?? ?? "
"48 8B F2 "
"48 81 C1 D0 00 00 00 "
"E8 ?? ?? ?? ?? "
"48 8B C8 "
"E8 ?? ?? ?? ??">(),
0x41 },
{ dku::Hook::Assembly::search_pattern<
"40 53 "
"55 "
"56 "
"57 "
"41 56 "
"41 57 "
"48 81 EC ?? ?? ?? ?? "
"48 8B 05 ?? ?? ?? ?? "
"48 33 C4 "
"48 89 84 24 ?? ?? ?? ?? "
"48 8B D9 "
"45 0F B7 F9 "
"48 8B 0D ?? ?? ?? ?? "
"49 8B F8 "
"48 81 C1 ?? ?? ?? ?? "
"48 8B EA "
"E8 ?? ?? ?? ?? "
"48 8B C8 "
"E8 ?? ?? ?? ??">(),
0x4A },
};
// game loads widget from "Widgets\\" folder
static void Hook_CreateWidget(
void* a_uiManager,
void* a_unk2,
const char** a_xaml, // heap
RE::Noesis::XamlLoadRequest* a_request,
void* a_allocator,
bool a_flag)
{
/**
auto* widget = _LoadFromFile(a_uiManager, a_unk2, a_xaml, a_request, a_allocator, a_flag);
WidgetMemoryMap[a_request->file.string_view()] = widget;
return widget;
/**/

return _LoadFromFile(a_uiManager, a_unk2, a_xaml, a_request, a_allocator, a_flag);
}

for (auto i = 0; i < std::extent_v<decltype(Patches)>; ++i) {
auto& [entry, offset] = Patches[i];
static inline std::add_pointer_t<decltype(Hook_CreateWidget)> _LoadFromFile{ nullptr };

auto patch = AsAddress(dku::Hook::adjust_pointer(entry, offset));
public:
static constexpr OpCode RelocPointer[4]{
0x48, 0x89, 0xC8, // mov rax, rcx
0xC3 // retn
};

static void Commit()
{
/**
// reloc retn for CreateWidget
auto* addr = dku::Hook::Assembly::search_pattern<
"90 "
"48 85 DB "
"74 ?? "
"48 8D 4B 18 "
"48 8B 01 "
"FF 50 20 "
"90 "
"EB ?? "
"49 8D 4F 30 "
"4C 8B C6 "
"49 8B D6 "
"E8 ?? ?? ?? ?? "
"48 81 C4 88 00 00 00 "
"41 5F "
"41 5E "
"41 5D "
"41 5C "
"5F "
"5E "
"5B "
"5D "
"C3">(); // +313DB99
if (!addr) {
// safe to fail
WARN("CreateWidgetRetn cannot be found!");
} else {
const auto createWidgetRetn = AsAddress(addr) + 0x35;
dku::Hook::WriteImm(createWidgetRetn, RelocPointer);
INFO("CreateWidgetRetn installed at {:X}", createWidgetRetn);
}
/**/

if (entry && TestAlByte.match(patch)) {
INFO("patch {} committed at {:X}", i + 1, patch);
dku::Hook::WriteImm(patch, Xor);
// CreateWidget callsite
auto* addr = dku::Hook::Assembly::search_pattern<
"48 8B CF "
"E8 ?? ?? ?? ?? "
"90 "
"83 7D 74 10 "
"72 ?? "
"48 8B 4D 60 "
"E8 ?? ?? ?? ?? "
"90 "
"EB ?? "
"0F B6 85 20 05 00 00 "
"88 44 24 28 "
"48 89 7C 24 20 "
"4D 8B CE "
"4C 8D 45 E8 "
"48 8B D3 "
"49 8B CD "
"E8 ?? ?? ?? ??">(); // +313E0E2
if (!addr) {
// safe to fail
WARN("CreateWidgetHook cannot be found!");
} else {
INFO("patch {} failed", i + 1);
const auto callsite = AsAddress(addr) + 0x38;
_LoadFromFile = dku::Hook::write_call<5>(callsite, Hook_CreateWidget);
INFO("CreateWidgetHook installed at {:X}", callsite);
}
}
}

static inline std::unordered_map<std::string_view, RE::ls::UIWidget*> WidgetMemoryMap;
};
} // namespace Patches


BOOL APIENTRY DllMain(HMODULE a_hModule, DWORD a_ul_reason_for_call, LPVOID a_lpReserved)
{
if (a_ul_reason_for_call == DLL_PROCESS_ATTACH) {
Expand All @@ -92,7 +205,9 @@ BOOL APIENTRY DllMain(HMODULE a_hModule, DWORD a_ul_reason_for_call, LPVOID a_lp

INFO("game type : {}", dku::Hook::GetProcessName());

Patches::Commit();
dku::Hook::Trampoline::AllocTrampoline(1 << 5);
Patches::IsAddonLoaded::Commit();
//Patches::UiWidgetCreator::Commit();
}

return TRUE;
Expand Down
Binary file added static/banner_modder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit b17efb1

Please sign in to comment.