What's new

Discussion C# Verify RSA Signature

J

Just1n

Enthusiast
Messages
73
Reaction score
15
I reversed the functions that the Xbox utilizes in order to verify it's RSA signatures. I have only tested this with verifying XDK bootloaders but should work with other signature checks since it uses the same functions. Honestly this is a half-*** release. I find it useful for when I'm replacing the SD bootloader in shadowboot roms and want to do a quick sig verify after its signed. You may ask me why not just use a wrapper from the SDK library... and to that I say IDK, don't ask.



I didn't think to include the function from my "XboxIO" class as they are very simple to do... like too simple.
Here's a list of what they do (if you couldn't tell from the function names...)
Code:
XboxIO.ToUInt64(byte[], UInt32) - Convert 0x08 byte array to a UInt64 integer
XboxIO.GetHighOrder128(UInt64, UInt64) - Multiply two UInt64 numbers and return the upper 64 bits of the product
XboxIO.GetBytes(UInt64) - Converts UInt64 integer back to 0x08 byte array
XboxIO.RotateLeft32(UInt32, UInt16) - Rotate a UInt32 integer left by a given value
XboxIO.RotateRight64(UInt64, UInt16) - Roteate a UInt64 integer right by a given value
(If I forgot some, I apologize)

And before you see the code, I just want to say I'm not the best at labeling things... Like at all. And there may be one function "XeCryptBnQwNeModMul" where I didn't clean it up, just straight from my reverse notes.
Code:
[StructLayout(LayoutKind.Sequential)]
struct XECRYPT_SIG
{
    private UInt64[] aqwPad;
    private Byte bOne;
    private Byte[] abSalt;
    private Byte[] abHash;
    private Byte bEnd;

    public XECRYPT_SIG(UInt64[] _aqwPad, Byte _bOne, Byte[] _abSalt, Byte[] _abHash, Byte _bEnd)
    {
        this.aqwPad = _aqwPad;
        this.bOne = _bOne;
        this.abSalt = _abSalt;
        this.abHash = _abHash;
        this.bEnd = _bEnd;
    }

    public void Copy(XECRYPT_SIG signature)
    {
        byte[] sigBuffer = signature.ToByteArray();

        for (int c = 0; c < 0x1C; c++)
            this.aqwPad[c] = XboxIO.ToUInt64(sigBuffer, (c * 0x08));

        this.bOne = sigBuffer[0xE0];
        Buffer.BlockCopy(sigBuffer, 0xE1, this.abSalt, 0x00, 0x0A);
        Buffer.BlockCopy(sigBuffer, 0xEB, this.abHash, 0x00, 0x14);
        this.bEnd = sigBuffer[0xFF];
    }

    public byte[] ToByteArray()
    {
        byte[] sigBuffer = new byte[0x100];

        for (int c = 0; c < 0x1C; c++)
            Buffer.BlockCopy(XboxIO.GetBytes(this.aqwPad[c]), 0x00, sigBuffer, (c * 0x08), 0x08);
        sigBuffer[0xE0] = this.bOne;
        Buffer.BlockCopy(this.abSalt, 0x00, sigBuffer, 0xE1, 0x0A);
        Buffer.BlockCopy(this.abHash, 0x00, sigBuffer, 0xEB, 0x14);
        sigBuffer[0xFF] = this.bEnd;

        return sigBuffer;
    }

    public UInt64[] ToUInt64Array()
    {
        UInt64[] sigBuffer = new UInt64[0x20];

        byte[] byteBuffer = this.ToByteArray();

        for (int c = 0; c < 0x20; c++)
            sigBuffer[c] = XboxIO.ToUInt64(byteBuffer, (c * 0x08));

        return sigBuffer;
    }
}

[StructLayout(LayoutKind.Sequential)]
struct XECRYPT_RSA
{
    private UInt32 cqwModulusCount;
    private UInt32 dwExponent;
    private UInt64 qwReserved;

    public XECRYPT_RSA(UInt32 _modulusCount, UInt32 _publicExponent, UInt64 _reserve)
    {
        this.cqwModulusCount = _modulusCount;
        this.dwExponent = _publicExponent;
        this.qwReserved = _reserve;
    }

    public UInt32 GetModulusCount()
    {
        return this.cqwModulusCount;
    }

    public UInt32 GetPublicExponent()
    {
        return this.dwExponent;
    }

