/// <summary> /// Create new thread and execute code in it. Wait until execution ends /// </summary> /// <param name="pCode">Code to execute</param> /// <param name="size">Code size</param> /// <param name="callResult">Code return value</param> /// <returns>Status</returns> NTSTATUS RemoteExec::ExecInNewThread( PVOID pCode, size_t size, uint64_t& callResult ) { AsmJitHelper a; NTSTATUS dwResult = STATUS_SUCCESS; // Write code dwResult = CopyCode( pCode, size ); if (dwResult != STATUS_SUCCESS) return dwResult; bool switchMode = (_proc.core().native()->GetWow64Barrier().type == wow_64_32); auto pExitThread = _mods.GetExport( _mods.GetModule( L"ntdll.dll", LdrList, switchMode ? mt_mod64 : mt_default ), "NtTerminateThread" ).procAddress; if (pExitThread == 0) return LastNtStatus( STATUS_NOT_FOUND ); a.GenPrologue( switchMode ); // Prepare thread to run in x64 mode if(switchMode) { // Allocate new x64 activation stack auto createActStack = _mods.GetExport( _mods.GetModule( L"ntdll.dll", LdrList, mt_mod64 ), "RtlAllocateActivationContextStack" ).procAddress; if (createActStack) { a.GenCall( static_cast<size_t>(createActStack), { _userData.ptr<size_t>() + 0x3100 } ); a->mov( a->zax, _userData.ptr<size_t>( ) + 0x3100 ); a->mov( a->zax, a->intptr_ptr( a->zax ) ); a.SetTebPtr(); a->mov( a->intptr_ptr( a->zdx, 0x2C8 ), a->zax ); } } a.GenCall( _userCode.ptr<size_t>(), { } ); a.ExitThreadWithStatus( (size_t)pExitThread, _userData.ptr<size_t>() + INTRET_OFFSET ); // Execute code in newly created thread if (_userCode.Write( size, a->getCodeSize(), a->make() ) == STATUS_SUCCESS) { auto thread = _threads.CreateNew( _userCode.ptr<ptr_t>() + size, _userData.ptr<ptr_t>()/*, HideFromDebug*/ ); dwResult = thread.Join(); callResult = _userData.Read<uint64_t>( INTRET_OFFSET, 0 ); } else dwResult = LastNtStatus(); return dwResult; }
/// <summary> /// Execute code in context of our worker thread /// </summary> /// <param name="pCode">Cde to execute</param> /// <param name="size">Code size.</param> /// <param name="callResult">Execution result</param> /// <returns>Status</returns> NTSTATUS RemoteExec::ExecInWorkerThread( PVOID pCode, size_t size, uint64_t& callResult ) { NTSTATUS dwResult = STATUS_SUCCESS; // Create thread if needed CreateRPCEnvironment(); // Write code dwResult = CopyCode( pCode, size ); if (dwResult != STATUS_SUCCESS) return dwResult; if (_hWaitEvent) ResetEvent( _hWaitEvent ); // Patch KiUserApcDispatcher #ifdef USE64 if (!_apcPatched && IsWindows7OrGreater() && !IsWindows8OrGreater()) { if (_proc.core().native()->GetWow64Barrier().type == wow_64_32) { auto patchBase = _proc.nativeLdr().APC64PatchAddress(); if (patchBase != 0) { DWORD flOld = 0; _memory.Protect(patchBase, 6, PAGE_EXECUTE_READWRITE, &flOld); _memory.Write(patchBase + 0x2, (uint8_t)0x0C); _memory.Write( patchBase + 0x4, (uint8_t)0x90 ); _memory.Protect( patchBase, 6, flOld, nullptr ); } _apcPatched = true; } else _apcPatched = true; } #endif // Execute code in thread context if (QueueUserAPC( _userCode.ptr<PAPCFUNC>(), _hWorkThd.handle(), _userCode.ptr<ULONG_PTR>() )) { dwResult = WaitForSingleObject( _hWaitEvent, INFINITE ); callResult = _userData.Read<uint64_t>( RET_OFFSET, 0 ); } else return LastNtStatus(); // Ensure APC function fully returns Sleep( 1 ); return dwResult; }
void PragEnding( void ) /*********************/ { if( CurrEntry == NULL ) return; CurrInfo->use = CurrAlias->use; /* for compare */ if( memcmp( CurrAlias, CurrInfo, sizeof( aux_info ) ) == 0 ) { CurrEntry->info = CurrAlias; CurrAlias->use++; CMemFree( CurrInfo ); } else { CopyParms(); CopyLinkage(); CopyCode(); CopyObjName(); #if _CPU == _AXP CopyExceptRtn(); #endif CurrInfo->use = 1; CurrEntry->info = CurrInfo; } /* If this pragma defines code, check to see if we already have a function body */ if( CurrEntry->name != NULL && CurrEntry->info != NULL && CurrEntry->info->code != NULL ) { SYM_HANDLE sym_handle; SYM_ENTRY sym; if( 0 != (sym_handle = SymLook( CalcHash( CurrEntry->name, strlen( CurrEntry->name ) ), CurrEntry->name )) ) { SymGet( &sym, sym_handle ); if( ( sym.flags & SYM_DEFINED ) && ( sym.flags & SYM_FUNCTION ) ) { CErr2p( ERR_SYM_ALREADY_DEFINED, CurrEntry->name ); } } } CurrEntry->next = AuxList; AuxList = CurrEntry; }
bool Compiler::CreateData( VM::Data& data, int codeSize ) { // Entry point for the program is main function. const FunctionTag* pTag = GetFunctionTag( "main" ); if( pTag == 0 ){ error( "Function : main is not found." ); return false; } data.m_Command = new unsigned char[ codeSize ]; // Binary data. data.m_TextBuffer = new char[ m_TextTable.size() ]; // Source code. data.m_CommandSize = codeSize; // Binary size. data.m_TextSize = (int)m_TextTable.size(); // Source code size. data.m_ValueSize = (int)m_Variables[ 0 ].GetSize(); data.m_EntryPoint = m_Labels[ pTag->m_Index ].m_Pos; // Entry point.(main function) if( data.m_TextSize != 0 ){ memcpy( data.m_TextBuffer, &m_TextTable[ 0 ], data.m_TextSize ); } std::for_each( m_Statement.begin(), m_Statement.end(), CopyCode( data.m_Command ) ); return true; }
/// <summary> /// Execute code in context of any existing thread /// </summary> /// <param name="pCode">Cde to execute</param> /// <param name="size">Code size.</param> /// <param name="callResult">Execution result</param> /// <param name="thd">Target thread</param> /// <returns>Status</returns> NTSTATUS RemoteExec::ExecInAnyThread( PVOID pCode, size_t size, uint64_t& callResult, Thread& thd ) { NTSTATUS dwResult = STATUS_SUCCESS; CONTEXT_T ctx; // Prepare for remote exec CreateRPCEnvironment( true ); // Write code dwResult = CopyCode( pCode, size ); if (dwResult != STATUS_SUCCESS) return dwResult; if (_hWaitEvent) ResetEvent( _hWaitEvent ); if (!thd.Suspend()) return LastNtStatus(); if (thd.GetContext( ctx, CONTEXT_ALL, true )) { AsmJitHelper a; #ifdef USE64 const int count = 15; asmjit::host::GpReg regs[] = { asmjit::host::rax, asmjit::host::rbx, asmjit::host::rcx, asmjit::host::rdx, asmjit::host::rsi, asmjit::host::rdi, asmjit::host::r8, asmjit::host::r9, asmjit::host::r10, asmjit::host::r11, asmjit::host::r12, asmjit::host::r13, asmjit::host::r14, asmjit::host::r15, asmjit::host::rbp }; // // Preserve thread context // I don't care about FPU, XMM and anything else // a->sub( asmjit::host::rsp, count * WordSize ); // Stack must be aligned on 16 bytes a->pushf(); // // Save registers for (int i = 0; i < count; i++) a->mov( asmjit::host::Mem( asmjit::host::rsp, i * WordSize ), regs[i] ); a.GenCall( _userCode.ptr<size_t>(), { _userData.ptr<size_t>() } ); AddReturnWithEvent( a, mt_default, rt_int32, INTRET_OFFSET ); // Restore registers for (int i = 0; i < count; i++) a->mov( regs[i], asmjit::host::Mem( asmjit::host::rsp, i * WordSize ) ); a->popf(); a->add( asmjit::host::rsp, count * WordSize ); a->jmp( asmjit::Imm( ctx.Rip ) ); #else a->pusha(); a->pushf(); a.GenCall( _userCode.ptr<size_t>(), { _userData.ptr<size_t>() } ); AddReturnWithEvent( a, mt_default, rt_int32, INTRET_OFFSET ); a->popf(); a->popa(); a->push( (size_t)ctx.NIP ); a->ret(); #endif if (_userCode.Write( size, a->getCodeSize(), a->make() ) == STATUS_SUCCESS) { ctx.NIP = _userCode.ptr<size_t>() + size; if (!thd.SetContext( ctx, true )) dwResult = LastNtStatus(); } else dwResult = LastNtStatus(); } else dwResult = LastNtStatus(); thd.Resume(); if (dwResult == STATUS_SUCCESS) { WaitForSingleObject( _hWaitEvent, INFINITE ); callResult = _userData.Read<size_t>( INTRET_OFFSET, 0 ); } return dwResult; }
/// <summary> /// Execute code in context of any existing thread /// </summary> /// <param name="pCode">Cde to execute</param> /// <param name="size">Code size.</param> /// <param name="callResult">Execution result</param> /// <param name="thd">Target thread</param> /// <returns>Status</returns> NTSTATUS RemoteExec::ExecInAnyThread( PVOID pCode, size_t size, uint64_t& callResult, Thread& thd ) { NTSTATUS dwResult = STATUS_SUCCESS; CONTEXT_T ctx; // Prepare for remote exec CreateRPCEnvironment( true ); // Write code dwResult = CopyCode( pCode, size ); if (dwResult != STATUS_SUCCESS) return dwResult; if (_hWaitEvent) ResetEvent( _hWaitEvent ); if (!thd.Suspend()) return LastNtStatus(); if (thd.GetContext( ctx, CONTEXT_ALL, true )) { AsmJit::Assembler a; AsmJitHelper ah( a ); #ifdef _M_AMD64 const int count = 15; AsmJit::GPReg regs[] = { AsmJit::rax, AsmJit::rbx, AsmJit::rcx, AsmJit::rdx, AsmJit::rsi, AsmJit::rdi, AsmJit::r8, AsmJit::r9, AsmJit::r10, AsmJit::r11, AsmJit::r12, AsmJit::r13, AsmJit::r14, AsmJit::r15, AsmJit::rbp }; // // Preserve thread context // I don't care about FPU, XMM and anything else // a.sub(AsmJit::rsp, count * WordSize); // Stack must be aligned on 16 bytes a.pushfq(); // // Save registers for (int i = 0; i < count; i++) a.mov( AsmJit::Mem( AsmJit::rsp, i * WordSize ), regs[i] ); ah.GenCall( _userCode.ptr<size_t>(), { _userData.ptr<size_t>() } ); AddReturnWithEvent( ah, rt_int32, INTRET_OFFSET ); // Restore registers for (int i = 0; i < count; i++) a.mov( regs[i], AsmJit::Mem( AsmJit::rsp, i * WordSize ) ); a.popfq(); a.add( AsmJit::rsp, count * WordSize ); a.jmp( ctx.Rip ); #else a.pushad(); a.pushfd(); ah.GenCall( _userCode.ptr<size_t>(), { _userData.ptr<size_t>() } ); AddReturnWithEvent( ah, rt_int32, INTRET_OFFSET ); a.popfd(); a.popad(); a.push( ctx.NIP ); a.ret(); #endif if (_userCode.Write( size, a.getCodeSize(), a.make() ) == STATUS_SUCCESS) { ctx.NIP = _userCode.ptr<size_t>() + size; if (!thd.SetContext( ctx, true )) dwResult = LastNtStatus(); } else dwResult = LastNtStatus(); } else dwResult = LastNtStatus(); thd.Resume(); if (dwResult == STATUS_SUCCESS) { WaitForSingleObject( _hWaitEvent, INFINITE ); callResult = _userData.Read<size_t>( INTRET_OFFSET, 0 ); } return dwResult; }
TInt E32ImageFile_ELF::Translate(const char* aFileName, TUint aDataBase, TBool aAllowDllData, \ TBool aSymLkupEnabled) // // Translate a ELF format file to a E32Image file // { iSource = EElfFile; ELFFile elffile; if (!elffile.Init((const TText * const)aFileName)) return KErrGeneral; iFileName = strdup(aFileName); Adjust(ALIGN4(sizeof(E32ImageHeaderV))); // fixed for now because holes not supported SetDefaultHeader(); iHdr->iDllRefTableCount = elffile.NumberOfImportDlls(); iHdr->iExportDirCount = elffile.NumberOfExports(); iHdr->iCodeBase = elffile.iLinkedBase; if(aSymLkupEnabled) { if( !SetUpLookupTable(elffile) ) return KErrGeneral; } TInt size = ALIGN4(sizeof(E32ImageHeaderV)); // fixed for now because holes not supported iHdr->iCodeOffset = size; TInt pos = size; size+=DoCodeHeader(elffile); size += DoSymbolLookupHeader(elffile, size - pos); TInt nimports=elffile.NumberOfImports(); TInt importSectionSize; char *newImportSection=CreateImportSection(elffile, importSectionSize); TInt t=DoDataHeader(elffile, aDataBase); if (t>0) { iHdr->iDataOffset = size; size += t; } if (importSectionSize!=0) { iHdr->iImportOffset=size; size+=ALIGN4(importSectionSize); } char *newCodeRelocs=NULL; char *newDataRelocs=NULL; TInt codeRelocSize=0, dataRelocSize=0; TInt nCodeRelocs=elffile.NumberOfCodeRelocs(); TInt nDataRelocs=elffile.NumberOfDataRelocs(); if (nCodeRelocs + nDataRelocs) { Elf32_Rel **codeRelocs=new Elf32_Rel * [nCodeRelocs]; Elf32_Rel **dataRelocs=new Elf32_Rel * [nDataRelocs]; if (!elffile.GetRelocs(codeRelocs, dataRelocs)) return KErrGeneral; FixRelocs(elffile, codeRelocs, dataRelocs); if (elffile.iCodeSegmentHdr) newCodeRelocs=CreateRelocs(elffile, codeRelocs, nCodeRelocs, codeRelocSize, elffile.iCodeSegmentHdr->p_vaddr); if (elffile.iDataSegmentHdr) newDataRelocs=CreateRelocs(elffile, dataRelocs, nDataRelocs, dataRelocSize, elffile.iDataSegmentHdr->p_vaddr); if (codeRelocSize) { iHdr->iCodeRelocOffset = size; size += codeRelocSize; } if (dataRelocSize) { iHdr->iDataRelocOffset = size; size += dataRelocSize; } delete [] codeRelocs; delete [] dataRelocs; } Adjust(size); t=CopyCode(iData + pos, elffile); if (t<0) return KErrGeneral; pos += t; t = CopyExportSymInfo(iData+pos, elffile); if (t<0) return KErrGeneral; pos += t; pos += CopyData(iData + pos, elffile); if (nimports) { memcpy(iData + pos, newImportSection, importSectionSize); pos += ALIGN4(importSectionSize); } if (codeRelocSize) { memcpy(iData + pos, newCodeRelocs, codeRelocSize); pos += codeRelocSize; } if (dataRelocSize) { memcpy(iData + pos, newDataRelocs, dataRelocSize); pos += dataRelocSize; } // locate the entry point TUint entryPointOffset=elffile.GetEntryPointOffset(); // Arrange a header for this E32 Image iHdr->iCpuIdentifier = (TUint16)ECpuArmV4; // Import format is ELF-derived iHdr->iFlags |= KImageImpFmt_ELF; // ABI is ARM EABI iHdr->iFlags |= KImageABI_EABI; if (ImageIsDll(elffile)) { iHdr->iFlags |= KImageDll; if (iHdr->iDataSize && !aAllowDllData) return Print(EError, "Dll '%s' has initialised data.\n", iFileName); if (iHdr->iBssSize && !aAllowDllData) return Print(EError, "Dll '%s' has uninitialised data.\n", iFileName); } iHdr->iHeapSizeMin = elffile.iHeapCommittedSize; iHdr->iHeapSizeMax = elffile.iHeapReservedSize; iHdr->iStackSize = elffile.iStackCommittedSize; iHdr->iEntryPoint = entryPointOffset; TInt r = DetermineEntryPointType(); if (r == KErrCorrupt) return Print(EError, "File '%s': Bad Entry Point.\n", iFileName); else if (r == KErrNotSupported) return Print(EError, "File '%s': Bad Entry Point Type.\n", iFileName); SetUpExceptions(elffile); delete [] newImportSection; delete [] newCodeRelocs; delete [] newDataRelocs; return KErrNone; }