public override void Compile(Instruction i, AsmBuilder ab, List <string> Offsets, MethodDefinition md) { if (!char.IsDigit(i.OpCode.Name.Split('.').Last()[0])) { //pop eax //mov dword[esp + 4], eax ab.Pop("eax"); ab.Mov("dword[ebp - " + (4 * (Convert.ToInt32(i.Operand.ToString().Split('_').Last()) + 1)) + "]", "eax"); } else { //pop eax //mov dword[esp + 4], eax ab.Pop("eax"); ab.Mov("dword[ebp - " + (4 * (Convert.ToInt32(i.OpCode.Name.Split('.').Last()) + 1)) + "]", "eax"); } }
public override void Compile(Instruction i, AsmBuilder ab, List <string> Offsets, MethodDefinition md) { if (Compiler.PlugIndex.ContainsKey(Utils.SafeName(i.Operand.ToString()))) { ab.Comment("Pluged"); ab.Call(Compiler.PlugIndex[Utils.SafeName(i.Operand.ToString())]); } else { ab.Call(Utils.SafeName(i.Operand.ToString())); } if ((i.Operand as MethodReference).ReturnType.ToString() != typeof(void).ToString()) { ab.Push("eax"); } }
public CodeEmitor(string name, Dictionary <string, FuncMeta> funcs) { Name = name; m_fileName = name + "_Script.exe"; FuncName2MethodInfo = new Dictionary <string, MethodInfo>(); AsmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(name), AssemblyBuilderAccess.RunAndSave); var moduleBuilder = AsmBuilder.DefineDynamicModule(name + "_MainModule", m_fileName); TypeBuilder = moduleBuilder.DefineType(name + "_MainClass"); GlobalField = TypeBuilder.DefineField("s_global", typeof(Dictionary <string, object>), FieldAttributes.Static | FieldAttributes.Private); buildStaticConstructor(); BuildinCodeEmitor.emitBuildins(this); var stmts = from kv in funcs select new StmtNodeVisitor_CodeEmitor(this, kv.Value); foreach (var stmt in stmts) { stmt.emit(); } m_mainClass = TypeBuilder.CreateType(); }
public override void Compile(Instruction i, AsmBuilder ab, List <string> Offsets, MethodDefinition md) { ab.Pop("ebx"); //addres ab.Mov("al", "byte[ebx]"); ab.Push("eax"); }
public override void Compile(Instruction i, AsmBuilder ab, List <string> Offsets, MethodDefinition md) { ab.Mov("eax", "dword [" + Utils.SafeName(i.Operand.ToString()) + "]"); ab.Push("eax"); }
public override void Compile(Instruction i, AsmBuilder ab, List <string> Offsets, MethodDefinition md) { ab.Pop("eax"); //flag ab.Cmp("eax", "1"); ab.Jmpe(Utils.SafeName(md.FullName) + i.Operand.ToString().Split(':')[0]); }
public void save() { AsmBuilder.SetEntryPoint(m_mainClass.GetMethod("Main"), PEFileKinds.ConsoleApplication); AsmBuilder.Save(m_fileName); }
public override void Compile(Instruction i, AsmBuilder ab, List <string> Offsets, MethodDefinition md) { }
//injection: loads the CLR on the specified thread of the specified process //it thereafter basically does the following: // appdomain=CLR->CreateDomain(setupparameters={..., AppBase-path, ...}) // asm=appdomain->load(specified assembly) // asm->CreateInstance(specified type) //... i could have used the default appdomain, but when i was testing remoting from the injected code // i noticed that the defautl appdomain gets a basepath equal to that of the injected process, which // causes Remoting to fail as client/server are referring different assembly paths, and the injected remoting // code can't find the assembly when trying to read type info to setup remoting proxies. // Changing the basepath is impossible, so we just create a new appdomain with the right basepath and // run code there. public static void Inject(ProcessHandler onprocess, ThreadHandler onthread, Assembly toinject, Type tocreate) { StreamHandler sh = new StreamHandler(onprocess); IntPtr RemotePage = onprocess.Allocate(4096);//allocate one page of readable, writable and executable memory //inject data sh.Position = (long)RemotePage; //write GUIDs //- write CLSID_CorRuntimeHost IntPtr pCLSIDCorRuntimeHost = (IntPtr)sh.Position; sh.Write(CLSID_CorRuntimeHost.ToByteArray(), 0, 16); //- write IID_ICorRuntimeHost IntPtr pIID_ICorRuntimeHost = (IntPtr)sh.Position; sh.Write(IID_ICorRuntimeHost.ToByteArray(), 0, 16); //- write IID_IAppSetup (not the actualy name i think) IntPtr pIID_IAppSetup = (IntPtr)sh.Position; sh.Write(IID_IAppSetup.ToByteArray(), 0, 16); //- write IID_IAppDomain (not the actualy name i think) IntPtr pIID_IAppDomain = (IntPtr)sh.Position; sh.Write(IID_IAppDomain.ToByteArray(), 0, 16); //- write VARIANT (result var for AppDomain.CreateInstance) UINTARG VariantArg = new UINTARG(0); IntPtr pVariant = (IntPtr)sh.Position; sh.Write <UINTARG>(VariantArg); //reserve space for variables (<- this could be done better by using the stack?) //- reserve uint stackbackup IntPtr pStackBackup = (IntPtr)sh.Position; sh.Write <uint>(0); //- reserve RuntimeObject pointer IntPtr pRuntimeObject = (IntPtr)sh.Position; sh.Write <uint>(0); //- reserve Module Handle pointer IntPtr pHandle = (IntPtr)sh.Position; sh.Write <uint>(0); //- reserve Setup Object pointer (IUnknown version) IntPtr pSetupObject = (IntPtr)sh.Position; sh.Write <uint>(0); //- reserve AppSetup Object pointer (after QueryInterface, so IAppSetup version) IntPtr pAppSetupObject = (IntPtr)sh.Position; sh.Write <uint>(0); //- reserve AppDomain object pointer (IUnknown version) IntPtr pDomainObject = (IntPtr)sh.Position; sh.Write <uint>(0); //- reserve AppDomain object pointer (IAppDomain version, after QueryInterface) IntPtr pAppDomainObject = (IntPtr)sh.Position; sh.Write <uint>(0); //- reserve Assembly object pointer IntPtr pAsm = (IntPtr)sh.Position; sh.Write <uint>(0); //- reserve uint function pointers IntPtr pCorBindToRuntimeEx = (IntPtr)sh.Position; sh.Write <uint>(0); //- write strings (for loadlibrary calls) sh.EnsureAlignment(2); IntPtr pStrCorBindToRuntimeEx = (IntPtr)sh.Position; sh.WriteString("CorBindToRuntimeEx"); sh.EnsureAlignment(2); IntPtr pStrMSCorEE = (IntPtr)sh.Position; sh.WriteString("MSCorEE.dll"); sh.EnsureAlignment(2); IntPtr pStrwks = (IntPtr)sh.Position; sh.WriteUnicodeString("wks");//workstation mode sh.EnsureAlignment(2); IntPtr pStrDomainName = (IntPtr)sh.Position; sh.WriteUnicodeString("injected_domain_" + onprocess.PID.ToString("X")); sh.EnsureAlignment(2); IntPtr pStrAppBase = (IntPtr)(sh.Position + 4);//+4 to skip pre-pendend length sh.WriteBSTR(System.IO.Path.GetDirectoryName(toinject.Location)); sh.EnsureAlignment(2); IntPtr pAssemblyName = (IntPtr)(sh.Position + 4);//+4 to skip pre-pendend length sh.WriteBSTR(toinject.GetName().Name); sh.EnsureAlignment(2); IntPtr pTypeName = (IntPtr)(sh.Position + 4);//+4 to skip pre-pendend length sh.WriteBSTR(tocreate.FullName); //get required function addresses //- LoadLibraryA, GetProcAddress from KERNEL32.dll uint pLoadLibraryA = onprocess.MainModule.PEHeader.ImportedLibraries["KERNEL32.dll"].ImportedSymbols["LoadLibraryA"].Address; uint pGetProcAddress = onprocess.MainModule.PEHeader.ImportedLibraries["KERNEL32.dll"].ImportedSymbols["GetProcAddress"].Address; //build code AsmBuilder _asm = new AsmBuilder(); //safety measures : push all registers, save the stack pointer _asm.Instructions.Add(new PushAll()); _asm.Instructions.Add(new BackupEsp((uint)pStackBackup)); //build loadlibrary, getprocaddress calls to get the pCorBindToRuntimeEx from MSCorEE.dll _asm.Instructions.Add(new PushImmediate((uint)pStrMSCorEE)); _asm.Instructions.Add(new CallRelative((int)pLoadLibraryA)); _asm.Instructions.Add(new MovMemoryEax((uint)pHandle)); _asm.Instructions.Add(new PushImmediate((uint)pStrCorBindToRuntimeEx)); _asm.Instructions.Add(new PushEax()); _asm.Instructions.Add(new CallRelative((int)pGetProcAddress)); _asm.Instructions.Add(new MovMemoryEax((uint)pCorBindToRuntimeEx)); //build CorBindToRuntimeEx call _asm.Instructions.Add(new PushImmediate((uint)pRuntimeObject)); _asm.Instructions.Add(new PushImmediate((uint)pIID_ICorRuntimeHost)); _asm.Instructions.Add(new PushImmediate((uint)pCLSIDCorRuntimeHost)); _asm.Instructions.Add(new PushImmediate(2)); _asm.Instructions.Add(new PushImmediate((uint)pStrwks)); _asm.Instructions.Add(new PushImmediate((uint)0)); _asm.Instructions.Add(new CallFunctionPointer((uint)pCorBindToRuntimeEx)); //pRuntimeObject->Start() _asm.Instructions.Add(new MovEaxMemory((uint)pRuntimeObject)); _asm.Instructions.Add(new MovEcxMemory((uint)pRuntimeObject));//<- shouldn't be necessary, it's not a C++ object, but a COM object, so this doesn't have to be stored in ecx _asm.Instructions.Add(new PushEax()); _asm.Instructions.Add(new DereferEax()); _asm.Instructions.Add(new DereferEaxTable(0x28));//Start() is at 0x28 in the vtbl _asm.Instructions.Add(new CallEax()); //pRuntimeObject->CreateDomainSetup(IUnkown ** pSetup) _asm.Instructions.Add(new PushImmediate((uint)pSetupObject)); _asm.Instructions.Add(new MovEaxMemory((uint)pRuntimeObject)); _asm.Instructions.Add(new MovEcxMemory((uint)pRuntimeObject));//<- shouldn't be necessary, it's not a C++ object, but a COM object, so this doesn't have to be stored in ecx _asm.Instructions.Add(new PushEax()); _asm.Instructions.Add(new DereferEax()); _asm.Instructions.Add(new DereferEaxTable(0x48));//CreateDomainSetup() is at 0x48 in the vtbl _asm.Instructions.Add(new CallEax()); //pSetupObject->QueryInterface(&IID_IAppSetup, IID_IAppSetup ** pAppsetup) _asm.Instructions.Add(new PushImmediate((uint)pAppSetupObject)); _asm.Instructions.Add(new PushImmediate((uint)pIID_IAppSetup)); _asm.Instructions.Add(new MovEaxMemory((uint)pSetupObject)); _asm.Instructions.Add(new MovEcxMemory((uint)pSetupObject));//<- shouldn't be necessary, it's not a C++ object, but a COM object, so this doesn't have to be stored in ecx _asm.Instructions.Add(new PushEax()); _asm.Instructions.Add(new DereferEax()); _asm.Instructions.Add(new DereferEaxTable(0x0));//QueryInterface() is at 0x0 in the vtbl _asm.Instructions.Add(new CallEax()); //AppSetup->put_ApplicationBase(BSTR pStrAppBase) _asm.Instructions.Add(new PushImmediate((uint)pStrAppBase)); _asm.Instructions.Add(new MovEaxMemory((uint)pAppSetupObject)); _asm.Instructions.Add(new MovEcxMemory((uint)pAppSetupObject));//<- shouldn't be necessary, it's not a C++ object, but a COM object, so this doesn't have to be stored in ecx _asm.Instructions.Add(new PushEax()); _asm.Instructions.Add(new DereferEax()); _asm.Instructions.Add(new DereferEaxTable(0x10));//put_ApplicationBase is at 0x10 in the vtbl _asm.Instructions.Add(new CallEax()); //pRuntimeObject->CreateDomainEx(unicode string pStrDomainName,pAppSetup,0,&pDomain); _asm.Instructions.Add(new PushImmediate((uint)pDomainObject)); _asm.Instructions.Add(new PushImmediate(0)); _asm.Instructions.Add(new MovEaxMemory((uint)pAppSetupObject)); _asm.Instructions.Add(new PushEax()); _asm.Instructions.Add(new PushImmediate((uint)pStrDomainName)); _asm.Instructions.Add(new MovEaxMemory((uint)pRuntimeObject)); _asm.Instructions.Add(new MovEcxMemory((uint)pRuntimeObject));//<- shouldn't be necessary, it's not a C++ object, but a COM object, so this doesn't have to be stored in ecx _asm.Instructions.Add(new PushEax()); _asm.Instructions.Add(new DereferEax()); _asm.Instructions.Add(new DereferEaxTable(0x44));//CreateDomainEx is at 0x44 in the vtbl _asm.Instructions.Add(new CallEax()); //pDomainObject->QueryInterface(IID_IDomain, IAppDomain * pAppDomain) _asm.Instructions.Add(new PushImmediate((uint)pAppDomainObject)); _asm.Instructions.Add(new PushImmediate((uint)pIID_IAppDomain)); _asm.Instructions.Add(new MovEaxMemory((uint)pDomainObject)); _asm.Instructions.Add(new MovEcxMemory((uint)pDomainObject));//<- shouldn't be necessary, it's not a C++ object, but a COM object, so this doesn't have to be stored in ecx _asm.Instructions.Add(new PushEax()); _asm.Instructions.Add(new DereferEax()); _asm.Instructions.Add(new DereferEaxTable(0x0));//QueryInterface is at 0x0 in the vtbl _asm.Instructions.Add(new CallEax()); //pAppDomain->Load_2(pAssemblyName, &pAsm) _asm.Instructions.Add(new PushImmediate((uint)pAsm)); _asm.Instructions.Add(new PushImmediate((uint)pAssemblyName)); _asm.Instructions.Add(new MovEaxMemory((uint)pAppDomainObject)); _asm.Instructions.Add(new MovEcxMemory((uint)pAppDomainObject));//<- shouldn't be necessary, it's not a C++ object, but a COM object, so this doesn't have to be stored in ecx _asm.Instructions.Add(new PushEax()); _asm.Instructions.Add(new DereferEax()); _asm.Instructions.Add(new DereferEaxTable(0xB0));//Load_2 is at 0xB0 in the vtbl _asm.Instructions.Add(new CallEax()); //pAsm->CreateInstance(pTypeName,&pVariant) _asm.Instructions.Add(new PushImmediate((uint)pVariant)); _asm.Instructions.Add(new PushImmediate((uint)pTypeName)); _asm.Instructions.Add(new MovEaxMemory((uint)pAsm)); _asm.Instructions.Add(new MovEcxMemory((uint)pAsm));//<- shouldn't be necessary, it's not a C++ object, but a COM object, so this doesn't have to be stored in ecx _asm.Instructions.Add(new PushEax()); _asm.Instructions.Add(new DereferEax()); _asm.Instructions.Add(new DereferEaxTable(0xA4));//CreateInstance is at 0xA4 in the vtbl _asm.Instructions.Add(new CallEax()); //freelibrary? //safety measures : restore stack pointer, pop all registers _asm.Instructions.Add(new RestoreEsp((uint)pStackBackup)); _asm.Instructions.Add(new PopAll()); //write code //- suspend thread onthread.Suspend(); //- read the context ThreadHandler.CONTEXT ctx = onthread.Context; //- add a jmp to the original eip _asm.Instructions.Add(new JmpRelative((int)ctx.Eip)); //- code will be written at half the allocated page ctx.Eip = ((uint)RemotePage + (4096 / 2)); //- write code _asm.Write(onprocess, (int)ctx.Eip); //- set the thread's context (EIP now points to our code) onthread.Context = ctx; //- resume the thread (our code executes and jumps back to the original eip) onthread.Resume(); }
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); }