// Optional RSA / session-seed patch, equivalent to xeon/EncryptionPatch (RSAPatch). // // NOT required for the 0.9.10 client this project targets: that build does not // enforce RSA signature verification on query_cur_region, and it reads the // session seed straight from the plaintext GetPlayerTokenRsp.secretKey field // (which the server already sets to 1337). Ship redirect.js alone for 0.9.10. // // Enable this only for signed builds (~2.7+) by adding it to gadget.config and // filling in the class/method names or byte patterns for that exact build. function patch(stage, parameters) { const module = "UserAssembly.dll"; const verify = Resolve.Method("Assembly-CSharp.dll", "MoleMole", "MiHoYoSDKUtil", "RsaVerify", 3); if (verify) { Interceptor.replace(verify, new NativeCallback(() => 1, 'bool', ['pointer', 'pointer', 'pointer'])); console.log("[Yuanshen] RSA verify forced true"); } const process = Process.getModuleByName(module); const scan = signature => { const hits = Memory.scanSync(process.base, process.size, signature); return hits.length ? hits[0].address : null; }; const nop = (address, count) => Memory.patchCode(address, count, code => code.writeByteArray(Array(count).fill(0x90))); let hit = scan("48 83 F8 01 75 08 49 8B C7 E9 E7 00 00 00 4C 8B 0D 9F E6 AB"); if (hit) nop(hit.add(4), 2); hit = scan("0F 85 EF 00 00 00 33 D2 49 8B CF E8 6B D2 6E 05 48 8B F8"); if (hit) nop(hit, 6); hit = scan("8B D8 E9 00 00 00 00 E8 DC 4A B5 F2 48 8B C8 49"); if (hit) Memory.patchCode(hit, 7, code => code.writeByteArray([0xC7, 0xC3, 0x39, 0x05, 0x00, 0x00, 0x90])); console.log("[Yuanshen] rsapatch scan complete"); } const Resolve = { Method(moduleName, namespace, className, methodName, argCount) { const api = (name, ret, argTypes, args) => { const fn = new NativeFunction(Module.findExportByName(null, name), ret, argTypes); return fn.apply(fn, args); }; const domain = api('il2cpp_domain_get', 'pointer', [], []); const sizeOut = Memory.alloc(8); const assemblies = api('il2cpp_domain_get_assemblies', 'pointer', ['pointer', 'pointer'], [domain, sizeOut]); const size = sizeOut.readU64(); let image = NULL; for (let i = 0; i < size; i++) { const assembly = assemblies.add(i * 8).readPointer(); const candidate = api('il2cpp_assembly_get_image', 'pointer', ['pointer'], [assembly]); if (api('il2cpp_image_get_name', 'pointer', ['pointer'], [candidate]).readUtf8String() === moduleName) { image = candidate; break; } } if (image.isNull()) return null; const klass = api('il2cpp_class_from_name', 'pointer', ['pointer', 'pointer', 'pointer'], [image, Memory.allocUtf8String(namespace), Memory.allocUtf8String(className)]); if (klass.isNull()) return null; const method = api('il2cpp_class_get_method_from_name', 'pointer', ['pointer', 'pointer', 'int'], [klass, Memory.allocUtf8String(methodName), argCount]); return method.isNull() ? null : method.readPointer(); } }; rpc.exports.init = patch;