//static constructor: inject code required to perform the call once static UnmanagedCall() { uint loopaddress; uint code_alignment; uint pAddress; uint pStacksize; uint ppStack; uint pThisPar; uint pRetVal; uint pStackPointerBackup; AsmBuilder asm = new AsmBuilder(); //should use our own heap, not the default heap; since the code buffer needs execution rights m_Parameters = Allocator.AllocateBuffer(7 * 4); m_Code = Allocator.AllocateBuffer(61); data_alignment = ((uint)m_Parameters.Address) % 4; code_alignment = ((uint)m_Code.Address) % 4; pAddress = (uint)m_Parameters.Address + data_alignment + 4 * 0; pStacksize = (uint)m_Parameters.Address + data_alignment + 4 * 1; ppStack = (uint)m_Parameters.Address + data_alignment + 4 * 2; pThisPar = (uint)m_Parameters.Address + data_alignment + 4 * 3; pRetVal = (uint)m_Parameters.Address + data_alignment + 4 * 4; pStackPointerBackup = (uint)m_Parameters.Address + data_alignment + 4 * 5; //backup context asm.Instructions.Add(new PushAll()); asm.Instructions.Add(new BackupEsp(pStackPointerBackup)); //build stack asm.Instructions.Add(new MovEcxMemory(pStacksize)); asm.Instructions.Add(new MovEdxMemory(ppStack)); //store current position for the stack push loop loopaddress = code_alignment + (uint)asm.Size; //relative //build stack builder loop asm.Instructions.Add(new MovEaxEdx()); asm.Instructions.Add(new DereferEax()); asm.Instructions.Add(new PushEax()); asm.Instructions.Add(new AddEdx(4)); asm.Instructions.Add(new DecEcx()); asm.Instructions.Add(new JnzRelativeShort((int)loopaddress)); //build call asm.Instructions.Add(new MovEcxMemory(pThisPar)); asm.Instructions.Add(new CallFunctionPointer(pAddress)); //store return value asm.Instructions.Add(new MovMemoryEax(pRetVal)); //restore context asm.Instructions.Add(new RestoreEsp(pStackPointerBackup)); asm.Instructions.Add(new PopAll()); //return asm.Instructions.Add(new Rtn()); //write code asm.Write(m_Code, (int)code_alignment); //build function pointer m_Call = (SimpleCallDelegate)Marshal.GetDelegateForFunctionPointer((IntPtr)((uint)m_Code.Address + code_alignment), typeof(SimpleCallDelegate)); }
private LocalHook(uint address, ushort stack_cleanup_size, bool IsVtblEntry) { uint skip_call_address; asmInstruction curinsn = null; ProcessHandler curprocess = ProcessHandler.CurrentProcess; StreamHandler sh = new StreamHandler(curprocess); CallRelative crel; JmpRelative jrel; int readsize = 0; m_Address = address; m_VtblHook = IsVtblEntry; //read original target address curprocess.Position = address; if (IsVtblEntry) { original_address = sh.Read <uint>(); } else { curinsn = disassembler.disassemble(curprocess); if (curinsn.Instruction.type == x86_insn_type.insn_call) { original_address = (uint)curinsn.ReadAddressOperand(); } else { original_address = 0;//not hooking a call readsize = curinsn.Instruction.size; while (readsize < 5) { curinsn = disassembler.disassemble(curprocess); readsize += curinsn.Instruction.size; } copied_instructions = new byte[readsize]; curprocess.Position = address; curprocess.Read(copied_instructions, 0, readsize); } } //allocate required space (60 bytes) m_HookMemory = Allocator.AllocateBuffer((uint)(46 + 32 + readsize)); m_EspBackup = Allocator.AllocateBuffer(4); skip_call_address = (uint)(m_HookMemory.Address.ToInt32() + 35 + readsize); //build unmanaged function pointer m_Delegate = new InternalHookDelegate(ActualHook); m_LateDelegate = new InternalHookDelegate(ActualLateHook); IntPtr unmanaged_hook_pointer = Marshal.GetFunctionPointerForDelegate(m_Delegate); IntPtr unmanaged_hook_pointerb = Marshal.GetFunctionPointerForDelegate(m_LateDelegate); //build hook code AsmBuilder hookcode = new AsmBuilder(); hookcode.Instructions.Add(new PushAll()); hookcode.Instructions.Add(new BackupEsp((uint)m_EspBackup.Address.ToInt32())); hookcode.Instructions.Add(new PushImmediate(address)); hookcode.Instructions.Add(new CallRelative(unmanaged_hook_pointer.ToInt32())); hookcode.Instructions.Add(new TestEaxEax()); hookcode.Instructions.Add(new JzRelativeShort((int)skip_call_address)); hookcode.Instructions.Add(new RestoreEsp((uint)m_EspBackup.Address.ToInt32())); hookcode.Instructions.Add(new PopAll()); //switch vtbl: return, non-call : jmp address+readsize, call, jmp original hookcode.Write(curprocess, m_HookMemory.Address.ToInt32()); if (original_address == 0) { curprocess.Position = m_HookMemory.Address.ToInt32() + 30; curprocess.Write(copied_instructions, 0, readsize); hookcode = new AsmBuilder(); hookcode.Instructions.Add(new JmpRelative((int)address + readsize)); } else { hookcode = new AsmBuilder(); hookcode.Instructions.Add(new JmpRelative((int)original_address)); } //end_code hookcode.Instructions.Add(new RestoreEsp((uint)m_EspBackup.Address.ToInt32())); hookcode.Instructions.Add(new PopAll()); if (stack_cleanup_size == 0) { hookcode.Instructions.Add(new Rtn()); } else { hookcode.Instructions.Add(new RtnStackSize(stack_cleanup_size)); } hookcode.Write(curprocess, (int)m_HookMemory.Address.ToInt32() + 30 + readsize); hookcode = new AsmBuilder(); hookcode.Instructions.Add(new PushImmediate(0)); hookcode.Instructions.Add(new PushAll()); hookcode.Instructions.Add(new BackupEsp((uint)m_EspBackup.Address.ToInt32())); hookcode.Instructions.Add(new PushImmediate(address)); hookcode.Instructions.Add(new CallRelative(unmanaged_hook_pointerb.ToInt32())); hookcode.Instructions.Add(new RestoreEsp((uint)m_EspBackup.Address.ToInt32())); hookcode.Instructions.Add(new PopAll()); hookcode.Instructions.Add(new Rtn()); hookcode.Write(curprocess, (int)m_HookMemory.Address.ToInt32() + 46 + readsize); m_LateHookAddress = (uint)(m_HookMemory.Address.ToInt32() + 46 + readsize); //install hook if (original_address != 0) { if (IsVtblEntry) { //vtbl_hook sh.Position = address; sh.Write <int>(m_HookMemory.Address.ToInt32()); } else { crel = new CallRelative((int)m_HookMemory.Address.ToInt32()); if (crel.Size != curinsn.Instruction.size) { throw new Exception("Can only hook call instructions with size equal to " + crel.Size.ToString()); } crel.Write(curprocess, (int)address); curprocess.Position = address + crel.Size; } } else { //random hook jrel = new JmpRelative((int)m_HookMemory.Address.ToInt32()); jrel.Write(curprocess, (int)address); curprocess.Position = address + jrel.Size; for (uint i = 0; i < (readsize - jrel.Size); i++) { curprocess.WriteByte(0x90);//NOP } } m_Hooks.Add(address, this); }