public String fetchRoflDownloadUrl(UInt64 matchId) { IntPtr funcAddr = _leagueClientMemoryEditor.AllocateMemory(asm.Length); //Structs not packed so 0x18 instead of 0x14 and 0xC is skipped IntPtr paramsAddr = _leagueClientMemoryEditor.AllocateMemory(0x18); //Write our custom function _leagueClientMemoryEditor.WriteBytes(funcAddr, asm); //Function Address is the address which our custom asm calls _leagueClientMemoryEditor.WriteUInt32(paramsAddr, _functionAddress); //Class Address is ECX, a class which is initialized which gets passed in to above function _leagueClientMemoryEditor.WriteUInt32(paramsAddr + 0x4, _classAddress); //Successful call will place a ptr to the download link here _leagueClientMemoryEditor.WriteUInt32(paramsAddr + 0x8, 0); //+16 (0x10) not +12 (0xC) because it wasnt packed, MatchID is a MatchID _leagueClientMemoryEditor.WriteUInt64(paramsAddr + 0x10, matchId); //Call Func and wait for completion _leagueClientMemoryEditor.WaitForSingleObject(_leagueClientMemoryEditor.CreateRemoteThread(funcAddr, paramsAddr)); IntPtr downloadUrlIntPtr; //Read the download Ptr _leagueClientMemoryEditor.ReadIntPtr(paramsAddr + 0x8, out downloadUrlIntPtr); String downloadUrl = ""; //If its null then call failed, Match Might not exist, User might not be logged in etc if (downloadUrlIntPtr != IntPtr.Zero) { _leagueClientMemoryEditor.ReadNullTerminatedString(downloadUrlIntPtr, out downloadUrl); } //Free Memory of the ones we allocated and also the injected function //TODO: Get LeagueClient to free the memory of the download URL though this is minor, though still a memory leak //TODO: Potentially just allocated and reuse memory once? _leagueClientMemoryEditor.FreeMemory(funcAddr); _leagueClientMemoryEditor.FreeMemory(paramsAddr); return(downloadUrl); }
/* * Byte[] asm = { 0xE8, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x00, 0xA1, 0xC0, 0x00, 0x00, 0x00 }; * X86Disassembler d = new X86Disassembler(new MemoryStreamReader(asm)); * X86Instruction i = d.ReadNextInstruction(); * i = d.ReadNextInstruction(); * i = d.ReadNextInstruction(); */ private static void LoadWadFiles(IntPtr function1Address, int funcOffset, IntPtr functionAddress, IntPtr ECDSA) { uint functionLength; uint functionLength1; uint ECDSALen; MemoryEditor.FindPattern(@"\xC2\x04\x00\xCC", "xxxx", ECDSA, out ECDSALen); MemoryEditor.FindPattern(@"\xC2\x08\x00\xCC", "xxxx", functionAddress, out functionLength); MemoryEditor.FindPattern(@"\xC3\x57\xE8\x00\x00\x00\x00\xCC", "xxx????x", function1Address, out functionLength1); functionLength = (functionLength - (uint)functionAddress) + 4; ECDSALen = (ECDSALen - (uint)ECDSA) + 4; functionLength1 = (functionLength1 - (uint)function1Address) + 8; //Steal the function: Byte[] asmECDSA; MemoryEditor.ReadBytes(ECDSA, (int)ECDSALen, out asmECDSA); Byte[] asm1; MemoryEditor.ReadBytes(function1Address, (int)functionLength1, out asm1); Byte[] asm; MemoryEditor.ReadBytes(functionAddress, (int)functionLength, out asm); //Allocate and copy the function to our new memory IntPtr AllocatedMemory = MemoryEditor.AllocateMemory(0x1000); //MemoryEditor.WriteBytes(AllocatedMemory, asm); //Fix the bytecode for the new offsets: X86Disassembler disassembler = new X86Disassembler(new MemoryStreamReader(asmECDSA)); while (disassembler.BaseStream.Position != disassembler.BaseStream.Length) { X86Instruction instruction = disassembler.ReadNextInstruction(); if (instruction.Mnemonic == X86Mnemonic.Je && instruction.Offset == 0x49) { Buffer.BlockCopy(new Byte[] { 0x90, 0x90 }, 0, asmECDSA, (int)instruction.Offset, 2); continue; } if (instruction.Mnemonic != X86Mnemonic.Call || (instruction.Operand1 != null && instruction.Operand1.OperandUsage == X86OperandUsage.DwordPointer)) { continue; } if (instruction.Operand1.Value.ToString() == "Eax") { continue; } //Fix the Call: int offset; MemoryEditor.ReadInt(ECDSA + (int)instruction.Offset + 1, out offset); int callAddress = (5 + (int)instruction.Offset + (int)ECDSA) + offset; offset = callAddress - ((int)AllocatedMemory + (int)instruction.Offset + 5); Buffer.BlockCopy(BitConverter.GetBytes(offset), 0, asmECDSA, (int)instruction.Offset + 1, 4); } MemoryEditor.WriteBytes(AllocatedMemory, asmECDSA); AllocatedMemory += asmECDSA.Length; disassembler = new X86Disassembler(new MemoryStreamReader(asm)); while (disassembler.BaseStream.Position != disassembler.BaseStream.Length) { X86Instruction instruction = disassembler.ReadNextInstruction(); /*if (instruction.Mnemonic == X86Mnemonic.Jne) * { * Buffer.BlockCopy(new Byte[] { 0xEB }, 0, asm, (int)instruction.Offset, 1); * continue; * }*/ if (instruction.Mnemonic != X86Mnemonic.Call || (instruction.Operand1 != null && instruction.Operand1.OperandUsage == X86OperandUsage.DwordPointer)) { continue; } if (instruction.Offset == 0x128) { Buffer.BlockCopy(BitConverter.GetBytes(((int)AllocatedMemory - asmECDSA.Length) - ((int)AllocatedMemory + (int)instruction.Offset + 5)) , 0, asm, (int)instruction.Offset + 1, 4); continue; } //Fix the Call: int offset; MemoryEditor.ReadInt(functionAddress + (int)instruction.Offset + 1, out offset); int callAddress = (5 + (int)instruction.Offset + (int)functionAddress) + offset; offset = callAddress - ((int)AllocatedMemory + (int)instruction.Offset + 5); Buffer.BlockCopy(BitConverter.GetBytes(offset), 0, asm, (int)instruction.Offset + 1, 4); } MemoryEditor.WriteBytes(AllocatedMemory, asm); AllocatedMemory += asm.Length; disassembler = new X86Disassembler(new MemoryStreamReader(asm1)); while (disassembler.BaseStream.Position != disassembler.BaseStream.Length) { X86Instruction instruction = disassembler.ReadNextInstruction(); if (instruction.Mnemonic != X86Mnemonic.Call || (instruction.Operand1 != null && instruction.Operand1.OperandUsage == X86OperandUsage.DwordPointer)) { continue; } if (instruction.Offset == funcOffset) { Buffer.BlockCopy(BitConverter.GetBytes(((int)AllocatedMemory - asm.Length) - ((int)AllocatedMemory + (int)instruction.Offset + 5)) , 0, asm1, (int)instruction.Offset + 1, 4); continue; } //Fix the Call: int offset; MemoryEditor.ReadInt(function1Address + (int)instruction.Offset + 1, out offset); int callAddress = (5 + (int)instruction.Offset + (int)function1Address) + offset; offset = callAddress - ((int)AllocatedMemory + (int)instruction.Offset + 5); Buffer.BlockCopy(BitConverter.GetBytes(offset), 0, asm1, (int)instruction.Offset + 1, 4); } MemoryEditor.WriteBytes(AllocatedMemory, asm1); IntPtr LoadWadFunction = AllocatedMemory; AllocatedMemory += asm1.Length; //Allocate Variables IntPtr StringAddress = AllocatedMemory + 0x10; //0x38 for failedFunctionCallback AllocatedMemory = StringAddress + 0x110; byte[] customAsm = { 0x60, //pushad 0x6A, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x5B, //pop x2, 0x5B, 0x61, //popad 0xEB, 0xFE //Endless Loop so we know to correct the EIP }; Buffer.BlockCopy(BitConverter.GetBytes((uint)StringAddress), 0, customAsm, 0x4, 4); Buffer.BlockCopy(BitConverter.GetBytes((uint)LoadWadFunction - ((uint)AllocatedMemory + 0xD)), 0, customAsm, 0x9, 4); MemoryEditor.WriteBytes(AllocatedMemory, customAsm); int lockedEip = (int)AllocatedMemory + customAsm.Length - 2; MemoryEditor.Suspend(); MemoryEditor.Context context = MemoryEditor.GetThreadContext(); uint originalEip = context.Eip; //Load Each WADFile: foreach (String wadFile in WadFiles) { MemoryEditor.Suspend(); context.Eip = (uint)AllocatedMemory; MemoryEditor.SetThreadContext(context); MemoryEditor.WriteNullTerminatedString(StringAddress, wadFile); MemoryEditor.Resume(); //NOTE: THE CODE HAS TO RUN ON MAIN THREAD TO PROPERLY LOAD WADS //MemoryEditor.WaitForSingleObject(MemoryEditor.CreateRemoteThread(AllocatedMemory, IntPtr.Zero)); bool loop = true; while (loop) { context = MemoryEditor.GetThreadContext(); loop = context.Eip != lockedEip; MemoryEditor.Resume(); } } context.Eip = originalEip; MemoryEditor.SetThreadContext(context); MemoryEditor.FreeMemory(AllocatedMemory); }