    public byte[] GetPublicExponentByteArray()
    {
        byte[] exponentBuffer = new byte[0x04];
        Buffer.BlockCopy(XboxIO.GetBytes(this.dwExponent), 0x00, exponentBuffer, 0x00, 0x04);
        return exponentBuffer;
    }

    public UInt64 GetReserve()
    {
        return this.qwReserved;
    }
}

[StructLayout(LayoutKind.Sequential)]
struct XECRYPT_RSAPUB_2048
{
    public XECRYPT_RSA rsa;
    private UInt64[] qwModulus;

    public XECRYPT_RSAPUB_2048(UInt32 _modulusCount, UInt32 _publicExponent, UInt64 _reserve, UInt64[] _qwModulus)
    {
        this.rsa = new XECRYPT_RSA(_modulusCount, _publicExponent, _reserve);
        this.qwModulus = _qwModulus;
    }

    public UInt64 GetModulus(int index)
    {
        return this.qwModulus[index];
    }

    public UInt64[] GetModulusArray()
    {
        return this.qwModulus;
    }

    public byte[] GetModulusByteArray()
    {
        byte[] modulusBuffer = new byte[0x100];
        for (int c = 0; c < 0x20; c++)
            Buffer.BlockCopy(XboxIO.GetBytes(this.qwModulus[c]), 0x00, modulusBuffer, (c * 0x08), 0x08);
        return modulusBuffer;
    }

    public byte[] ToByteArray()
    {
        byte[] keyBuffer = new byte[0x110];

        Buffer.BlockCopy(XboxIO.GetBytes(this.rsa.GetModulusCount()), 0x00, keyBuffer, 0x00, 0x04);
        Buffer.BlockCopy(XboxIO.GetBytes(this.rsa.GetPublicExponent()), 0x00, keyBuffer, 0x04, 0x04);
        Buffer.BlockCopy(XboxIO.GetBytes(this.rsa.GetReserve()), 0x00, keyBuffer, 0x08, 0x08);

        for (int c = 0; c < 0x20; c++)
            Buffer.BlockCopy(XboxIO.GetBytes(this.qwModulus[c]), 0x00, keyBuffer, (10 + (c * 0x08)), 0x08);

        return keyBuffer;
    }

    public byte[] ToReverseByteArray()
    {
        byte[] keyBuffer = new byte[0x110];

      

       Buffer.BlockCopy(XboxIO.GetBytes(this.rsa.GetModulusCount()).Reverse().ToArray(), 0x00, keyBuffer, 0x00, 0x04);
       Buffer.BlockCopy(XboxIO.GetBytes(this.rsa.GetPublicExponent()).Reverse().ToArray(), 0x00, keyBuffer, 0x04, 0x04);
       Buffer.BlockCopy(XboxIO.GetBytes(this.rsa.GetReserve()).Reverse().ToArray(), 0x00, keyBuffer, 0x08, 0x08);

       for (int c = 0; c < 0x20; c++)
           Buffer.BlockCopy(XboxIO.GetBytes(this.qwModulus[c]).Reverse().ToArray(), 0x00, keyBuffer, (10 + (c * 0x08)), 0x08);

        return keyBuffer.Reverse().ToArray();
    }
}

[StructLayout(LayoutKind.Sequential)]
struct XECRYPT_RSAPRV_2048
{
    public XECRYPT_RSA rsa;
    private UInt64[] qwModulus; // Public Modulus
    private UInt64[] qwP;       // Prime 1
    private UInt64[] qwQ;       // Prime 2
    private UInt64[] qwDP;      // Exponent 1
    private UInt64[] qwDQ;      // Exponent 2
    private UInt64[] qwCR;      // Coefficient

    public XECRYPT_RSAPRV_2048(UInt32 _modulusCount, UInt32 _publicExponent, UInt64 _reserve, UInt64[] _qwModulus, UInt64[] _qwPrime1, UInt64[] _qwPrime2, UInt64[] _qwExponent1, UInt64[] _qwExponent2, UInt64[] _qwCoefficient)
    {
        this.rsa = new XECRYPT_RSA(_modulusCount, _publicExponent, _reserve);
        this.qwModulus = _qwModulus;
        this.qwP = _qwPrime1;
        this.qwQ = _qwPrime2;
        this.qwDP = _qwExponent1;
        this.qwDQ = _qwExponent2;
        this.qwCR = _qwCoefficient;
    }

