Kotel Posted April 2, 2018 Group: Members Topic Count: 1 Topics Per Day: 0.00 Content Count: 8 Reputation: 2 Joined: 07/05/13 Last Seen: December 8, 2024 Share Posted April 2, 2018 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 2 Quote Link to comment Share on other sites More sharing options...
Radian Posted April 2, 2018 Group: Members Topic Count: 162 Topics Per Day: 0.04 Content Count: 1546 Reputation: 192 Joined: 07/23/14 Last Seen: June 24, 2024 Share Posted April 2, 2018 Im using a 2017-01-25aRagexeRE and it didnt work. Quote Link to comment Share on other sites More sharing options...
Kotel Posted April 2, 2018 Group: Members Topic Count: 1 Topics Per Day: 0.00 Content Count: 8 Reputation: 2 Joined: 07/05/13 Last Seen: December 8, 2024 Author Share Posted April 2, 2018 I cant patch 2017-01-25aRagexeRE anyway, so there is another problem: Failed in Step 2 - Unknown instruction before reference Quote Link to comment Share on other sites More sharing options...
Radian Posted April 2, 2018 Group: Members Topic Count: 162 Topics Per Day: 0.04 Content Count: 1546 Reputation: 192 Joined: 07/23/14 Last Seen: June 24, 2024 Share Posted April 2, 2018 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.. Quote Link to comment Share on other sites More sharing options...
iubantot Posted April 3, 2018 Group: Members Topic Count: 117 Topics Per Day: 0.03 Content Count: 312 Reputation: 34 Joined: 10/15/12 Last Seen: 21 hours ago Share Posted April 3, 2018 (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 April 4, 2018 by iubantot upon further testing Quote Link to comment Share on other sites More sharing options...
Kotel Posted April 4, 2018 Group: Members Topic Count: 1 Topics Per Day: 0.00 Content Count: 8 Reputation: 2 Joined: 07/05/13 Last Seen: December 8, 2024 Author Share Posted April 4, 2018 Probably bug in style. Try change grf. Some style packs are bugged. Quote Link to comment Share on other sites More sharing options...
joelolopez Posted April 5, 2018 Group: Members Topic Count: 154 Topics Per Day: 0.03 Content Count: 493 Reputation: 46 Joined: 01/24/12 Last Seen: August 25, 2022 Share Posted April 5, 2018 (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 April 5, 2018 by joelolopez Quote Link to comment Share on other sites More sharing options...
Kotel Posted April 6, 2018 Group: Members Topic Count: 1 Topics Per Day: 0.00 Content Count: 8 Reputation: 2 Joined: 07/05/13 Last Seen: December 8, 2024 Author Share Posted April 6, 2018 For me works perfect in 2017-05-17aRagexeRE, but 2018 clients looks better, so i no more use this client. Quote Link to comment Share on other sites More sharing options...
Digos Posted April 27, 2018 Group: Members Topic Count: 12 Topics Per Day: 0.00 Content Count: 88 Reputation: 23 Joined: 01/30/12 Last Seen: February 19 Share Posted April 27, 2018 (edited) Confirmed to work on 2016-12-28aRagexeRE. Thanks for the fix! Oops game crashed after a while Edited April 27, 2018 by Digos Quote Link to comment Share on other sites More sharing options...
Lelouch vi Britannia Posted April 28, 2018 Group: Members Topic Count: 45 Topics Per Day: 0.01 Content Count: 715 Reputation: 84 Joined: 01/05/12 Last Seen: April 10, 2023 Share Posted April 28, 2018 https://gitlab.com/4144/Nemo/commit/5bd67dbedb93ce2b3d310a2dae5e136f9e8555f4 Quote Link to comment Share on other sites More sharing options...
iubantot Posted May 2, 2018 Group: Members Topic Count: 117 Topics Per Day: 0.03 Content Count: 312 Reputation: 34 Joined: 10/15/12 Last Seen: 21 hours ago Share Posted May 2, 2018 On 4/28/2018 at 3:05 PM, Lelouch vi Britannia said: https://gitlab.com/4144/Nemo/commit/5bd67dbedb93ce2b3d310a2dae5e136f9e8555f4 i already tried this fork here but it still gives me error im using 2017-06-14 btw. what client are you using? Quote Link to comment Share on other sites More sharing options...
spinzaku Posted May 14, 2018 Group: Members Topic Count: 10 Topics Per Day: 0.00 Content Count: 82 Reputation: 6 Joined: 04/20/16 Last Seen: July 23, 2024 Share Posted May 14, 2018 Anyone got a fix yet? 2017 or 2018 client has the hair style crash bug. Quote Link to comment Share on other sites More sharing options...
Sukiyomi Posted May 22, 2018 Group: Members Topic Count: 0 Topics Per Day: 0 Content Count: 1 Reputation: 0 Joined: 12/09/14 Last Seen: April 12, 2019 Share Posted May 22, 2018 (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 May 22, 2018 by Sukiyomi added code Quote Link to comment Share on other sites More sharing options...
Kotel Posted August 20, 2018 Group: Members Topic Count: 1 Topics Per Day: 0.00 Content Count: 8 Reputation: 2 Joined: 07/05/13 Last Seen: December 8, 2024 Author Share Posted August 20, 2018 (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 August 21, 2018 by Kotel Quote Link to comment Share on other sites More sharing options...
Kotel Posted August 21, 2018 Group: Members Topic Count: 1 Topics Per Day: 0.00 Content Count: 8 Reputation: 2 Joined: 07/05/13 Last Seen: December 8, 2024 Author Share Posted August 21, 2018 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"; Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.