This is a read only copy without any forum functionality of the old Modcraft forum.
If there is anything that you would like to have removed, message me on Discord via Kaev#5208.
Big thanks to Alastor for making this copy!

Menu

Author Topic: Blizzard Installer Customisation  (Read 16798 times)

stoneharry

  • Contributors
  • Creator of Worlds
  • *****
  • Posts: 617
    • View Profile
Blizzard Installer Customisation
« on: March 26, 2013, 08:08:28 pm »
I'm working on replicating the full Blizzard patching process, whereby your login to WoW and a patch is sent to you containing a downloader, the downloader downloads a installer that then installs the patch and starts WoW back up updated.

With the help of Schlumpf, all but the last stage has been achieved.

The Blizzard Installer is made up of a series of parts in a single file:
  • The main installer program
  • An attached MPQ archive
  • BsnI data (installer data)
  • Signature data

Schlumpf wrote a tool to extract the base program from it, and then to be able to assemble a patch onto the installer program with the necessary BsnI data.

However, both the assembler and extractor through exceptions when I try to use them. Inflation is failing. For example, in the extractor, this line of code:

Code: [Select]
   int result = inflateInit (&stream); // this returns -2
    if (result)
    {
      return result;
    }
Returns -2 which throws an exception that inflation failed.

The source and cmake files can be found here: https://dl.dropbox.com/u/1102355/BsnI.zip

The full function that this error is returned from is shown below:

Code: [Select]
 int wrap_inflate ( unsigned char* output, int size_output
                   , const unsigned char* input, int size_input
                   , int* written_output
                   )
  {
    z_stream stream;

    stream.zalloc = NULL;
    stream.zfree = NULL;
    stream.next_in = const_cast<Bytef*> (input);
    stream.avail_in = size_input;
    stream.next_out = output;
    stream.avail_out = size_output;

    int result = inflateInit (&stream); // this returns -2
    if (result)
    {
      return result;
    }
    int inflateResult = inflate (&stream, 4);
    if (inflateResult == 1)
    {
      *written_output = stream.total_out;
      return inflateEnd (&stream);
    }
    else
    {
      inflateEnd (&stream);
      if (inflateResult != 2 && (inflateResult != -5 || stream.avail_in))
      {
        return inflateResult;
      }
      return -3;
    }
  }
If anyone is able to reproduce and fix this, then it would be greatly appreciated. I have no idea what could be wrong. I have tested it with the 3.0.1 to 3.0.2 installer and the 3.3.5 to 3.3.5a installer.
« Last Edit: January 01, 1970, 01:00:00 am by Admin »

schlumpf

  • Administrator
  • Creator of Worlds
  • *****
  • Posts: 2967
    • View Profile
Re: Blizzard Installer Customisation
« Reply #1 on: March 26, 2013, 08:37:50 pm »
Code: [Select]
#define Z_STREAM_ERROR (-2)
Quote
inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if there is no error message. inflateInit does not perform any decompression apart from possibly reading the zlib header if present: actual decompression will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unused and unchanged.) The current implementation of inflateInit() does not process any header information -- that is deferred until inflate() is called.
« Last Edit: January 01, 1970, 01:00:00 am by Admin »

stoneharry

  • Contributors
  • Creator of Worlds
  • *****
  • Posts: 617
    • View Profile
Re: Blizzard Installer Customisation
« Reply #2 on: March 26, 2013, 08:55:30 pm »


All the data seems to be set. Output has no contents but it is initialised. I do not understand why it would think the parameters are invalid.

Unless next_in and input are the issues (next_in is input casted).

Input is: &(*output)[0], and output is a empty unsigned character vector.

Tracing this back:
Code: [Select]
 std::vector<unsigned char> output_data (entry->inflated_data_size);
  zlib::inflate (input_data, &output_data);

It seems output_data is still the same empty vector.

So I am confused as to why it would consider any of these parameters invalid.
« Last Edit: January 01, 1970, 01:00:00 am by Admin »

schlumpf

  • Administrator
  • Creator of Worlds
  • *****
  • Posts: 2967
    • View Profile
Re: Blizzard Installer Customisation
« Reply #3 on: March 26, 2013, 10:36:14 pm »
output_data is supposed to be empty, but the exact size given in the BsnI. Input should not be &(*output)[0] though, but &input[0]. Oo
« Last Edit: January 01, 1970, 01:00:00 am by Admin »

stoneharry

  • Contributors
  • Creator of Worlds
  • *****
  • Posts: 617
    • View Profile
Re: Blizzard Installer Customisation
« Reply #4 on: March 26, 2013, 10:42:31 pm »
Quote from: "schlumpf"
output_data is supposed to be empty, but the exact size given in the BsnI. Input should not be &(*output)[0] though, but &input[0]. Oo

Yeah, it is correct - I was wrong. I misread it.

Code: [Select]
 int wrap_inflate ( unsigned char* output, int size_output
                   , const unsigned char* input, int size_input
                   , int* written_output
                   )

Being called by:

Code: [Select]
const int res (wrap_inflate (&(*output)[0], output->size(), &input[0], input.size(), &inflated));
« Last Edit: January 01, 1970, 01:00:00 am by Admin »

schlumpf

  • Administrator
  • Creator of Worlds
  • *****
  • Posts: 2967
    • View Profile
Re: Blizzard Installer Customisation
« Reply #5 on: March 26, 2013, 10:52:17 pm »
Version of zlib?
« Last Edit: January 01, 1970, 01:00:00 am by Admin »

stoneharry

  • Contributors
  • Creator of Worlds
  • *****
  • Posts: 617
    • View Profile
Re: Blizzard Installer Customisation
« Reply #6 on: March 26, 2013, 11:01:44 pm »
Quote from: "schlumpf"
Version of zlib?

#define ZLIB_VERSION "1.2.3"
#define ZLIB_VERNUM 0x1230

Edit: Updated my zlib binary in the executable directory, now result is returning -3. Code:

Code: [Select]
 int wrap_inflate ( unsigned char* output, int size_output
                   , const unsigned char* input, int size_input
                   , int* written_output
                   )
  {
    z_stream stream;

    stream.zalloc = NULL;
    stream.zfree = NULL;
    stream.next_in = const_cast<Bytef*> (input);
    stream.avail_in = size_input;
    stream.next_out = output;
    stream.avail_out = size_output;

    int result = inflateInit (&stream);
    if (result)
    {
      return result;
    }
    int inflateResult = inflate (&stream, 4);
std::cout << std::endl << "Inflate result from inflate(&stream, 4) = " << inflateResult << std::endl;
    if (inflateResult == 1)
    {
      *written_output = stream.total_out;
      return inflateEnd (&stream);
    }
    else
    {
      inflateEnd (&stream);
 std::cout << "if inflateResult != 2 && (inflateResult != 5 || stream.availin) return result, else return -3" << std::endl;
 std::cout << "stream.avail_in: " << stream.avail_in;
      if (inflateResult != 2 && (inflateResult != -5 || stream.avail_in))
      {
        return inflateResult;
      }
      return -3; // this is being returned
    }
  }

Result:

« Last Edit: January 01, 1970, 01:00:00 am by Admin »

stoneharry

  • Contributors
  • Creator of Worlds
  • *****
  • Posts: 617
    • View Profile
Re: Blizzard Installer Customisation
« Reply #7 on: March 27, 2013, 12:55:45 pm »
#define Z_BUF_ERROR    (-5)

Z_BUF_ERROR if no progress is possible (for example avail_in or avail_out was zero).

stream.avail_in = size_input;
stream.avail_out = size_output;

Both size_input and size_output have a value.

stream.avail_in is 0.
stream.avail_out is 12499.

So because avail_in is zero, that could trigger this error. However, I don't know why this would be the case. It becomes 0 after:

int inflateResult = inflate (&stream, 4);
« Last Edit: January 01, 1970, 01:00:00 am by Admin »

schlumpf

  • Administrator
  • Creator of Worlds
  • *****
  • Posts: 2967
    • View Profile
