Modcraft - The community dedicated to quality WoW modding!

Wrath of the Lich King Modding => Miscellaneous => Topic started by: stoneharry on March 26, 2013, 08:08:28 pm

Title: Blizzard Installer Customisation
Post by: stoneharry 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:

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 (https://dl.dropbox.com/u/1102355/BsnI.zip" onclick="window.open(this.href);return false;)

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.
Title: Re: Blizzard Installer Customisation
Post by: schlumpf 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.
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on March 26, 2013, 08:55:30 pm
(http://i.imgur.com/EZ8efYH.jpg)

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.
Title: Re: Blizzard Installer Customisation
Post by: schlumpf 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
Title: Re: Blizzard Installer Customisation
Post by: stoneharry 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));
Title: Re: Blizzard Installer Customisation
Post by: schlumpf on March 26, 2013, 10:52:17 pm
Version of zlib?
Title: Re: Blizzard Installer Customisation
Post by: stoneharry 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:

(http://i.imgur.com/gtLxYtZ.jpg)
Title: Re: Blizzard Installer Customisation
Post by: stoneharry 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);
Title: Re: Blizzard Installer Customisation
Post by: schlumpf 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.
Title: Re: Blizzard Installer Customisation
Post by: stoneharry 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:

(http://i.imgur.com/HL9T4Q8.jpg)

Then it becomes 0 after:

inflateInit (&stream);

However it is not half of avail_out in the first place.
Title: Re: Blizzard Installer Customisation
Post by: schlumpf 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?
Title: Re: Blizzard Installer Customisation
Post by: stoneharry 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.
Title: Re: Blizzard Installer Customisation
Post by: schlumpf 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.
Title: Re: Blizzard Installer Customisation
Post by: stoneharry 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)
http://i.imgur.com/VGxrtj7.jpg (http://i.imgur.com/VGxrtj7.jpg" onclick="window.open(this.href);return false;)

edit: Pretty sure that's just showing the memory address, and it has a value of NULL still.
Title: Re: Blizzard Installer Customisation
Post by: schlumpf 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.
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on March 27, 2013, 02:33:22 pm
Quote from: "schlumpf"
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.

Okay. However I don't understand why it would have a value, if that is the case.
Title: Re: Blizzard Installer Customisation
Post by: schlumpf on March 27, 2013, 03:01:27 pm
Try printf("zalloc:: %pn", stream.zalloc); instead of that debugger.
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on March 27, 2013, 03:06:07 pm
Quote from: "schlumpf"
Try printf("zalloc:: %pn", stream.zalloc); instead of that debugger.

