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 Dalamud.Hooking;
using Serilog;
using SharpDX.DXGI;
namespace Dalamud.Game.Internal.Network {
public sealed class GameNetwork : IDisposable {
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
private delegate void ProcessZonePacketDelegate(IntPtr a, IntPtr b, IntPtr dataPtr);
#region Hooks
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 IntPtr baseAddress;
public delegate void OnZonePacketDelegate(IntPtr dataPtr);
[Obsolete("Please use OnNetworkMessage instead. For modifications, it will take precedence.")]
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[]>();
public GameNetwork(Dalamud dalamud, SigScanner scanner) {
this.dalamud = dalamud;
public GameNetwork(SigScanner scanner) {
Address = new GameNetworkAddressResolver();
Address.Setup(scanner);
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 =
new Hook<ProcessZonePacketDelegate>(Address.ProcessZonePacket,
new ProcessZonePacketDelegate(ProcessZonePacketDetour),
this.processZonePacketDownHook =
new Hook<ProcessZonePacketDownDelegate>(Address.ProcessZonePacketDown,
new ProcessZonePacketDownDelegate(ProcessZonePacketDownDetour),
this);
this.processZonePacketUpHook =
new Hook<ProcessZonePacketUpDelegate>(Address.ProcessZonePacketUp,
new ProcessZonePacketUpDelegate(ProcessZonePacketUpDetour),
this);
}
public void Enable() {
this.processZonePacketHook.Enable();
this.processZonePacketDownHook.Enable();
this.processZonePacketUpHook.Enable();
}
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;
// Call events
this.OnZonePacket?.Invoke(dataPtr);
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) {
string header;
try {
@ -63,12 +87,45 @@ namespace Dalamud.Game.Internal.Network {
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
public void InjectZoneProtoPacket(byte[] data) {
this.zoneInjectQueue.Enqueue(data);
@ -102,7 +159,7 @@ namespace Dalamud.Game.Internal.Network {
Marshal.Copy(packetData, 0, unmanagedPacketData, packetData.Length);
if (this.baseAddress != IntPtr.Zero) {
this.processZonePacketHook.Original(this.baseAddress, IntPtr.Zero, unmanagedPacketData);
this.processZonePacketDownHook.Original(this.baseAddress, IntPtr.Zero, unmanagedPacketData);
}
Marshal.FreeHGlobal(unmanagedPacketData);

View file

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