pvpgn / pvpgn-server

Next generation of PvPGN server
https://pvpgn.pro
GNU General Public License v2.0
541 stars 155 forks source link

0x4B SID_EXTRAWORK #72

Closed HarpyWar closed 8 years ago

HarpyWar commented 9 years ago

After sending server → client SID_REQUIREDWORD packet, client should download mpq file and then call ExtraWork function from dll inside of mpq, with sending output from the function back from client → server SID_EXTRAWORK.

I found two different versions of IX86ExtraWork.dll from official Battle.net and add one of them into IX86ExtraWork.mpq using MpqEditor. This file correctly received by a game client (I tried DIablo 2, Warcraft3 and Starcraft), but then nothing happened (no response from the client).

I even create own dll that shows messagebox, but it doesn't work too. You can try it by yourself ExtraWorkTest.zip Code for ExtraWork.exe was taken from here:

#include <windows.h>
#include <iostream>

using namespace std;

typedef bool (__fastcall *ExtraWorkProc)(void *);

enum GameType {
  Diablo2 = 1,
  Warcraft3 = 2,
  Starcraft = 3,
  WorldOfWarcraft = 4
};

struct EXTRAWORK {
  WORD GameType;
  WORD Length;
  char OutBuffer[1024];
};

int main() {
   HINSTANCE      hLib;
   ExtraWorkProc   lpfnExtraWork;
   BOOL         bReturn;
   EXTRAWORK      ew;

   hLib = LoadLibrary("IX86ExtraWork.dll");

   bool success = false;
   if (hLib) {
      lpfnExtraWork = (ExtraWorkProc)GetProcAddress(hLib, "ExtraWork");

      if (lpfnExtraWork) {
         bReturn = (*lpfnExtraWork)(&ew);

         cout << "ExtraWork returned " << (bReturn?"TRUE":"FALSE") << endl;
         cout << "GameType: " << ew.GameType << "\t\t" << "Length: " << ew.Length << endl << endl;
         cout << "Message: " << ew.OutBuffer << endl;

         success = true;
      }
      FreeLibrary(hLib);
   }
   if (!success)
      cout << "Could not load " << "IX86ExtraWork.dll" << endl;

   return 0;
}
HarpyWar commented 9 years ago

