~ruther/NosSmooth

cf61a90c01f4422396808ed2f731127acc456529 — František Boháček 3 years ago 53f156e
feat: add walk detour support
M Local/NosSmooth.LocalCore/Character.cpp => Local/NosSmooth.LocalCore/Character.cpp +15 -34
@@ 1,47 1,28 @@
#include "Character.h"
#include <windows.h>
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<NativeWalkCallback>(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();
}

M Local/NosSmooth.LocalCore/Character.h => Local/NosSmooth.LocalCore/Character.h +13 -2
@@ 1,5 1,6 @@
#pragma once
#include "ModuleHook.h"
#include "CharacterUnmanaged.h"

namespace NosSmoothCore
{


@@ 18,9 19,19 @@ namespace NosSmoothCore
		/// <param name="x">The x coordinate to walk to.</param>
		/// <param name="y">The y coordinate to walk to.</param>
		void Walk(int x, int y);

		/// <summary>
		/// Registers the callback for walk function.
		/// </summary>
		/// <param name="walkCallback">The callback to call.</param>
		void SetWalkCallback(WalkCallback^ walkCallback);

		/// <summary>
		/// Reset the registered hooks.
		/// </summary>
		void ResetHooks();
	private:
		unsigned int _playerObject;
		unsigned int _walkFunction;
		WalkCallback^ _walkCallback;
	};
}


A Local/NosSmooth.LocalCore/CharacterUnmanaged.cpp => Local/NosSmooth.LocalCore/CharacterUnmanaged.cpp +119 -0
@@ 0,0 1,119 @@
#include "CharacterUnmanaged.h"
#include <detours.h>

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

A Local/NosSmooth.LocalCore/CharacterUnmanaged.h => Local/NosSmooth.LocalCore/CharacterUnmanaged.h +56 -0
@@ 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:
		/// <summary>
		/// Set ups the addresses of objects.
		/// </summary>
		/// <param name="moduleHook">The hooking module holding the information about NostaleX.dat</param>
		void Setup(NosSmoothCore::ModuleHook moduleHook);

		/// <summary>
		/// Starts walking to the specified x, y position
		/// </summary>
		/// <param name="x">The coordinate to walk to.</param>
		void Walk(DWORD position);

		/// <summary>
		/// Registers the callback for walk function.
		/// </summary>
		/// <param name="walkCallback">The callback to call.</param>
		void SetWalkCallback(NativeWalkCallback walkCallback);

		/// <summary>
		/// Reset the registered hooks.
		/// </summary>
		void ResetHooks();

		/// <summary>
		/// Executes the walk callback.
		/// </summary>
		/// <param name="position">The coordinate the user wants to walk to.</param>
		/// <returns>Whether to accept the walk.</returns>
		bool ExecuteWalkCallback(const DWORD position);

		static CharacterUnmanaged* GetInstance()
		{
			static CharacterUnmanaged instance;
			return reinterpret_cast<CharacterUnmanaged*>(&instance);
		}
		unsigned int _walkFunctionAddress;
		unsigned int _characterObjectAddress;
	private:
		CharacterUnmanaged();


		NativeWalkCallback _walkCallback;
	};
}


M Local/NosSmooth.LocalCore/NetworkUnmanaged.cpp => Local/NosSmooth.LocalCore/NetworkUnmanaged.cpp +11 -3
@@ 1,6 1,8 @@
#include "NetworkUnmanaged.h"
#include <detours.h>
#include <windows.h>
#include <chrono>
#include <iostream>

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<void*&>(_sendPacketAddress), PacketSendDetour);
    DetourAttach(&(PVOID&)_receivePacketAddress, PacketReceiveDetour);
    DetourAttach(&reinterpret_cast<void*&>(_sendPacketAddress), PacketSendDetour);
    DetourTransactionCommit();
}



@@ 129,8 131,14 @@ void NetworkUnmanaged::ResetHooks()
{
    DetourTransactionBegin();
    DetourUpdateThread(GetCurrentThread());
    DetourDetach(&reinterpret_cast<void*&>(_sendPacketAddress), PacketSendDetour);
    if (_sendCallback != nullptr) {
        DetourDetach(&reinterpret_cast<void*&>(_sendPacketAddress), PacketSendDetour);
    }

    if (_receiveCallback != nullptr) {
    DetourDetach(&(PVOID&)_receivePacketAddress, PacketReceiveDetour);
    }

    DetourTransactionCommit();
}


M Local/NosSmooth.LocalCore/NosSmooth.LocalCore.vcxproj => Local/NosSmooth.LocalCore/NosSmooth.LocalCore.vcxproj +3 -0
@@ 166,6 166,7 @@
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="Character.h" />
    <ClInclude Include="CharacterUnmanaged.h" />
    <ClInclude Include="ModuleHook.h" />
    <ClInclude Include="Network.h" />
    <ClInclude Include="NetworkUnmanaged.h" />


@@ 174,12 175,14 @@
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="Character.cpp" />
    <ClCompile Include="CharacterUnmanaged.cpp" />
    <ClCompile Include="ModuleHook.cpp" />
    <ClCompile Include="Network.cpp" />
    <ClCompile Include="NetworkUnmanaged.cpp" />
    <ClCompile Include="NosSmoothCore.cpp" />
  </ItemGroup>
  <ItemGroup>
    <None Include="..\..\stylecop.json" />
    <None Include="packages.config" />
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

M Local/NosSmooth.LocalCore/NosSmooth.LocalCore.vcxproj.filters => Local/NosSmooth.LocalCore/NosSmooth.LocalCore.vcxproj.filters +7 -0
@@ 33,6 33,9 @@
    <ClInclude Include="NetworkUnmanaged.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="CharacterUnmanaged.h">
      <Filter>Header Files</Filter>
    </ClInclude>
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="NosSmoothCore.cpp">


@@ 50,8 53,12 @@
    <ClCompile Include="NetworkUnmanaged.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="CharacterUnmanaged.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
  </ItemGroup>
  <ItemGroup>
    <None Include="packages.config" />
    <None Include="..\..\stylecop.json" />
  </ItemGroup>
</Project>
\ No newline at end of file

M Local/NosSmooth.LocalCore/NosSmoothCore.cpp => Local/NosSmooth.LocalCore/NosSmoothCore.cpp +1 -0
@@ 30,4 30,5 @@ Network^ NosClient::GetNetwork()
void NosClient::ResetHooks() 
{
	_network->ResetHooks();
	_character->ResetHooks();
}
\ No newline at end of file

Do not follow this link