1. //###########################################################################
  2. //# Purpose: Restore the original code that created the Login Window inside #
  3. //# CLoginMode::OnChangeState function and Add supporting Changes #
  4. //# to make it work #
  5. //###########################################################################
  6. function RestoreLoginWindow() {
  7. //Step 1a - Find the code where we need to make client call the login window
  8. var code =
  9. " 50" //PUSH EAX
  10. + " E8 AB AB AB FF" //CALL g_ResMgr
  11. + " 8B C8" //MOV ECX, EAX
  12. + " E8 AB AB AB FF" //CALL CResMgr::Get
  13. + " 50" //PUSH EAX
  14. + " B9 AB AB AB 00" //MOV ECX, OFFSET g_windowMgr
  15. + " E8 AB AB AB FF" //CALL UIWindowMgr::SetWallpaper
  16. + " 80 3D AB AB AB 00 00" //CMP BYTE PTR DS:[g_Tparam], 0 <- The parameter push + call to UIWindowManager::MakeWindow originally here
  17. + " 74 13" //JZ SHORT addr1 - after the JMP
  18. + " C6 AB AB AB AB 00 00" //MOV BYTE PTR DS:[g_Tparam], 0
  19. + " C7 AB AB 04 00 00 00" //MOV DWORD PTR DS:[EBX+0C], 4 <- till here we need to overwrite
  20. + " E9" //JMP addr2
  21. ;
  22. var codeOffset = exe.findCode(code, PTYPE_HEX, true, "\xAB");
  23. // newer exes have g_tParam located past 00nnnn, so we need to expand the search!
  24. if (codeOffset === -1)
  25. {
  26. code = code.replace(" 80 3D AB AB AB 00", " 80 3D AB AB AB 01");
  27. code = code.replace(" C6 AB AB AB AB 00", " C6 AB AB AB AB 01");
  28. codeOffset = exe.findCode(code, PTYPE_HEX, true, "\xAB");
  29. }
  30. if (codeOffset === -1)
  31. return "Failed in Step 1";
  32. //Step 1b - Extract the MOV ECX, g_windowMgr statement
  33. var movEcx = exe.fetchHex(codeOffset + 14, 5);
  34. //==============================================//
  35. // Next we need to find UIWindowMgr::MakeWindow //
  36. //==============================================//
  37. //Step 2a - Find offset of NUMACCOUNT
  38. var offset = exe.findString("NUMACCOUNT", RVA);
  39. if (offset === -1)
  40. return "Failed in Step 2 - NUMACCOUNT not found";
  41. //Step 2b - Find the UIWindowMgr::MakeWindow call
  42. code =
  43. movEcx //MOV ECX, OFFSET g_windowMgr
  44. + " E8 AB AB AB FF" //CALL UIWindowMgr::MakeWindow
  45. + " 6A 00" //PUSH 0
  46. + " 6A 00" //PUSH 0
  47. + " 68" + offset.packToHex(4) //PUSH addr ; ASCII "NUMACCOUNT"
  48. ;
  49. var o2 = exe.findCode(code, PTYPE_HEX, true, "\xAB");
  50. if (o2 === -1)
  51. return "Failed in Step 2 - MakeWindow not found";
  52. //Step 2c - Extract the Function address relative to target location
  53. var windowMgr = ((o2 + 10 + exe.fetchDWord(o2 + 6)) - (codeOffset + 24 + 2 + 5 + 5)).packToHex(4)
  54. //Step 3a - Prepare the code to overwrite with - originally present in old clients
  55. code =
  56. " 6A 03" //PUSH 3
  57. + movEcx //MOV ECX, OFFSET g_windowMgr
  58. + " E8" + windowMgr //CALL UIWindowMgr::MakeWindow
  59. + " EB 09" //JMP SHORT addr ; skip over to the MOV [EBX+0C], 4
  60. //90".repeat(11) //Bunch of NOPs
  61. ;
  62. //Step 3b - Overwrite with the code.
  63. exe.replace(codeOffset + 24, code, PTYPE_HEX);
  64. //===============================================//
  65. // Now for some additional stuff to make it work //
  66. //===============================================//
  67. //Step 4a - Force the client to send old login packet irrespective of LangType (Also inside CLoginMode::ChangeState)
  68. // all JZ will be NOPed out
  69. var LANGTYPE = GetLangType();//Langtype value overrides Service settings hence they use the same variable - g_serviceType
  70. if (LANGTYPE.length === 1)
  71. return "Failed in Step 4 - " + LANGTYPE[0];
  72. code =
  73. " 80 3D AB AB AB 00 00" //CMP BYTE PTR DS:[g_passwordencrypt], 0
  74. + " 0F 85 AB AB 00 00" //JNE addr1
  75. + " A1" + LANGTYPE //MOV EAX, DWORD PTR DS:[g_serviceType]
  76. + " AB AB" //TEST EAX, EAX - (some clients use CMP EAX, EBP instead)
  77. + " 0F 84 AB AB 00 00" //JZ addr2 -> Send SSO Packet (ID = 0x825. was 0x2B0 in Old clients)
  78. + " 83 AB 12" //CMP EAX, 12
  79. + " 0F 84 AB AB 00 00" //JZ addr2 -> Send SSO Packet (ID = 0x825. was 0x2B0 in Old clients)
  80. ;
  81. offset = exe.findCode(code, PTYPE_HEX, true, "\xAB");
  82. if (offset === -1) {
  83. code = code.replace(" A1", " 8B AB"); //MOV reg32_A, DWORD PTR DS:[g_serviceType]
  84. offset = exe.findCode(code, PTYPE_HEX, true, "\xAB");
  85. }
  86. if (offset === -1)
  87. return "Failed in Step 4 - LangType comparison missing";
  88. offset += code.hexlength();
  89. if (exe.fetchUByte(offset) === 0x83 && exe.fetchByte(offset + 2) === 0x0C)//create a JMP to location after the JZs
  90. var repl = "EB 18";
  91. else
  92. var repl = "EB 0F";
  93. exe.replace(offset - 0x11, repl, PTYPE_HEX);
  94. /*===========================================================================================================================
  95. Shinryo: We need to make the client return to Login Interface when Error occurs (such as wrong password, failed to connect).
  96. For this in the CModeMgr::SendMsg function, we set the return mode to 3 (Login) and pass 0x271D as idle value
  97. and skip the quit operation.
  98. =============================================================================================================================
  99. First we need to find the g_modeMgr & mode setting function address. The address is kept indirectly =>
  100. MOV ECX, DWORD PTR DS:[Reference]
  101. MOV EAX, DWORD PTR DS:[ECX]
  102. MOV EDX, DWORD PTR DS:[EAX+18]
  103. now ECX + C contains g_modeMgr & EDX is the function address we need. But these 3 instructions are not always kept together as of recent clients.
  104. ===========================================================================================================================*/
  105. //Step 5a - First we look for one location that appears always after g_modeMgr is retrieved
  106. code =
  107. " 6A 00" //PUSH 0
  108. + " 6A 00" //PUSH 0
  109. + " 6A 00" //PUSH 0
  110. + " 68 F6 00 00 00" //PUSH F6
  111. + " FF" //CALL reg32_A or CALL DWORD PTR DS:[reg32_A+const]
  112. ;
  113. offset = exe.findCode(code, PTYPE_HEX, false);
  114. if (offset === -1)
  115. return "Failed in Step 5 - Unable to find g_modeMgr code";
  116. //Step 5b - Find the start of the function
  117. code =
  118. " 83 3D AB AB AB AB 01" //CMP DWORD PTR DS:[addr1], 1
  119. + " 75 AB" //JNE addr2
  120. + " 8B 0D" //MOV ECX, DWORD PTR DS:[Reference]
  121. ;
  122. var offset = exe.find(code, PTYPE_HEX, true, "\xAB", offset - 30, offset);
  123. if (offset === -1)
  124. return "Failed in Step 5 - Start of Function missing";
  125. //Step 5c - Extract the reference and construct the code for getting g_modeMgr to ECX + C & mode setter to EDX (same as shown initially)
  126. var infix =
  127. exe.fetchHex(offset + code.hexlength() - 2, 6) //MOV ECX, DWORD PTR DS:[Reference]
  128. + " 8B 01" //MOV EAX, DWORD PTR DS:[ECX]
  129. + " 8B 50 18" //MOV EDX, DWORD PTR DS:[EAX+18]
  130. ;
  131. //Step 5d - Find how many PUSH 0s are there. Older clients had 3 arguments but newer ones only have 3
  132. var pushes = exe.findAll("6A 00", PTYPE_HEX, false, "", offset + code.hexlength() + 4, offset + code.hexlength() + 16);
  133. //Step 5e - Find error handler = CModeMgr::Quit
  134. code =
  135. " 8B F1" //MOV ESI,ECX
  136. + " 8B 46 04" //MOV EAX,DWORD PTR DS:[ESI+4]
  137. + " C7 40 14 00 00 00 00" //MOV DWORD PTR DS:[EAX+14], 0
  138. + " 83 3D" + LANGTYPE + " 0B" //CMP DWORD PTR DS:[g_serviceType], 0B
  139. + " 75 1D" //JNE SHORT addr1 -> after CALL instruction below
  140. + " 8B 0D AB AB AB 00" //MOV ECX,DWORD PTR DS:[g_hMainWnd]
  141. + " 6A 01" //PUSH 1
  142. + " 6A 00" //PUSH 0
  143. + " 6A 00" //PUSH 0
  144. + " 68 AB AB AB 00" //PUSH addr2 ; ASCII "http://www.ragnarok.co.in/index.php"
  145. + " 68 AB AB AB 00" //PUSH addr3 ; ASCII "open"
  146. + " 51" //PUSH ECX
  147. + " FF 15 AB AB AB 00" //CALL DWORD PTR DS:[<&SHELL32.ShellExecuteA>]
  148. + " C7 06 00 00 00 00" //MOV DWORD PTR DS:[ESI],0 (ESI is supposed to have g_modeMgr but it doesn't always point to it, so we assign it another way)
  149. ;
  150. /*==============================================================================
  151. Shinryo:
  152. The easiest way would be probably to set this value to a random value instead of 0,
  153. but the client would dimmer down/flicker and appear again at login interface.
  154. ===============================================================================*/
  155. offset = exe.findCode(code, PTYPE_HEX, true, "\xAB");
  156. if (offset === -1) {//For recent client g_hMainWnd is directly pushed instead of assigning to ECX first
  157. code = code.replace(" 75 1D 8B 0D AB AB AB 00", " 75 1C"); //remove the ECX assignment and fix the JNE address accordingly
  158. code = code.replace(" 51 FF 15 AB", " FF 35 AB AB AB 00 FF 15 AB"); //replace PUSH ECX with PUSH DWORD PTR DS:[g_hMainWnd]
  159. offset = exe.findCode(code, PTYPE_HEX, true, "\xAB");
  160. if (offset === -1)
  161. {
  162. // and newer clients push hwndParent further, so !
  163. code = code.replace(" FF 35 AB AB AB 00 FF 15 AB", " FF 35 AB AB AB 01 FF 15 AB");
  164. offset = exe.findCode(code, PTYPE_HEX, true, "\xAB");
  165. }
  166. }
  167. if (offset === -1)
  168. return "Failed in Step 5 - Unable to find SendMsg function";
  169. //Step 5f - Construct the replacement code
  170. var replace =
  171. " 52" //PUSH EDX
  172. + " 50" //PUSH EAX
  173. + infix //MOV ECX,DWORD PTR DS:[Reference]
  174. //MOV EAX,DWORD PTR DS:[ECX]
  175. //MOV EDX,DWORD PTR DS:[EAX+18]
  176. + " 6A 00".repeat(pushes.length) //PUSH 0 sequence
  177. + " 68 1D 27 00 00" //PUSH 271D
  178. + " C7 41 0C 03 00 00 00" //MOV DWORD PTR DS:[ECX+0C],3
  179. + " FF D2" //CALL EDX
  180. + " 58" //POP EAX
  181. + " 5A" //POP EDX
  182. ;
  183. //replace += " 90".repeat(code.hexlength() - replace.hexlength()); // Bunch of NOPs
  184. replace += " EB" + (code.hexlength() - replace.hexlength() - 2).packToHex(1); //Skip to the POP ESI
  185. //Step 5g - Overwrite the SendMsg function.
  186. exe.replace(offset, replace, PTYPE_HEX);
  187. //==========================================================================//
  188. // Extra for certain 2013 - 2014 clients. Need to fix a function to return 1//
  189. //==========================================================================//
  190. if (exe.getClientDate() >= 20130320 && exe.getClientDate() <= 20140226) {
  191. //Step 6a - Find offset of "ID"
  192. offset = exe.findString("ID", RVA);
  193. if (offset === -1)
  194. return "Failed in Step 6 - ID not found";
  195. //Step 6b - Find its reference
  196. // PUSH 1
  197. // PUSH 0
  198. // PUSH addr; "ID"
  199. offset = exe.findCode("6A 01 6A 00 68" + offset.packToHex(4), PTYPE_HEX, false);
  200. if (offset === -1)
  201. return "Failed in Step 6 - ID reference not found";
  202. //Step 6c - Find the new function call in 2013 clients
  203. // PUSH EAX
  204. // CALL func
  205. // JMP addr
  206. offset = exe.find("50 E8 AB AB AB 00 EB", PTYPE_HEX, true, "\xAB", offset - 80, offset);
  207. if (offset === -1)
  208. return "Failed in Step 6 - Function not found";
  209. //Step 6d - Extract the called address
  210. var call = exe.fetchDWord(offset + 2) + offset + 6;
  211. //Step 6e - Sly devils have made a jump here so search for that.
  212. offset = exe.find("E9", PTYPE_HEX, false, "", call);
  213. if (offset === -1)
  214. return "Failed in Step 6 - Jump Not found";
  215. //Step 6f - Now get the jump offset
  216. call = offset + 5 + exe.fetchDWord(offset+1);//rva conversions are not needed since we are referring to same code section.
  217. //Step 6g - Search for pattern to get func call <- need to remove that call
  218. // PUSH 13
  219. // CALL DWORD PTR DS:[addr]
  220. // AND EAX, 000000FF
  221. offset = exe.find(" 6A 13 FF 15 AB AB AB 00 25 FF 00 00 00", PTYPE_HEX, true, "\xAB", call);
  222. if (offset === -1)
  223. return "Failed in Step 6 - Pattern not found";
  224. //Step 6h - This part is tricky we are going to replace the call with xor eax,eax & add esp, c for now since i dunno what its purpose was anyways. 13 is a hint
  225. // XOR EAX, EAX
  226. // ADD ESP, 0C
  227. // NOP
  228. exe.replace(offset + 2, " 31 C0 83 C4 0C 90", PTYPE_HEX);
  229. }
  230. return true;
  231. }
  232. //==============================================================//
  233. // Disable for Unneeded Clients - Only VC9+ Client dont have it //
  234. //==============================================================//
  235. function RestoreLoginWindow_() {
  236. return (exe.getClientDate() > 20100803);
  237. }

RestoreLoginWindow.qs