This can be tested with the latest commit (https://github.com/HarpyWar/pvpgn/commit/10650635614a1249726ed02627cccaa094fe1bb4).

--api.client_requiredwork(account.name, "IX86ExtraWork.mpq")
--DEBUG(string.format("Received EXTRAWORK packet with GameType: %d and Length: %d (%s)", gametype, length, data))
bnetd::file_send: [656] sending file "IX86ExtraWork.mpq" ("files/IX86ExtraWork.mpq") of length 3602

or another line if the file was cached in bncache.dat:

bnetd::_client_fileinforeq: [656] file requested: "IX86ExtraWork.mpq" - type = 0x80000006
RElesgoe commented 9 years ago

The client won't load the dll because it requires the mpq file to be signed.

HarpyWar commented 9 years ago

I can't find original IX86ExtraWork.mpq nowhere to at least test a response. This file is not more stored in official Battle.net servers. Well, may be someone will find the way to bypass or make a sign, it will be a ready tutorial.

RElesgoe commented 9 years ago

A bypass will require client modifications and creating the signature will require a certain private RSA key. I'm not able to find the original file too

HarpyWar commented 9 years ago

Yes, I think it is possible to disable signature check (or add own) using game loader or a launcher. For instance, Warcraft 3 and Diablo 2 don't work without a loader, and w3l.exe sources are public.

HarpyWar commented 9 years ago

Addition that can be interesting. I found this chunk in Starcraft bncache.dat while testing:

0000E628   00 00 EE 23 00 00 00 00  53 59 53 44 45 53 43 2E  64 6C 6C 00 45 78 74 72     î#    SYSDESC.dll Extr
0000E640   61 57 6F 72 6B 00 00 00  00 00 00 00 00 00 01 00  00 00 01 00 00 00 45 52   aWork                 ER
0000E658   52 3A 20 44 69 72 65 63  74 44 72 61 77 43 72 65  61 74 65 20 66 61 69 6C   R: DirectDrawCreate fail
0000E670   65 64 0A 00 00 00 45 52  52 3A 20 51 75 65 72 79  49 6E 74 65 72 66 61 63   ed    ERR: QueryInterfac
0000E688   65 20 66 61 69 6C 65 64  0A 00 45 52 52 3A 20 47  65 74 44 65 76 69 63 65   e failed  ERR: GetDevice
0000E6A0   49 64 65 6E 74 69 66 69  65 72 20 66 61 69 6C 65  64 0A 00 00 00 00 56 69   Identifier failed     Vi
0000E6B8   64 25 64 3A 20 56 65 6E  64 6F 72 20 25 30 38 78  20 44 65 76 69 63 65 20   d%d: Vendor %08x Device 
0000E6D0   25 30 38 78 20 22 25 73  22 0A 00 00 00 00 3F 00  00 00 41 75 64 25 64 3A   %08x "%s"     ?   Aud%d:
0000E6E8   20 4D 6F 64 75 6C 65 20  22 25 73 22 20 44 65 76  69 63 65 20 22 25 73 22    Module "%s" Device "%s"
0000E700   0A 00 45 52 52 3A 20 52  65 67 4F 70 65 6E 4B 65  79 45 78 20 66 61 69 6C     ERR: RegOpenKeyEx fail
0000E718   65 64 0A 00 00 00 45 52  52 3A 20 52 65 67 51 75  65 72 79 56 61 6C 75 65   ed    ERR: RegQueryValue
0000E730   45 78 20 66 61 69 6C 65  64 0A 00 00 00 00 45 52  52 3A 20 52 65 67 51 75   Ex failed     ERR: RegQu
0000E748   65 72 79 56 61 6C 75 65  45 78 20 72 65 74 75 72  6E 65 64 20 61 6E 20 75   eryValueEx returned an u
0000E760   6E 65 78 70 65 63 74 65  64 20 74 79 70 65 20 25  64 0A 00 00 00 00 44 58   nexpected type %d     DX
0000E778   3A 20 20 20 25 73 0A 00  00 00 56 65 72 73 69 6F  6E 00 53 4F 46 54 57 41   :   %s    Version SOFTWA
0000E790   52 45 5C 4D 69 63 72 6F  73 6F 66 74 5C 44 69 72  65 63 74 58 00 00 45 52   RE\Microsoft\DirectX  ER
0000E7A8   52 3A 20 47 65 74 56 65  72 73 69 6F 6E 45 78 20  66 61 69 6C 65 64 0A 00   R: GetVersionEx failed  
0000E7C0   00 00 57 69 6E 4E 54 00  00 00 4F 53 3A 20 20 20  25 73 20 25 64 2E 25 64     WinNT   OS:   %s %d.%d
0000E7D8   20 22 25 73 22 20 42 75  69 6C 64 20 25 64 0A 00  00 00 57 69 6E 39 78 00    "%s" Build %d    Win9x 
0000E7F0   00 00 52 41 4D 3A 20 20  25 64 20 4D 42 0A 00 00  00 00 00 00 00 00 43 50     RAM:  %d MB         CP
0000E808   55 3A 20 20 25 73 20 54  79 70 65 20 25 58 20 46  61 6D 69 6C 79 20 25 58   U:  %s Type %X Family %X
0000E820   20 4D 6F 64 65 6C 20 25  58 20 53 74 65 70 70 69  6E 67 20 25 58 20 42 72    Model %X Stepping %X Br
0000E838   61 6E 64 20 25 58 20 25  64 20 4D 48 7A 0A 00 00  00 00 47 61 6D 65 3A 20   and %X %d MHz     Game: 
0000E850   25 73 0A 00 00 00 55 6E  6B 6E 6F 77 6E 00 57 6F  72 6C 64 4F 66 57 61 72   %s    Unknown WorldOfWar
0000E868   63 72 61 66 74 00 57 61  72 63 72 61 66 74 33 00  00 00 44 69 61 62 6C 6F   craft Warcraft3   Diablo
0000E880   32 00 53 74 61 72 63 72  61 66 74 00 00 00 53 79  73 44 65 73 63 00 53 4F   2 Starcraft   SysDesc SO
0000E898   46 54 57 41 52 45 5C 42  61 74 74 6C 65 2E 6E 65  74 5C 4F 70 74 69 6D 69   FTWARE\Battle.net\Optimi
0000E8B0   7A 65 00 00 00 00 45 52  52 3A 20 4C 65 6E 67 74  68 20 25 64 0A 00 45 52   ze    ERR: Length %d  ER
0000E8C8   52 3A 20 54 79 70 65 20  25 64 0A 00 00 00 53 79  73 74 65 6D 20 44 65 62   R: Type %d    System Deb
0000E8E0   75 67 20 49 6E 66 6F 20  25 64 2E 25 30 32 64 0A  00 00 00 00 00 00 47 65   ug Info %d.%02d       Ge
0000E8F8   6E 75 69 6E 65 54 4D 78  38 36 00 00 00 00 43 65  6E 74 61 75 72 48 61 75   nuineTMx86    CentaurHau
0000E910   6C 73 00 00 00 00 43 79  72 69 78 49 6E 73 74 65  61 64 00 00 00 00 41 75   ls    CyrixInstead    Au
0000E928   74 68 65 6E 74 69 63 41  4D 44 00 00 00 00 47 65  6E 75 69 6E 65 49 6E 74   thenticAMD    GenuineInt
0000E940   65 6C 00 00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00   el                      

It may mean that gametype enumeration sequence is wrong on bnetdocs. It should be:

    0x01: Starcraft
    0x02: Diablo II
    0x03: Warcraft III
    0x04: World of Warcraft 
tesseract2048 commented 9 years ago

You can create weak signature now by using the private key.

I've commited this: https://github.com/tesseract2048/StormLib

HarpyWar commented 9 years ago

@tesseract2048 could you please give a simple example how to sign MPQ using StormLib?

cen1 commented 9 years ago

Judging by the commit, you call SFileAllocateWeakSignature(HANDLE hMpq), reopen archive and then SFileSignArchiveWeak(HANDLE hMpq)

RElesgoe commented 9 years ago

Thank you @tesseract2048 for informing us, I was about to put together some resources to crack the private key(which would probably take months).

tesseract2048 commented 9 years ago

Actually you can get it done within a week in a small cluster (~300 cores) with CADO-NFS.

RElesgoe commented 9 years ago

I don't have that much resources available to use so it would have been months for me

HarpyWar commented 9 years ago

@tesseract2048 can be maps from Starcraft or Warcraft 3 signed using the same way?

And I want to clarify yuor information. What is the key that you provide here, can it be used to sign MPQ, or we still need a cluster to find working key? I'm not familiar with program CADO-NFS, but may be someone have an access to a university super computer to get this job done faster.

RElesgoe commented 9 years ago

@HarpyWar About signing maps, it depends. I'm almost sure that you can sign StarCraft maps with this but I think WarCraft 3 uses the Blizzard Strong Digital Signature RSA private/public key pair for more security. I'm going to guess that WarCraft 3 will accept the Blizzard Weak Digital Signature for the ExtraWork module(or else Blizzard would have to make a second copy of the mpq file and sign it every time they want to turn on ExtraWork). If that is true, just send a dll to disable signature verification checks. @tesseract2048 has already provided the Blizzard Weak Digital Signature private key so we don't need to use a cluster to factor it.

tesseract2048 commented 9 years ago

@HarpyWar Sorry I am not sure about map signing issues. The private key i provided is against what I uncovered in Storm.dll (Diablo II 1.11b), so yes it works with MPQs in Diablo II (including ExtraWork and VersionCheck). Sure you can use it with every Diablo II anti-cheating features (Warden depends, for it is complicated so i didn't invest time on testing it). But Warcraft III and other games are not verified yet (since I no longer work with games). As far as I know, signing War3 maps require a strong signature, which is much harder to factor (or say impossible so far).

I do think @xboi209 's approach is a good one, suppose you can send signed extra work / version check modules to disable map signing verification inside client.

tesseract2048 commented 9 years ago

BTW i think it's a good idea to integrate this feature with PvPGN, for example PvPGN can automatically sign these modules and send it to client, with only raw DLLs are provided manually.

RElesgoe commented 9 years ago

@tesseract2048 That'd be a great feature to have, we just need to make sure that the signing and mpq manipulation is cross compatible between operating systems

HarpyWar commented 9 years ago

Great! I'm not sure that it should be added into PvPGN, because it is not a server's function. It's better to sign MPQ using standalone exe program that can be runned after compile DLL on a developer's machine, automatically (using post-build IDE features) or manually.

Can someone write the console program with two usages depending on file extension: app.exe file.dll key.ppk (pack file into file.mpq and sign with key.ppk) app.exe file.mpq key.ppk (sign mpq with key.ppk)

RElesgoe commented 9 years ago

I've checked that StarCraft and WarCraft 3 maps are signed using Blizzard Strong Digital Signature key. We won't be able to sign custom maps. Also, we don't need .ppk files because the Blizzard Weak Digital Signature implenentation is very specific and that implementation only has this one public/private key pair so it's fine to hardcode it.

RElesgoe commented 9 years ago

@tesseract2048 Is it normal for the (listfile) to be deleted when signing a mpq file?

RElesgoe commented 9 years ago

TODO: -Universal IX86 CheckRevision mpq -Disable RSA verification via ExtraWork mpq(for all games)

tesseract2048 commented 9 years ago

@xboi209 I think (listfile) should be deleted by all means, for client does not require it.

RElesgoe commented 9 years ago

http://pastebin.com/ZRCFZ9s9 http://pastebin.com/mELEWU1Q

RElesgoe commented 9 years ago

https://github.com/HarpyWar/pvpgn/blob/master/src/bnetd/handle_bnet.cpp#L5393 The if statement on line 5393 should not be satisfied

HarpyWar commented 9 years ago

@xboi209 It works fine with Warcraft 3 - data from DLL is correctly returned to a server! But I still getting error with a crash in Starcraft and also in Diablo 2 on Windows 8.1 / Windows 7 (with or withour admin rights). The client's crash occurred when calling DLL ExtraWork function, before sending data to a server.

I just compiled your ExtraWork DLL template and sign it with MPQSigner, then replace the result MPQ file in my server files directory.

2014-10-28 11 48 46 2014-10-28 13 08 03

IX86ExtraWork.dll IX86ExtraWork.mpq

RElesgoe commented 9 years ago

That's strange, I recompiled the code and I got the same error which didn't happen before. Even more strange is that it only works on WarCraft 3.

HarpyWar commented 9 years ago

Any news how to suppress that error?

RElesgoe commented 9 years ago

No, I don't know the cause of the error but I tried removing all the unnecessary code in the function and the client still crashes, so knowing the return value of LoadLibrary should help. We'll need someone to hook the LoadLibrary function to tell us the return value before the client crashes.

tesseract2048 commented 9 years ago

Is that relevant to differences between versions of battle.net client library?

HarpyWar commented 9 years ago

@tesseract2048 the same error occured in Starcraft and Diablo 2 with official DLL from Battle.net, that I found in the internet (link in the first message of the topic). But I can't find original MPQ - only DLL, then it was signed with your library using MPQSigner.

tesseract2048 commented 9 years ago

ExtraWork.cpp

#include <Windows.h>

 __declspec(dllexport) BOOL __fastcall ExtraWork(void *) {
     MessageBoxA(NULL, "it worked", NULL, MB_OK);
     return FALSE;
}

ExtraWork.def

LIBRARY
    ExtraWork

EXPORTS
    ExtraWork

Code above worked for me, to be more specific:

RElesgoe commented 9 years ago

So __declspec(dllexport) was missing from my code, everything is good now.

cen1 commented 9 years ago

Here is a wild idea: can this packet be pushed in the connecting to server stage and make W3 patch itself instead of using w3lh loader?

RElesgoe commented 9 years ago

That might actually be possible. Client will start the logon sequence using SID_AUTHINFO and instead of immediately replying back to that packet, we could try sending ExtraWork to disable server signature verification before replying.

cen1 commented 9 years ago

If someone has time, try to push AlertBox before the logon sequence and see what happens.

RElesgoe commented 9 years ago

For what purpose?

cen1 commented 9 years ago

I guess to see if the game accepts packets out of the blue like this.

cen1 commented 9 years ago

I have added conn_client_requiredwork(c, "IX86ExtraWork.mpq"); in handle_init.cpp line 74 which should be asap after successful connection, placed the above provided IX86ExtraWork.mpq to ./var/files but nothing happened. Am I doing something wrong?

RElesgoe commented 9 years ago

I don't think that's an acceptable place to put it(for clean code). I would suggest placing it in handle_bnet.cpp at line 568. This is still bad code because ideally we should confirm that the client completely downloaded the file before the server moves on with the connection process.

Check your bncache.dat file to see if your client downloaded IX86ExtraWork.mpq.

cen1 commented 9 years ago

This is just for testing purpose so position is far from final. I'll check it out.

cen1 commented 9 years ago

Ok, I tried to put it where you recommended but EXTRAWORK is never sent from the client. Then I tried to put it on channel join just for a sanity check and it worked:

Apr 19 10:20:22 [info ] pvpgn::bnetd::_client_fileinforeq: [600] file requested: "IX86ExtraWork.mpq" - type = 0xa0000006
Apr 19 10:20:22 [debug] pvpgn::bnetd::_client_extrawork: [600] Received EXTRAWORK packet with GameType: 2 and Length: 29 (IX86ExtraWork v1.0 by xboi209)

It seems that client does not react to REQUIREWORK in early stage but more testing is probably needed.

RElesgoe commented 8 years ago

ExtraWork has matured and has been placed under the PvPGN organization.