    public byte[] GetModulusByteArray()
    {
        byte[] modulusBuffer = new byte[0x100];
        for (int c = 0; c < 0x20; c++)
            Buffer.BlockCopy(XboxIO.GetBytes(this.qwModulus[c]), 0x00, modulusBuffer, (c * 0x08), 0x08);
        return modulusBuffer;
    }

    public byte[] GetPrime1ByteArray()
    {
        byte[] primeBuffer = new byte[0x80];
        for (int c = 0; c < 0x10; c++)
            Buffer.BlockCopy(XboxIO.GetBytes(this.qwP[c]), 0x00, primeBuffer, (c * 0x08), 0x08);
        return primeBuffer;
    }

    public byte[] GetPrime2ByteArray()
    {
        byte[] primeBuffer = new byte[0x80];
        for (int c = 0; c < 0x10; c++)
            Buffer.BlockCopy(XboxIO.GetBytes(this.qwQ[c]), 0x00, primeBuffer, (c * 0x08), 0x08);
        return primeBuffer;
    }

    public byte[] GetExponent1ByteArray()
    {
        byte[] exponentBuffer = new byte[0x80];
        for (int c = 0; c < 0x10; c++)
            Buffer.BlockCopy(XboxIO.GetBytes(this.qwDP[c]), 0x00, exponentBuffer, (c * 0x08), 0x08);
        return exponentBuffer;
    }

    public byte[] GetExponent2ByteArray()
    {
        byte[] exponentBuffer = new byte[0x80];
        for (int c = 0; c < 0x10; c++)
            Buffer.BlockCopy(XboxIO.GetBytes(this.qwDQ[c]), 0x00, exponentBuffer, (c * 0x08), 0x08);
        return exponentBuffer;
    }

    public byte[] GetCoefficientByteArray()
    {
        byte[] coefficientBuffer = new byte[0x80];
        for (int c = 0; c < 0x10; c++)
            Buffer.BlockCopy(XboxIO.GetBytes(this.qwCR[c]), 0x00, coefficientBuffer, (c * 0x08), 0x08);
        return coefficientBuffer;
    }

    public byte[] ToByteArray()
    {
        byte[] keyBuffer = new byte[0x390];

        Buffer.BlockCopy(XboxIO.GetBytes(this.rsa.GetModulusCount()), 0x00, keyBuffer, 0x00, 0x04);
        Buffer.BlockCopy(XboxIO.GetBytes(this.rsa.GetPublicExponent()), 0x00, keyBuffer, 0x04, 0x04);
        Buffer.BlockCopy(XboxIO.GetBytes(this.rsa.GetReserve()), 0x00, keyBuffer, 0x08, 0x08);

        for (int c = 0; c < 0x20; c++)
            Buffer.BlockCopy(XboxIO.GetBytes(this.qwModulus[c]), 0x00, keyBuffer, ((0x10) + (c * 0x08)), 0x08);

        for (int c = 0; c < 0x10; c++)
        {
            Buffer.BlockCopy(XboxIO.GetBytes(this.qwP[c]), 0x00, keyBuffer, ((0x110) + (c * 0x08)), 0x08);
            Buffer.BlockCopy(XboxIO.GetBytes(this.qwQ[c]), 0x00, keyBuffer, ((0x190) + (c * 0x08)), 0x08);
            Buffer.BlockCopy(XboxIO.GetBytes(this.qwDP[c]), 0x00, keyBuffer, ((0x210) + (c * 0x08)), 0x08);
            Buffer.BlockCopy(XboxIO.GetBytes(this.qwDQ[c]), 0x00, keyBuffer, ((0x290) + (c * 0x08)), 0x08);
            Buffer.BlockCopy(XboxIO.GetBytes(this.qwCR[c]), 0x00, keyBuffer, ((0x310) + (c * 0x08)), 0x08);
        }

        return keyBuffer;
    }

