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);
        }
Пример #2
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);
        }
Пример #3
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!");
            }
        }
Пример #5
0
        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();
        }
Пример #6
0
        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,
            });
        }