Jump to content

Recommended Posts

Posted

This is fix for 2017 clients, patch Enable 64k Hairstyle

 

Problem:

client crashes with some hair style ids (31, 81 and randomly 30, 32 and others)

 

Solution:

edit Enable64kHairstyle.qs

 

after:

  //Step 4b - Remove the reg32_B * 4 from all the matches
  for (var i = 0; i < offsets.length; i++) {
    offset2 = offsets[i] + code.hexlength();
    exe.replaceWord(offset2 - 1, 0x9010 + (exe.fetchByte(offset2) & 0x7));
  }   

 

add:

  //Step X - extra for 2017 clients, again Find the string table fetchers
  code =
      " 8B AB AB AB AB AB"  //MOV reg32_B, DWORD PTR DS:[EBP - 8C]
    + " A1 AB AB AB 00"    //MOV reg32_A, DWORD PTR DS:[addr]
    + " 8B 14"             //MOV EDX, DWORD PTR DS:[reg32_B * 4 + reg32_A]
    ;
	//need find probably 2 occurences
    offsets = exe.findAll(code, PTYPE_HEX, true, "\xAB", offset-1000, assignOffset);
  

  if (offsets.length !== 0) { 

      for (var i = 0; i < offsets.length; i++) {
        offset2 = offsets[i] + code.hexlength();
        exe.replaceWord(offset2 - 1, 0x9010 + (exe.fetchByte(offset2) & 0x7));
      }
  }  

 

 

Tested on:

2017-06-14bRagexeRE 
2017-05-17aRagexeRE

 

  • Upvote 2
Posted
12 minutes ago, Kotel said:

I cant patch 2017-01-25aRagexeRE anyway, so there is another problem:

Failed in Step 2 - Unknown instruction before reference

Yea that's exactly the problem..

Posted (edited)

 

...

Its still giving errors im using hairstyle 41, client ver : 2017-06-14

tested on 2017-5-17 and it still gives errors

Edited by iubantot
upon further testing
Posted (edited)

oh boy it work for the first time but the 2nd tym i login my account my client crashes, what seems to be the problem with ur fix.. it looks like ur missing something..  i was able to change my hairstyle to 30 31 and then it crashes

Edited by joelolopez
  • 3 weeks later...
  • 2 weeks later...
Posted (edited)

Got this working on my 2017-06-14b Client with Secret Nemo w/ the Patch for 64k from both people on this page.

I have 84 hairstyles working, but problem I'm having is 1-29 for Male and Female Hairstyles, about half of them work with Color Palette's 1-8 (which are the default hair colors). I'm using the 553/251 Cloth/Hair Dye pack. I figure it's somewhere in the Coding for 64k Hairstyles. With it turned off the Palette's work perfectly, but of course I can only use 29 Hairstyles then.

 

My Enable64kHairstyle.qs:

//####################################################
//# Purpose: Disable hard-coded hair style table and #
//#          generate hair style IDs ad-hoc instead  #
//####################################################

function Enable64kHairstyle() {
  //Step 1a - Find address of Format String 
  var code = "\xC0\xCE\xB0\xA3\xC1\xB7\\\xB8\xD3\xB8\xAE\xC5\xEB\\%s\\%s_%s.%s"; // "인간족\머리통\%s\%s_%s.%s"
  var doramOn = false;
  var offset = exe.findString(code, RAW);
  
  if (offset === -1) {//Doram Client 
    code = "\\\xB8\xD3\xB8\xAE\xC5\xEB\\%s\\%s_%s.%s"; // "\머리통\%s\%s_%s.%s"
    doramOn = true;
    offset = exe.findString(code, RAW);
  }
  
  if (offset === -1)
    return "Failed in Step 1 - String not found";
  
  //Step 1b - Change the 2nd %s to %u
  exe.replace(offset + code.length - 7, "75", PTYPE_HEX);
  
  //Step 1c - Find the string reference
  offset = exe.findCode("68" + exe.Raw2Rva(offset).packToHex(4), PTYPE_HEX, false);
  if (offset === -1)
    return "Failed in Step 1 - String reference missing";
  
  //Step 2a - Move offset to previous instruction which should be an LEA reg, [ESP+x] or LEA reg, [EBP-x]
  var fpEnb = HasFramePointer();
  if (!fpEnb)
    offset = offset - 4;
  else 
    offset = offset - 3;
  
  if (exe.fetchUByte(offset) !== 0x8D) // x > 0x7F => accomodating for the extra 3 bytes of x
    offset = offset - 3;
  
  if (exe.fetchUByte(offset) !== 0x8D)
    return "Failed in Step 2 - Unknown instruction before reference";
  
  //Step 2b - Extract the register code used in the second last PUSH reg32 before the LEA instruction (0x8D)
  var regNum = exe.fetchUByte(offset - 2) - 0x50;
  if (regNum < 0 || regNum > 7)
    return "Failed in Step 2 - Missing Reg PUSH";
  
  if (fpEnb)
    regc = (0x45 | (regNum << 3)).packToHex(1);
  else
    regc = (0x44 | (regNum << 3)).packToHex(1);
  
  //Step 2c - Now look for the location where it is assigned. Dont remove the AB at the end, the code size is used later.
  if (fpEnb) {//VC9-VC10
    code =
      " 83 7D AB 10"       //CMP DWORD PTR SS:[EBP-y], 10 ; y is unknown
    + " 8B" + regc + " AB" //MOV reg32, DWORD PTR SS:[EBP-z] ; z = y+5*4
    + " 73 03"             //JAE SHORT addr ; after LEA below
    + " 8D" + regc + " AB" //LEA reg32, [EBP-z]
    ;
  }
  else {
    code =
      " 83 7C 24 AB 10"       //CMP DWORD PTR SS:[ESP+y], 10 ; y is unknown
    + " 8B" + regc + " 24 AB" //MOV reg32, DWORD PTR SS:[ESP+z] ; z = y+5*4
    + " 73 04"                //JAE SHORT addr ; after LEA below
    + " 8D" + regc + " 24 AB" //LEA reg32, [ESP+z]
    ;
  }
  var offset2 = exe.find(code, PTYPE_HEX, true, "\xAB", offset - 0x50, offset);
  
  if (offset2 === -1) {//VC11
    if (fpEnb) {
      code = 
        " 83 7D AB 10"          //CMP DWORD PTR SS:[EBP-y], 10 ; y is unknown
      + " 8D" + regc + " AB"    //LEA reg32, [EBP-z] ; z = y+5*4
      + " 0F 43" + regc + " AB" //CMOVAE reg32, DWORD PTR SS:[EBP-z]
      ;
    }
    else {
      code = 
        " 83 7C 24 AB 10"          //CMP DWORD PTR SS:[ESP+y], 10 ; y is unknown
      + " 8D" + regc + " 24 AB"    //LEA reg32, [ESP+z] ; z = y+5*4
      + " 0F 43" + regc + " 24 AB" //CMOVAE reg32, DWORD PTR SS:[ESP+z]
      ;
    }
    
    offset2 = exe.find(code, PTYPE_HEX, true, "\xAB", offset - 0x50, offset);
  }
  
  if (offset2 === -1)
    return "Failed in Step 2 - Register assignment missing";
  
  //Step 2d - Save the offset2 and code size (We need to NOP out the excess)
  var assignOffset = offset2;
  var csize = code.hexlength();
  
  //Step 3a - Find the start of the function (has a common signature like many others)
  code =
    " 6A FF"             //PUSH -1
  + " 68 AB AB AB 00"    //PUSH value
  + " 64 A1 00 00 00 00" //MOV EAX, FS:[0]
  + " 50"                //PUSH EAX
  + " 83 EC"             //SUB ESP, const
  ;
  offset = exe.find(code, PTYPE_HEX, true, "\xAB", offset2 - 0x1B0, offset2);

  if (offset === -1) {//const is > 0x7F
    code =
      " 6A FF"             //PUSH -1
    + " 68 AB AB AB 00"    //PUSH value
    + " 64 A1 00 00 00 00" //MOV EAX, FS:[0]
    + " 50"                //PUSH EAX
    + " 81 EC"             //SUB ESP, const
    ;
    offset = exe.find(code, PTYPE_HEX, true, "\xAB", offset2 - 0x2A0, offset2);
  }
  
  if (offset === -1) { // 2017 +
    offset = exe.find(code, PTYPE_HEX, true, "\xAB", offset2 - 0x2A0, offset2);
  }
  
  if (offset === -1)
    return "Failed in Step 3 - Function start missing";
  
	offset += code.hexlength();

  
  //Step 3b - Get the Stack offset w.r.t. ESP/EBP for Arg.5
  var arg5Dist = 5*4; //for the 5 PUSHes of the arguments
  
  if (fpEnb) {
    arg5Dist += 4; //Account for the PUSH EBP in the beginning
  }
  else {
    arg5Dist += 7*4;//Account for PUSH -1, PUSH addr and 5 reg32 PUSHes
    
    if (exe.fetchUByte(offset - 2) === 0x81) // Add the const from SUB ESP, const
      arg5Dist += exe.fetchDWord(offset);
    else
      arg5Dist += exe.fetchByte(offset);
    
    //Step 3c - Account for an extra PUSH instruction (security related) in VC9 clients
    code =
      " A1 AB AB AB 00" //MOV EAX, DWORD PTR DS:[__security_cookie]; 
    + " 33 C4"          //XOR EAX, ESP
    + " 50"             //PUSH EAX
    ;
    if (exe.find(code, PTYPE_HEX, true, "\xAB", offset + 0x4, offset + 0x20) !== -1)
      arg5Dist += 4;
  }
  //Step 3d - Prep code to change assignment (hairstyle index instead of the string)
  if (fpEnb) {
    code = " 8B" + regc + arg5Dist.packToHex(1); //MOV reg32_A, DWORD PTR SS:[EBP + arg5Dist]; ARG.5
  }
  else if (arg5Dist > 0x7F) {
    code = " 8B" + (0x84 | (regNum << 3)).packToHex(1) + " 24" + arg5Dist.packToHex(4); //MOV reg32_A, DWORD PTR SS:[ESP + arg5Dist]; ARG.5
  }
  else {
    code = " 8B" + regc + " 24" + arg5Dist.packToHex(1); //MOV reg32_A, DWORD PTR SS:[ESP + arg5Dist]; ARG.5
  }
  
  code += " 8B" + ((regNum << 3) | regNum).packToHex(1); //MOV reg32_A, DWORD PTR DS:[reg32_A]
  code += " 90".repeat(csize - code.hexlength());//Fill rest with NOPs
  
  //Step 3e - Replace the original at assignOffset
  exe.replace(assignOffset, code, PTYPE_HEX);
  
  //Step 4a - Find the string table fetchers
  code =
    " 8B AB AB AB AB 00" //MOV reg32_A, DWORD PTR DS:[addr]
  + " 8B AB 00"          //MOV reg32_B, DWORD PTR DS:[EBP]
  + " 8B 14"             //MOV EDX, DWORD PTR DS:[reg32_B * 4 + reg32_A]
  ;
  var offsets = exe.findAll(code, PTYPE_HEX, true, "\xAB", offset, assignOffset);
  
  if (offsets.length === 0) {
    code =
      " 8B AB"             //MOV reg32_B, DWORD PTR DS:[reg32_C]
    + " 8B AB AB AB AB 00" //MOV reg32_A, DWORD PTR DS:[addr]
    + " 8B 14"             //MOV EDX, DWORD PTR DS:[reg32_B * 4 + reg32_A]
    ;
    offsets = exe.findAll(code, PTYPE_HEX, true, "\xAB", offset, assignOffset);
  }
  
  if (offsets.length === 0) {
    code =
      " 8B AB"             //MOV reg32_B, DWORD PTR DS:[reg32_C]
    + " A1 AB AB AB 00"    //MOV reg32_A, DWORD PTR DS:[addr]
    + " 8B 14"             //MOV EDX, DWORD PTR DS:[reg32_B * 4 + reg32_A]
    ;
    offsets = exe.findAll(code, PTYPE_HEX, true, "\xAB", offset, assignOffset);
  }

  if (offsets.length === 0) {  // 2017 +
    code =
      " 8B AB"             //MOV reg32_B, DWORD PTR DS:[reg32_C]
    + " A1 AB AB AB 01"    //MOV reg32_A, DWORD PTR DS:[addr]
    + " 8B 14"             //MOV EDX, DWORD PTR DS:[reg32_B * 4 + reg32_A]
    ;
    offsets = exe.findAll(code, PTYPE_HEX, true, "\xAB", offset, assignOffset);
  }
  
  if (offsets.length === 0) {  // 2017 +
    code =
      " 8B AB"             //MOV reg32_B, DWORD PTR DS:[reg32_C]
    + " A1 AB AB AB 01"    //MOV reg32_A, DWORD PTR DS:[addr]
    + " 8B 14"             //MOV EDX, DWORD PTR DS:[reg32_B * 4 + reg32_A]
    ;
    offsets = exe.findAll(code, PTYPE_HEX, true, "\xAB", offset, assignOffset);
  }

 
  if (offsets.length === 0)
    return "Failed in Step 4 - Table fetchers missing";
  
  //Step 4b - Remove the reg32_B * 4 from all the matches
  for (var i = 0; i < offsets.length; i++) {
    offset2 = offsets[i] + code.hexlength();
    exe.replaceWord(offset2 - 1, 0x9010 + (exe.fetchByte(offset2) & 0x7));
  }
  
 //Step X - extra for 2017 clients, again Find the string table fetchers
  code =
      " 8B AB AB AB AB AB"  //MOV reg32_B, DWORD PTR DS:[EBP - 8C]
    + " A1 AB AB AB 00"    //MOV reg32_A, DWORD PTR DS:[addr]
    + " 8B 14"             //MOV EDX, DWORD PTR DS:[reg32_B * 4 + reg32_A]
    ;
	//need find probably 2 occurences
    offsets = exe.findAll(code, PTYPE_HEX, true, "\xAB", offset-1000, assignOffset);
  

  if (offsets.length !== 0) { 

      for (var i = 0; i < offsets.length; i++) {
        offset2 = offsets[i] + code.hexlength();
        exe.replaceWord(offset2 - 1, 0x9010 + (exe.fetchByte(offset2) & 0x7));
      }
  }  
  
  //Step 5a - Find the Hairstyle limiting comparison within the function
  code = 
    " 7C 05"    //JL SHORT addr1; skips the next two instructions
  + " 83 AB AB" //CMP reg32_A, const; const = max hairstyle ID
  + " 7E AB"    //JLE SHORT addr2; skip the next assignment - AB should be 06 or 07
  + " C7"       //MOV DWORD PTR DS:[reg32_B], 0D
  ;
  offset2 = exe.find(code, PTYPE_HEX, true, "\xAB", offset + 4, offset + 0x50);//VC9 - VC10
  
  if (offset2 === -1) {
    code = 
      " 78 05"    //JL SHORT addr1; skips the next two instructions
    + " 83 AB AB" //CMP reg32_A, const; const = max hairstyle ID
    + " 7E AB"    //JLE SHORT addr2; skip the next assignment - AB should be 06 or 07
    + " C7"       //MOV DWORD PTR DS:[reg32_B], 0D
    ;

    offset2 = exe.find(code, PTYPE_HEX, true, "\xAB", offset + 4, offset + 0x50);//VC11
  }
  
  if (offset2 === -1 && doramOn) {//For Doram Client, its farther away since there are extra checks for Job ID within Doram Range or Human Range
    offset2 = exe.find(code, PTYPE_HEX, true, "\xAB", offset + 0x100, offset + 0x200);
  }
  
  if (offset2 === -1)
    return "Failed in Step 5 - Limit checker missing";
  
  offset2 += code.hexlength();
  
  //Step 5b - Change the JLE to JMP
  exe.replace(offset2 - 3, "EB", PTYPE_HEX);
  
  //Step 5c - Change 0D to 02 in MOV instruction
  code = exe.fetchUByte(offset2);
  if (code === 0x04 || code > 0x07)
    exe.replace(offset2 + 2, "02");
  else
    exe.replace(offset2 + 1, "02");
  
  //Remove the && 0 to enable for Doram
  if (doramOn && 0) {//Repeat 5a & 5b for Doram race which appears before offset2. 
    //Step 6a - Find the Hairstyle limiting comparison within the function for Doram race
    code = 
      " 7C 05"    //JL SHORT addr1; skips the next two instructions
    + " 83 AB AB" //CMP reg32_A, const; const = max hairstyle ID
    + " 7C AB"    //JLE SHORT addr2; skip the next assignment - AB should be 06 or 07
    + " C7"       //MOV DWORD PTR DS:[reg32_B], 06
    ;
    
    offset = exe.find(code, PTYPE_HEX, true, "\xAB", offset2 - 0x75, offset2 - 0x10);
    if (offset === -1)
      return "Failed in Step 6 - Doram Limit Checker missing";
  
    offset += code.hexlength();
    
    //Step 6b - Change the JLE to JMP
    exe.replace(offset - 3, "EB", PTYPE_HEX);
    
    //Step 6c - Change 0D to 02 in MOV instruction
    code = exe.fetchUByte(offset);
    if (code === 0x04 || code > 0x07)
      exe.replace(offset + 2, "02");
    else
      exe.replace(offset + 1, "02");
  }
  
  return true;
}

