You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I was using ImHex v1.31.0 where local GDB connection below worked without a problem and I was able to read/write bytes using ImHex via GDB provider on emulated GDB server (see code below). After updating on v1.35.4 (downloaded msi from release page on GitHub) I am having a following error:
Creating server in .NET using TcpListener expecting connections on 127.0.0.1:3333, which will create a TcpClient after connection is established from ImHex. The moment I will try to send data back, connection will crash on
SocketException: System.Net.Sockets.SocketException (0x80004005): An established connection was aborted by the software in your host machine
On ImHex side I will get unspecified error in notification area in the bottom right corner
I have tried to open a port 3333 in Windows Firewall, but the connection will crash anyway
I have replicated behavior on Windows 11 and Windows 10
Edition Windows 11 Pro
Version 23H2
OS build 22631.4169
Experience Windows Feature Experience Pack 1000.22700.1034.0
Edition Windows 10 Pro
Version 22H2
OS build 19045.4894
Experience Windows Feature Experience Pack 1000.19060.1000.0
It seems that it is some regression issue. I have downgraded back to v1.31.0 and everything works fine.
How can the issue be reproduced?
Below is a code I am using for emulated GDB server which works in v1.31.0. Code is compiled in Visual Studio. Should be possible to compile in .NET Core (dotnet) on Linux too. After I will create the server and try to connect to it via ImHex -> Other Providers -> GDB -> 127.0.0.1 / 3333 / 0xFFFFFFFF, connection will get established. The moment I will try to send data back via _tcp.Client.Send(frame); connection will crash and ImHex throws Unspecified Error
GDB server
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using System.Net;
namespace GDBServer
{
/// <summary>
/// Implementation of GDB server to be used as a provider for ImHex
/// </summary>
public class GdbServer : IDisposable
{
TcpClient _tcp;
Queue<string> _receivedFrames;
AutoResetEvent _frameReceiveComplete;
Thread _serverThread;
bool _serverThreadStop;
int _port;
bool _sendAck;
public event ReadDataEventHandler OnRead;
public event WriteDataEventHandler OnWrite;
public GdbServer(int port = 3333)
{
_receivedFrames = new Queue<string>();
_frameReceiveComplete = new AutoResetEvent(false);
_port = port;
_serverThread = new Thread(ServerListenAndTalk);
_serverThread.Start();
}
void ServerListenAndTalk()
{
_sendAck = true;
GdbServerState sm = GdbServerState.WaitConnection;
GdbFrame parsedFrame = null;
_serverThreadStop = false;
TcpListener server = null;
string strFrame = string.Empty;
try
{
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
server = new TcpListener(localAddr, _port);
// Start listening for client requests.
server.Start();
// Enter the listening loop.
while (!_serverThreadStop)
{
switch (sm)
{
case GdbServerState.WaitConnection:
Console.WriteLine($"[GDB] Waiting for a connection @ {localAddr}:{_port}... ");
_tcp = server.AcceptTcpClient();
Console.WriteLine("[GDB] Connected!");
sm = GdbServerState.ReceiveFrame;
break;
case GdbServerState.ReceiveFrame:
strFrame = ReceiveViaTcp();
//Did we received something?
if(!string.IsNullOrEmpty(strFrame))
{
//Is ACK frame?
if (strFrame == "+")
{
//Do nothing
continue;
}
//Is command frame?
else if (strFrame.StartsWith("$"))
{
//Log.LogDebug(strFrame);
sm = GdbServerState.ParseFrame;
}
else
{
Console.WriteLine("Error [GDB] Unknown frame - " + strFrame);
}
}
break;
case GdbServerState.AckFrame:
if (_sendAck)
{
SendViaTcp("+");
}
sm = GdbServerState.ProcessRequest;
break;
case GdbServerState.ParseFrame:
parsedFrame = ParseFrame(strFrame);
if(parsedFrame == null)
{
//NACK should be here
sm = GdbServerState.ReceiveFrame;
}
else
{
sm = GdbServerState.AckFrame;
}
break;
case GdbServerState.ProcessRequest:
string response = ProcessRequest(parsedFrame);
SendViaTcp(parsedFrame.ConstructFrame(response));
sm = GdbServerState.ReceiveFrame;
break;
default:
break;
}
}
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server.Stop();
}
}
private string ReceiveViaTcp()
{
//Dequeue and send all the frames
if (_receivedFrames.Count != 0)
{
return _receivedFrames.Dequeue();
}
//Prepare for receiving new frames
var args = new SocketAsyncEventArgs();
int bufferSize = 0x1000;
args.SetBuffer(new byte[bufferSize], 0, bufferSize);
args.Completed += Receive_Completed;
_frameReceiveComplete.Reset();
_tcp.Client.ReceiveAsync(args);
_frameReceiveComplete.WaitOne(100); //Wait timeout
if (_receivedFrames.Count != 0)
{
args.Dispose();
return _receivedFrames.Dequeue();
}
else
{
return null;
}
}
private void Receive_Completed(object sender, SocketAsyncEventArgs e)
{
if (e.BytesTransferred > 1)
{
byte[] received = e.Buffer.Take(e.BytesTransferred).ToArray();
string fr = Encoding.ASCII.GetString(received);
//Store just one GDB command, ignore stuffed rest of commands
int sonp = fr.IndexOf('$', 1);
if (sonp > 0)
{
_receivedFrames.Enqueue(fr.Substring(0, sonp));
_receivedFrames.Enqueue(fr.Substring(sonp));
}
else
{
_receivedFrames.Enqueue(fr);
}
_frameReceiveComplete.Set();
}
}
private void SendViaTcp(string data)
{
//Log.LogDebug(data);
var frame = Encoding.ASCII.GetBytes(data);
if (!_tcp.Connected)
{
throw new Exception("[GDB] Disconnected");
}
_tcp.Client.Send(frame);
}
public void Dispose()
{
_serverThreadStop = true;
}
private GdbFrame ParseFrame(string frame)
{
try
{
GdbFrame gdb = new GdbFrame();
gdb.ParseFrame(frame);
return gdb;
}
catch(Exception ex)
{
Console.WriteLine("Parse Error: " + ex.Message);
return null;
}
}
private string ProcessRequest(GdbFrame frame)
{
if (frame.Data.StartsWith("QStartNoAckMode"))
{
if (_sendAck)
{
Console.WriteLine("ACK disabled");
_sendAck = false;
}
return "OK";
}
else if (frame.Data[0] == 'm')
{
//Read memory
return ReadMemory(frame);
}
else if (frame.Data[0] == 'M')
{
//Read memory
return WriteMemory(frame);
}
else
{
//Some random error
Console.WriteLine("[GDB] Unknown Request: " + frame.Data);
return string.Empty;
}
}
private string ReadMemory(GdbFrame frame)
{
var d = frame.Data.Split(',');
string strAddress = d[0].Substring(1);
string strLength = d[1];
uint address = Convert.ToUInt32(strAddress, 16);
int length = Convert.ToInt32(strLength, 16);
//Log.LogDebug($"Mocked reading {length:X} byte @ {address:X8}");
byte[] data = OnRead?.Invoke(address, length);
return frame.Encode16(data);
}
private string WriteMemory(GdbFrame frame)
{
//MA00000C9,1:AA
//Console.WriteLine(frame.Data);
var d = frame.Data.Split(',');
string strAddress = d[0].Substring(1);
var e = d[1].Split(':');
string strLen = e[0];
string strData = e[1];
uint address = Convert.ToUInt32(strAddress, 16);
int length = Convert.ToByte(strLen, 16);
byte[] data = frame.Decode16(length, strData);
OnWrite?.Invoke(address, data);
return string.Empty;
}
enum GdbServerState
{
/// <summary>
/// Wait on TCP connection
/// </summary>
WaitConnection,
/// <summary>
/// Receive data from TCP connection as parsed string $data#cs
/// </summary>
ReceiveFrame,
/// <summary>
/// Parse frame
/// </summary>
ParseFrame,
/// <summary>
/// Send + if received properly and if ACK was not disabled
/// </summary>
AckFrame,
/// <summary>
/// When frame was successfully received, process request
/// </summary>
ProcessRequest,
}
}
public delegate byte[] ReadDataEventHandler(uint address, int length);
public delegate void WriteDataEventHandler(uint address, byte[] data);
}
GDB Frame
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GDBServer
{
public class GdbFrame
{
public string Data { get; set; }
/// <summary>
/// $data#cs
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public string ConstructFrame(string data)
{
return $"${data}#{Checksum(data):x2}";
}
public string ParseFrame(string frame)
{
if(string.IsNullOrEmpty(frame))
{
return string.Empty;
}
if(!frame.StartsWith("$"))
{
throw new ArgumentException("GDB frame must start with $");
}
if (frame[frame.Length - 3] != '#')
{
throw new ArgumentException("GDB frame is missing CS #");
}
Data = frame.Substring(1, frame.Length - 4);
//Verify CS
string expCsStr = frame.Substring(frame.Length - 2, 2);
byte cs = Checksum(Data);
byte expCs = Convert.ToByte(expCsStr, 16);
if (cs == expCs)
{
return Data;
}
else
{
throw new ArgumentException("GDB frame has invalid CS");
}
}
public byte[] Decode16(int length, string s)
{
byte[] datagram = new byte[length];
s = s.Replace(" ", "");
int pos = 0;
for (int i = 0; i < s.Length; i += 2)
{
string sByte = s.Substring(i, 2);
datagram[pos++] = Convert.ToByte(sByte, 16);
//Prevent writing outside the field
if(pos == length)
{
break;
}
}
return datagram;
}
public string Encode16(byte[] input)
{
StringBuilder output = new StringBuilder(input.Length * 2);
for (int i = 0; i < input.Length; i++)
{
output.Append(input[i].ToString("X2"));
}
return output.ToString();
}
private byte Checksum(string data)
{
uint checksum = 0;
for (int i = 0; i < data.Length; i++)
{
checksum += (byte)data[i];
}
return (byte)(checksum & 0xFF);
}
public override string ToString()
{
return Data;
}
}
}
ImHex Version
1.35.4
ImHex Build Type
Nightly or built from sources
Installation type
msi
Additional context?
No response
The text was updated successfully, but these errors were encountered:
Operating System
Windows
What's the issue you encountered?
I was using ImHex v1.31.0 where local GDB connection below worked without a problem and I was able to read/write bytes using ImHex via GDB provider on emulated GDB server (see code below). After updating on v1.35.4 (downloaded msi from release page on GitHub) I am having a following error:
Creating server in .NET using
TcpListener
expecting connections on 127.0.0.1:3333, which will create aTcpClient
after connection is established from ImHex. The moment I will try to send data back, connection will crash onOn ImHex side I will get unspecified error in notification area in the bottom right corner
I have tried to open a port 3333 in Windows Firewall, but the connection will crash anyway
I have replicated behavior on Windows 11 and Windows 10
It seems that it is some regression issue. I have downgraded back to v1.31.0 and everything works fine.
How can the issue be reproduced?
Below is a code I am using for emulated GDB server which works in v1.31.0. Code is compiled in Visual Studio. Should be possible to compile in .NET Core (dotnet) on Linux too. After I will create the server and try to connect to it via ImHex -> Other Providers -> GDB -> 127.0.0.1 / 3333 / 0xFFFFFFFF, connection will get established. The moment I will try to send data back via
_tcp.Client.Send(frame);
connection will crash and ImHex throwsUnspecified Error
GDB server
GDB Frame
ImHex Version
1.35.4
ImHex Build Type
Installation type
msi
Additional context?
No response
The text was updated successfully, but these errors were encountered: