Example #1
0
        private static bool FuncFind(Stream onstream, asmChunk fromfunction, uint required_stacksize, bool backwards, out asmInstruction found)
        {
            asmChunk curfunc;

            found = null;
            while (fromfunction.FindByType(x86_insn_type.insn_call, backwards, out found))
            {
                onstream.Position = found.ReadAddressOperand();
                curfunc           = disassembler.disassemble_chunk(onstream);
                if (StackSize(curfunc) == required_stacksize)
                {
                    return(true);
                }
                fromfunction.MoveNext();
            }
            return(false);
        }
Example #2
0
        public bool ExecuteActionList(Stream onstream, BinaryTree <uint, long> knowns, ref asmChunk curChunk, ref asmInstruction curInstruction, Stack <string> ErrorStack)
        {
            bool backwards = false;

            Tools.StreamHandler sh = new Tools.StreamHandler(onstream);

            knowns.Add(0, onstream.Position);

            uint i = 0;

            //first action must be chunk or func parse
            foreach (Action currentaction in Actions)
            {
                switch (currentaction.m_type)
                {
                case ActionType.DISASM_CHUNK:
                    if (!knowns.ContainsKey((uint)currentaction.knownpar))
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] Missing Dependency: " + currentaction.knownpar.ToString());
                        return(false);
                    }
                    onstream.Position = knowns[(uint)currentaction.knownpar];
                    curChunk          = disassembler.disassemble_chunk(onstream);
                    break;

                case ActionType.DISASM_FUNCTION:
                    if (!knowns.ContainsKey((uint)currentaction.knownpar))
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] Missing Dependency: " + currentaction.knownpar.ToString());
                        return(false);
                    }
                    onstream.Position = knowns[(uint)currentaction.knownpar];
                    curChunk          = disassembler.disassemble_function(onstream);
                    break;

                case ActionType.FIND_SEQUENCE:
                    if (curChunk == null)
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] No disassembled code chunk available to search!");
                        return(false);
                    }
                    if (!currentaction.seqpar.Find(curChunk, backwards, knowns, out curInstruction))
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] Failed to find sequence: " + currentaction.seqpar.name);
                        return(false);
                    }
                    break;

                case ActionType.FOLLOW_CALL:
                    if ((curInstruction == null) || (curInstruction.Instruction.type != x86_insn_type.insn_call))
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] Need a call instruction to follow!");
                        return(false);
                    }
                    onstream.Position = curInstruction.ReadAddressOperand();
                    if (currentaction.boolpar)
                    {
                        curChunk = disassembler.disassemble_chunk(onstream);
                    }
                    else
                    {
                        curChunk = disassembler.disassemble_function(onstream);
                    }
                    break;

                case ActionType.JUMP_KNOWN:
                    if (!knowns.ContainsKey((uint)currentaction.knownpar))
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] Missing Dependency: " + currentaction.knownpar.ToString());
                        return(false);
                    }
                    knowns.Remove(0);
                    knowns.Add(0, knowns[(uint)currentaction.knownpar]);
                    onstream.Position = knowns[(uint)currentaction.knownpar];
                    break;

                case ActionType.RETURN_ADDRESS:
                    if (curInstruction == null)
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] No Current Instruction!");
                        return(false);
                    }
                    knowns.Remove((uint)currentaction.knownpar);
                    knowns.Add((uint)currentaction.knownpar, curInstruction.Address);
                    break;

                case ActionType.RETURN_DATA:
                    if ((curInstruction == null) || ((int)currentaction.uintpar > (curInstruction.Operands.Count - 1)))
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] No Suitable Current Instruction!");
                        return(false);
                    }
                    knowns.Remove((uint)currentaction.knownpar);
                    if (curInstruction.Operands[(int)currentaction.uintpar].Type == x86_op_type.op_expression)
                    {
                        knowns.Add((uint)currentaction.knownpar, (long)curInstruction.Operands[(int)currentaction.uintpar].Data.expression.disp);
                    }
                    else if (curInstruction.Operands[(int)currentaction.uintpar].Type == x86_op_type.op_offset)
                    {
                        knowns.Add((uint)currentaction.knownpar, (long)curInstruction.Operands[(int)currentaction.uintpar].Data.offset);
                    }
                    else
                    {
                        knowns.Add((uint)currentaction.knownpar, (long)curInstruction.Operands[(int)currentaction.uintpar].Data.dword);
                    }
                    break;

                case ActionType.RETURN_DISP:
                    if ((curInstruction == null) || ((int)currentaction.uintpar > (curInstruction.Operands.Count - 1)))
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] No Suitable Current Instruction!");
                        return(false);
                    }
                    knowns.Remove((uint)currentaction.knownpar);
                    knowns.Add((uint)currentaction.knownpar, (long)curInstruction.Operands[(int)currentaction.uintpar].Data.expression.disp);
                    break;

                case ActionType.SET_BACKWARDS:
                    if (backwards != currentaction.boolpar)
                    {
                        backwards = currentaction.boolpar;
                    }
                    break;

                case ActionType.TO_END:
                    if (curChunk == null)
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] No disassembled code chunk available!");
                        return(false);
                    }
                    curChunk.ToEnd();
                    break;

                case ActionType.TO_START:
                    if (curChunk == null)
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] No disassembled code chunk available!");
                        return(false);
                    }
                    curChunk.ToStart();
                    break;

                case ActionType.RETURN_TARGETADDRESS:
                    if ((curInstruction == null) || ((int)currentaction.uintpar > (curInstruction.Operands.Count - 1)))
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] No Suitable Current Instruction!");
                        return(false);
                    }
                    knowns.Remove((uint)currentaction.knownpar);
                    knowns.Add((uint)currentaction.knownpar, curInstruction.ReadAddressOperand());
                    break;

                case ActionType.FUNC_FIND:
                    if (curChunk == null)
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] No disassembled code chunk available!");
                        return(false);
                    }
                    if (!FuncFind(onstream, curChunk, currentaction.uintpar, backwards, out curInstruction))
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] Failed to find stdcall function with stacksize 0x" + currentaction.uintpar.ToString("X") + "!");
                        return(false);
                    }
                    break;

                case ActionType.SWITCH:
                    if (!knowns.ContainsKey((uint)currentaction.knownpar))
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] Missing Dependency: " + currentaction.knownpar.ToString());
                        return(false);
                    }
                    sh.Position       = (knowns[(uint)currentaction.knownpar] + 4 * currentaction.uintpar);
                    onstream.Position = (long)sh.Read <uint>();
                    if (currentaction.boolpar)
                    {
                        curChunk = disassembler.disassemble_chunk(onstream);
                    }
                    else
                    {
                        curChunk = disassembler.disassemble_function(onstream);
                    }
                    break;

                case ActionType.CONDITIONAL:
                    if (currentaction.actlist != null)
                    {
                        if (currentaction.actlist.ExecuteActionList(onstream, knowns, ref curChunk, ref curInstruction, new Stack <string>()))
                        {
                            if (currentaction.ontrue != null)
                            {
                                if (!currentaction.ontrue.ExecuteActionList(onstream, knowns, ref curChunk, ref curInstruction, ErrorStack))
                                {
                                    ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] OnTrue handler (" + currentaction.ontrue.name + ") of Condition " + currentaction.actlist.ToString() + " failed!");
                                    return(false);
                                }
                            }
                        }
                        else
                        {
                            if (currentaction.onfalse != null)
                            {
                                if (!currentaction.onfalse.ExecuteActionList(onstream, knowns, ref curChunk, ref curInstruction, ErrorStack))
                                {
                                    ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] OnFalse handler (" + currentaction.onfalse.name + ") of Condition " + currentaction.actlist.ToString() + " failed!");
                                    return(false);
                                }
                            }
                        }
                    }
                    break;

                case ActionType.ASSIGN_VALUE:
                    if (knowns.ContainsKey((uint)currentaction.knownpar))
                    {
                        knowns.Remove((uint)currentaction.knownpar);
                    }
                    knowns.Add((uint)currentaction.knownpar, (long)currentaction.uintpar);
                    break;

                case ActionType.ASSIGN_KNOWN:
                    if (knowns.ContainsKey((uint)currentaction.knownpar))
                    {
                        knowns.Remove((uint)currentaction.knownpar);
                    }
                    if (!knowns.ContainsKey((uint)currentaction.knownpar2))
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] Missing Dependency: " + currentaction.knownpar2.ToString());
                        return(false);
                    }
                    knowns.Add((uint)currentaction.knownpar, knowns[(uint)currentaction.knownpar2]);
                    break;

                case ActionType.CHECK_INSTRUCTION:
                    if (curInstruction == null)
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] No Suitable Current Instruction!");
                        return(false);
                    }
                    if (!currentaction.tocheck.Check(curInstruction, knowns))
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] Instruction verification failed!");
                        return(false);
                    }
                    break;

                case ActionType.EXECUTE_ACTIONSLIST:
                    if (!currentaction.actlist.ExecuteActionList(onstream, knowns, ref curChunk, ref curInstruction, ErrorStack))
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] ActionList " + currentaction.actlist.name + " failed!");
                        return(false);
                    }
                    break;

                case ActionType.TRY_ACTIONLIST:
                    if (!currentaction.actlist.ExecuteActionList(onstream, knowns, ref curChunk, ref curInstruction, ErrorStack))
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] (Try) ActionList " + currentaction.actlist.name + " failed!");
                    }
                    break;

                case ActionType.FOLLOW_JMP:
                    if ((curInstruction == null) || (!((curInstruction.Instruction.type == x86_insn_type.insn_jmp) || (curInstruction.Instruction.type == x86_insn_type.insn_jcc))))
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] No Suitable Current Instruction!");
                        return(false);
                    }
                    onstream.Position = curInstruction.ReadAddressOperand();
                    if (currentaction.boolpar)
                    {
                        curChunk = disassembler.disassemble_chunk(onstream);
                    }
                    else
                    {
                        curChunk = disassembler.disassemble_function(onstream);
                    }
                    break;

                case ActionType.RETURN_SCALE:
                    if ((curInstruction == null) || ((int)currentaction.uintpar > (curInstruction.Operands.Count - 1)))
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] No Suitable Current Instruction!");
                        return(false);
                    }
                    knowns.Add((uint)currentaction.knownpar, (long)curInstruction.Operands[(int)currentaction.uintpar].Data.expression.scale);
                    break;

                case ActionType.FIND_LOOP:
                    if (curChunk != null)
                    {
                        if (!curChunk.FindLoop(out curInstruction))
                        {
                            ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] Failed to find a loop in the current code chunk!");
                            return(false);
                        }
                    }
                    break;

                case ActionType.RETURN_CHUNK_ADDRESS:
                    if (curChunk == null)
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] No disassembled code chunk available!");
                        return(false);
                    }
                    knowns.Add((uint)currentaction.knownpar, curChunk.Address);
                    break;

                case ActionType.MOVE_NEXT:
                    if (curChunk == null)
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] No disassembled code chunk available!");
                        return(false);
                    }
                    curChunk.MoveNext();
                    break;

                case ActionType.MOVE_PREVIOUS:
                    if (curChunk == null)
                    {
                        ErrorStack.Push("[#" + i.ToString() + " : " + currentaction.name + "] No disassembled code chunk available!");
                        return(false);
                    }
                    curChunk.MovePrevious();
                    break;
                }
                i++;
            }
            return(true);
        }
Example #3
0
        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);
        }