Skip to content

V_CODEs

Robert Jordan edited this page Apr 11, 2020 · 13 revisions

V_CODEs are two codes contained within the CatSystem2 Windows executable resources that are used as keys for decryption and encryption.

Resources

The Type, Name, (and optionally the Language), are used to obtain the resource from the executable using Windows API methods.

Type Name Language Description
KEY_CODE KEY 0x0411 Key to decrypt V_CODEs
V_CODE DATA 0x0411 Game validation. Often present in config/startup.xml
V_CODE2 DATA 0x0411 Used to decrypt KIF Archives

Note: Although 0x0411 is the expected language, it is possible to use a different language (likely depending on the executable's language in VS_VERSION_INFO). This has been observed with the Grisaia no Kajitsu Steam localization. The executable even contains a comment from the program used to modify it. However this is non-standard, and not something necessarily worth checking unless you plan on overwriting the V_CODEs and KEY_CODE resources of a game.

Extracting

V_CODEs can be extracted from the CatSystem2 executable using Windows API methods such as LoadLibraryEx, FindResource, LoadResource, LockResource, SizeofResource, and FreeLibrary. (These will not be linked to because Microsoft will change up their URLs and break these within a year's time)

Important Note: The executable used to launch the game may not be the CatSystem2 executable. Grisaia games often have a .bin file with the same name that is actually launched when running the .exe file. In this situation, the .bin file is the CatSystem2 executable with the V_CODE resources.

Decrypting

V_CODEs are decrypted using the KEY_CODE and a Blowfish cipher. First, take the KEY_CODE byte array, and XOR each byte by 0xCD. Then pass the modified KEY_CODE to the Blowfish cipher as the key. Because Blowfish requires buffers to be a multiple of 8 bytes, make sure your V_CODE byte array is a multiple of 8 bytes rounded up.

Code Sample

string DecryptVCode(byte[] vcode, byte[] keyCode) {
    // This assumes the keyCode buffer passed in will not be used after this.
    // If you want to reuse the keyCode buffer, either perform the XOR once
    // beforehand outside of the method, or perform the same XOR again at
    // the end of the method before returning.
    for (int i = 0; i < keyCode.Length; i++)
        keyCode[i] ^= 0xCD;

    // Key does not need to be a multiple of 8.
    Blowfish blowfish = new Blowfish(keyCode);

    // Decryption buffer needs to be rounded up to the next multiple of 8.
    // & ~7 is equivalent to `(int) / 8 * 8`.
    byte[] vcodeBuffer = new byte[(vcode.Length + 7) & ~7];
    Array.Copy(vcodeData, vcodeBuffer, vcode.Length);

    blowfish.Decrypt(vcodeBuffer);

    // Shorten the string if there is a null-character.
    int index = Array.IndexOf(vcodeBuffer, 0);
    int length = (index != -1 ? index : vcodeBuffer.Length);
    return Encoding.ASCII.GetString(vcodeBuffer, 0, length);
}

Structure of Codes

The following information is only trivia. And not required for decryption.

KEY_CODE

KEY_CODEs are often reused with games by the same developer. If not reused, then only changes a bit.

The XOR applied to the KEY_CODE isn't meaningless. The XOR of 0xCD will most often translate the code into plain ASCII or Shift JIS text. With this in mind. You can assume the real or original KEY_CODE is that with the XOR applied after extraction.

Likewise, the V_CODEs will always decrypt to plain ASCII.

Some examples of decrypted codes in plain text can be seen below.
These will not be identified to any specific game

Resource Decrypted
KEY_CODE
4EB94E404E5E4EAA-
4E884E8E4E5E4E82
フロントウイング
"furontouingu", AKA "Frontwing"
KEY_CODE
BAA4A3A9A0A4A1A1
windmill
Commonly used by games that have not changed KEY_CODE

V_CODEs

V_CODEs on the other hand, are always unique to each game, and even more so each release of a game.

Decrypted V_CODEs generally adhere to the same kind of pattern when converted to text: DEV-XXXXXXXX, e.g. WM-QU4L4341 (not a real code)

Where DEV is a 2-3 letter identifier of the developer, such as WM for Windmill, and XXXXXXXX is a string of 8 characters in the set of [0-9A-Z] (always uppercase), such as QU4L4341. This 8-letter code could just be a randomly generated number, it's also possible that it represents a Base36, Base32 (where lookalike letters all map to the same value), or even Base 64 (assuming the lowercase letters are never reached, but unlikely).

Identifying this pattern is unnecessary or more considered out of curiosity.

Clone this wiki locally