From cf61a90c01f4422396808ed2f731127acc456529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Franti=C5=A1ek=20Boh=C3=A1=C4=8Dek?= Date: Thu, 23 Dec 2021 16:10:24 +0100 Subject: [PATCH] feat: add walk detour support --- Local/NosSmooth.LocalCore/Character.cpp | 49 +++----- Local/NosSmooth.LocalCore/Character.h | 15 ++- .../CharacterUnmanaged.cpp | 119 ++++++++++++++++++ .../NosSmooth.LocalCore/CharacterUnmanaged.h | 56 +++++++++ .../NosSmooth.LocalCore/NetworkUnmanaged.cpp | 14 ++- .../NosSmooth.LocalCore.vcxproj | 3 + .../NosSmooth.LocalCore.vcxproj.filters | 7 ++ Local/NosSmooth.LocalCore/NosSmoothCore.cpp | 1 + 8 files changed, 225 insertions(+), 39 deletions(-) create mode 100644 Local/NosSmooth.LocalCore/CharacterUnmanaged.cpp create mode 100644 Local/NosSmooth.LocalCore/CharacterUnmanaged.h diff --git a/Local/NosSmooth.LocalCore/Character.cpp b/Local/NosSmooth.LocalCore/Character.cpp index 29bb014..0fc7c60 100644 --- a/Local/NosSmooth.LocalCore/Character.cpp +++ b/Local/NosSmooth.LocalCore/Character.cpp @@ -1,47 +1,28 @@ #include "Character.h" +#include using namespace NosSmoothCore; - -const BYTE WALK_OBJECT_PATTERN[] = { 0x33, 0xC9, 0x8B, 0x55, 0xFC, 0xA1, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00 }; -const BYTE WALK_FUNCTION_PATTERN[] = { 0x55, 0x8B, 0xEC, 0x83, 0xC4, 0xEC, 0x53, 0x56, 0x57, 0x66, 0x89, 0x4D, 0xFA }; - -LPCSTR WALK_OBJECT_MASK = "xxxxxx????x????"; -LPCSTR WALK_FUNCTION_MASK = "xxxxxxxxxxxxx"; +using namespace System; +using namespace System::Runtime::InteropServices; Character::Character(ModuleHook moduleHook) { - auto walkFunction = moduleHook.FindPattern(WALK_FUNCTION_PATTERN, WALK_FUNCTION_MASK); - auto walkObject = *(unsigned int*)(moduleHook.FindPattern(WALK_OBJECT_PATTERN, WALK_OBJECT_MASK) + 0x6); - - if (walkFunction == 0) - { - throw "Could not find walk function."; - } - - if (walkObject == 0) - { - throw "Could not find player object."; - } - - _walkFunction = walkFunction; - _playerObject = walkObject; + CharacterUnmanaged::GetInstance()->Setup(moduleHook); } -void CallWalk(int x, int y, unsigned int playerObject, unsigned int walkFunction) +void Character::Walk(int x, int y) { DWORD position = (y << 16) | x; + CharacterUnmanaged::GetInstance()->Walk(position); +} - __asm - { - push 1 - xor ecx, ecx - mov edx, position - mov eax, dword ptr ds : [playerObject] - mov eax, dword ptr ds : [eax] - call walkFunction - } +void Character::SetWalkCallback(WalkCallback^ walkCallback) +{ + _walkCallback = walkCallback; + IntPtr functionPointer = Marshal::GetFunctionPointerForDelegate(walkCallback); + CharacterUnmanaged::GetInstance()->SetWalkCallback(static_cast(functionPointer.ToPointer())); } -void Character::Walk(int x, int y) +void NosSmoothCore::Character::ResetHooks() { - CallWalk(x, y, _playerObject, _walkFunction); -} \ No newline at end of file + CharacterUnmanaged::GetInstance()->ResetHooks(); +} diff --git a/Local/NosSmooth.LocalCore/Character.h b/Local/NosSmooth.LocalCore/Character.h index abdaf06..c882385 100644 --- a/Local/NosSmooth.LocalCore/Character.h +++ b/Local/NosSmooth.LocalCore/Character.h @@ -1,5 +1,6 @@ #pragma once #include "ModuleHook.h" +#include "CharacterUnmanaged.h" namespace NosSmoothCore { @@ -18,9 +19,19 @@ namespace NosSmoothCore /// The x coordinate to walk to. /// The y coordinate to walk to. void Walk(int x, int y); + + /// + /// Registers the callback for walk function. + /// + /// The callback to call. + void SetWalkCallback(WalkCallback^ walkCallback); + + /// + /// Reset the registered hooks. + /// + void ResetHooks(); private: - unsigned int _playerObject; - unsigned int _walkFunction; + WalkCallback^ _walkCallback; }; } diff --git a/Local/NosSmooth.LocalCore/CharacterUnmanaged.cpp b/Local/NosSmooth.LocalCore/CharacterUnmanaged.cpp new file mode 100644 index 0000000..a0960a7 --- /dev/null +++ b/Local/NosSmooth.LocalCore/CharacterUnmanaged.cpp @@ -0,0 +1,119 @@ +#include "CharacterUnmanaged.h" +#include + +using namespace NosSmoothCore; + +const BYTE WALK_OBJECT_PATTERN[] = { 0x33, 0xC9, 0x8B, 0x55, 0xFC, 0xA1, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00 }; +const BYTE WALK_FUNCTION_PATTERN[] = { 0x55, 0x8B, 0xEC, 0x83, 0xC4, 0xEC, 0x53, 0x56, 0x57, 0x66, 0x89, 0x4D, 0xFA }; + +LPCSTR WALK_OBJECT_MASK = "xxxxxx????x????"; +LPCSTR WALK_FUNCTION_MASK = "xxxxxxxxxxxxx"; + +void CharacterWalkDetourIn() +{ + DWORD position = 0; + + __asm + { + pushad + pushfd + + mov position, edx + } + + bool isAccepted = CharacterUnmanaged::GetInstance()->ExecuteWalkCallback(position); + + __asm + { + popfd + popad + } + + if (isAccepted) { + CharacterUnmanaged::GetInstance()->Walk(position); + } +} + +// Detour entrypoint +// declspec naked to not mess up the stack +void __declspec(naked) CharacterWalkDetour() +{ + unsigned int returnPush; + __asm { + pop eax + pop ebx + mov returnPush, eax // we have to push this value on the stack before returning + } + + CharacterWalkDetourIn(); + + __asm { + push returnPush + ret + } +} + +CharacterUnmanaged::CharacterUnmanaged() +{ +} + +void CharacterUnmanaged::Setup(ModuleHook moduleHook) +{ + auto walkFunction = moduleHook.FindPattern(WALK_FUNCTION_PATTERN, WALK_FUNCTION_MASK); + auto walkObject = *(unsigned int*)(moduleHook.FindPattern(WALK_OBJECT_PATTERN, WALK_OBJECT_MASK) + 0x6); + + if (walkFunction == 0) + { + throw "Could not find walk function."; + } + + if (walkObject == 0) + { + throw "Could not find player object."; + } + + _walkFunctionAddress = walkFunction; + _characterObjectAddress = walkObject; +} + +void CharacterUnmanaged::SetWalkCallback(NativeWalkCallback walkCallback) +{ + _walkCallback = walkCallback; + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + DetourAttach(&(PVOID&)_walkFunctionAddress, CharacterWalkDetour); + DetourTransactionCommit(); +} + +void CharacterUnmanaged::Walk(DWORD position) +{ + unsigned int walkFunction = _walkFunctionAddress; + unsigned int characterObject = _characterObjectAddress; + + __asm + { + push 1 + xor ecx, ecx + mov edx, position + mov eax, dword ptr ds : [characterObject] + mov eax, dword ptr ds : [eax] + call walkFunction + } +} + +void CharacterUnmanaged::ResetHooks() +{ + DetourTransactionBegin(); + DetourUpdateThread(GetCurrentThread()); + DetourDetach(&(PVOID&)_walkFunctionAddress, CharacterWalkDetour); + DetourTransactionCommit(); +} + +bool CharacterUnmanaged::ExecuteWalkCallback(const DWORD position) +{ + if (_walkCallback != nullptr) { + return _walkCallback(position); + } + + return true; +} \ No newline at end of file diff --git a/Local/NosSmooth.LocalCore/CharacterUnmanaged.h b/Local/NosSmooth.LocalCore/CharacterUnmanaged.h new file mode 100644 index 0000000..5275eff --- /dev/null +++ b/Local/NosSmooth.LocalCore/CharacterUnmanaged.h @@ -0,0 +1,56 @@ +#pragma once +#include "ModuleHook.h" + +namespace NosSmoothCore +{ + public delegate bool WalkCallback(int position); + typedef bool(__stdcall* NativeWalkCallback)(int position); + + class CharacterUnmanaged + { + public: + /// + /// Set ups the addresses of objects. + /// + /// The hooking module holding the information about NostaleX.dat + void Setup(NosSmoothCore::ModuleHook moduleHook); + + /// + /// Starts walking to the specified x, y position + /// + /// The coordinate to walk to. + void Walk(DWORD position); + + /// + /// Registers the callback for walk function. + /// + /// The callback to call. + void SetWalkCallback(NativeWalkCallback walkCallback); + + /// + /// Reset the registered hooks. + /// + void ResetHooks(); + + /// + /// Executes the walk callback. + /// + /// The coordinate the user wants to walk to. + /// Whether to accept the walk. + bool ExecuteWalkCallback(const DWORD position); + + static CharacterUnmanaged* GetInstance() + { + static CharacterUnmanaged instance; + return reinterpret_cast(&instance); + } + unsigned int _walkFunctionAddress; + unsigned int _characterObjectAddress; + private: + CharacterUnmanaged(); + + + NativeWalkCallback _walkCallback; + }; +} + diff --git a/Local/NosSmooth.LocalCore/NetworkUnmanaged.cpp b/Local/NosSmooth.LocalCore/NetworkUnmanaged.cpp index c0cac02..8126085 100644 --- a/Local/NosSmooth.LocalCore/NetworkUnmanaged.cpp +++ b/Local/NosSmooth.LocalCore/NetworkUnmanaged.cpp @@ -1,6 +1,8 @@ #include "NetworkUnmanaged.h" #include #include +#include +#include using namespace NosSmoothCore; @@ -35,7 +37,7 @@ void PacketSendDetour() popfd popad } - + if (isAccepted) { NetworkUnmanaged::GetInstance()->SendPacket(packet); } @@ -93,8 +95,8 @@ void NetworkUnmanaged::Setup(ModuleHook moduleHook) DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); - DetourAttach(&reinterpret_cast(_sendPacketAddress), PacketSendDetour); DetourAttach(&(PVOID&)_receivePacketAddress, PacketReceiveDetour); + DetourAttach(&reinterpret_cast(_sendPacketAddress), PacketSendDetour); DetourTransactionCommit(); } @@ -129,8 +131,14 @@ void NetworkUnmanaged::ResetHooks() { DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); - DetourDetach(&reinterpret_cast(_sendPacketAddress), PacketSendDetour); + if (_sendCallback != nullptr) { + DetourDetach(&reinterpret_cast(_sendPacketAddress), PacketSendDetour); + } + + if (_receiveCallback != nullptr) { DetourDetach(&(PVOID&)_receivePacketAddress, PacketReceiveDetour); + } + DetourTransactionCommit(); } diff --git a/Local/NosSmooth.LocalCore/NosSmooth.LocalCore.vcxproj b/Local/NosSmooth.LocalCore/NosSmooth.LocalCore.vcxproj index 150cad2..3b9b3b5 100644 --- a/Local/NosSmooth.LocalCore/NosSmooth.LocalCore.vcxproj +++ b/Local/NosSmooth.LocalCore/NosSmooth.LocalCore.vcxproj @@ -166,6 +166,7 @@ + @@ -174,12 +175,14 @@ + + diff --git a/Local/NosSmooth.LocalCore/NosSmooth.LocalCore.vcxproj.filters b/Local/NosSmooth.LocalCore/NosSmooth.LocalCore.vcxproj.filters index 341bd38..516c7b7 100644 --- a/Local/NosSmooth.LocalCore/NosSmooth.LocalCore.vcxproj.filters +++ b/Local/NosSmooth.LocalCore/NosSmooth.LocalCore.vcxproj.filters @@ -33,6 +33,9 @@ Header Files + + Header Files + @@ -50,8 +53,12 @@ Source Files + + Source Files + + \ No newline at end of file diff --git a/Local/NosSmooth.LocalCore/NosSmoothCore.cpp b/Local/NosSmooth.LocalCore/NosSmoothCore.cpp index b26e142..caef309 100644 --- a/Local/NosSmooth.LocalCore/NosSmoothCore.cpp +++ b/Local/NosSmooth.LocalCore/NosSmoothCore.cpp @@ -30,4 +30,5 @@ Network^ NosClient::GetNetwork() void NosClient::ResetHooks() { _network->ResetHooks(); + _character->ResetHooks(); } \ No newline at end of file -- 2.48.1