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); }