Advertisement
Guest User

Untitled

a guest
Aug 8th, 2018
347
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.94 KB | None | 0 0
  1. //####################################################
  2. //# Purpose: Disable hard-coded hair style table and #
  3. //#          generate hair style IDs ad-hoc instead  #
  4. //####################################################
  5.  
  6. function Enable64kHairstyle() {
  7.   //Step 1a - Find address of Format String
  8.   var code = "\xC0\xCE\xB0\xA3\xC1\xB7\\\xB8\xD3\xB8\xAE\xC5\xEB\\%s\\%s_%s.%s"; // "인간족\머리통\%s\%s_%s.%s"
  9.   var doramOn = false;
  10.   var offset = exe.findString(code, RAW);
  11.  
  12.   if (offset === -1) {//Doram Client
  13.     code = "\\\xB8\xD3\xB8\xAE\xC5\xEB\\%s\\%s_%s.%s"; // "\머리통\%s\%s_%s.%s"
  14.     doramOn = true;
  15.     offset = exe.findString(code, RAW);
  16.   }
  17.  
  18.   if (offset === -1)
  19.     return "Failed in Step 1 - String not found";
  20.  
  21.   //Step 1b - Change the 2nd %s to %u
  22.   exe.replace(offset + code.length - 7, "75", PTYPE_HEX);
  23.  
  24.   //Step 1c - Find the string reference
  25.   offset = exe.findCode("68" + exe.Raw2Rva(offset).packToHex(4), PTYPE_HEX, false);
  26.   if (offset === -1)
  27.     return "Failed in Step 1 - String reference missing";
  28.  
  29.   //Step 2a - Move offset to previous instruction which should be an LEA reg, [ESP+x] or LEA reg, [EBP-x]
  30.   var fpEnb = HasFramePointer();
  31.   if (!fpEnb)
  32.     offset = offset - 4;
  33.   else
  34.     offset = offset - 3;
  35.  
  36.   if (exe.fetchUByte(offset) !== 0x8D) // x > 0x7F => accomodating for the extra 3 bytes of x
  37.     offset = offset - 3;
  38.  
  39.   if (exe.fetchUByte(offset) !== 0x8D)
  40.     return "Failed in Step 2 - Unknown instruction before reference";
  41.  
  42.   //Step 2b - Extract the register code used in the second last PUSH reg32 before the LEA instruction (0x8D)
  43.   var regNum = exe.fetchUByte(offset - 2) - 0x50;
  44.   if (regNum < 0 || regNum > 7)
  45.     return "Failed in Step 2 - Missing Reg PUSH";
  46.  
  47.   if (fpEnb)
  48.     regc = (0x45 | (regNum << 3)).packToHex(1);
  49.   else
  50.     regc = (0x44 | (regNum << 3)).packToHex(1);
  51.  
  52.   //Step 2c - Now look for the location where it is assigned. Dont remove the AB at the end, the code size is used later.
  53.   if (fpEnb) {//VC9-VC10
  54.     code =
  55.       " 83 7D AB 10"       //CMP DWORD PTR SS:[EBP-y], 10 ; y is unknown
  56.     + " 8B" + regc + " AB" //MOV reg32, DWORD PTR SS:[EBP-z] ; z = y+5*4
  57.     + " 73 03"             //JAE SHORT addr ; after LEA below
  58.     + " 8D" + regc + " AB" //LEA reg32, [EBP-z]
  59.     ;
  60.   }
  61.   else {
  62.     code =
  63.       " 83 7C 24 AB 10"       //CMP DWORD PTR SS:[ESP+y], 10 ; y is unknown
  64.     + " 8B" + regc + " 24 AB" //MOV reg32, DWORD PTR SS:[ESP+z] ; z = y+5*4
  65.     + " 73 04"                //JAE SHORT addr ; after LEA below
  66.     + " 8D" + regc + " 24 AB" //LEA reg32, [ESP+z]
  67.     ;
  68.   }
  69.   var offset2 = exe.find(code, PTYPE_HEX, true, "\xAB", offset - 0x50, offset);
  70.  
  71.   if (offset2 === -1) {//VC11
  72.     if (fpEnb) {
  73.       code =
  74.         " 83 7D AB 10"          //CMP DWORD PTR SS:[EBP-y], 10 ; y is unknown
  75.       + " 8D" + regc + " AB"    //LEA reg32, [EBP-z] ; z = y+5*4
  76.       + " 0F 43" + regc + " AB" //CMOVAE reg32, DWORD PTR SS:[EBP-z]
  77.       ;
  78.     }
  79.     else {
  80.       code =
  81.         " 83 7C 24 AB 10"          //CMP DWORD PTR SS:[ESP+y], 10 ; y is unknown
  82.       + " 8D" + regc + " 24 AB"    //LEA reg32, [ESP+z] ; z = y+5*4
  83.       + " 0F 43" + regc + " 24 AB" //CMOVAE reg32, DWORD PTR SS:[ESP+z]
  84.       ;
  85.     }
  86.    
  87.     offset2 = exe.find(code, PTYPE_HEX, true, "\xAB", offset - 0x50, offset);
  88.   }
  89.  
  90.   if (offset2 === -1)
  91.     return "Failed in Step 2 - Register assignment missing";
  92.  
  93.   //Step 2d - Save the offset2 and code size (We need to NOP out the excess)
  94.   var assignOffset = offset2;
  95.   var csize = code.hexlength();
  96.  
  97.   //Step 3a - Find the start of the function (has a common signature like many others)
  98.   code =
  99.     " 6A FF"             //PUSH -1
  100.   + " 68 AB AB AB 00"    //PUSH value
  101.   + " 64 A1 00 00 00 00" //MOV EAX, FS:[0]
  102.   + " 50"                //PUSH EAX
  103.   + " 83 EC"             //SUB ESP, const
  104.   ;
  105.   offset = exe.find(code, PTYPE_HEX, true, "\xAB", offset2 - 0x1B0, offset2);
  106.  
  107.   if (offset === -1) {//const is > 0x7F
  108.     code = code.replace(" 83", " 81");
  109.     offset = exe.find(code, PTYPE_HEX, true, "\xAB", offset2 - 0x2A0, offset2);
  110.   }
  111.  
  112.   offset += code.hexlength();
  113.  
  114.   if (offset === -1)
  115.     return "Failed in Step 3 - Function start missing";
  116.  
  117.   //Step 3b - Get the Stack offset w.r.t. ESP/EBP for Arg.5
  118.   var arg5Dist = 5*4; //for the 5 PUSHes of the arguments
  119.  
  120.   if (fpEnb) {
  121.     arg5Dist += 4; //Account for the PUSH EBP in the beginning
  122.   }
  123.   else {
  124.     arg5Dist += 7*4;//Account for PUSH -1, PUSH addr and 5 reg32 PUSHes
  125.    
  126.     if (exe.fetchUByte(offset - 2) === 0x81) // Add the const from SUB ESP, const
  127.       arg5Dist += exe.fetchDWord(offset);
  128.     else
  129.       arg5Dist += exe.fetchByte(offset);
  130.    
  131.     //Step 3c - Account for an extra PUSH instruction (security related) in VC9 clients
  132.     code =
  133.       " A1 AB AB AB 00" //MOV EAX, DWORD PTR DS:[__security_cookie];
  134.     + " 33 C4"          //XOR EAX, ESP
  135.     + " 50"             //PUSH EAX
  136.     ;
  137.     if (exe.find(code, PTYPE_HEX, true, "\xAB", offset + 0x4, offset + 0x20) !== -1)
  138.       arg5Dist += 4;
  139.   }
  140.   //Step 3d - Prep code to change assignment (hairstyle index instead of the string)
  141.   if (fpEnb) {
  142.     code = " 8B" + regc + arg5Dist.packToHex(1); //MOV reg32_A, DWORD PTR SS:[EBP + arg5Dist]; ARG.5
  143.   }
  144.   else if (arg5Dist > 0x7F) {
  145.     code = " 8B" + (0x84 | (regNum << 3)).packToHex(1) + " 24" + arg5Dist.packToHex(4); //MOV reg32_A, DWORD PTR SS:[ESP + arg5Dist]; ARG.5
  146.   }
  147.   else {
  148.     code = " 8B" + regc + " 24" + arg5Dist.packToHex(1); //MOV reg32_A, DWORD PTR SS:[ESP + arg5Dist]; ARG.5
  149.   }
  150.  
  151.   code += " 8B" + ((regNum << 3) | regNum).packToHex(1); //MOV reg32_A, DWORD PTR DS:[reg32_A]
  152.   code += " 90".repeat(csize - code.hexlength());//Fill rest with NOPs
  153.  
  154.   //Step 3e - Replace the original at assignOffset
  155.   exe.replace(assignOffset, code, PTYPE_HEX);
  156.  
  157.   //Step 4a - Find the string table fetchers
  158.   code =
  159.     " 8B AB AB AB AB 00" //MOV reg32_A, DWORD PTR DS:[addr]
  160.   + " 8B AB 00"          //MOV reg32_B, DWORD PTR DS:[EBP]
  161.   + " 8B 14"             //MOV EDX, DWORD PTR DS:[reg32_B * 4 + reg32_A]
  162.   ;
  163.   var offsets = exe.findAll(code, PTYPE_HEX, true, "\xAB", offset, assignOffset);
  164.  
  165.   if (offsets.length === 0) {
  166.     code =
  167.       " 8B AB"             //MOV reg32_B, DWORD PTR DS:[reg32_C]
  168.     + " 8B AB AB AB AB 00" //MOV reg32_A, DWORD PTR DS:[addr]
  169.     + " 8B 14"             //MOV EDX, DWORD PTR DS:[reg32_B * 4 + reg32_A]
  170.     ;
  171.     offsets = exe.findAll(code, PTYPE_HEX, true, "\xAB", offset, assignOffset);
  172.   }
  173.  
  174.   if (offsets.length === 0) {
  175.     code = code.replace(" 8B AB AB", " A1 AB");//reg32_A is EAX
  176.     offsets = exe.findAll(code, PTYPE_HEX, true, "\xAB", offset, assignOffset);
  177.   }
  178.  
  179.   if (offsets.length === 0) {  // 2017 +
  180.     code =
  181.       " 8B AB"             //MOV reg32_B, DWORD PTR DS:[reg32_C]
  182.     + " A1 AB AB AB 01"    //MOV reg32_A, DWORD PTR DS:[addr]
  183.     + " 8B 14"             //MOV EDX, DWORD PTR DS:[reg32_B * 4 + reg32_A]
  184.     ;
  185.     offsets = exe.findAll(code, PTYPE_HEX, true, "\xAB", offset, assignOffset);
  186.   }
  187.  
  188.  
  189.   if (offsets.length === 0)
  190.     return "Failed in Step 4 - Table fetchers missing";
  191.  
  192.   //Step 4b - Remove the reg32_B * 4 from all the matches
  193.   for (var i = 0; i < offsets.length; i++) {
  194.     offset2 = offsets[i] + code.hexlength();
  195.     exe.replaceWord(offset2 - 1, 0x9010 + (exe.fetchByte(offset2) & 0x7));
  196.   }
  197.  
  198.   //Step 5a - Find the Hairstyle limiting comparison within the function
  199.   code =
  200.     " 7C 05"    //JL SHORT addr1; skips the next two instructions
  201.   + " 83 AB AB" //CMP reg32_A, const; const = max hairstyle ID
  202.   + " 7E AB"    //JLE SHORT addr2; skip the next assignment - AB should be 06 or 07
  203.   + " C7"       //MOV DWORD PTR DS:[reg32_B], 0D
  204.   ;
  205.   offset2 = exe.find(code, PTYPE_HEX, true, "\xAB", offset + 4, offset + 0x50);//VC9 - VC10
  206.  
  207.   if (offset2 === -1) {
  208.     code = code.replace(" 7C", " 78");//changing JL to JS
  209.     offset2 = exe.find(code, PTYPE_HEX, true, "\xAB", offset + 4, offset + 0x50);//VC11
  210.   }
  211.  
  212.   if (offset2 === -1 && doramOn) {//For Doram Client, its farther away since there are extra checks for Job ID within Doram Range or Human Range
  213.     offset2 = exe.find(code, PTYPE_HEX, true, "\xAB", offset + 0x100, offset + 0x200);
  214.   }
  215.  
  216.   if (offset2 === -1)
  217.     return "Failed in Step 5 - Limit checker missing";
  218.  
  219.   offset2 += code.hexlength();
  220.  
  221.   //Step 5b - Change the JLE to JMP
  222.   exe.replace(offset2 - 3, "EB", PTYPE_HEX);
  223.  
  224.   //Step 5c - Change 0D to 02 in MOV instruction
  225.   code = exe.fetchUByte(offset2);
  226.   if (code === 0x04 || code > 0x07)
  227.     exe.replace(offset2 + 2, "02");
  228.   else
  229.     exe.replace(offset2 + 1, "02");
  230.  
  231.   //Remove the && 0 to enable for Doram
  232.   if (doramOn && 0) {//Repeat 5a & 5b for Doram race which appears before offset2.
  233.     //Step 6a - Find the Hairstyle limiting comparison within the function for Doram race
  234.     code =
  235.       " 7C 05"    //JL SHORT addr1; skips the next two instructions
  236.     + " 83 AB AB" //CMP reg32_A, const; const = max hairstyle ID
  237.     + " 7C AB"    //JLE SHORT addr2; skip the next assignment - AB should be 06 or 07
  238.     + " C7"       //MOV DWORD PTR DS:[reg32_B], 06
  239.     ;
  240.    
  241.     offset = exe.find(code, PTYPE_HEX, true, "\xAB", offset2 - 0x75, offset2 - 0x10);
  242.     if (offset === -1)
  243.       return "Failed in Step 6 - Doram Limit Checker missing";
  244.  
  245.     offset += code.hexlength();
  246.    
  247.     //Step 6b - Change the JLE to JMP
  248.     exe.replace(offset - 3, "EB", PTYPE_HEX);
  249.    
  250.     //Step 6c - Change 0D to 02 in MOV instruction
  251.     code = exe.fetchUByte(offset);
  252.     if (code === 0x04 || code > 0x07)
  253.       exe.replace(offset + 2, "02");
  254.     else
  255.       exe.replace(offset + 1, "02");
  256.   }
  257.   //Step p_1a - Find address of Format String
  258.     code = "\xB8\xD3\xB8\xAE\\\xB8\xD3\xB8\xAE%s_%s_%d.pal"; // "머리\머리%s_%s_%d.pal"
  259.     offset = exe.findString(code, RAW);
  260.  
  261.    
  262.     if (offset === -1)
  263.         return "Failed in Step p_1 - String not found";
  264.  
  265.     //Step p_1b - Change the 1st %s to %u
  266.     exe.replace(offset + code.length - 0xB, "75", PTYPE_HEX);
  267.  
  268.     //Step p_1c - Find the string reference
  269.     offset = exe.findCode("68" + exe.Raw2Rva(offset).packToHex(4), PTYPE_HEX, false);
  270.     if (offset === -1)
  271.         return "Failed in Step p_1 - String reference missing";
  272.  
  273.     //Step p_2a - Move offset to previous instruction which should be an LEA reg, [ESP+x] or LEA reg, [EBP-x]
  274.     fpEnb = HasFramePointer();
  275.     if (!fpEnb)
  276.         offset = offset - 4;
  277.     else
  278.         offset = offset - 3;
  279.  
  280.     if (exe.fetchUByte(offset) !== 0x8D) // x > 0x7F => accomodating for the extra 3 bytes of x
  281.         offset = offset - 3;
  282.  
  283.     if (exe.fetchUByte(offset) !== 0x8D)
  284.         return "Failed in Step p_2 - Unknown instruction before reference";
  285.  
  286.     //Step p_2b - Extract the register code used in the first last PUSH reg32 before the LEA instruction (0x8D)
  287.     regNum = exe.fetchUByte(offset - 1) - 0x50;
  288.     if (regNum < 0 || regNum > 7)
  289.         return "Failed in Step 2 - Missing Reg PUSH";
  290.  
  291.     if (fpEnb)
  292.         regc = (0x45 | (regNum << 3)).packToHex(1);
  293.     else
  294.         regc = (0x44 | (regNum << 3)).packToHex(1);
  295.  
  296.     //Step 2c - Now look for the location where it is assigned. Dont remove the AB at the end, the code size is used later.
  297.     if (fpEnb)
  298.     {
  299.         code =
  300.           " 8D" + regc + " AB"    //LEA reg32, [EBP-z] ; z = y+5*4
  301.         + " 0F 43" + regc + " AB" //CMOVAE reg32, DWORD PTR SS:[EBP-z]
  302.         ;
  303.     }
  304.     else
  305.     {
  306.         code =
  307.           " 8D" + regc + " 24 AB"    //LEA reg32, [ESP+z] ; z = y+5*4
  308.         + " 0F 43" + regc + " 24 AB" //CMOVAE reg32, DWORD PTR SS:[ESP+z]
  309.         ;
  310.     }
  311.  
  312.     offset2 = exe.find(code, PTYPE_HEX, true, "\xAB", offset - 0x50, offset);
  313.  
  314.     if (offset2 === -1)
  315.         return "Failed in Step p_2 - Register assignment missing";
  316.  
  317.     //Step p_2d - Save the offset2 and code size (We need to NOP out the excess)
  318.     assignOffset = offset2;
  319.     csize = code.hexlength();
  320.  
  321.     //Step p_3a - Find the start of the function (has a common signature like many others)
  322.     code =
  323.         " 6A FF"             //PUSH -1
  324.       + " 68 AB AB AB 00"    //PUSH value
  325.       + " 64 A1 00 00 00 00" //MOV EAX, FS:[0]
  326.       + " 50"                //PUSH EAX
  327.       + " 83 EC"             //SUB ESP, const
  328.       ;
  329.     offset = exe.find(code, PTYPE_HEX, true, "\xAB", offset2 - 0x1B0, offset2);
  330.  
  331.     if (offset === -1)
  332.     {  //const is > 0x7F
  333.         code =
  334.           " 6A FF"             //PUSH -1
  335.         + " 68 AB AB AB 00"    //PUSH value
  336.         + " 64 A1 00 00 00 00" //MOV EAX, FS:[0]
  337.         + " 50"                //PUSH EAX
  338.         + " 81 EC"             //SUB ESP, const
  339.         ;
  340.         offset = exe.find(code, PTYPE_HEX, true, "\xAB", offset2 - 0x280, offset2);
  341.     }
  342.  
  343.     if (offset === -1)
  344.     { // 2017 +
  345.         offset = exe.find(code, PTYPE_HEX, true, "\xAB", offset2 - 0x3A5, offset2);
  346.     }
  347.  
  348.     if (offset === -1)
  349.         return "Failed in Step p_3 - Function start missing";
  350.  
  351.     offset += code.hexlength();
  352.  
  353.     //Step p_3b - Get the Stack offset w.r.t. ESP/EBP for Arg.2
  354.     var arg2Dist = 2*4; //for the 5 PUSHes of the arguments
  355.  
  356.     if (fpEnb)
  357.     {
  358.         arg2Dist += 4; //Account for the PUSH EBP in the beginning
  359.     }
  360.     else
  361.     {
  362.         arg2Dist += 4*4;//Account for PUSH -1, PUSH addr and 5 reg32 PUSHes
  363.  
  364.         if (exe.fetchUByte(offset - 2) === 0x81) // Add the const from SUB ESP, const
  365.             arg2Dist += exe.fetchDWord(offset);
  366.         else
  367.             arg2Dist += exe.fetchByte(offset);
  368.  
  369.         //Step p_3c - Account for an extra PUSH instruction (security related) in VC9 clients
  370.         code =
  371.             " A1 AB AB AB 00" //MOV EAX, DWORD PTR DS:[__security_cookie];
  372.           + " 33 C4"          //XOR EAX, ESP
  373.           + " 50"             //PUSH EAX
  374.           ;
  375.         if (exe.find(code, PTYPE_HEX, true, "\xAB", offset + 0x4, offset + 0x20) !== -1)
  376.             arg2Dist += 4;
  377.     }
  378.     //Step p_3d - Prep code to change assignment (hairstyle index instead of the string)
  379.     if (fpEnb)
  380.     {
  381.         code = " 8B" + regc + arg2Dist.packToHex(1); //MOV reg32_A, DWORD PTR SS:[EBP + arg2Dist]; ARG.2
  382.     }
  383.     else if (arg2Dist > 0x7F)
  384.     {
  385.         code = " 8B" + (0x84 | (regNum << 3)).packToHex(1) + " 24" + arg2Dist.packToHex(4); //MOV reg32_A, DWORD PTR SS:[ESP + arg2Dist]; ARG.2
  386.     }
  387.     else
  388.     {
  389.         code = " 8B" + regc + " 24" + arg2Dist.packToHex(1); //MOV reg32_A, DWORD PTR SS:[ESP + arg2Dist]; ARG.2
  390.     }
  391.  
  392.     code += " 90".repeat(csize - code.hexlength());//Fill rest with NOPs
  393.  
  394.     //Step p_3e - Replace the original at assignOffset
  395.     exe.replace(assignOffset, code, PTYPE_HEX);
  396.  
  397.     //Step p_4a - Find the string table fetchers
  398.     code =
  399.         " 8B AB AB AB AB 00" //MOV reg32_A, DWORD PTR DS:[addr]
  400.       + " 8B 14"             //MOV EDX, DWORD PTR DS:[reg32_B * 4 + reg32_A]
  401.       ;
  402.     offsets = exe.findAll(code, PTYPE_HEX, true, "\xAB", offset, assignOffset);
  403.    
  404.     if (offsets.length === 0)
  405.     {
  406.         code =
  407.             " A1 AB AB AB 00"    //MOV reg32_A, DWORD PTR DS:[addr]
  408.           + " 8B 14"             //MOV EDX, DWORD PTR DS:[reg32_B * 4 + reg32_A]
  409.           ;
  410.         offsets = exe.findAll(code, PTYPE_HEX, true, "\xAB", offset, assignOffset);
  411.     }
  412.  
  413.     if (offsets.length === 0)
  414.     {  // 2017 +
  415.         code =
  416.             " A1 AB AB AB 01"    //MOV reg32_A, DWORD PTR DS:[addr]
  417.           + " 8B 14"             //MOV EDX, DWORD PTR DS:[reg32_B * 4 + reg32_A
  418.           ;
  419.         offsets = exe.findAll(code, PTYPE_HEX, true, "\xAB", offset, assignOffset);
  420.     }
  421.  
  422.     if (offsets.length === 0)
  423.         return "Failed in Step p_4 - Table fetchers missing";
  424.  
  425.     //Step p_4b - Remove the reg32_B * 4 from all the matches
  426.     for (var i = 0; i < offsets.length; i++)
  427.     {
  428.         offset2 = offsets[i] + code.hexlength();
  429.         exe.replaceWord(offset2 - 1, 0x9010 + (exe.fetchByte(offset2) & 0x7));
  430.     }
  431.  
  432.   return true;
  433. }
  434.  
  435. //=================================//
  436. // Disable for Unsupported Clients //
  437. //=================================//
  438. function Enable64kHairstyle_() {
  439.   return (exe.getClientDate() > 20111102);
  440. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement