CheckRevision
CheckRevision is a module sent by the server during the logon process. The purpose of CheckRevision is to ensure that only official, unmodified Battle.net clients are connecting to Battle.net servers. Some PvPGN servers have been known to compile their own CheckRevision modules to add client-side features or detect hacks.
Procedure
In all versions of CheckRevision, the following procedure is used to obtain CheckRevision and run it to return some values to the server:
-
The client sends the server its platform ID, product ID, and version byte via
C>S 0x06 SID_STARTVERSIONING or C>S 0x50 SID_AUTH_INFO. -
The server will then determine which CheckRevision to serve the client and then send the appropriate filename and filetime of the CheckRevision MPQ and a formula for the CheckRevision function via S>C 0x06 SID_STARTVERSIONING or S>C 0x50 SID_AUTH_INFO.
-
The client checks bncache for CheckRevision. If CheckRevision is not found in bncache, the client initiates a BNFTPv1 connection to download CheckRevision.
-
The client verifies that the CheckRevision MPQ contains a valid Blizzard Weak Digital Signature. If one is not found, the client immediately closes the connection to the server. It appears that this does not apply for XMAC/PMAC clients.
-
The client extracts the CheckRevision DLL, whose base filename is the same as the CheckRevision MPQ's base filename (e.g. CheckRevision.mpq contains CheckRevision.dll). Modern versions of game clients verifies the CheckRevision DLL's signature. If one is not found, the client immediately closes the connection to the server.
-
The client calls
CheckRevision()
. If the function returns 0, the client immediately closes the connection to the server. -
Information returned from
CheckRevision()
is sent to the server via C>S 0x07 SID_REPORTVERSION or C>S 0x51 SID_AUTH_CHECK.
CheckRevision() function declaration in C++
extern "C" __declspec(dllexport) std::int32_t __stdcall CheckRevision(const char* filename1, const char* filename2, const char* filename3, const char* formula, std::uint32_t* version, std::uint32_t* checksum, char* exeinfo);
Filenames
Product | filename1 | filename2 | filename3 |
---|---|---|---|
W2BN | WarCraft II BNE.exe | Storm.dll | Battle.snp |
STAR, SEXP | StarCraft.exe | Storm.dll | Battle.snp |
D2DV, D2XP | Game.exe | Bnclient.dll | D2Client.snp |
WAR3, W3XP | War3.exe | Storm.dll | Game.dll |
* - In the more recent versions of some products, NULL pointers are passed in for the filename2
and filename3
when the corresponding files are missing.
Version 1a
Introduced around March 1997, and also known as "classic CheckRevision", this version uses the following naming format: {PLATFORM}ver{NUM}.mpq
(ex: IX86ver0.mpq
).
{PLATFORM}
: IX86
, XMAC
, PMAC
{NUM}
: 0
- 7
Formula/Seed
The formula given by the server is generally in the following format: A={int} B={int} C={int} 4 A=A{op}S B=B{op}C C=C{op}A A=A{op}B
.
{int}
: A positive integer, whose max value is presumably the max value of a 32-bit signed integer.
{op}
: +
, -
, *
, /
, ^
(XOR)
Example formulas:
A=5 B=10 C=15 4 A=A+S B=B-C C=C+A A=A-B
A=1239576727 C=1604096186 B=4198521212 4 A=A+S B=B-C C=C^A A=A+B
A=0 B=0 C=0 4 A=A+S C=C+A
It is possible that some operators may never be used, and also possible that the operands will not be consistent, so custom implementations should be wary of this.
In some cases, Battle.net may return a "default" formula, A=0 B=0 C=0 4 A=A+S C=C+A
.
Known Cases:
- Connecting with StarCraft pre-1.18
Checksum Algorithm
Each file is compiled with a different "hash code" that is first XOR'd with the A value from the formula.
For {NUM}
0-7, the hash codes are 0xE7F4CB62
, 0xF6A14FFC
, 0xAA5504AF
, 0x871FCDC2
, 0x11BF6A18
, 0xC57292E6
, 0x7927D27E
, and 0x2FEC8733
respectively.
Each of up to 3 hash files are read in 4-byte chunks (as integers) as 'S' and then each operation in the formula is performed on every chunk. The resulting value of 'C' is returned as the checksum
.
Version and EXE Info
The version
value is a combination of dwProductVersionMS
and dwProductVersionLS
from VS_FIXEDFILEINFO for the EXE.
The exeinfo
value is a space-delimited C string containing the following values:
- EXE Name (ex.
war3.exe
) - Last Modified Date (ex.
08/16/09
) - Last Modified Time (ex.
19:21:59
) - Filesize in bytes (ex.
471040
)
An example of a valid string would be: war3.exe 08/16/09 19:21:59 471040
Version 1b
In late 2006, Blizzard began to serve CheckRevision 1b to Diablo 2 and WarCraft 3 clients. Perhaps the main reason for this update is due to a bug in CheckRevision 1a's checksum algorithm that results in an access violation error on systems with Data Execution Prevention (DEP) enabled.
This version uses the following naming format: ver-{PLATFORM}-{NUM}.mpq
(ex: ver-IX86-3.mpq
).
{PLATFORM}
: IX86
, XMAC
, PMAC
, OSXI
{NUM}
: 0
- 7
Formula/Seed
The formula format is the same as in CheckRevision 1a.
Checksum Algorithm
The only change in the algorithm is that the hashed files were padded to the next 1024-byte interval using bytes of descending values starting at 0xFF and going to 0x00 before looping back around.
Digital Signing
In May 2016, Blizzard signed CheckRevision 1b DLLs. Starting with StarCraft 1.17.0 and Diablo II 1.14d, the client will verify the signature of the CheckRevision DLL.
Version 2
CheckRevision 2 is a relatively sophisticated library introduced in late 2006 and served to Diablo, StarCraft, and WarCraft 2 clients. This version incorporates stronger defense measures than previous versions of CheckRevision.
There are two variants of CheckRevision 2, lockdown
and psistorm
for PC and Mac clients respectively. This version uses the following naming format: {VARIANT}-{PLATFORM}-{NUM}.mpq
(ex: lockdown-IX86-03.mpq
or psistorm-XMAC-11.mpq
).
{VARIANT}
: lockdown
, psistorm
{PLATFORM}
: IX86
(valid only for lockdown
variant), XMAC
(valid only for psistorm
variant), PMAC
(valid only for psistorm
variant)
{NUM}
: 00
- 19
Formula/Seed
TODO.
Checksum Algorithm
The algorithm for this version is somewhat more complicated. In short (for Lockdown at least), the seed string is shuffled and then hashed along with various parts of the game files, the library (DLL) itself, and a dump from the game's video memory. The hashing function used for this hash is another variation of SHA-1 (different from both standard SHA-1 and XSHA-1 used in password hashing).
For more information, see the following resources:
- Research by Skywing: An Objective Analysis of the Lockdown Protection System for Battle.net
- JBLS implementation (JBLS refers to this as version 3 but their version 2 is our version 1b).
Version and EXE Info
The version
value is the same as from CheckRevision v1.
The info
value is a null-terminated, shuffled continuation of the hash digest returned when calculating the checksum. The shuffling process will sometimes affect the size of this value, so it may not always be 16 bytes in length (not including the terminator).
Version 3a
After a server reset on January 4, 2019, Battle.net began serving CheckRevision 3a to Diablo 2 clients. Unlike previous versions, this version does not have multiple variants. The file name is CheckRevision.mpq
.
Formula/Seed
The seed is a base64-encoded, 9 byte (including the null terminator) value. Unlike previous versions, the seed appears to be randomly generated for each connection.
Example seeds:
kjen1QAA
BLRZcAAA
cj/B0QAA
Checksum Algorithm
The algorithm is much simpler than the algorithm from previous versions. It does not verify the full checksum of the client, instead it verifies the executable's file version number. Because of this it can be emulated without having a copy of the client executable.
Once decoded, the first 4 bytes of the seed are combined with a colon :
, the executable's file version number (as a dot-separated string, ex: 1.14.3.71
), another colon, and a single byte 0x01
. This value is then hashed using standard SHA-1.
result = b64encode(sha1(b64decode(seed)[:4], ':' + version + ':', 0x01))
The first 4 bytes of this result are used as the checksum
value.
Version and EXE Info
The version
value is always 0
.
The exeinfo
value is a null-terminated continuation of the result. It should be 25 bytes long, including the null terminator.
Version 3b
Version 3b appeared along with the re-release of Diablo 1 and WarCraft 2. It is (so far) only used for these 2 games, and only on their entirely separate, special server connect-forever.classic.blizzard.com
. Like version 3a, this version does not have any variants. The file name is CheckRevisionD1.mpq
.
If calling the CheckRevision() function from the v3 DLL, the calling app's version needs to match the version of the game EXE and have any valid signature.
Formula/Seed
The seed format for this version is the same as for version 3a.
Checksum Algorithm
In addition to the checksum algorithm in version 3a, version 3b includes the base64-encoded SHA1 hash of the executable file signature's public key (as a hex string) and the 4-byte seed value, appended to the result, after a colon ':'. This only affects the value returned for exeinfo
.
result += ':' + b64encode(sha1(public_key, value))
See the implementation in Warden.dll for more details.
Version and EXE Info
The version
value is always 6
.
The exeinfo
value is a null-terminated continuation of the result.
History
- February 25, 2020 CheckRevision 3a (
CheckRevision.mpq
) recompiled. - March 28, 2019 GOG releases W2BN client,
connect-forever.classic.blizzard.com:6112
serve CheckRevision 3b (CheckRevisionD1.mpq
) to W2BN clients. - March 7, 2019 GOG releases DRTL client,
connect-forever.classic.blizzard.com:6112
serve CheckRevision 3b (CheckRevisionD1.mpq
) to DRTL clients. - February 2, 2019 CheckRevision 3b (
CheckRevisionD1.mpq
) compiled. - January 4, 2019 Battle.net server reset, traditional Battle.net servers serve CheckRevision 3a (
CheckRevision.mpq
) to D2DV and D2XP clients. - January 3, 2019 CheckRevision 3a (
CheckRevision.mpq
) compiled. - May 27, 2016 CheckRevision 1b DLL files signed
- April 21, 2016 CheckRevision 2 updated for XMAC
- March 5, 2007 CheckRevision is updated
- Late 2006 CheckRevision 2 released
- Late 2006 Checkrevision 1b released
- August 10, 2006 CheckRevision 1b compiled.
- March 3, 1997 CheckRevision 1a compiled.
- January 17, 1997 ix86std.dll compiled
Comments
Added information on the new algorithm for v3.
I found that if D2 1.13c is served IX86ver1.mpq
, it crashes with a 0xc00000005
error. Serving it ver-IX86-1.mpq
, which is what Battle.net served, no longer causes it to crash. This leads me to think that Blizzard didn't just rename CheckRevision v1 files in 2006, they probably recompiled CheckRevision v1 with the same code or different code while keeping the output the same.
ix86std.dll
is found in an MPQ embedded in DRTL 1.02, 1.03, and 1.04 manual patches.
Recently (possibly on August 13), Blizzard removed many CheckRevision v2 files from US West, US East, and Europe servers. As of now, Asia server still retains all of the CheckRevision v2 files.
I tested the following at US West:
lockdown-IX86-{NUM}.mpq
: 00
still exists, 01
- 19
are removed.
psistorm-PMAC-{NUM}.mpq
: 00
still exists. 01
, 02
, and presumably the rest have been removed too.
psistorm-XMAC-{NUM}.mpq
: 00
- 02
no longer exists, presumably the rest have been removed too.
When attempting to connect to US West, US East, or Europe with W2BN, Battle.net sends SID_STARTVERSIONING with a randomly chosen CheckRevision v2 filename despite that the chosen file may be missing. The filetime is null if the file is missing. The client hangs after receiving this packet if the filetime is null.