//=================================//
// Disable for Unsupported Clients //
//=================================//
function Enable64kHairstyle_() {
  return (exe.getClientDate() > 20111102);
}

 

Edited by Sukiyomi
added code
  • 2 months later...
Posted (edited)

Some part is individual for every client.

more universal code (AB can be everythink):

 

//Step X - extra for 2017/2018 clients, again Find the string table fetchers and remove reg32_B * 4
  code =
      " 8B AB AB AB AB AB"  //MOV reg32_B, DWORD PTR DS:[EBP - 8C]
    + " A1 AB AB AB AB"    //MOV reg32_A, DWORD PTR DS:[addr]
    + " 8B 14"             //MOV EDX, DWORD PTR DS:[reg32_B * 4 + reg32_A]
    ;
	//need find probably 2 occurences (male, female)
    offsets = exe.findAll(code, PTYPE_HEX, true, "\xAB", offset-1000, assignOffset);
  

  if (offsets.length !== 0) { 

      for (var i = 0; i < offsets.length; i++) {
        offset2 = offsets[i] + code.hexlength();
        exe.replaceWord(offset2 - 1, 0x9010 + (exe.fetchByte(offset2) & 0x7));
      }
  } 

 

this works for 2018-01-24bRagexeRE and maybe 2017

 

