Valve’s ‘VLV’ Signature

Categories: Reversing

[Note: This is a years old writeup which I never posted (not for any good reason; it just got lost in the drafts). All I did now was take a look at the latest steamservice.dll to update the offsets and verify it still worked the same way.]

If you are ever analyzing a binary produced by Valve you may notice that there is some unusual data where the DOS stub and ‘Rich’ header would typically be. In fact this is a custom header containing an RSA signature which we can use to verify the integrity/provenance of the file even in the absence of an Authenticode signature. One important example of files like this are VAC (anti-cheat) and CEG (DRM) modules, which was my original interest. If you want to verify these signatures yourself, everything you need is below.

Raw header structure:

struct vlv_file_header
{
  // k_vlv_header_magic - 0x00564C56 ('VLV')
  std::uint32_t magic;
  // k_vlv_header_version - Always '1'?
  std::uint32_t version;
  // Size of the signed data. For regular files this will typically exclude the digital signature overlay. For VAC/CEG
  // modules no such overlay is present so this will typically match the raw file size.
  std::uint32_t size;
  // Different to export dir timestamp. Always later? Probably the time the file is signed, and the export dir timestamp
  // is obviously set when the binary is built (assuming it's not spoofed).
  std::uint32_t timestamp;
  // RSA PKCS#1 v1.5 SHA-1
  std::array signature;
};

Public key (as X.509 SubjectPublicKeyInfo):

30819D300D06092A864886F70D010101050003818B0030818702818100B1260881BDFE84463D88C6AB8DB914A2E593893C10508B8A5ABDF692E9A5419A3EDBAE86A052849983B75E3B425C18178B260003D857DF0B6505C6CF9C84F5859FCE3B63F1FB2D4818501F6C5FA4AD1430EEB081A74ABD74CD1F4AA1FCCA3B88DD0548AED34443CEB52444EAE9099AA4FE66B2E6224D02381C248025C7044079020111

Note that the optional header checksum and the security data directory VA/size should be zeroed before verification, since they are excluded from the signature (for obvious reasons).

Valid as of steamservice.dll 6.17.23.25 [1], though it has worked this way for years prior and will likely continue to do so. The public key can be found at 0x101B0F38 and the relevant verification code can be found at 0x10053070.

Magic: 0x00564c56
Version: 0x00000001
Size: 0x00268800
Timestamp: 0x5f9a014f
Signature: 8c55d81d3ba0860e279aa77569160ed11dc0dbbd9bcb0854bb079f0757166072a90162df35fcb13ab8afc7070bb2e6ec8a1d1a8f6ec4374b50b9eb8accc8ebad04e012c6e53640b01e6b225fc80c55a798f9e83edb98d90171d5af959e8f5ac56e75f0da96d9d65fc7fe5c3301b37fdaaf54e4949505d73dd5c15df5c9321a0a
Verified.

[1] 8dc5dfbbf8a6a246ada7a9fffe8e3a8fc6e0115d24041ecb3d144d7216fda6b (Password is industry standard ‘infected’. Obviously the file is clean though.)


    Leave a Reply

    Your email address will not be published. Required fields are marked *