feat: add handler for client send packets

This commit is contained in:
goat 2020-04-28 01:48:36 +02:00
parent bd2e5cda2a
commit 017c30e107
4 changed files with 109 additions and 49 deletions

View file

@ -4,55 +4,79 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Dalamud.Hooking; using Dalamud.Hooking;
using Serilog; using Serilog;
using SharpDX.DXGI;
namespace Dalamud.Game.Internal.Network { namespace Dalamud.Game.Internal.Network {
public sealed class GameNetwork : IDisposable { public sealed class GameNetwork : IDisposable {
[UnmanagedFunctionPointer(CallingConvention.ThisCall)] #region Hooks
private delegate void ProcessZonePacketDelegate(IntPtr a, IntPtr b, IntPtr dataPtr);
private readonly Hook<ProcessZonePacketDelegate> processZonePacketHook; [UnmanagedFunctionPointer(CallingConvention.ThisCall)]
private delegate void ProcessZonePacketDownDelegate(IntPtr a, IntPtr b, IntPtr dataPtr);
private readonly Hook<ProcessZonePacketDownDelegate> processZonePacketDownHook;
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
private delegate byte ProcessZonePacketUpDelegate(IntPtr a1, IntPtr dataPtr, IntPtr a3, byte a4);
private readonly Hook<ProcessZonePacketUpDelegate> processZonePacketUpHook;
#endregion
private GameNetworkAddressResolver Address { get; } private GameNetworkAddressResolver Address { get; }
private IntPtr baseAddress; private IntPtr baseAddress;
public delegate void OnZonePacketDelegate(IntPtr dataPtr); public delegate void OnZonePacketDelegate(IntPtr dataPtr);
[Obsolete("Please use OnNetworkMessage instead. For modifications, it will take precedence.")]
public OnZonePacketDelegate OnZonePacket; public OnZonePacketDelegate OnZonePacket;
private readonly Dalamud dalamud; public delegate void OnNetworkMessageDelegate(IntPtr dataPtr, NetworkMessageDirection direction);
/// <summary>
/// Event that is called when a network message is sent/received.
/// </summary>
public OnNetworkMessageDelegate OnNetworkMessage;
private readonly Queue<byte[]> zoneInjectQueue = new Queue<byte[]>(); private readonly Queue<byte[]> zoneInjectQueue = new Queue<byte[]>();
public GameNetwork(Dalamud dalamud, SigScanner scanner) { public GameNetwork(SigScanner scanner) {
this.dalamud = dalamud;
Address = new GameNetworkAddressResolver(); Address = new GameNetworkAddressResolver();
Address.Setup(scanner); Address.Setup(scanner);
Log.Verbose("===== G A M E N E T W O R K ====="); Log.Verbose("===== G A M E N E T W O R K =====");
Log.Verbose("ProcessZonePacket address {ProcessZonePacket}", Address.ProcessZonePacket); Log.Verbose("ProcessZonePacketDown address {ProcessZonePacketDown}", Address.ProcessZonePacketDown);
Log.Verbose("ProcessZonePacketUp address {ProcessZonePacketUp}", Address.ProcessZonePacketUp);
this.processZonePacketHook = this.processZonePacketDownHook =
new Hook<ProcessZonePacketDelegate>(Address.ProcessZonePacket, new Hook<ProcessZonePacketDownDelegate>(Address.ProcessZonePacketDown,
new ProcessZonePacketDelegate(ProcessZonePacketDetour), new ProcessZonePacketDownDelegate(ProcessZonePacketDownDetour),
this); this);
this.processZonePacketUpHook =
new Hook<ProcessZonePacketUpDelegate>(Address.ProcessZonePacketUp,
new ProcessZonePacketUpDelegate(ProcessZonePacketUpDetour),
this);
} }
public void Enable() { public void Enable() {
this.processZonePacketHook.Enable(); this.processZonePacketDownHook.Enable();
this.processZonePacketUpHook.Enable();
} }
public void Dispose() { public void Dispose() {
this.processZonePacketHook.Dispose(); this.processZonePacketDownHook.Dispose();
this.processZonePacketUpHook.Dispose();
} }
private void ProcessZonePacketDetour(IntPtr a, IntPtr b, IntPtr dataPtr) { private void ProcessZonePacketDownDetour(IntPtr a, IntPtr b, IntPtr dataPtr) {
this.baseAddress = a; this.baseAddress = a;
// Call events
this.OnZonePacket?.Invoke(dataPtr);
try { try {
this.processZonePacketHook.Original(a, b, dataPtr); // Call events
this.OnZonePacket?.Invoke(dataPtr);
this.OnNetworkMessage?.Invoke(dataPtr, NetworkMessageDirection.ZoneDown);
this.processZonePacketDownHook.Original(a, b, dataPtr);
} catch (Exception ex) { } catch (Exception ex) {
string header; string header;
try { try {
@ -63,12 +87,45 @@ namespace Dalamud.Game.Internal.Network {
header = "failed"; header = "failed";
} }
Log.Error(ex, "Exception on ProcessZonePacket hook. Header: " + header); Log.Error(ex, "Exception on ProcessZonePacketDown hook. Header: " + header);
this.processZonePacketHook.Original(a, b, dataPtr); this.processZonePacketDownHook.Original(a, b, dataPtr);
} }
} }
private byte ProcessZonePacketUpDetour(IntPtr a1, IntPtr dataPtr, IntPtr a3, byte a4) {
try
{
// Call events
this.OnNetworkMessage?.Invoke(dataPtr, NetworkMessageDirection.ZoneUp);
var op = Marshal.ReadInt16(dataPtr);
var length = Marshal.ReadInt16(dataPtr, 8);
Log.Verbose("[ZONEUP] op: {0} len: {1}", op.ToString("X"), length);
Util.DumpMemory(dataPtr + 0x20, length);
}
catch (Exception ex)
{
string header;
try
{
var data = new byte[32];
Marshal.Copy(dataPtr, data, 0, 32);
header = BitConverter.ToString(data);
}
catch (Exception)
{
header = "failed";
}
Log.Error(ex, "Exception on ProcessZonePacketUp hook. Header: " + header);
}
return this.processZonePacketUpHook.Original(a1, dataPtr, a3, a4);
}
#if DEBUG #if DEBUG
public void InjectZoneProtoPacket(byte[] data) { public void InjectZoneProtoPacket(byte[] data) {
this.zoneInjectQueue.Enqueue(data); this.zoneInjectQueue.Enqueue(data);
@ -102,7 +159,7 @@ namespace Dalamud.Game.Internal.Network {
Marshal.Copy(packetData, 0, unmanagedPacketData, packetData.Length); Marshal.Copy(packetData, 0, unmanagedPacketData, packetData.Length);
if (this.baseAddress != IntPtr.Zero) { if (this.baseAddress != IntPtr.Zero) {
this.processZonePacketHook.Original(this.baseAddress, IntPtr.Zero, unmanagedPacketData); this.processZonePacketDownHook.Original(this.baseAddress, IntPtr.Zero, unmanagedPacketData);
} }
Marshal.FreeHGlobal(unmanagedPacketData); Marshal.FreeHGlobal(unmanagedPacketData);

View file

@ -2,12 +2,15 @@ using System;
namespace Dalamud.Game.Internal.Network { namespace Dalamud.Game.Internal.Network {
public sealed class GameNetworkAddressResolver : BaseAddressResolver { public sealed class GameNetworkAddressResolver : BaseAddressResolver {
public IntPtr ProcessZonePacket { get; private set; } public IntPtr ProcessZonePacketDown { get; private set; }
public IntPtr ProcessZonePacketUp { get; private set; }
protected override void Setup64Bit(SigScanner sig) { protected override void Setup64Bit(SigScanner sig) {
//ProcessZonePacket = sig.ScanText("48 89 74 24 18 57 48 83 EC 50 8B F2 49 8B F8 41 0F B7 50 02 8B CE E8 ?? ?? 7A FF 0F B7 57 02 8D 42 89 3D 5F 02 00 00 0F 87 60 01 00 00 4C 8D 05"); //ProcessZonePacket = sig.ScanText("48 89 74 24 18 57 48 83 EC 50 8B F2 49 8B F8 41 0F B7 50 02 8B CE E8 ?? ?? 7A FF 0F B7 57 02 8D 42 89 3D 5F 02 00 00 0F 87 60 01 00 00 4C 8D 05");
//ProcessZonePacket = sig.ScanText("48 89 74 24 18 57 48 83 EC 50 8B F2 49 8B F8 41 0F B7 50 02 8B CE E8 ?? ?? 73 FF 0F B7 57 02 8D 42 ?? 3D ?? ?? 00 00 0F 87 60 01 00 00 4C 8D 05"); //ProcessZonePacket = sig.ScanText("48 89 74 24 18 57 48 83 EC 50 8B F2 49 8B F8 41 0F B7 50 02 8B CE E8 ?? ?? 73 FF 0F B7 57 02 8D 42 ?? 3D ?? ?? 00 00 0F 87 60 01 00 00 4C 8D 05");
ProcessZonePacket = sig.ScanText("48 89 74 24 ?? 57 48 83 EC 50 8B FA 49 8B F0"); ProcessZonePacketDown = sig.ScanText("48 89 74 24 ?? 57 48 83 EC 50 8B FA 49 8B F0");
ProcessZonePacketUp =
sig.ScanText("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 41 56 41 57 48 83 EC 70 8B 81 ?? ?? ?? ??");
} }
} }
} }

View file

@ -0,0 +1,6 @@
namespace Dalamud.Game.Internal.Network {
public enum NetworkMessageDirection {
ZoneDown,
ZoneUp
}
}

View file

@ -1,19 +1,21 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Serilog;
namespace Dalamud namespace Dalamud {
{ internal static class Util {
static class Util public static void DumpMemory(IntPtr offset, int len = 512) {
{ var data = new byte[len];
public static string ByteArrayToHex(byte[] bytes, int offset = 0, int bytesPerLine = 16) Marshal.Copy(offset, data, 0, len);
{ Log.Information(ByteArrayToHex(data));
if (bytes == null) }
{
return String.Empty; public static string ByteArrayToHex(byte[] bytes, int offset = 0, int bytesPerLine = 16) {
} if (bytes == null) return string.Empty;
var hexChars = "0123456789ABCDEF".ToCharArray(); var hexChars = "0123456789ABCDEF".ToCharArray();
@ -26,8 +28,7 @@ namespace Dalamud
var sb = new StringBuilder(numLines * lineLength); var sb = new StringBuilder(numLines * lineLength);
for (var i = 0; i < bytes.Length; i += bytesPerLine) for (var i = 0; i < bytes.Length; i += bytesPerLine) {
{
var h = i + offset; var h = i + offset;
line[0] = hexChars[(h >> 28) & 0xF]; line[0] = hexChars[(h >> 28) & 0xF];
@ -42,25 +43,18 @@ namespace Dalamud
var hexColumn = offsetBlock; var hexColumn = offsetBlock;
var charColumn = byteBlock; var charColumn = byteBlock;
for (var j = 0; j < bytesPerLine; j++) for (var j = 0; j < bytesPerLine; j++) {
{ if (j > 0 && (j & 7) == 0) hexColumn++;
if (j > 0 && (j & 7) == 0)
{
hexColumn++;
}
if (i + j >= bytes.Length) if (i + j >= bytes.Length) {
{
line[hexColumn] = ' '; line[hexColumn] = ' ';
line[hexColumn + 1] = ' '; line[hexColumn + 1] = ' ';
line[charColumn] = ' '; line[charColumn] = ' ';
} } else {
else
{
var by = bytes[i + j]; var by = bytes[i + j];
line[hexColumn] = hexChars[(@by >> 4) & 0xF]; line[hexColumn] = hexChars[(by >> 4) & 0xF];
line[hexColumn + 1] = hexChars[@by & 0xF]; line[hexColumn + 1] = hexChars[by & 0xF];
line[charColumn] = @by < 32 ? '.' : (char)@by; line[charColumn] = by < 32 ? '.' : (char) by;
} }
hexColumn += 3; hexColumn += 3;