XIV Docs

SqexArg

This is the “encrypted argument” format used by a lot of FFXIV programs and is used in place of regular plaintext command line arguments. However, this is barely a security measure and just prevents easily snooping stuff like your login token. Despite this, the SqexArg format is well known, reversible and easily breakable.

Format #

When viewing the command line arguments for, say ffxiv.exe you will see it’s only something like this:

//**sqex0003S2_Utl8qdamv3_82SH7Lhtk=S**//

(Yes, I did garble some of the text, so it’s not actually decodable :-))

There are three distinct parts of this string:

//**sqex0003S2_Utl8qdamv3_82SH7Lhtk=S**//
           ^^                       ^
    version||                       |
            | base64 string         |
                                    | checksum

Let’s break them down:

Encryption Algorithm #

The resulting bytes when you decode the base64 string is going to Blowfish ECB encrypted.

Note: In the new Steam launcher update, Square Enix has actually switched to a more sane version of Blowfish ECB without their weird changes. Please look at XIVQuickLauncher for the changes required, as I have not tested this yet.

Key #

The key used for encrypting/decrypting the encrypted arguments is just your system’s uptime clock. All FFXIV executables just call GetTickCount(), and theres about ~50 or so ticks of freedom before the game or launcher considers it invalid. There is a specific transformation you need to do in order to fetch a valid key though:

unsigned int rawTicks = TickCount();
unsigned int ticks = rawTicks & 0xFFFFFFFFu;
unsigned int key = ticks & 0xFFFF0000u;

char buffer[9] = {};
sprintf(buffer, "%08x", key);

To make this easier, here is a couple of platform-specific implementations of TickCount(). Thank you Wine for being easily searchable, as this is what Wine is actually doing under the hood to emulate GetTickCount(), so these are exact and have been tested on Astra for all platforms.

Windows #
uint32_t TickCount() {
    return GetTickCount();
}
macOS #
uint32_t TickCount() {
    struct mach_timebase_info timebase;
    mach_timebase_info(&timebase);

    auto machtime = mach_continuous_time();
    auto numer = uint64_t (timebase.numer);
    auto denom = uint64_t(timebase.denom);
    auto monotonic_time = machtime * numer / denom / 100;
    return monotonic_time / 10000;
}
Linux #
uint32_t TickCount() {
    struct timespec ts;

    clock_gettime(CLOCK_MONOTONIC, &ts);

    return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
}

Checksum #

If you’re just interested in decrypting game arguments, this is not essential. This is presumably used as a checksum when the game checks your encrypted string.

static char ChecksumTable[] = {
    'f', 'X', '1', 'p', 'G', 't', 'd', 'S',
    '5', 'C', 'A', 'P', '4', '_', 'V', 'L'
};

static char GetChecksum(unsigned int key) {
    auto value = key & 0x000F0000;
    return ChecksumTable[value >> 16];
}

Decrypting #

You can try the dedicated argcracker in Novus for this purpose. It allows you to easily crack any SqexArg enabled program assuming you have access to the string.

Notes #

Every instance where SqexArg is used, the first argument is always T, where T is set to the value of ticks (as shown above). I’m not sure what the purpose of this really is, maybe for verifying the checksum?

The arguments (before encoding of course) must be formatted as " /%1 =%2". The extra space is required, even at the beginning of the arguments. Make sure that any spaces in your string is double padded as well.

See Also #

Implementations #