public bool NeedsUpdate(LeagueProcess league) { byte[] dataPE = league.ReadMemory(league.Base, 0x1000); uint actualChecksum = LeagueProcess.ExtractChecksum(dataPE); return(actualChecksum != this.Checksum || this.PMethArrayOffset == 0 || this.FileProviderListOffset == 0); }
public bool NeedsUpdate(LeagueProcess league) { byte[] dataPE = league.ReadMemory(league.Base, 0x1000); uint actualChecksum = LeagueProcess.ExtractChecksum(dataPE); return(actualChecksum != this.Checksum || this.CreateFileARefOffset == 0 || this.CreateFileAOffset == 0 || this.ReturnAddressOffset == 0 || this.FreePointerOffset == 0 || this.FreeFunctionOffset == 0); }
public void Start(string overlayFolder, PatcherMessageCallback messageCallback, PatcherErrorCallback errorCallback) { this.Prefix = overlayFolder; this._messageCallback = messageCallback; this._errorCallback = errorCallback; this._thread = new Thread(() => { messageCallback?.Invoke("Starting patcher"); this.PrintConfig(); messageCallback?.Invoke("Looking for league process..."); try { while (true) { Process process = GetLeagueProcess(); if (process == null) { Thread.Sleep(3000); continue; } messageCallback?.Invoke("Found League process"); bool offsetsUpdated = false; using (LeagueProcess league = new LeagueProcess(process)) { bool needsUpdate = NeedsUpdate(league); if (process.WaitForInputIdle()) { if (needsUpdate) { messageCallback?.Invoke("Updating offsets"); UpdateOffsets(league); offsetsUpdated = true; messageCallback?.Invoke("Offsets updated"); } messageCallback?.Invoke("Patching League..."); Patch(league); } else { messageCallback?.Invoke("Failed to wait for idle input from process"); } } if (offsetsUpdated) { WriteConfig(_configPath); } process.WaitForExit(); Thread.Sleep(1000); messageCallback?.Invoke("Looking for league process..."); } } catch (Exception exception) { errorCallback?.Invoke(exception); } }); this._thread.IsBackground = true; //Thread needs to be background so it closes when the parent process dies this._thread.Start(); }
public void UpdateOffsets(LeagueProcess league) { byte[] data = league.Dump(); uint checksum = LeagueProcess.ExtractChecksum(data); int pmethArrayOffsetIndex = PATERN_PMETH_ARRAY.Find(data); int fileProviderListOffsetIndex = PATERN_FILE_PROVIDER_LIST.Find(data); if (pmethArrayOffsetIndex > 0 && fileProviderListOffsetIndex > 0) { this.Checksum = checksum; this.PMethArrayOffset = BitConverter.ToUInt32(data, pmethArrayOffsetIndex) - league.Base; this.FileProviderListOffset = BitConverter.ToUInt32(data, fileProviderListOffsetIndex) - league.Base; this._messageCallback?.Invoke(string.Format("Checksum: {0}", checksum)); this._messageCallback?.Invoke(string.Format("PMethArrayOffsetIndex: {0}", pmethArrayOffsetIndex)); this._messageCallback?.Invoke(string.Format("FileProviderListOffsetIndex: {0}", fileProviderListOffsetIndex)); } else { throw new IOException("Failed to update offsets!"); } }
public void UpdateOffsets(LeagueProcess league) { byte[] data = league.Dump(); uint checksum = LeagueProcess.ExtractChecksum(data); int createFileARefOffset = PAT_CreateFileA_CALL.Find(data); if (createFileARefOffset == -1) { throw new IOException("Failed to find CreateFileA reference index!"); } int createFileAOffset = BitConverter.ToInt32(data, createFileARefOffset) - (int)league.Base; int returnAddressOffset = PAT_ReturnAddress.Find(data); if (returnAddressOffset == -1) { throw new IOException("Failed to find ReturnAddress!"); } int freePointerOffsetIndex = PAT_FreePointerOffset.Find(data); if (freePointerOffsetIndex == -1) { throw new IOException("Failed to find FreePointer!"); } int freePointerOffset = BitConverter.ToInt32(data, freePointerOffsetIndex) - (int)league.Base; int freeFunctionOffset = freePointerOffsetIndex + OFF_FreeFunctionOffset; this.Checksum = checksum; this.CreateFileARefOffset = (uint)createFileARefOffset; this.CreateFileAOffset = (uint)createFileAOffset; this.ReturnAddressOffset = (uint)returnAddressOffset; this.FreePointerOffset = (uint)freePointerOffset; this.FreeFunctionOffset = (uint)freeFunctionOffset; this.PrintConfig(); }
public void Patch(LeagueProcess league) { uint createFileARefPointer = this.CreateFileARefOffset + league.Base; uint createFileAPointer = this.CreateFileAOffset + league.Base; uint returnAddress = this.ReturnAddressOffset + league.Base; uint freePointer = this.FreePointerOffset + league.Base; uint freeFunction = this.FreeFunctionOffset + league.Base; // wait untill CreateFileA has been used and unpacmaned league.WaitPointerEquals(createFileARefPointer, createFileAPointer); // wait until free pointer has been set league.WaitPointerNonZero(freePointer); // read trampoline shellcode that league creates for CreateFileA uint createFileATrampolinePointer = league.Read <uint>(createFileAPointer); ImportTrampoline originalCreateFileATrampoline = league.Read <ImportTrampoline>(createFileATrampolinePointer); uint payloadPointer = league.AllocateMemory(0x1000); Payload payload = new Payload( payloadPointer: payloadPointer, originalCreateFileATrampoline: originalCreateFileATrampoline, prefix: PrefixNormalized, originalFreePointer: freeFunction, findReturnAddress: returnAddress ); uint hookCreateFileAPointer = payload.HookCreateFileAPointer(payloadPointer); uint hookFreePointer = payload.HookFreePointer(payloadPointer); ImportTrampoline hookCreateFileATrampoline = new ImportTrampoline(hookCreateFileAPointer); league.Write(payloadPointer, payload); league.MarkMemoryExecutable(payloadPointer, 0x1000); // write hooks league.Write(freePointer, hookFreePointer); league.Write(createFileATrampolinePointer, hookCreateFileATrampoline); }
public void Start(string overlayFolder, PatcherMessageCallback messageCallback, PatcherErrorCallback errorCallback) { this.Prefix = overlayFolder; this._messageCallback = messageCallback; this._errorCallback = errorCallback; this._thread = new Thread(delegate() { try { messageCallback?.Invoke("Starting patcher"); while (true) { foreach (Process process in Process.GetProcessesByName("League of Legends")) { if (!IsLeague(process)) { break; } messageCallback?.Invoke("Found League process"); bool offsetsUpdated = false; using (LeagueProcess league = new LeagueProcess(process)) { bool needsUpdate = NeedsUpdate(league); if (process.WaitForInputIdle(PROCESS_IDLE_TIMEOUT)) { if (needsUpdate) { messageCallback?.Invoke("Updating offsets"); UpdateOffsets(league); offsetsUpdated = true; messageCallback?.Invoke("Offsets updated"); } messageCallback?.Invoke("Patching League..."); Patch(league); } else { messageCallback?.Invoke("Patcher timed out while waiting for idle input"); } } if (offsetsUpdated) { WriteConfig(); } process.WaitForExit(); break; } Thread.Sleep(1000); } } catch (Exception exception) { errorCallback?.Invoke(exception); } }); this._thread.IsBackground = true; //Thread needs to be background so it closes when the parent process dies this._thread.Start(); }
public void Patch(LeagueProcess league) { uint codePointer = league.AllocateMemory(0x900); uint codeVerifyPointer = codePointer + 0x000; uint codePrefixFnPointer = codePointer + 0x100; uint codeOpenPointer = codePointer + 0x200; uint codeCheckAccessPointer = codePointer + 0x300; uint codeCreateIteratorPointer = codePointer + 0x400; uint codeVectorDeleterPointer = codePointer + 0x500; uint codeIsRadsPointer = codePointer + 0x600; league.WriteMemory(codeVerifyPointer, new byte[] { 0xB8, 0x01, 0x00, 0x00, 0x00, 0xC3, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, }); league.WriteMemory(codePrefixFnPointer, new byte[] { 0x57, 0x56, 0x8b, 0x54, 0x24, 0x0c, 0x8b, 0x74, 0x24, 0x14, 0x89, 0xd7, 0xac, 0xaa, 0x84, 0xc0, 0x75, 0xfa, 0x8b, 0x74, 0x24, 0x10, 0x83, 0xef, 0x01, 0xac, 0xaa, 0x84, 0xc0, 0x75, 0xfa, 0x5e, 0x89, 0xd0, 0x5f, 0xc3, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, }); league.WriteMemory(codeOpenPointer, new byte[] { 0x56, 0x53, 0x81, 0xec, 0x14, 0x02, 0x00, 0x00, 0x8b, 0x41, 0x04, 0x8b, 0x58, 0x08, 0x8b, 0x03, 0x8b, 0x30, 0x8d, 0x41, 0x0c, 0x89, 0x44, 0x24, 0x08, 0x8b, 0x84, 0x24, 0x20, 0x02, 0x00, 0x00, 0x89, 0x44, 0x24, 0x04, 0x8d, 0x44, 0x24, 0x10, 0x89, 0x04, 0x24, 0xff, 0x51, 0x08, 0x8b, 0x94, 0x24, 0x24, 0x02, 0x00, 0x00, 0x89, 0xd9, 0x89, 0x04, 0x24, 0x89, 0x54, 0x24, 0x04, 0xff, 0xd6, 0x83, 0xec, 0x08, 0x81, 0xc4, 0x14, 0x02, 0x00, 0x00, 0x5b, 0x5e, 0xc2, 0x08, 0x00, 0x90, 0x90, }); league.WriteMemory(codeCheckAccessPointer, new byte[] { 0x56, 0x53, 0x81, 0xec, 0x14, 0x02, 0x00, 0x00, 0x8b, 0x41, 0x04, 0x8b, 0x58, 0x08, 0x8b, 0x03, 0x8b, 0x70, 0x04, 0x8d, 0x41, 0x0c, 0x89, 0x44, 0x24, 0x08, 0x8b, 0x84, 0x24, 0x20, 0x02, 0x00, 0x00, 0x89, 0x44, 0x24, 0x04, 0x8d, 0x44, 0x24, 0x10, 0x89, 0x04, 0x24, 0xff, 0x51, 0x08, 0x8b, 0x94, 0x24, 0x24, 0x02, 0x00, 0x00, 0x89, 0xd9, 0x89, 0x04, 0x24, 0x89, 0x54, 0x24, 0x04, 0xff, 0xd6, 0x83, 0xec, 0x08, 0x81, 0xc4, 0x14, 0x02, 0x00, 0x00, 0x5b, 0x5e, 0xc2, 0x08, 0x00, 0x90, }); league.WriteMemory(codeCreateIteratorPointer, new byte[] { 0x31, 0xc0, 0xc2, 0x08, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, }); league.WriteMemory(codeVectorDeleterPointer, new byte[] { 0x89, 0xc8, 0xc2, 0x04, 0x00, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, }); league.WriteMemory(codeIsRadsPointer, new byte[] { 0x31, 0xc0, 0xc3, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, }); // Mark shellcode executable // League AC will trip over if we allocate ReadWriteExecutable in one go // So page can only be either ReadWrite or Executable league.MarkMemoryExecutable(codePointer, 0x900); uint modifiedPMethPointer = league.Allocate <EVP_PKEY_METHOD>(); uint orgignalPMethArrayPointer = this.PMethArrayOffset + league.Base; // Read first pointer when it gets initialized(tnx pacman) uint originalPMethFirstPointer = league.WaitPointerNonZero(orgignalPMethArrayPointer); // Read first PKEY_METHOD EVP_PKEY_METHOD originalPMeth = league.Read <EVP_PKEY_METHOD>(originalPMethFirstPointer); // Change verify function pointer originalPMeth.verify = codeVerifyPointer; // Write our new PKEY_METHOD league.Write(modifiedPMethPointer, originalPMeth); // Write the pointer to out PKEY_METHOD into pointer array league.Write(orgignalPMethArrayPointer, modifiedPMethPointer); uint orginalFileProviderListPointer = this.FileProviderListOffset + league.Base; // Those get deallocated upon exit so we need separate pages uint modifiedFileProviderPointer = league.Allocate <FileProvider>(); uint modifiedFileProviderVtablePointer = league.Allocate <FileProviderVtable>(); league.Write(modifiedFileProviderPointer, new FileProvider { vtable = modifiedFileProviderVtablePointer, list = orginalFileProviderListPointer, prefixFn = codePrefixFnPointer, prefix = _prefixBytes, }); league.Write(modifiedFileProviderVtablePointer, new FileProviderVtable { Open = codeOpenPointer, CheckAccess = codeCheckAccessPointer, CreateIterator = codeCreateIteratorPointer, VectorDeleter = codeVectorDeleterPointer, IsRads = codeIsRadsPointer, }); // Wait until providers have been registerd(first pointer turns non-0) league.WaitPointerNonZero(orginalFileProviderListPointer); FileProviderList originalFileProviderList = league.Read <FileProviderList>(orginalFileProviderListPointer); league.Write(orginalFileProviderListPointer, new FileProviderList { fileProviderPointer0 = modifiedFileProviderPointer, fileProviderPointer1 = originalFileProviderList.fileProviderPointer0, fileProviderPointer2 = originalFileProviderList.fileProviderPointer1, fileProviderPointer3 = originalFileProviderList.fileProviderPointer2, size = originalFileProviderList.size + 1, }); }