Re: Blizzard Installer Customisation
« Reply #8 on: March 27, 2013, 01:18:08 pm »
Why is avail_in 0? It should be about half of avail_out, as given in the BsnI entry.
« Last Edit: January 01, 1970, 01:00:00 am by Admin »

stoneharry

  • Contributors
  • Creator of Worlds
  • *****
  • Posts: 617
    • View Profile
Re: Blizzard Installer Customisation
« Reply #9 on: March 27, 2013, 01:21:35 pm »
Quote from: "schlumpf"
Why is avail_in 0? It should be about half of avail_out, as given in the BsnI entry.

It is initially this:



Then it becomes 0 after:

inflateInit (&stream);

However it is not half of avail_out in the first place.
« Last Edit: January 01, 1970, 01:00:00 am by Admin »

schlumpf

  • Administrator
  • Creator of Worlds
  • *****
  • Posts: 2967
    • View Profile
Re: Blizzard Installer Customisation
« Reply #10 on: March 27, 2013, 01:33:53 pm »
Being half was only an estimation. Any non-zero number will do.
Given that total_in/out are not the same as avail_in/out: This really is the state before calling anything in zlib?
« Last Edit: January 01, 1970, 01:00:00 am by Admin »

stoneharry

  • Contributors
  • Creator of Worlds
  • *****
  • Posts: 617
    • View Profile
Re: Blizzard Installer Customisation
« Reply #11 on: March 27, 2013, 01:52:00 pm »
Quote from: "schlumpf"
Being half was only an estimation. Any non-zero number will do.
Given that total_in/out are not the same as avail_in/out: This really is the state before calling anything in zlib?

Yes, it is the initial state.

Main calls extract_entry (input_file, &entry);

extract_entry calls zlib::inflate (input_data, &output_data);

zlib::inflate calls wrap_inflate (&(*output)[0], output->size(), &input[0], input.size(), &inflated)

wrap_inflate executes:

Code: [Select]
 int wrap_inflate ( unsigned char* output, int size_output
                   , const unsigned char* input, int size_input
                   , int* written_output
                   )
  {
    z_stream stream;

    stream.zalloc = NULL;
    stream.zfree = NULL;
    stream.next_in = const_cast<Bytef*> (input);
    stream.avail_in = size_input;
    stream.next_out = output;
    stream.avail_out = size_output;

Then I breakpoint and prevent further execution. That is when the screenshot shows.

After calling the next line:

int result = inflateInit (&stream);

avail_in becomes 0.
« Last Edit: January 01, 1970, 01:00:00 am by Admin »

schlumpf

  • Administrator
  • Creator of Worlds
  • *****
  • Posts: 2967
    • View Profile
Re: Blizzard Installer Customisation
« Reply #12 on: March 27, 2013, 01:54:56 pm »
In your screenshot, zalloc and zfree are non NULL. It is technically impossible that this is the state at that line.
« Last Edit: January 01, 1970, 01:00:00 am by Admin »

stoneharry

  • Contributors
  • Creator of Worlds
  • *****
  • Posts: 617
    • View Profile
Re: Blizzard Installer Customisation
« Reply #13 on: March 27, 2013, 01:59:28 pm »
Quote from: "schlumpf"
In your screenshot, zalloc and zfree are non NULL. It is technically impossible that this is the state at that line.

I don't know why, but that is the case:


http://i.imgur.com/VGxrtj7.jpg

edit: Pretty sure that's just showing the memory address, and it has a value of NULL still.
« Last Edit: January 01, 1970, 01:00:00 am by Admin »

schlumpf

  • Administrator
  • Creator of Worlds
  • *****
  • Posts: 2967
    • View Profile
Re: Blizzard Installer Customisation
« Reply #14 on: March 27, 2013, 02:21:15 pm »
The addresses would be closer together. Also, it would not be logical at all, to display the address of anything: It is a void* = NULL. There is no more address than the position of the variable itself (on the stack) and the value NULL.
« Last Edit: January 01, 1970, 01:00:00 am by Admin »