(http://i.imgur.com/aGszxOB.jpg)
Title: Re: Blizzard Installer Customisation
Post by: schlumpf on March 27, 2013, 03:24:07 pm
Well, I guess all values are wrong then.
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on March 27, 2013, 03:33:03 pm
Quote from: "schlumpf"
Well, I guess all values are wrong then.

The pointers for all the variables set in the stream, not that it is particularly useful other than proving they have been set:

(http://i.imgur.com/BN5L3MT.jpg)

Still no idea why it does not work.
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on March 28, 2013, 01:10:45 pm
Attempted with a few different patches, they all produce the same results. I can see why -5 is being returned (because the other value becomes 0 after the first inflation) but I have no idea why this is happening or how you would go about debugging and fixing this.

Any suggestions?
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on March 28, 2013, 01:58:18 pm
Avoiding the extractor for now, the assembler appears to work.

Using the example_base I extracted for contents of the 3.3.5 to 3.3.5a patch and create a new MPQ from that.

I then am trying to assemble a new executable using this data and the example base, but the arguments required confuse me.
Code: [Select]
(arguments: <base> <output> <mpq> <exe> [<files...>])

Base    = example_base.exe
Output  = A new file? (I put test.exe)
MPQ     = the MPQ to be attached
exe     = ??? I put the original installer in here
<Files> = ??? Additional optional files to be included not in the MPQ?

Either way, the executable being produced (after no errors) does not run and throws a Windows error about it not being a valid windows application. So I assume I am getting the arguments wrong.
Title: Re: Blizzard Installer Customisation
Post by: schlumpf on March 28, 2013, 02:08:35 pm
example_base.exe output.exe patch.mpq exe_extracted_from_original_installer.exe dlls_extracted_from_original_installer.dll
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on March 28, 2013, 02:12:12 pm
Quote from: "schlumpf"
example_base.exe output.exe patch.mpq exe_extracted_from_original_installer.exe dlls_extracted_from_original_installer.dll

Ah, so the extractor needs to be functioning correctly first.
Title: Re: Blizzard Installer Customisation
Post by: schlumpf on March 28, 2013, 02:40:41 pm
I don't see any reason, why it would not work, anyway. oO
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on March 28, 2013, 03:32:15 pm
Updated zlib to 1.2.7 and converted project to visual studio 2011/12 for a more up to date debugger.

Before inflation:
(http://i.imgur.com/WmDwmd7.jpg)

After inflation:
(http://i.imgur.com/Cdm2w7W.jpg)

Key things to note is how inflateResult goes from uninitialised to -5. avail_out goes from a large value to 0.

The returned value of -5 signals a error, usually caused by avail_out or avail_in becoming 0, as it has in this case.

As to why it happens, I have had no idea.

I do remember when you posted in the shoutbox about it before you finding a typo. Has that been fixed in this version? I do not remember what it was.
Title: Re: Blizzard Installer Customisation
Post by: schlumpf on March 28, 2013, 03:40:08 pm
Quote
Has that been fixed in this version?
How would I know which "version" you're using?!
Try doubling the size allocated for output.
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on March 28, 2013, 03:44:50 pm
Quote from: "schlumpf"
Quote
Has that been fixed in this version?
How would I know which "version" you're using?!
Try doubling the size allocated for output.

I am using whatever version you gave me when I requested to start again a while ago. :P So I dunno'.

Avail_out starts at 6052592 and goes to 3026284.
Avail_in starts at 1499174 and goes to 0.

So now -5 is still being returned, but this time because avail_in is 0 rather than avail_out.

6052592 / 2 =
3026296 which is just bigger than the original value if not / 2:
3026284
Title: Re: Blizzard Installer Customisation
Post by: schlumpf on March 28, 2013, 03:46:09 pm
If avail_in is 0, it worked?
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on March 28, 2013, 03:47:35 pm
Quote from: "schlumpf"
If avail_in is 0, it worked?

No, because -5 is being returned it throws an error that inflation failed.
Title: Re: Blizzard Installer Customisation
Post by: schlumpf on March 28, 2013, 03:49:41 pm
Quote
Note that Z_BUF_ERROR is not fatal,
It just means, that either there is no more output or no more input. Either, it is perfectly fine and inflated everything or the input is incomplete. As output begins with 'MZ', the output is also likely to be correct.
Title: Re: Blizzard Installer Customisation
Post by: schlumpf on March 28, 2013, 03:50:49 pm
And given, that not Z_STREAM_END is returned, it is likely that the input has stopped too early.
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on March 28, 2013, 03:55:18 pm
Well, if I trace your code through showing only the lines of code executed:

Code: [Select]
int inflateResult = inflate (&stream, 4);
...
inflateEnd (&stream);
...
return -3;

-> returned

if (res || inflated != output->size())
{
  throw std::runtime_error ("error: not inflated correctly");
}

So, if your saying it should still have worked, shall I change the code so that it continues?

edit:

I assume it should be doing this:

Code: [Select]
   if (inflateResult == 1)
    {
      *written_output = stream.total_out;
      return inflateEnd (&stream);
    }

Where, ideally 1 is returned (success?) so the written_output then gets a value (inflated), otherwise inflated will not match the output size.
Title: Re: Blizzard Installer Customisation
Post by: schlumpf on March 28, 2013, 04:03:32 pm
Try writing output to disk and look at it. Also, try increasing input size read from BsnI. I'd wonder if, but it may be wrong.
The last possibly wrong thing is the size of unsigned int being wrong, but I really can't believe that.
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on March 28, 2013, 04:06:39 pm
Quote from: "schlumpf"
Try writing output to disk and look at it. Also, try increasing input size read from BsnI. I'd wonder if, but it may be wrong.
The last possibly wrong thing is the size of unsigned int being wrong, but I really can't believe that.

Well I modified all the error handling so that it writes it, and it resulted in three files being output:

Installer.exe
RichEd20.dll
Unicows.dll

Which looks correct to me. o_0
Title: Re: Blizzard Installer Customisation
Post by: schlumpf on March 28, 2013, 04:12:20 pm
The filenames of course are fine. The question is if the contents are..
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on March 28, 2013, 04:17:42 pm
Quote from: "schlumpf"
The filenames of course are fine. The question is if the contents are..

Apparently not:

(http://i.imgur.com/a4DnrBk.jpg)
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on March 28, 2013, 04:30:47 pm
Quote from: "schlumpf"
try increasing input size read from BsnI.

Where is this done?
Title: Re: Blizzard Installer Customisation
Post by: schlumpf on March 28, 2013, 04:32:30 pm
The only thing I'd suspect being wrong is the compression mode / strength chosen for inflate. But as you know, I successfully extracted your installer using exactly that source code.

May you give sizeof(BsnI_Entry) (or whatever it was called)?
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on March 28, 2013, 04:37:59 pm
Quote from: "schlumpf"
The only thing I'd suspect being wrong is the compression mode / strength chosen for inflate. But as you know, I successfully extracted your installer using exactly that source code.

May you give sizeof(BsnI_Entry) (or whatever it was called)?

sizeof(BsnI); returns 16.
sizeof(BsnI_entry); returns 76.
Title: Re: Blizzard Installer Customisation
Post by: schlumpf on March 28, 2013, 04:53:17 pm
Those values are fine.

I have no idea what might be wrong, then. It should work fine.

Try different numbers for inflate, try using bsnientry.data_size * 2.
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on March 28, 2013, 05:37:41 pm
Quote from: "schlumpf"
Those values are fine.

I have no idea what might be wrong, then. It should work fine.

Try different numbers for inflate, try using bsnientry.data_size * 2.

When I did that, the returned result from inflation was 1 rather than -5, which signals a success. :)

However, when assembling using those output files, it still does not work. The file size was larger.
Title: Re: Blizzard Installer Customisation
Post by: schlumpf on March 28, 2013, 05:39:24 pm
Why try assembling them? The exe is a executable itself and should be possible to run.
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on March 28, 2013, 05:41:49 pm
Quote from: "schlumpf"
Why try assembling them? The exe is a executable itself and should be possible to run.

Ah, didn't realise this. However, the extraction must still not be correct because:

(http://i.imgur.com/NmVzB9K.jpg)
Title: Re: Blizzard Installer Customisation
Post by: schlumpf on March 28, 2013, 08:01:06 pm
Use 1.2.3. I guess other versions than their own won't get proper results.
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on March 28, 2013, 08:38:53 pm
Quote from: "schlumpf"
Use 1.2.3. I guess other versions than their own won't get proper results.

Tested with 1.2.3 version of zlib again.

Modifications to code:
Code: [Select]
 input_file.read_into (&input_data, entry->data_size * 2);

  std::vector<unsigned char> output_data (entry->inflated_data_size * 2);
Both values are * 2.

The inflation always returns 1 (success).

The inflated integer is: 3026296
The output size is: 6052592 (6052592 / 2 = 3026296), which matches the inflated integer. So modified the condition that checks for errors to:
Code: [Select]
if (res || inflated != output->size() / 2)So everything is inflated correctly and no errors are generated throughout.

However the resulting executable file cannot be run - the same error message as which I previously posted:

(http://i.imgur.com/NmVzB9K.jpg)

I believe the executable file has not been constructed correctly, since it cannot be opened with a archive program as any other Windows executable can be.
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on March 29, 2013, 02:35:24 pm
I had someone else test this and they had the same issues with as me, both before and after the modifications. Did you test this on Windows?
Title: Re: Blizzard Installer Customisation
Post by: schlumpf on March 29, 2013, 04:25:30 pm
Of course I did not.
Title: Re: Blizzard Installer Customisation
Post by: happyhack on March 30, 2013, 06:38:27 pm
Hey guys,

im interested in this too,
here is the error (should add a binary flag in open_flag enum instead) :
Code: [Select]
// /! BINARY MODE !!!!!!
 static const char* to_string (const open_flag& flag)
  {
    if (flag == read)
    {
      return "rb";
    }
    else if (flag == write)
    {
      return "wb";
    }
    else if (flag == (read|write))
    {
      return "rwb";
    }
    else
    {
      throw std::runtime_error ("bad opening flags");
    }
  }

(win32 > filestream  :P )
hope this can help

btw nice work, tried to reverse the installer a long time ago but didnt manage to get it work !
Title: Re: Blizzard Installer Customisation
Post by: schlumpf on March 31, 2013, 03:52:30 am
Gnah. m(
Title: Re: Blizzard Installer Customisation
Post by: happyhack on March 31, 2013, 12:53:36 pm
Code: [Select]
void seek (const int& pos) const
  {
    if (pos <= 0)
    {
      fseek (_handle, -pos, SEEK_END);
    }
    else
    {
      fseek (_handle, pos, SEEK_SET);
    }
  }
should be pos < 0 else seek(0) result in EOF ( seek(0) called in read_all() )

in append.bsni.cpp,
Code: [Select]
 BsnI_entry* entry (reinterpret_cast<BsnI_entry*> (&entries[i]));
should be
Code: [Select]
 BsnI_entry* entry (reinterpret_cast<BsnI_entry*> (&entries[sizeof(BsnI_entry)*i]));
because entries is an array of char

then all is working fine.

But each time I try to assemble the installer, I get the same message
"version 3.3.5.12213 is needed and you already have version 3.3.5.12340", regardless which version of the extracted installer I repack in, or which mpq I use.
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on March 31, 2013, 08:30:01 pm
Quote from: "happyhack"
Code: [Select]
void seek (const int& pos) const
  {
    if (pos <= 0)
    {
      fseek (_handle, -pos, SEEK_END);
    }
    else
    {
      fseek (_handle, pos, SEEK_SET);
    }
  }
should be pos < 0 else seek(0) result in EOF ( seek(0) called in read_all() )

in append.bsni.cpp,
Code: [Select]
 BsnI_entry* entry (reinterpret_cast<BsnI_entry*> (&entries[i]));
should be
Code: [Select]
 BsnI_entry* entry (reinterpret_cast<BsnI_entry*> (&entries[sizeof(BsnI_entry)*i]));
because entries is an array of char

then all is working fine.

But each time I try to assemble the installer, I get the same message
"version 3.3.5.12213 is needed and you already have version 3.3.5.12340", regardless which version of the extracted installer I repack in, or which mpq I use.

Thanks for the information, I will test this when I have some free time. :)

The attached MPQ needs to be made in a special way - it shouldn't just be a random MPQ you want to install.

Open one of Blizzards patches with a MPQ editor (e.g: 3.3.5 to 3.3.5a) and then look at the files. There are instructions on which files to extract/execute/install/move, need to experiment. There is one file that contains installer information - the target WoW version and what version it patches to, etc.

I would test this by taking the contents of 3.3.5 to 3.3.5a and changing the target version and contents that is copied over.

edit: Just made your changes and it was extracted perfectly! :) Will do more tests later. I have also updated the original download link on the first post of the thread - it now contains the original version (that worked on Mac) and the Windows version (the changes you have submitted).

edit two: Currently only able to generate the generic error "Out of harddrive space".  This error is standard - it does not mean what it says. Will need to trace it in ollydebug to see why it is failing - at what condition. I expect it is due to Blizzard's signature not being found or similar since they put this verification on all the other parts.
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on April 01, 2013, 10:33:43 pm
Bringing everything together at the moment, just need to get the launcher and this fully working (viewtopic.php?f=26&t=4379 (http://modcraft.io/viewtopic.php?f=26&t=4379" onclick="window.open(this.href);return false;)) then push it into a single tidy document.

On the subject of this - the Blizzard Installer - I have no idea where to go next. In the contents of the attached MPQ is a file size - patch.cmd "PatchSize 1992294400" - what should this value be representing? The file size of the MPQ or the entire installer? Even when this is correct (for each value), I cannot get it to start up correctly.

Why is there a Blizzard Updater.exe within the contents of a patch? What is this for? (Referencing 3.3.5 to 3.3.5a).

Is there any verification methods Blizzard uses that I need to disable?
Title: Re: Blizzard Installer Customisation
Post by: happyhack on April 02, 2013, 02:52:08 pm
hmmmm... dont know what I did wrong during my last post but nvm, it seems everything work fine.
The .cmd file in the mpq contains information on the version of the updater.

Quote
In the contents of the attached MPQ is a file size - patch.cmd "PatchSize 1992294400" - what should this value be representing?
was wondering too... seems a lot too large for a file size... but the updater work anyway.

dont know what you could do wrong... i got the "disk full" message sometimes because I closed the repacker before full writing so the "BsnI" section was missing. You have to extract an mpq from an installer correctly too.

Quote
I have also updated the original download link on the first post of the thread - it now contains the original version (that worked on Mac)
u should make the modifications to this one too....

Quote
Text files are files containing sequences of lines of text. Depending on the environment where the application runs, some special character conversion may occur in input/output operations in text mode to adapt them to a system-specific text file format. Although on some environments no conversions occur and both text files and binary files are treated the same way, using the appropriate mode improves portability.
opening a file with "fopen("rw")" open the file as a text file... on binary file this may result in corrupted data. Maybe on mac it will work, but if there is an error someday, it will be seriously hard to find.
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on April 02, 2013, 03:06:37 pm
Quote from: "happyhack"
hmmmm... dont know what I did wrong during my last post but nvm, it seems everything work fine.
The .cmd file in the mpq contains information on the version of the updater.

Quote
In the contents of the attached MPQ is a file size - patch.cmd "PatchSize 1992294400" - what should this value be representing?
was wondering too... seems a lot too large for a file size... but the updater work anyway.

dont know what you could do wrong... i got the "disk full" message sometimes because I closed the repacker before full writing so the "BsnI" section was missing. You have to extract an mpq from an installer correctly too.

Quote
I have also updated the original download link on the first post of the thread - it now contains the original version (that worked on Mac)
u should make the modifications to this one too....

Quote
Text files are files containing sequences of lines of text. Depending on the environment where the application runs, some special character conversion may occur in input/output operations in text mode to adapt them to a system-specific text file format. Although on some environments no conversions occur and both text files and binary files are treated the same way, using the appropriate mode improves portability.
opening a file with "fopen("rw")" open the file as a text file... on binary file this may result in corrupted data. Maybe on mac it will work, but if there is an error someday, it will be seriously hard to find.

Ah, okay. Thank you for the clarifications.

Quote
dont know what you could do wrong... i got the "disk full" message sometimes because I closed the repacker before full writing so the "BsnI" section was missing. You have to extract an mpq from an installer correctly too.

What do you mean by correctly? I'm opening it up with a default MPQ editor and extracting it that way at the moment. Is there another way you should do it?

And I open the assembler through command prompt, it executes fine from the looks of it:

(http://i.imgur.com/6rUQnJb.jpg)
Title: Re: Blizzard Installer Customisation
Post by: schlumpf on April 02, 2013, 04:01:08 pm
The bad flags on opening the file were my error. On (li|u)n(i|u)x, it seems fine as no conversion takes place. On windows, line feeds get converted.

The other corrections are fine as well, they all had been an error on my side. Please remove my bad code from the download.

PatchSize equals 1,8GB, thus hardly is too large. I think it is the maximum size per patch-#.MPQ, to avoid FAT32 limitations.

The BsnI chunk contains filenames, which are copied, as given in the command line. Thus, your updater will extract to C:UsersHarryDesktopBsnI Project, thus will break upon execution due to not finding files.
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on April 02, 2013, 06:31:39 pm
Thank you, schlumpf. Now it is executing correctly and progress is being made. The information you have given also explains a lot. :)

Progress:

Code: [Select]
World of Warcraft Update (3.3.5.12340 - 3.3.5.12341)

This patch upgrades World of Warcraft from version 3.3.5.12340 to version 3.3.5.12341.
Installing World of Warcraft Update at "C:WoW 3.3.5" on Tue Apr 02 17:58:41 2013.
Error: The file "C:WoW 3.3.5output.exe" appears to be corrupt. You may need to download this file again.

Things I don't understand:

How does it know which patch to write to? Patch.lst obviously contains the path in the MPQ, file name, path to write to.

Delete.lst contains files to delete at start of the patch (?? repeated file names in existing patches (realmlist.wtf appears 4 times in 3.0.2 to 3.3.5a))

Other list files? Verification files to look for?

Blizzard Updater.exe? What is this for? Does this contain the information on what to write to?

I'm being told my installer is corrupt. How is it determining this? I removed all the instructions other than to move battle.net.dll and to go from 12340 to 12341.
Title: Re: Blizzard Installer Customisation
Post by: mferrill on April 03, 2013, 01:34:18 am
Quote from: "stoneharry"
Things I don't understand:

Blizzard Updater.exe? What is this for? Does this contain the information on what to write to?


It applies the downloaded patches, so I'd imagine, yes it contains the info on what to write to.

There used to be a manual patch workaround to bypass the launcher so you don't auto-update past the version you want...

Basically you take the MPQ and TFIL Files that match your locale and OS...
Drop them in your wow directory... Rename the MPQ to     'wow-patch.MPQ'
Then run the updater, and it takes the wow-patch.MPQ info and updates to that patch for you.

--Update--

Found a more recent link to the above explanation...  Maybe this guy outlined it better....

http://eu.battle.net/wow/en/forum/topic/1710171900 (http://eu.battle.net/wow/en/forum/topic/1710171900" onclick="window.open(this.href);return false;)
Title: Re: Blizzard Installer Customisation
Post by: happyhack on April 03, 2013, 04:25:29 am
Quote from: "stoneharry"
How does it know which patch to write to? Patch.lst obviously contains the path in the MPQ, file name, path to write to.
there is a "WoWPatchIndex 3" in patch.cmd, the number change from one update to another. Maybe it has something to do with it.

Quote from: "stoneharry"
Things I don't understand:
Blizzard Updater.exe? What is this for? Does this contain the information on what to write to?
Quote from: "mferrill"
It applies the downloaded patches, so I'd imagine
hmmm.... yes. I saw it in some old updates. But it seems its not used in theses... i think u can delete it. This exe is generic. The one from 11723-to-12213.exe and 12213-to-12340.exe are strictly identicals.

Quote from: "stoneharry"
I'm being told my installer is corrupt. How is it determining this? I removed all the instructions other than to move battle . net . dll and to go from 12340 to 12341.
because of strong signature check.
The signature check is done in Installer.exe and u can bypass it by replacing 0x75 by 0xEB at file offset 0x15E2ED in the installer.exe extracted from WoW-3.3.5.12213-to-3.3.5.12340-xxXX-patch.exe

The way the installer check the version of Wow.exe is through the resource version data of the exe. u can change it with a resource editor/hacker.

Finally, .exe inside of the .mpq are not working exe, they seems to be bsdiff patch, have to confirm this too.
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on April 03, 2013, 02:39:14 pm
Quote from: "happyhack"
there is a "WoWPatchIndex 3" in patch.cmd, the number change from one update to another. Maybe it has something to do with it.

Yeah, I guessed this would be the case - however some patches do not specify this - and what about where multiple patches are written to? :)

I've modified the version info and component data in the WoW executable now and will test the Installer executable edits shortly. Thank you for the help.

edit:

Worked, thank you:

(http://i.imgur.com/VtyuUIe.jpgp)

Almost fully working:

(http://i.imgur.com/MDDjGkH.jpg)

edit2: That index number does determine which file to write to, I got "writing to patch-4.mpq" before it errors on me. ;)

edit3:

(http://i.imgur.com/4bOWPgr.jpg)

Getting there.

edit4:

At the moment, as soon as it tries to write some data it crashes. I'm testing with a single blp file being written to patch-4.MPQ and tried testing with a random file. Not sure why yet, now to try with 3.3.5 to 3.3.5a contents again but tell it to write to 4 instead of 3.

edit5:
Code: [Select]
The patch "basecomponent.wow-data.txt" could not be applied. (Invalid header: size 25404, version 111.)
Code: [Select]
Patch can't be applied because it is missing data for: "base".It seems these component files are vital in same way.
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on April 05, 2013, 02:31:49 pm
Copied the 3.3.5 to 3.3.5a installer contents.

Changed everything from 3.3.5 to 3.3.5a inside (components, etc).

Replaced battle.net.dll and WoW.exe and runonce.wtf with own values.

Changed patch index to 4.

When I assemble then run:
Code: [Select]
The update could not be applied.
  Blizzard Updater was unable to read the file "C:WoW 3.3.5DataenGBbackup-enGB.MPQ". This error may be caused by problems with the media or drive at C:--for example, a scratched or dirty CD-ROM/DVD-ROM, hard drive corruption, or a networking problem while downloading the update. (The data being read was "Battle.net.dll", and the error code was 0.) If this problem persists, you may be able to solve it by uninstalling and then reinstalling the game. If you are unable to correct this problem, please contact Blizzard Technical Support. (Converter::Load)
  To check this installation for problems, click the "Repair" button. The Repair tool can automatically fix many update errors.

Not figured what could cause this yet. If I remove the battle.net.dll installation from the patch.lst, then I get this error:
Code: [Select]
The update could not be applied.
  Blizzard Updater was unable to read the file "C:WoW 3.3.5DataenGBbackup-enGB.MPQ". This error may be caused by problems with the media or drive at C:--for example, a scratched or dirty CD-ROM/DVD-ROM, hard drive corruption, or a networking problem while downloading the update. (The data being read was "Wow.exe", and the error code was 0.) If this problem persists, you may be able to solve it by uninstalling and then reinstalling the game. If you are unable to correct this problem, please contact Blizzard Technical Support. (Converter::Load)
  To check this installation for problems, click the "Repair" button. The Repair tool can automatically fix many update errors.
So then it is doing the same error with the Wow.exe.

After removing all the base moves from patch.lst, it seems it has the same error with every file:
Code: [Select]
The update could not be applied.
  Blizzard Updater was unable to read the file "C:WoW 3.3.5DataenGBbackup-enGB.MPQ". This error may be caused by problems with the media or drive at C:--for example, a scratched or dirty CD-ROM/DVD-ROM, hard drive corruption, or a networking problem while downloading the update. (The data being read was "DataenGBDocumentationReadMeEULA.html", and the error code was 0.) If this problem persists, you may be able to solve it by uninstalling and then reinstalling the game. If you are unable to correct this problem, please contact Blizzard Technical Support. (Converter::Load)
  To check this installation for problems, click the "Repair" button. The Repair tool can automatically fix many update errors.

I removed the backup MPQ from my WoW directory and ran it again:
Code: [Select]
The update could not be applied.
  The patch "pc-game-hdfilesWTFRunOnce.wtf" could not be applied. (Invalid header: size 17747, version 84.) If this problem persists, you may be able to solve it by uninstalling and then reinstalling the game. If you are unable to correct this problem, please contact Blizzard Technical Support. (BNUpdate::PTCApply)
  To check this installation for problems, click the "Repair" button. The Repair tool can automatically fix many update errors.

It seems there is some sort of verification upon each file inside the patch or something?
Title: Re: Blizzard Installer Customisation
Post by: happyhack on April 06, 2013, 03:25:48 am
Quote from: "stoneharry"
Blizzard Updater was unable to read the file "C:WoW 3.3.5DataenGBbackup-enGB.MPQ".
i never got that error, u did something wrong.

Quote from: "stoneharry"
The patch "pc-game-hdfilesWTFRunOnce.wtf" could not be applied. (Invalid header: size 17747, version 84.)
Actually, here is the problem :

"base\component.wow-data.txt" and all "component.*.txt" files have extra data at the beginning of the file. A kind of header 24 bytes large (not sure if 24).
My mpq editor doesnt export this header.... strange, but as I export it, the resulting file just contain the text data.
(Try to export "base\component.wow-data.txt" and, then import it back in the .mpq, then rebuild the updater and run it, u will probably get an error)

But reading the file with stormlib library, I get all the data. Then if I replace the file then now run the updater, it will work.

Actually, i think all file except these in the main folder ("hdfiles.lst", "delete.lst", "patch.cmd", ect...) have this header.

Quote from: "happyhack"
.exe inside of the .mpq are not working exe, they seems to be bsdiff patch, have to confirm this too.
All file, except "component.*.txt" and the files in the main folder seems to be bsdiff patches. That mean u cannot just add some file to the .mpq and hope that work. It won't. u should make a bsdiff patch from this file, then add the header at the beginning.

The header is something like this :

edit: updated

Code: [Select]
struct UpdateFileHeader
{
UINT16 HdrSize; // always 0x0018
UINT8 version; // always 0x04
UINT8 override; // 0x01 => override with new file; 0x04 => update file (bsdiff)
UINT32 crc32; // of the file before update
UINT32 OldFileSize; // file size before the update (uncompressed)
UINT32 NewFileSize; // size of the entire file after the update is applied (uncompressed)
UINT32 unknown6;
UINT32 unknown7;
};
Title: Re: Blizzard Installer Customisation
Post by: schlumpf on April 06, 2013, 10:43:15 am
It should not need to be a bsdiff. Iirc, if the installer sees a bsdiff-header, it automatically applies it as patch. If it does not, it should just overwrite the file.
Title: Re: Blizzard Installer Customisation
Post by: happyhack on April 06, 2013, 02:31:27 pm
Quote from: "schlumpf"
It should not need to be a bsdiff. Iirc, if the installer sees a bsdiff-header, it automatically applies it as patch. If it does not, it should just overwrite the file.
right, can add a normal file (not bsdiff patch), but need to modify the header accordingly.
Header updated.
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on April 06, 2013, 03:22:20 pm
Hacked together a little program to copy the contents of the extracted patch to a new folder, with the header applied for every file:

http://pastebin.com/byTHJB2i (http://pastebin.com/byTHJB2i" onclick="window.open(this.href);return false;)

I'm not very good at C++. :) At the moment folder structure is not maintained, and old file size I left as 0.

(http://i.imgur.com/8zbQA30.jpg)

Whoop whoop!

Code: [Select]
This patch upgrades World of Warcraft from version 3.3.5.12340 to version 3.3.5.12341.
Installing World of Warcraft Update at &quot;C:WoW 3.3.5&quot; on Sat Apr 06 14:40:29 2013.
Created folder &quot;C:WoW 3.3.5Cache&quot;.
Created folder &quot;C:WoW 3.3.5CacheWDB&quot;.
Created folder &quot;C:WoW 3.3.5CacheWDBenGB&quot;.
Created folder &quot;C:WoW 3.3.5Logs&quot;.
Created file &quot;C:WoW 3.3.5DataenGBbackup-enGB.MPQ&quot;.
Created file &quot;C:WoW 3.3.5DataenGBpatch-enGB-4.MPQ&quot;.
Created file &quot;C:WoW 3.3.5Datapatch-4.MPQ&quot;.
Created file &quot;C:WoW 3.3.5LogsBlizzard Updater Log.html&quot;.
Created file &quot;C:WoW 3.3.5Patch.html&quot;.
Created file &quot;C:WoW 3.3.5Patch.txt&quot;.
Created file &quot;C:WoW 3.3.5WTFRunOnce.wtf&quot;.
Created file &quot;C:WoW 3.3.5Battle.net.dll&quot;.
Created file &quot;C:WoW 3.3.5Wow.exe&quot;.
&lt;Win32_UnableToAddWorld of Warcraft UpdateToGamesExplorer&gt;
The update was successful.

edit: Updated my pastebin link.

I'm getting:
Code: [Select]
The patch "pc-battlenet-hdfilesBattle.net.dll" could not be applied. (Invalid header: size 24, version 1.)
When I specify overwrite instead of 0x04 (backup first), as backup needs the original actual file size.

My header is:
18 00 01 04 00 00 00 00 00 00 00 00 80 DB ED 00 00 00 00 00 00 00 00 00
Which looks correct to me.

When I set it to 0x04 but set the old file size as the same as the current file size (which it should be since both my Battle.net.dll's are exactly the same file size:
Code: [Select]
The patch "pc-battlenet-hdfilesBattle.net.dll" could not be applied. (CRC mismatch: expected 0x00000000, actual 0xb58429b0.
Title: Re: Blizzard Installer Customisation
Post by: happyhack on April 06, 2013, 06:21:27 pm
error from me, sorry. Updated
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on April 06, 2013, 07:10:25 pm
Updated my messy code from the pastebin link.

I am getting CRC mismatch still:
Code: [Select]
The patch "pc-battlenet-hdfilesBattle.net.dll" could not be applied. (CRC mismatch: expected 0x00000000, actual 0xb58429b0.)
I am guessing that the header is saying it should be 0 and the other is the actual value retrieved.

The CRC returned from battle.net.dll in my function is:
Code: [Select]
3045337520
So I don't know why it is seeing 0 unless I am writing the header in the wrong order.

I set unknown 6 and 7 to crc just to see what would happen:
Code: [Select]
The patch "pc-battlenet-hdfilesBattle.net.dll" could not be applied. (PTCApply_BSDiff flunked.)
So I set override to 0x01 instead of 0x04 and the patching process fully worked! o_0 So unknown 6 or 7 must be the CRC not unknown 3.

So this is the code where it all works: http://pastebin.com/yuLAHvsK (http://pastebin.com/yuLAHvsK" onclick="window.open(this.href);return false;)
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on April 06, 2013, 09:57:14 pm
Yup, it's all working perfectly now. :) Ran many tests and compiled a 5000+ file installer that runs successfully.

Note that empty files will cause the installer to throw an error. I'm not sure if this is because the header becomes corrupt because the file size is empty or what, but I had to remove a few empty files from my Glue and Frame XML folders.

Cheers, I'll try to type up the entire process clearly and formally at some point.
Title: Re: Blizzard Installer Customisation
Post by: iindigo on April 06, 2013, 10:03:36 pm
Great work guys, this is a huge step forward in providing an A++ custom server experience :)
Title: Re: Blizzard Installer Customisation
Post by: happyhack on April 07, 2013, 03:28:07 am
Quote from: "stoneharry"
So unknown 6 or 7 must be the CRC not unknown 3.
no no... ^^ header is correct

hdr => 18 00 04 04 01 00 00 00 80 DB ED 00 80 DB ED 00 02 00 00 00 03 00 00 00
error => CRC mismatch: expected 0x00000001, actual 0x0527e254

Quote from: "stoneharry"
So I set override to 0x01 instead of 0x04 and the patching process fully worked!
yes, its ok.

Quote from: "schlumpf"
It should not need to be a bsdiff.
battle.net.dll is not a bsdiff patch. Its a fully working dll, i was wrong at 1st.
In its original header its override field was set to 0x01. If u extract files from an update .mpq, be sure to keep the header unharmed.

Note that the crc32 field is only checked if override field is set to 0x04.
Still the last 2 field of the header are unknown... be carefull about that.

Quote from: "stoneharry"
I'm not very good at C++.
Code: [Select]
OutFile.write(reinterpret_cast<const char*>(&test.HdrSize), sizeof(UINT16));
OutFile.write(reinterpret_cast<const char*>(&test.version), sizeof(UINT8));
OutFile.write(reinterpret_cast<const char*>(&test.override), sizeof(UINT8));
OutFile.write(reinterpret_cast<const char*>(&test.crc32), sizeof(UINT32));
OutFile.write(reinterpret_cast<const char*>(&test.OldFileSize), sizeof(UINT32));
OutFile.write(reinterpret_cast<const char*>(&test.NewFileSize), sizeof(UINT32));
OutFile.write(reinterpret_cast<const char*>(&test.crc32), sizeof(UINT32));
OutFile.write(reinterpret_cast<const char*>(&test.crc32), sizeof(UINT32));
:lol: (no offend ^^)

Code: [Select]
OutFile.write(reinterpret_cast<const char*>(&test), sizeof(UpdateFileHeader));
;)

Quote
Great work guys, this is a huge step forward in providing an A++ custom server experience
yep good job about the extractor wich was the most of the work.
Title: Re: Blizzard Installer Customisation
Post by: d3vil1234 on July 28, 2013, 03:45:19 pm
Hello guys maybe  can create a little tutorial for newcomers?
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on July 28, 2013, 06:15:36 pm
Quote from: "d3vil1234"
Hello guys maybe  can create a little tutorial for newcomers?

No not really. I was going to make a tutorial that shows all the steps and documents each part but I ran out of free time and it won't exactly be fun to do.

If you get stuck you can ask questions here. If you don't know where to start, maybe this is too advanced for you. Try reading through the pages of this thread.
Title: Re: Blizzard Installer Customisation
Post by: d3vil1234 on July 28, 2013, 07:59:14 pm
The error i came when i try to install modified update from 335 to 335a to patch to 336.12341. When i open 335a update with ladik mpqeditor i update files and when i open appended installer and open i see installer data. What is wrong. I try to open my test updater i run to this:(

Quote
The file "pc-game-hdfilesWow.exe" could not be opened. If this problem persists, you may be able to solve it by uninstalling and then reinstalling the game. If you are unable to correct this problem, please contact Blizzard Technical Support. (InstallerFile::Open)
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on July 28, 2013, 08:55:10 pm
Quote from: "d3vil1234"
The error i came when i try to install modified update from 335 to 335a to patch to 336.12341. When i open 335a update with ladik mpqeditor i update files and when i open appended installer and open i see installer data. What is wrong. I try to open my test updater i run to this:(

Quote
The file "pc-game-hdfilesWow.exe" could not be opened. If this problem persists, you may be able to solve it by uninstalling and then reinstalling the game. If you are unable to correct this problem, please contact Blizzard Technical Support. (InstallerFile::Open)

Not sure what you are trying to say because your English is poor (sorry!).

The primary steps are:
Title: Re: Blizzard Installer Customisation
Post by: d3vil1234 on July 28, 2013, 09:35:17 pm
it is normal to have size of wow executable around 24bytes?
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on July 29, 2013, 12:44:57 am
Quote from: "d3vil1234"
it is normal to have size of wow executable around 24bytes?

No. :) You wrote just the header and not the original data.

For me:

Before header:
7,704,216 bytes.

After header:
7,704,240 bytes.

File size difference = 24 bytes.

Header:
(http://i.imgur.com/GegeyTY.png)
Title: Re: Blizzard Installer Customisation
Post by: d3vil1234 on August 04, 2013, 04:06:35 pm
thank stoneharry i achieved that thing. I append  with example_base.exe as base and is working like intended.

Edit :
component-*.txt need to have the header?
Title: Re: Blizzard Installer Customisation
Post by: stoneharry on August 04, 2013, 06:30:34 pm
Quote from: "d3vil1234"
thank stoneharry i achieved that thing. I append  with example_base.exe as base and is working like intended.

Edit :
component-*.txt need to have the header?

I am not sure what the component file is for - it seems to have no effect no matter what it says. It does need to have a header if you are including it.

One thing I have discovered is that an AVI file (movie) does need a header to install but the installer doesn't strip the header when copying it into the MPQ for some reason. If anyone knows how to solve this it would be appreciated.