4

Consider following structure where the length of both username and password is 17:

struct LoginPacket
{
    public int unk1;
    public string username;
    public string password;
}

Also this byte array

00 00 00 00 6A 6D 32 6D 65 00 72 00 7A 76 72 00 98 FD 18 00 A0 68 65 72 65 49 73
70 61 73 73 00 00 00 00 00 FF FF 31 2E 30 30 2E 30 30 00 00 00 C7 9D 72 00 04 00
00 31 2E 31 30 2E 32 37 00 0C 2C F6 24 16 2C F6 24 16

Is it possible to load this byte array into the above structure? There is something called Marshal, but it doesn't quite work for me.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
jM2.me
  • 3,839
  • 12
  • 44
  • 58

4 Answers4

9

Here you are, this answer uses the marshalling system in .NET. The structure itself contains the recipe on how to decipher a byte array. If you can't do that, you need manual code.

void Main()
{
    byte[] bytes = new byte[]
    {
        0x00, 0x00, 0x00, 0x00, 0x6A, 0x6D, 0x32, 0x6D, 0x65, 0x00, 0x72, 0x00, 0x7A, 0x76, 0x72, 0x00, 0x98, 0xFD, 0x18, 0x00, 0xA0, 0x68, 0x65, 0x72, 0x65, 0x49, 0x73,
        0x70, 0x61, 0x73, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x31, 0x2E, 0x30, 0x30, 0x2E, 0x30, 0x30, 0x00, 0x00, 0x00, 0xC7, 0x9D, 0x72, 0x00, 0x04, 0x00,
        0x00, 0x31, 0x2E, 0x31, 0x30, 0x2E, 0x32, 0x37, 0x00, 0x0C, 0x2C, 0xF6, 0x24, 0x16, 0x2C, 0xF6, 0x24, 0x16
    };

    var packet = BytesToStructure<LoginPacket>(bytes);
    packet.Dump();
}

static T BytesToStructure<T>(byte[] bytes)
{
    int size = Marshal.SizeOf(typeof(T));
    if (bytes.Length < size)
        throw new Exception("Invalid parameter");

    IntPtr ptr = Marshal.AllocHGlobal(size);
    try
    {
        Marshal.Copy(bytes, 0, ptr, size);
        return (T)Marshal.PtrToStructure(ptr, typeof(T));
    }
    finally
    {
        Marshal.FreeHGlobal(ptr);
    }
}

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet=CharSet.Ansi)]
struct LoginPacket
{
    public int unk1;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=17)]
    public string username;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=17)]
    public string password;
}

When executed in LINQPad you get this:

unk1: 0 
username: jm2me 
password: hereIspass
Elmue
  • 7,602
  • 3
  • 47
  • 57
Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
4

Assuming strings are in UTF8 encoding. If not, replace UTF8 with your encoding

struct LoginPacket
{
    public int unk1;
    public string username;
    public string password;

    public void Parse(byte[] b)
    {
        unk1 = BitConverter.ToInt32(b, 0);
        username = Encoding.UTF8.GetString(b, 4, 17);
        password = Encoding.UTF8.GetString(b, 4 + 17, 17);
    }
}
Albin Sunnanbo
  • 46,430
  • 8
  • 69
  • 108
  • This actually looks like fastest and easiest way so far. With struct constructor it will work perfectly for my project. Thumbs up for this answer so far. – jM2.me Feb 22 '11 at 09:39
  • 2
    I don't think that is going to work. You are interpreting the first 17 bytes as UTF-8. This doesn't necessarily mean 17 characters. It can even mean you are trying to interpret half of an original character as UTF8 – Daniel Hilgarth Feb 22 '11 at 09:41
  • 1
    The client is fixed to send 17 bytes for username only a-z0-9 UTF8 so I think I should be good. – jM2.me Feb 22 '11 at 09:42
  • 1
    You will see, that it is not going to work. If the client would use UTF-8 and send only the characters you said, the sample data would be 38 bytes long. But it isn't. – Daniel Hilgarth Feb 22 '11 at 09:56
0

I think you'd need to use Encoding.GetString(byte[]) to get your bytes.

So you'd need to represent your bytes as a byte[] and then use the above method to convert it to to a string.

LoginPacket packet;

byte[] mybytes = "..." //your bytes

packet.username = Encoding.GetBytes(mybytes);

etc...

You might need to have several byte arrays each containing the bytes for your different struct fields. If (starting from beginning) each field is 17 bytes, that shouldn't be too hard, if that isn't the case, it will depend on how you know where each field starts in your byte array

Tony The Lion
  • 61,704
  • 67
  • 242
  • 415
  • That would work, but I would lvoe to use struct cause in future i can edit packet structures easly. – jM2.me Feb 22 '11 at 09:34
  • @user621033: You can use the struct, but you have to get your bytes from wherever they come from into the struct, right? So this is my advice on how to do so. – Tony The Lion Feb 22 '11 at 10:30
0

One way is to use unsafe code:

        byte[] packetBytes;

        LoginPacket lp = new LoginPacket();
        lp.unk1 = BitConverter.ToInt32(packetBytes, 0);
        fixed (byte* buffer = &packetBytes[4])
        {
            lp.username = Marshal.PtrToStringUni((IntPtr)buffer);
            lp.password = Marshal.PtrToStringUni((IntPtr)buffer + (IntPtr)Encoding.Unicode.GetByteCount(lp.username));
        }
logicnp
  • 5,796
  • 1
  • 28
  • 32