    public byte[] ToReverseByteArray()
    {
        byte[] keyBuffer = new byte[0x390];

        Buffer.BlockCopy(XboxIO.GetBytes(this.rsa.GetModulusCount()).Reverse().ToArray(), 0x00, keyBuffer, 0x00, 0x04);
        Buffer.BlockCopy(XboxIO.GetBytes(this.rsa.GetPublicExponent()).Reverse().ToArray(), 0x00, keyBuffer, 0x04, 0x04);
        Buffer.BlockCopy(XboxIO.GetBytes(this.rsa.GetReserve()).Reverse().ToArray(), 0x00, keyBuffer, 0x08, 0x08);

        for (int c = 0; c < 0x20; c++)
            Buffer.BlockCopy(XboxIO.GetBytes(this.qwModulus[c]).Reverse().ToArray(), 0x00, keyBuffer, (10 + (c * 0x08)), 0x08);

        for (int c = 0; c < 0x10; c++)
        {
            Buffer.BlockCopy(XboxIO.GetBytes(this.qwP[c]).Reverse().ToArray(), 0x00, keyBuffer, ((0x110) + (c * 0x08)), 0x08);
            Buffer.BlockCopy(XboxIO.GetBytes(this.qwQ[c]).Reverse().ToArray(), 0x00, keyBuffer, ((0x190) + (c * 0x08)), 0x08);
            Buffer.BlockCopy(XboxIO.GetBytes(this.qwDP[c]).Reverse().ToArray(), 0x00, keyBuffer, ((0x210) + (c * 0x08)), 0x08);
            Buffer.BlockCopy(XboxIO.GetBytes(this.qwDQ[c]).Reverse().ToArray(), 0x00, keyBuffer, ((0x290) + (c * 0x08)), 0x08);
            Buffer.BlockCopy(XboxIO.GetBytes(this.qwCR[c]).Reverse().ToArray(), 0x00, keyBuffer, ((0x310) + (c * 0x08)), 0x08);
        }

        return keyBuffer;
    }

    public XECRYPT_RSAPUB_2048 ToPublicKey()
    {
        return new XECRYPT_RSAPUB_2048(this.rsa.GetModulusCount(), this.rsa.GetPublicExponent(), this.rsa.GetReserve(), this.qwModulus);
    }
}

Code:
// I may have stolen "XeCryptBnQwNeModInv" from somewhere, idk where so thanks for saving me a couple minutes!!! Creds to you!
public static UInt64 XeCryptBnQwNeModInv(UInt64 qwInput)
{
    UInt64 val = (qwInput * 0x03) ^ 0x02;
    qwInput = 1 - (val * qwInput);

    for (int c = 5; c < 0x20; c = c << 1)
    {
        val = val * (qwInput + 1);
        qwInput = qwInput * qwInput;
    }

    val = val * (qwInput + 1);
    return val;
}



