Jump to content

Sukiyomi

Members
  • Posts

    1
  • Joined

  • Last visited

Posts posted by Sukiyomi

  1. 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);
    }

     

×
×
  • Create New...