Example #1
0
/// <summary>
/// Create activation context
/// Target memory layout:
/// -----------------------------
/// | hCtx | ACTCTX | file_path |
/// -----------------------------
/// </summary>
/// <param name="path">Image file path.</param>
/// <param name="id">Manifest resource id</param>
/// <returns>true on success</returns>
bool MMap::CreateActx( const std::wstring& path, int id /*= 2 */ )
{
    AsmJit::Assembler a;
    AsmJitHelper ah( a );

    uint64_t result = 0;
    ACTCTXW act = { 0 };

    _pAContext = _process.memory().Allocate( 512, PAGE_READWRITE );
    
    act.cbSize = sizeof(act);
    act.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
    act.lpSource = reinterpret_cast<LPCWSTR>(_pAContext.ptr<size_t>() + sizeof(HANDLE) + sizeof(act));
    act.lpResourceName = MAKEINTRESOURCEW( id );

    bool switchMode = (_process.core().native()->GetWow64Barrier().type == wow_64_32);
    auto pCreateActx = _process.modules().GetExport( _process.modules().GetModule( L"kernel32.dll" ), "CreateActCtxW" );
    if (pCreateActx.procAddress == 0)
        return nullptr;

    // CreateActCtx(&act)
    // Emulate Wow64
    if (switchMode)
    {
        _ACTCTXW_T<DWORD> act32 = { 0 };

        act32.cbSize = sizeof(act32);
        act32.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
        act32.lpSource = _pAContext.ptr<DWORD>() + sizeof(HANDLE) + sizeof(act32);
        act32.lpResourceName = id ;

        a.push( _pAContext.ptr<DWORD>() + static_cast<DWORD>(sizeof(HANDLE)) );
        a.mov( AsmJit::eax, static_cast<DWORD>(pCreateActx.procAddress) );
        a.call( AsmJit::nax );
        a.mov( AsmJit::edx, _pAContext.ptr<DWORD>() );
        a.mov( AsmJit::dword_ptr( AsmJit::edx ), AsmJit::eax );

        auto pTermThd = _process.modules().GetExport( _process.modules().GetModule( L"ntdll.dll" ), "NtTerminateThread" );
        a.push( AsmJit::nax );
        a.push( DWORD( 0 ) );
        a.mov( AsmJit::eax, static_cast<DWORD>(pTermThd.procAddress) );
        a.call( AsmJit::nax );
        a.ret( 4 );
        
        // Write path to file
        _pAContext.Write( sizeof(HANDLE), act32 );
        _pAContext.Write( sizeof(HANDLE) + sizeof(act32), (path.length() + 1) * sizeof(wchar_t), path.c_str() );

        auto pCode = _process.memory().Allocate( 0x1000 );
        pCode.Write( 0, a.getCodeSize(), a.make() );

        result = _process.remote().ExecDirect( pCode.ptr<ptr_t>(), _pAContext.ptr<size_t>() + sizeof(HANDLE) );
    }
    // Native way
    else
    {
        ah.GenPrologue();

        ah.GenCall( static_cast<size_t>(pCreateActx.procAddress), { _pAContext.ptr<size_t>() + sizeof(HANDLE) } );

        a.mov( AsmJit::ndx, _pAContext.ptr<size_t>() );
        a.mov( AsmJit::sysint_ptr( AsmJit::ndx ), AsmJit::nax );

        _process.remote().AddReturnWithEvent( ah );
        ah.GenEpilogue();

        // Write path to file
        _pAContext.Write( sizeof(HANDLE), act );
        _pAContext.Write( sizeof(HANDLE) + sizeof(act), (path.length() + 1) * sizeof(wchar_t), path.c_str() );

        _process.remote().ExecInWorkerThread( a.make(), a.getCodeSize(), result );
    }


    if (reinterpret_cast<HANDLE>(result) == INVALID_HANDLE_VALUE)
    {
        _pAContext.Free();

        // SetLastError( err::mapping::CantCreateActx );
        return false;
    }

    return true;
}
Example #2
0
/// <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;
}