public static void XeCryptBnQwNeModMul(UInt64[] pqwA, UInt64[] pqwB, ref UInt64[] pqwC, UInt64 inverse, UInt64[] pqwM, Int32 cqwModulus)
{
    byte[] buffer = new byte[0x210];

    UInt64 r10 = (UInt64)(inverse * pqwA[0x00]);
    UInt64 r11 = 0; UInt64 r12 = 0; UInt64 r14 = 0; UInt64 r15 = 0; UInt64 r16 = 0; UInt64 r17 = 0; UInt64 r18 = 0; UInt64 r19 = 0; UInt64 r20 = 0;

    int index = 0x08; // 0x58
    for (int a = 0; a < cqwModulus; a++)
    {
        // reset index
        index = 0x08;
        r11 = pqwB[a];
        r12 = (UInt64)(r10 * r11);
        r16 = XboxIO.ToUInt64(buffer, index);
        r17 = XboxIO.ToUInt64(buffer, index + 0x108);
        r16 = r16 - r17;
        r16 = (UInt64)(r16 * inverse);
        r12 = r12 + r16;

        r14 = 0;
        r15 = 0;

        for (int b = 0; b < cqwModulus; b++)
        {
            r16 = pqwA[b];
            r17 = XboxIO.GetHighOrder128(r11, r16);
            r18 = (UInt64)(r11 * r16);
            r16 = XboxIO.ToUInt64(buffer, index);
            r18 = r18 + r16;
            if (r18 < r16)
                r17 = r17 + 0x01;

            r18 = r18 + r14;
            if (r18 < r14)
                r17 = r17 + 0x01;

            r14 = r17;
            Buffer.BlockCopy(XboxIO.GetBytes(r18), 0x00, buffer, index - 0x08, 0x08);
            r16 = pqwM[b];
            r17 = XboxIO.GetHighOrder128(r12, r16);
            r18 = (UInt64)(r12 * r16);
            r16 = XboxIO.ToUInt64(buffer, index + 0x108);
            r18 = r18 + r16;
            if (r18 < r16)
                r17 = r17 + 0x01;

            r18 = r18 + r15;
            if (r18 < r15)
                r17 = r17 + 0x01;

            r15 = r17;
            Buffer.BlockCopy(XboxIO.GetBytes(r18), 0x00, buffer, index + 0x100, 0x08);
            index = index + 0x08;
        }

        Buffer.BlockCopy(XboxIO.GetBytes(r14), 0x00, buffer, index - 0x08, 0x08);
        Buffer.BlockCopy(XboxIO.GetBytes(r15), 0x00, buffer, index + 0x100, 0x08);
    }

    r14 = 0;
    r15 = 0;
    index = (int)XboxIO.RotateLeft32((uint)cqwModulus, 0x03);
    for (int c = 0; c < cqwModulus; c++)
    {
        r16 = XboxIO.ToUInt64(buffer, index);
        r17 = XboxIO.ToUInt64(buffer, index + 0x108);
        if (r16 != r17)
            break;

        index = index - 0x08;
    }

    index = 0x08;
    if (r16 > r17)
    {
        for (int c = 0; c < cqwModulus; c++)
        {
            r16 = XboxIO.ToUInt64(buffer, index);
            r17 = XboxIO.ToUInt64(buffer, index + 0x108);
            r18 = r16 - r17;
            r18 = r18 - r14;
            pqwC[c] = r18;

            r17 = r17 ^ r16;
            r18 = r18 ^ r16;
            r18 = r18 | r17;
            r16 = r16 ^ r18;
            r14 = (UInt64)(XboxIO.RotateRight64(r16, 63) & 0x01);

            index = index + 0x08;
        }
    }
    else
    {
        for (int c = 0; c < cqwModulus; c++)
        {
            r16 = XboxIO.ToUInt64(buffer, index);
            r17 = XboxIO.ToUInt64(buffer, index + 0x108);
            r18 = pqwM[c];
            r19 = r16 + r18;
            r19 = r19 + r14;
            r20 = r19 - r17;
            r20 = r20 - r15;
            pqwC[c] = r20;

            r18 = r18 ^ r19;
            r16 = r16 ^ r19;
            r16 = r16 | r18;
            r16 = r16 ^ r19;
            r14 = (UInt64)(XboxIO.RotateRight64(r16, 63) & 0x01);
            r20 = r20 ^ r19;
            r17 = r17 ^ r19;
            r17 = r17 | r20;
            r17 = r17 ^ r19;
            r15 = (UInt64)(XboxIO.RotateRight64(r17, 63) & 0x01);

            index = index + 0x08;
        }
    }
}

public static void XeCryptBnQwBeSigFormat(ref UInt64[] signature, byte[] hash, byte[] salt)
{
    byte[] buffer = new byte[0x100];
    for (int c = 0; c < 0x20; c++)
        Buffer.BlockCopy(XboxIO.GetBytes(signature[c]), 0x00, buffer, (c * 0x08), 0x08);

    Buffer.BlockCopy(new byte[0xE0], 0x00, buffer, 0x00, 0xE0);

    buffer[0xE0] = (byte)(0x01);

    Buffer.BlockCopy(salt, 0x00, buffer, 0xE1, 0x0A);

    buffer[0xFF] = (byte)(0xBC);

    SHA1CryptoServiceProvider sha = new SHA1CryptoServiceProvider();
    sha.TransformBlock(buffer, 0x00, 0x08, null, 0x00);
    sha.TransformBlock(hash, 0x00, 0x14, null, 0x00);
    sha.TransformFinalBlock(salt, 0x00, 0x0A);
    Buffer.BlockCopy(sha.Hash, 0x00, buffer, 0xEB, 0x14);

    byte[] encBuffer = new byte[0xEB];
    Buffer.BlockCopy(buffer, 0x00, encBuffer, 0x00, 0xEB);

    XeCryptRC4Ecb(encBuffer, encBuffer.Length, sha.Hash, sha.Hash.Length);

    Buffer.BlockCopy(encBuffer, 0x00, buffer, 0x00, 0xEB);

    buffer[0x00] = (byte)(buffer[0x00] & 0x7F);

    int index = 0x1F;
    for (int c = 0; c < 0x20; c++)
        signature[index--] = XboxIO.ToUInt64(buffer, (c * 0x08));
}

