private InlineHook(QHackContext ctx, AssemblyCode code, HookParameters parameters) { Context = ctx; Code = code.Copy(); MemoryAllocation = new MemoryAllocation(ctx); Parameters = parameters; byte[] headInstBytes = GetHeadBytes(Context.DataAccess.ReadBytes(Parameters.TargetAddress, 32)); nuint allocAddr = MemoryAllocation.AllocationBase; nuint safeFreeFlagAddr = allocAddr + (uint)HookInfo.Offset_SafeFreeFlag; nuint onceFlagAddr = allocAddr + (uint)HookInfo.Offset_OnceFlag; nuint codeAddr = allocAddr + (uint)HookInfo.HeaderSize; nuint retAddr = Parameters.TargetAddress + (uint)headInstBytes.Length; HookInfo info = new(allocAddr, headInstBytes); Assembler assembler = new(); assembler.Emit(DataHelper.GetBytes(info)); //emit the header before runnable code assembler.Emit((Instruction)$"mov dword ptr [{safeFreeFlagAddr}],1"); assembler.Emit(Parameters.IsOnce ? GetOnceCheckedCode(Code, onceFlagAddr) : Code); //once or not if (Parameters.Original) { assembler.Emit(headInstBytes); //emit the raw code replaced by hook jmp } assembler.Emit((Instruction)$"mov dword ptr [{safeFreeFlagAddr}],0"); assembler.Emit((Instruction)$"jmp {retAddr}"); Context.DataAccess.WriteBytes(allocAddr, assembler.GetByteCode(allocAddr)); JmpHeadBytes = new byte[headInstBytes.Length]; Array.Fill <byte>(JmpHeadBytes, 0x90); Assembler.Assemble($"jmp {codeAddr}", Parameters.TargetAddress).CopyTo(JmpHeadBytes, 0); }
public static InlineHook Hook(QHackContext ctx, AssemblyCode code, HookParameters parameters) { var hook = new InlineHook(ctx, code, parameters); hook.Attach(); return(hook); }
private RemoteThread(QHackContext ctx, AssemblyCode asm, uint size = 0x1000) { Context = ctx; Allocation = new MemoryAllocation(ctx, size); Header = new RemoteThreadHeader(Allocation.AllocationBase); Assembler assembler = new(); assembler.Emit(DataHelper.GetBytes(Header)); assembler.Emit((Instruction)$"mov dword ptr [{Header.Address_SafeFreeFlag}],1"); assembler.Emit(asm); assembler.Emit((Instruction)$"mov dword ptr [{Header.Address_SafeFreeFlag}],0"); assembler.Emit((Instruction)"ret"); Context.DataAccess.WriteBytes(Header.AllocationAddress, assembler.GetByteCode(Header.AllocationAddress)); }
public static MemoryAllocation Alloc(QHackContext ctx, uint size = 0x1000) => new(ctx, size);
/// <summary> /// Do not use this. /// </summary> /// <param name="ctx"></param> /// <param name="base"></param> /// <param name="size"></param> internal MemoryAllocation(QHackContext ctx, nuint @base, uint size) { Context = ctx; AllocationBase = @base; AllocationSize = size; }
public MemoryAllocation(QHackContext ctx, uint size = 0x1000) { Context = ctx; AllocationBase = Alloc(ctx.Handle, size); AllocationSize = size; }
/// <summary> /// Allocates space and fills the code in before calling <see cref="RunOnNativeThread"/> to start a remote native thread.<br/> /// To avoid a memory leak, call <see cref="Dispose"/> to release the allocated space when the thread is not running. /// </summary> /// <param name="ctx"></param> /// <param name="asm"></param> /// <returns></returns> public static RemoteThread Create(QHackContext ctx, AssemblyCode asm) => new(ctx, asm);
/// <summary> /// Size is in bytes /// </summary> /// <param name="ctx"></param> /// <param name="base"></param> /// <param name="size"></param> public RemoteMemorySpan(QHackContext ctx, nuint @base, int size) { Context = ctx; Base = @base; Size = size; }