edit: found another problem, this works only without headgear ?

Edited by Kotel
Posted

Maybe final solution, but not universal (each client has probably different function start). This is for 2018-01-24bRagexeRE

 

previous post + this

 

before this :

  return true;
}

//=================================//
// Disable for Unsupported Clients //
//=================================//
function Enable64kHairstyle_() {
  return (exe.getClientDate() > 20111102);
}

 

add this:

 

      code =
      " 55"                 //PUSH ebp
    + " 8B EC"              //mov ebp, esp
    + " 6A FF"              //push 0xffffffff
    + " 68 AB AB AB AB"     //PUSH address
    + " 64 A1 00 00 00 00"  //mov eax,dword ptr [0x0] 
    + " 50"                 //push eax 
    + " 81 EC 90 00 00 00"  //sub esp,0x90
    + " A1 AB AB AB AB"    //mov eax,dword ptr address
    + " 33 C5"              //xor eax, ebp
    + " 89 AB AB"         //mov dword ptr [ebp-0x10],eax
    + " 53"              //push ebx
    + " 56"              //push esi
    + " 57"              //push edi
    + " 50"              //push eax
    ;
    offset = exe.find(code, PTYPE_HEX, true, "\xAB");
    
  
 if(offset !== -1) 
 {
    code =
        " 8B 0E"              //MOV ecx, [esi]
      + " A1 AB AB AB AB"    //MOV reg32_A, DWORD PTR DS:[addr]
      + " 8B 14"             //MOV EDX, DWORD PTR DS:[reg32_B * 4 + reg32_A]
      ;
      offsets = exe.findAll(code, PTYPE_HEX, true, "\xAB", offset, offset+1000);


    if (offsets.length == 2) { 

        for (var i = 0; i < offsets.length; i++) {
          offset2 = offsets[i] + code.hexlength();
          exe.replaceWord(offset2 - 1, 0x9010 + (exe.fetchByte(offset2) & 0x7));
        }
    } 
    else
 	    return "Failed in Step Y - offsets not found";
 }
 else
	 return "Failed in Step Y - start of the function not found";

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...