public static bool XeCryptBnQwBeSigVerify(XECRYPT_SIG signatureIn, byte[] hash, byte[] salt, XECRYPT_RSAPUB_2048 key)
{
    if (key.rsa.GetModulusCount() != 0x20 | (key.rsa.GetPublicExponent() != 0x03 && key.rsa.GetPublicExponent() != 0x10001))
        return false;

    UInt64 inverse = XeCryptBnQwNeModInv(key.GetModulus(0));

    UInt64[] signature = signatureIn.ToUInt64Array();
    UInt64[] signatureBuffer = signatureIn.ToUInt64Array();

    UInt32 exponent = key.rsa.GetPublicExponent() >> 0x01;
    while (exponent > 0)
    {
        XeCryptBnQwNeModMul(signature, signature, ref signature, inverse, key.GetModulusArray(), 0x20);

        exponent = exponent >> 0x01;
    }

    XeCryptBnQwNeModMul(signature, signatureBuffer, ref signatureBuffer, inverse, key.GetModulusArray(), 0x20);

    XeCryptBnQwBeSigFormat(ref signature, hash, salt);

    for (int c = 0; c < 0x20; c++)
    {
        if (signature[c] != signatureBuffer[c])
            return false;
    }

    return true;
}

Sorry for not code purging :frown: I hope you don't mind it.

Edit: I forgot to add the "XECRYPT_RSAPUB_KEY" struct... fixed now!
 
Last edited:
T

TEIR1plus2

Getting There
Messages
506
Reaction score
225
Good job on the reversing part, however I'm sorry to say you did a lot of work for nothing really, Microsoft uses standard crypto implementations in their XeCrypt libraries, meaning using something like openssl will yield the same result, they don't do anything special to their functions (with a couple exceptions, they do have a couple functions that are of their own design).

Just keep in mind that programming isn't about reinventing the wheel, gotta get used to using premade libraries otherwise you'll waste a lot of time if you intend to go forward in this field.
 
J

Just1n

Enthusiast
Messages
73
Reaction score
15
Good job on the reversing part, however I'm sorry to say you did a lot of work for nothing really, Microsoft uses standard crypto implementations in their XeCrypt libraries, meaning using something like openssl will yield the same result, they don't do anything special to their functions (with a couple exceptions, they do have a couple functions that are of their own design).

Just keep in mind that programming isn't about reinventing the wheel, gotta get used to using premade libraries otherwise you'll waste a lot of time if you intend to go forward in this field.
Well it wasn’t that much work so no biggie. This is more or less a quick and dirty reimplementation of how they do it without linking libraries. And you can have raw binary keys instead of worrying about the dumb key format. So I like this better for verifying and signing signatures.

And can you clarify what functions they do differently in their XeCrypt library?
 
T

TEIR1plus2

Getting There
Messages
506
Reaction score
225
Well it wasn’t that much work so no biggie. This is more or less a quick and dirty reimplementation of how they do it without linking libraries. And you can have raw binary keys instead of worrying about the dumb key format. So I like this better for verifying and signing signatures.

And can you clarify what functions they do differently in their XeCrypt library?
off the top of my head, XeCryptRotSum/XeCryptRotSum4/XeCryptRotSumSha. You won't find any algorithms on those, at least none that have to do with anything besides xbox. Probably some others as well, XeCryptSwizzle is one I haven't found much info on.

I reversed those a while back: Idk how well that will work on little endian systems or if endian will change anything
 
J

Just1n

Enthusiast
Messages
73
Reaction score
15
off the top of my head, XeCryptRotSum/XeCryptRotSum4/XeCryptRotSumSha. You won't find any algorithms on those, at least none that have to do with anything besides xbox. Probably some others as well, XeCryptSwizzle is one I haven't found much info on.

I reversed those a while back: Idk how well that will work on little endian systems or if endian will change anything
Thanks for the insight. And the endian would matter, looks like you got some primitive data types within a struct and passed as args.
 
T

TEIR1plus2

Getting There
Messages
506
Reaction score
225
yes... that was from the hv where everything is handled as 64bits (including pointers). I keep all types as qwords by default and change them if I notice it being handled as 32bits or I just forget and everything gets left as qwords, should still work if you try running it on the console. figure it out..
 
Top Bottom