Esempio n. 1
0
	NTSTATUS ProcessMemory::Read(ptr_t dwAddress, size_t dwSize, PVOID pResult, bool handleHoles /*= false*/) {
		DWORD64 dwRead = 0;
		if(dwAddress == 0)
			return LastNtStatus(STATUS_INVALID_ADDRESS);
		LastNtStatus(STATUS_SUCCESS);
		// Simple read
		if(!handleHoles) {
			return _core.GetNative()->ReadProcessMemoryT(dwAddress, pResult, dwSize, &dwRead);
		}
		// Read all committed memory regions
		else {
			MEMORY_BASIC_INFORMATION64 mbi = {0};
			for(ptr_t memptr = dwAddress; memptr < dwAddress + dwSize; memptr = mbi.BaseAddress + mbi.RegionSize) {
				if(_core.GetNative()->VirtualQueryExT(memptr, &mbi) != STATUS_SUCCESS)
					continue;
				// Filter empty regions
				if(mbi.State != MEM_COMMIT || mbi.Protect == PAGE_NOACCESS)
					continue;
				uint64_t region_ptr = memptr - dwAddress;
				if(_core.GetNative()->ReadProcessMemoryT(mbi.BaseAddress,
					reinterpret_cast<uint8_t*>(pResult) + region_ptr,
					static_cast<size_t>(mbi.RegionSize),
					&dwRead) != STATUS_SUCCESS) {
					return LastNtStatus();
				}
			}
		}
		return STATUS_SUCCESS;
	}
Esempio n. 2
0
#include "Wow64Subsystem.h"
#include "../Misc/DynImport.h"
#include "../Include/Macro.h"

namespace blackbone
{

NativeWow64::NativeWow64( HANDLE hProcess )
    : Native( hProcess )
{
    HMODULE ntdll32 = GetModuleHandleW( L"Ntdll.dll" );

    DynImport::load( "NtWow64QueryInformationProcess64", ntdll32 );
    DynImport::load( "NtWow64AllocateVirtualMemory64",   ntdll32 );
    DynImport::load( "NtWow64QueryVirtualMemory64",      ntdll32 );
    DynImport::load( "NtWow64ReadVirtualMemory64",       ntdll32 );
    DynImport::load( "NtWow64WriteVirtualMemory64",      ntdll32 );
}

NativeWow64::~NativeWow64()
{
}

/// <summary>
/// Allocate virtual memory
/// </summary>
/// <param name="lpAddress">Allocation address</param>
/// <param name="dwSize">Region size</param>
/// <param name="flAllocationType">Allocation type</param>
/// <param name="flProtect">Memory protection</param>
/// <returns>Status code</returns>
NTSTATUS NativeWow64::VirualAllocExT( ptr_t& lpAddress, size_t dwSize, DWORD flAllocationType, DWORD flProtect )
{
    DWORD64 size64 = dwSize;
    static ptr_t ntavm = _local.GetProcAddress64( _local.getNTDLL64(), "NtAllocateVirtualMemory" );
    if (ntavm == 0)
        return STATUS_ORDINAL_NOT_FOUND;

    return static_cast<NTSTATUS>(_local.X64Call( ntavm, _hProcess, &lpAddress, 0, &size64, flAllocationType, flProtect ));
}

/// <summary>
/// Free virtual memory
/// </summary>
/// <param name="lpAddress">Memory address</param>
/// <param name="dwSize">Region size</param>
/// <param name="dwFreeType">Memory release type.</param>
/// <returns>Status code</returns>
NTSTATUS NativeWow64::VirualFreeExT( ptr_t lpAddress, size_t dwSize, DWORD dwFreeType )
{
    static ptr_t ntfvm = _local.GetProcAddress64( _local.getNTDLL64( ), "NtFreeVirtualMemory" );
    if (ntfvm == 0)
        return STATUS_ORDINAL_NOT_FOUND;

    DWORD64 tmpAddr = lpAddress;
    DWORD64 tmpSize = dwSize;

    return static_cast<NTSTATUS>(_local.X64Call( ntfvm, _hProcess, &tmpAddr, &tmpSize, dwFreeType ));
}

/// <summary>
/// Query virtual memory
/// </summary>
/// <param name="lpAddress">Address to query</param>
/// <param name="lpBuffer">Retrieved memory info</param>
/// <returns>Status code</returns>
NTSTATUS NativeWow64::VirtualQueryExT( ptr_t lpAddress, PMEMORY_BASIC_INFORMATION64 lpBuffer )
{
    return GET_IMPORT( NtWow64QueryVirtualMemory64 )( _hProcess, lpAddress, 0, lpBuffer, sizeof(MEMORY_BASIC_INFORMATION64), nullptr );
}

/// <summary>
/// Query virtual memory
/// </summary>
/// <param name="lpAddress">Address to query</param>
/// <param name="lpBuffer">Retrieved memory info</param>
/// <returns>Status code</returns>
NTSTATUS NativeWow64::VirtualQueryExT( ptr_t lpAddress, MEMORY_INFORMATION_CLASS infoClass, LPVOID lpBuffer, size_t bufSize )
{
    static ptr_t ntqvm = _local.GetProcAddress64( _local.getNTDLL64(), "NtQueryVirtualMemory" );
    if (ntqvm == 0)
        return STATUS_ORDINAL_NOT_FOUND;

    return static_cast<NTSTATUS>(_local.X64Call( ntqvm, _hProcess, lpAddress, infoClass, lpBuffer, bufSize, 0 ));
}

/// <summary>
/// Change memory protection
/// </summary>
/// <param name="lpAddress">Memory address.</param>
/// <param name="dwSize">Region size</param>
/// <param name="flProtect">New protection.</param>
/// <param name="flOld">Old protection</param>
/// <returns>Status code</returns>
NTSTATUS NativeWow64::VirtualProtectExT( ptr_t lpAddress, DWORD64 dwSize, DWORD flProtect, DWORD* flOld )
{
    static ptr_t ntpvm = _local.GetProcAddress64( _local.getNTDLL64(), "NtProtectVirtualMemory" );
    if (ntpvm == 0)
        return STATUS_ORDINAL_NOT_FOUND;

    return static_cast<NTSTATUS>(_local.X64Call( ntpvm, _hProcess, &lpAddress, &dwSize, flProtect, flOld ));
}

/// <summary>
/// Read virtual memory
/// </summary>
/// <param name="lpBaseAddress">Memory address</param>
/// <param name="lpBuffer">Output buffer</param>
/// <param name="nSize">Number of bytes to read</param>
/// <param name="lpBytes">Mumber of bytes read</param>
/// <returns>Status code</returns>
NTSTATUS NativeWow64::ReadProcessMemoryT( ptr_t lpBaseAddress, LPVOID lpBuffer, size_t nSize, DWORD64 *lpBytes /*= nullptr */ )
{
    DWORD64 junk = 0;
    if (lpBytes == nullptr)
        lpBytes = &junk;

    return GET_IMPORT( NtWow64ReadVirtualMemory64 )( _hProcess, lpBaseAddress, lpBuffer, nSize, lpBytes );
}

/// <summary>
/// Write virtual memory
/// </summary>
/// <param name="lpBaseAddress">Memory address</param>
/// <param name="lpBuffer">Buffer to write</param>
/// <param name="nSize">Number of bytes to read</param>
/// <param name="lpBytes">Mumber of bytes read</param>
/// <returns>Status code</returns>
NTSTATUS NativeWow64::WriteProcessMemoryT( ptr_t lpBaseAddress, LPCVOID lpBuffer, size_t nSize, DWORD64 *lpBytes /*= nullptr */ )
{
    DWORD64 junk = 0;
    if (lpBytes == nullptr)
        lpBytes = &junk;

    return GET_IMPORT( NtWow64WriteVirtualMemory64 )( _hProcess, lpBaseAddress, (LPVOID)lpBuffer, nSize, lpBytes );
}

/// <summary>
/// Call NtQueryInformationProcess for underlying process
/// </summary>
/// <param name="infoClass">Information class</param>
/// <param name="lpBuffer">Output buffer</param>
/// <param name="bufSize">Buffer size</param>
/// <returns>Status code</returns>
NTSTATUS NativeWow64::QueryProcessInfoT( PROCESSINFOCLASS infoClass, LPVOID lpBuffer, uint32_t bufSize )
{
    ULONG length = 0;
    return GET_IMPORT( NtWow64QueryInformationProcess64 )(_hProcess, infoClass, lpBuffer, bufSize, &length);
}


/// <summary>
/// Call NtSetInformationProcess for underlying process
/// </summary>
/// <param name="infoClass">Information class</param>
/// <param name="lpBuffer">Input buffer</param>
/// <param name="bufSize">Buffer size</param>
/// <returns>Status code</returns>
NTSTATUS NativeWow64::SetProcessInfoT( PROCESSINFOCLASS infoClass, LPVOID lpBuffer, uint32_t bufSize )
{
    static ptr_t ntspi = _local.GetProcAddress64( _local.getNTDLL64(), "NtSetInformationProcess" );
    if (ntspi == 0)
        return STATUS_ORDINAL_NOT_FOUND;

    return static_cast<NTSTATUS>(_local.X64Call( ntspi, _hProcess, infoClass, lpBuffer, bufSize ));
}

/// <summary>
/// Creates new thread in the remote process
/// </summary>
/// <param name="hThread">Created thread handle</param>
/// <param name="entry">Thread entry point</param>
/// <param name="arg">Thread argument</param>
/// <param name="flags">Creation flags</param>
/// <returns>Status code</returns>*/
NTSTATUS NativeWow64::CreateRemoteThreadT( HANDLE& hThread, ptr_t entry, ptr_t arg, CreateThreadFlags flags, DWORD access )
{
    // Try to use default routine if possible
    /*if(_wowBarrier.targetWow64 == true)
    {
        return Native::CreateRemoteThreadT( hThread, entry, arg, flags, access );
    }
    else*/
    {
        LastNtStatus( STATUS_SUCCESS );

        static DWORD64 NtCreateThreadEx = _local.GetProcAddress64( _local.getNTDLL64(), "NtCreateThreadEx" );

        if (NtCreateThreadEx == 0)
            return LastNtStatus( STATUS_ORDINAL_NOT_FOUND );

        // hThread can't be used directly because x64Call will zero stack space near variable
        DWORD64 hThd2 = NULL;

        NTSTATUS status = static_cast<NTSTATUS>(_local.X64Call(
            NtCreateThreadEx, &hThd2, access, NULL,
            _hProcess, entry, arg, flags,
            0, 0x1000, 0x100000, NULL
            ));

        hThread = reinterpret_cast<HANDLE>(hThd2);
        return status;
    }
}
Esempio n. 3
0
/// <summary>
/// Creates new thread in the remote process
/// </summary>
/// <param name="hThread">Created thread handle</param>
/// <param name="entry">Thread entry point</param>
/// <param name="arg">Thread argument</param>
/// <param name="flags">Creation flags</param>
/// <param name="access">Access override</param>
/// <returns>Status code</returns>
NTSTATUS Native::CreateRemoteThreadT( HANDLE& hThread, ptr_t entry, ptr_t arg, CreateThreadFlags flags, DWORD access /*= THREAD_ALL_ACCESS*/ )
{
    LastNtStatus( STATUS_SUCCESS );
    NTSTATUS status = 0; 
    auto pCreateThread = GET_IMPORT( NtCreateThreadEx );

    if (pCreateThread)
    {
        status = pCreateThread(
            &hThread, access, NULL,
            _hProcess, reinterpret_cast<PTHREAD_START_ROUTINE>(entry),
            reinterpret_cast<LPVOID>(arg), static_cast<DWORD>(flags),
            0, 0x1000, 0x100000, NULL
            );

        if (!NT_SUCCESS( status ))
            hThread = NULL;
    }
    else
    {
        DWORD win32Flags = 0;

        if (flags & CreateSuspended)
            win32Flags = CREATE_SUSPENDED;

        hThread = CreateRemoteThread( 
            _hProcess, NULL, 0, reinterpret_cast<PTHREAD_START_ROUTINE>(entry),
            reinterpret_cast<LPVOID>(arg), win32Flags, NULL
            );

        status = LastNtStatus();
    }

    return status;
}
Esempio n. 4
0
/// <summary>
/// Grant current process arbitrary privilege
/// </summary>
/// <param name="name">Privilege name</param>
/// <returns>Status</returns>
NTSTATUS Process::GrantPriviledge( const std::basic_string<TCHAR>& name )
{
    TOKEN_PRIVILEGES Priv, PrivOld;
    DWORD cbPriv = sizeof(PrivOld);
    HANDLE hToken;

    if (!OpenThreadToken( GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, FALSE, &hToken ))
    {
        if (GetLastError() != ERROR_NO_TOKEN)
            return LastNtStatus();

        if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken ))
            return LastNtStatus();
    }

    Priv.PrivilegeCount = 1;
    Priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    LookupPrivilegeValue( NULL, name.c_str(), &Priv.Privileges[0].Luid );

    if (!AdjustTokenPrivileges( hToken, FALSE, &Priv, sizeof(Priv), &PrivOld, &cbPriv ))
    {
        CloseHandle( hToken );
        return LastNtStatus();
    }

    if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
    {
        CloseHandle( hToken );
        return LastNtStatus();
    }
    
    return STATUS_SUCCESS;
}
Esempio n. 5
0
/// <summary>
///  Fix relocations if image wasn't loaded at base address
/// </summary>
/// <param name="pImage">image data</param>
/// <returns>true on success</returns>
bool MMap::RelocateImage( ImageContext* pImage )
{
    // Reloc delta
    size_t Delta = pImage->imgMem.ptr<size_t>() - static_cast<size_t>(pImage->PEImage.imageBase());

    // No need to relocate
    if (Delta == 0)
    {
        LastNtStatus( STATUS_SUCCESS );
        return true;
    }

    pe::RelocData* fixrec = reinterpret_cast<pe::RelocData*>(pImage->PEImage.DirectoryAddress( IMAGE_DIRECTORY_ENTRY_BASERELOC ));
    if (fixrec == nullptr)
    {
        // TODO: return proper error code
        LastNtStatus( STATUS_IMAGE_NOT_AT_BASE );
        return false;
    }

    while (fixrec->BlockSize)
    {
        DWORD count = (fixrec->BlockSize - 8) >> 1;             // records count

        for (DWORD i = 0; i < count; ++i)
        {
            WORD fixtype = (fixrec->Item[i].Type);              // fixup type
            WORD fixoffset = (fixrec->Item[i].Offset) % 4096;   // offset in 4K block

            // no fixup required
            if (fixtype == IMAGE_REL_BASED_ABSOLUTE)
                continue;

            // add delta 
            if (fixtype == IMAGE_REL_BASED_HIGHLOW || fixtype == IMAGE_REL_BASED_DIR64)
            {
                size_t fixRVA = static_cast<ULONG>(fixoffset) + fixrec->PageRVA;
                size_t val = *reinterpret_cast<size_t*>(
                    reinterpret_cast<size_t>(pImage->FileImage.base()) + fixoffset + fixrec->PageRVA) 
                    + Delta;

                // Apply relocation
                if (pImage->imgMem.Write( fixRVA, val ) != STATUS_SUCCESS)
                    return false;
            }
            else
            {
                // TODO: support for all remaining relocations
                LastNtStatus( STATUS_INVALID_IMAGE_FORMAT );
                return false;
            }
        }

        // next reloc entry
        fixrec = reinterpret_cast<pe::RelocData*>(reinterpret_cast<size_t>(fixrec) + fixrec->BlockSize);
    }

    return true;
}
Esempio n. 6
0
/// <summary>
/// Allocate virtual memory
/// </summary>
/// <param name="lpAddress">Allocation address</param>
/// <param name="dwSize">Region size</param>
/// <param name="flAllocationType">Allocation type</param>
/// <param name="flProtect">Memory protection</param>
/// <returns>Status code</returns>
NTSTATUS Native::VirualAllocExT( ptr_t& lpAddress, size_t dwSize, DWORD flAllocationType, DWORD flProtect )
{
    LastNtStatus( STATUS_SUCCESS );
    lpAddress = reinterpret_cast<ptr_t>
        (VirtualAllocEx( _hProcess, reinterpret_cast<LPVOID>(lpAddress), dwSize, flAllocationType, flProtect ));

    return LastNtStatus();
}
Esempio n. 7
0
/// <summary>
/// Query virtual memory
/// </summary>
/// <param name="lpAddress">Address to query</param>
/// <param name="lpBuffer">Retrieved memory info</param>
/// <returns>Status code</returns>
NTSTATUS Native::VirtualQueryExT( ptr_t lpAddress, PMEMORY_BASIC_INFORMATION64 lpBuffer )
{
    LastNtStatus( STATUS_SUCCESS );
    VirtualQueryEx(
        _hProcess, reinterpret_cast<LPCVOID>(lpAddress),
        reinterpret_cast<PMEMORY_BASIC_INFORMATION>(lpBuffer),
        sizeof( MEMORY_BASIC_INFORMATION )
        );

    return LastNtStatus();
}
Esempio n. 8
0
	bool MMap::RelocateImage(ImageContext* pImage) {
		BLACBONE_TRACE(L"ManualMap: Relocating image '%ls'", pImage->FilePath.c_str());
		// Reloc delta
		size_t Delta = pImage->imgMem.Ptr<size_t>() - static_cast<size_t>(pImage->peImage.ImageBase());
		// No need to relocate
		if(Delta == 0) {
			BLACBONE_TRACE(L"ManualMap: No need for relocation");
			LastNtStatus(STATUS_SUCCESS);
			return true;
		}
		auto start = pImage->peImage.DirectoryAddress(IMAGE_DIRECTORY_ENTRY_BASERELOC);
		auto end = start + pImage->peImage.DirectorySize(IMAGE_DIRECTORY_ENTRY_BASERELOC);
		RelocData* fixrec = reinterpret_cast<RelocData*>(start);
		if(fixrec == nullptr) {
			// TODO: return proper error code
			BLACBONE_TRACE(L"ManualMap: Can't relocate image, no relocation data");
			LastNtStatus(STATUS_IMAGE_NOT_AT_BASE);
			return false;
		}
		while((size_t)fixrec < end && fixrec->BlockSize) {
			DWORD count = (fixrec->BlockSize - 8) >> 1;             // records count
			for(DWORD i = 0; i < count; ++i) {
				WORD fixtype = (fixrec->Item[i].Type);              // fixup type
				WORD fixoffset = (fixrec->Item[i].Offset) % 4096;   // offset in 4K block
																	// no fixup required
				if(fixtype == IMAGE_REL_BASED_ABSOLUTE)
					continue;
				// add delta 
				if(fixtype == IMAGE_REL_BASED_HIGHLOW || fixtype == IMAGE_REL_BASED_DIR64) {
					size_t fixRVA = fixoffset + fixrec->PageRVA;
					size_t val = *reinterpret_cast<size_t*>(pImage->peImage.ResolveRVAToVA(fixoffset + fixrec->PageRVA)) + Delta;
					auto status = STATUS_SUCCESS;
					if(pImage->flags & HideVAD)
						status = Driver().WriteMem(_process.Id(), pImage->imgMem.Ptr() + fixRVA, sizeof(val), &val);
					else
						status = pImage->imgMem.Write(fixRVA, val);
					// Apply relocation
					if(!NT_SUCCESS(status)) {
						BLACBONE_TRACE(L"ManualMap: Failed to apply relocation at offset 0x%x. Status = 0x%x", fixRVA, status);
						return false;
					}
				} else {
					// TODO: support for all remaining relocations
					BLACBONE_TRACE(L"ManualMap: Abnormal relocation type %d. Aborting", fixtype);
					LastNtStatus(STATUS_INVALID_IMAGE_FORMAT);
					return false;
				}
			}
			// next reloc entry
			fixrec = reinterpret_cast<RelocData*>(reinterpret_cast<size_t>(fixrec) + fixrec->BlockSize);
		}
		return true;
	}
Esempio n. 9
0
/// <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;
}
Esempio n. 10
0
/// <summary>
/// Change memory protection
/// </summary>
/// <param name="lpAddress">Memory address.</param>
/// <param name="dwSize">Region size</param>
/// <param name="flProtect">New protection.</param>
/// <param name="flOld">Old protection</param>
/// <returns>Status code</returns>
NTSTATUS Native::VirtualProtectExT( ptr_t lpAddress, DWORD64 dwSize, DWORD flProtect, DWORD* flOld )
{
    DWORD junk = 0;
    if (!flOld)
        flOld = &junk;

    LastNtStatus( STATUS_SUCCESS );

    VirtualProtectEx( _hProcess, reinterpret_cast<LPVOID>(lpAddress), static_cast<SIZE_T>(dwSize), flProtect, flOld );

    return LastNtStatus();
}
Esempio n. 11
0
/// <summary>
/// Set WOW64 thread context
/// </summary>
/// <param name="hThread">Thread handle.</param>
/// <param name="ctx">Thread context</param>
/// <returns>Status code</returns>
NTSTATUS NativeWow64::SetThreadContextT( HANDLE hThread, _CONTEXT32& ctx )
{
    // Target process is x64. 32bit CONTEXT is not available.
    if (_wowBarrier.targetWow64 == false)
    {
        return STATUS_NOT_SUPPORTED;
    }
    else
    {
        LastNtStatus( STATUS_SUCCESS );
        SetThreadContext( hThread, reinterpret_cast<const CONTEXT*>(&ctx) );
        return LastNtStatus();
    }
}
Esempio n. 12
0
/// <summary>
/// Set WOW64 thread context
/// </summary>
/// <param name="hThread">Thread handle.</param>
/// <param name="ctx">Thread context</param>
/// <returns>Status code</returns>
NTSTATUS Native::SetThreadContextT( HANDLE hThread, _CONTEXT32& ctx )
{
    // Target process is x64. 32bit CONTEXT is not available.
    if (_wowBarrier.targetWow64 == false)
    {
        return 0;
    }
    else
    {
        LastNtStatus( STATUS_SUCCESS );
        SAFE_CALL( Wow64SetThreadContext, hThread, reinterpret_cast<PWOW64_CONTEXT>(&ctx));
        return LastNtStatus();
    }
}
Esempio n. 13
0
/// <summary>
/// Copy executable code into remote codecave for future execution
/// </summary>
/// <param name="pCode">Code to copy</param>
/// <param name="size">Code size</param>
/// <returns>Status</returns>
NTSTATUS RemoteExec::CopyCode( PVOID pCode, size_t size )
{
    if (!_userCode.valid())
        _userCode = _memory.Allocate( size );

    // Reallocate for larger code
    if (size > _userCode.size())
        if ((_userCode.Realloc(size)) == 0)
            return LastNtStatus();

    if (_userCode.Write( 0, size, pCode ) != STATUS_SUCCESS)
        return LastNtStatus();

    return STATUS_SUCCESS;
}
Esempio n. 14
0
/// <summary>
/// Reload driver
/// </summary>
/// <param name="path">Path to the driver file</param>
/// <returns>Status code</returns>
NTSTATUS DriverControl::Reload( std::wstring path /*= L"" */ )
{
    NTSTATUS status = STATUS_SUCCESS;

    Unload();

    // Use default path
    if (path.empty())
    {
        const wchar_t* filename = nullptr;

        if (IsWindows10OrGreater())
            filename = L"BlackBoneDrv10.sys";
        else if (IsWindows8Point1OrGreater())
            filename = L"BlackBoneDrv81.sys";
        else if (IsWindows8OrGreater())
            filename = L"BlackBoneDrv8.sys";
        else if (IsWindows7OrGreater())
            filename = L"BlackBoneDrv7.sys";
        else
            filename = L"BlackBoneDrv.sys";

        path = Utils::GetExeDirectory() + L"\\" + filename;
    }

    status = _loadStatus = LoadDriver( DRIVER_SVC_NAME, path );
    if (!NT_SUCCESS( status ))
    {
        BLACBONE_TRACE( L"Failed to load driver %ls. Status 0x%X", path.c_str(), status );
        return LastNtStatus( status );
    }

    _hDriver = CreateFileW(
                   BLACKBONE_DEVICE_FILE,
                   GENERIC_READ | GENERIC_WRITE,
                   FILE_SHARE_READ | FILE_SHARE_WRITE,
                   NULL, OPEN_EXISTING, 0, NULL
               );

    if (_hDriver == INVALID_HANDLE_VALUE)
    {
        status = LastNtStatus();
        BLACBONE_TRACE( L"Failed to open driver handle. Status 0x%X", status );
        return status;
    }

    return status;
}
Esempio n. 15
0
/// <summary>
/// Create environment for future remote procedure calls
///
/// _userData layout (x86/x64):
/// --------------------------------------------------------------------------------------------------------------------------
/// | Internal return value | Return value |  Last Status code  |  Event handle   |  Space for copied arguments and strings  |
/// -------------------------------------------------------------------------------------------------------------------------
/// |       8/8 bytes       |   8/8 bytes  |      8/8 bytes     |   16/16 bytes   |                                          |
/// --------------------------------------------------------------------------------------------------------------------------
/// </summary>
/// <param name="noThread">Create only codecave and sync event, without thread</param>
/// <returns>Status</returns>
NTSTATUS RemoteExec::CreateRPCEnvironment( bool noThread /*= false*/ )
{
    NTSTATUS dwResult = STATUS_SUCCESS;
    DWORD thdID = 0;
    bool status = true;

    //
    // Allocate environment codecave
    //
    if (!_workerCode.valid())
        _workerCode = _memory.Allocate( 0x1000 );

    if (!_userData.valid())
        _userData = _memory.Allocate( 0x4000, PAGE_READWRITE );

    if (!_userCode.valid())
        _userCode = _memory.Allocate( 0x1000 );

    // Create RPC thread and sync event
    if (noThread == false)
    {
        thdID = CreateWorkerThread();
        if (thdID)
            status = CreateAPCEvent( thdID );
    }

    if (thdID == 0 || status == false)
        dwResult = LastNtStatus();

    return dwResult;
}
Esempio n. 16
0
/// <summary>
/// Maps single memory region into current process
/// </summary>
/// <param name="pid">Target PID</param>
/// <param name="base">Region base address</param>
/// <param name="size">Region size</param>
/// <param name="result">Mapped region info</param>
/// <returns>Status code</returns>
NTSTATUS DriverControl::MapMemoryRegion( DWORD pid, ptr_t base, uint32_t size, MapMemoryRegionResult& result )
{
    MAP_MEMORY_REGION data = { 0 };
    MAP_MEMORY_REGION_RESULT mapResult = { 0 };
    DWORD bytes = 0;

    // Not loaded
    if (_hDriver == INVALID_HANDLE_VALUE)
        return STATUS_DEVICE_DOES_NOT_EXIST;

    data.pid = pid;
    data.base = base;
    data.size = size;

    if (DeviceIoControl( _hDriver, IOCTL_BLACKBONE_MAP_REGION, &data, sizeof( data ), &mapResult, sizeof( mapResult ), &bytes, NULL ))
    {
        result.newPtr = mapResult.newPtr;
        result.originalPtr = mapResult.originalPtr;
        result.removedPtr = mapResult.removedPtr;
        result.removedSize = mapResult.removedSize;
        result.size = mapResult.size;

        return STATUS_SUCCESS;
    }

    return LastNtStatus();
}
Esempio n. 17
0
/// <summary>
/// Free virtual memory
/// </summary>
/// <param name="pid">Tarhet PID</param>
/// <param name="base">Desired base. If 0 address is chosed by the system</param>
/// <param name="size">Region size</param>
/// <param name="type">Free type - MEM_RELEASE/MEM_DECOMMIT</param>
/// <returns>Status code</returns>
NTSTATUS DriverControl::FreeMem( DWORD pid, ptr_t base, ptr_t size, DWORD type )
{
    DWORD bytes = 0;
    ALLOCATE_FREE_MEMORY freeMem = { 0 };
    ALLOCATE_FREE_MEMORY_RESULT result = { 0 };

    freeMem.pid = pid;
    freeMem.base = base;
    freeMem.size = size;
    freeMem.type = type;
    freeMem.allocate = FALSE;
    freeMem.physical = FALSE;

    // Not loaded
    if (_hDriver == INVALID_HANDLE_VALUE)
        return STATUS_DEVICE_DOES_NOT_EXIST;

    if (!DeviceIoControl(
        _hDriver, IOCTL_BLACKBONE_ALLOCATE_FREE_MEMORY,
        &freeMem, sizeof( freeMem ),
        &result, sizeof( result ), &bytes, NULL
        ))
    {
        return LastNtStatus();
    }

    return STATUS_SUCCESS;
}
Esempio n. 18
0
/// <summary>
/// Reallocate existing block for new size
/// </summary>
/// <param name="size">New block size</param>
/// <param name="desired">Desired base address of new block</param>
/// <param name="protection">Memory protection</param>
/// <returns>New block address</returns>
ptr_t MemBlock::Realloc( size_t size, ptr_t desired /*= 0*/, DWORD protection /*= PAGE_EXECUTE_READWRITE*/ )
{
    ptr_t desired64 = desired;
    _memory->core().native()->VirualAllocExT( desired64, size, MEM_COMMIT, protection );

    if (!desired64)
    {
        desired64 = 0;
        _memory->core( ).native( )->VirualAllocExT( desired64, size, MEM_COMMIT, protection );

        if (desired64)
            LastNtStatus( STATUS_IMAGE_NOT_AT_BASE );
    }

    // Replace current instance
    if (desired64)
    {
        Free();

        _ptr = desired64;
        _size = size;
        _protection = protection;
    }

    return desired64;
}
Esempio n. 19
0
/// <summary>
/// Inject DLL into arbitrary process
/// </summary>
/// <param name="pid">Target PID</param>
/// <param name="path">Full qualified dll path</param>
/// <param name="itype">Injection type</param>
/// <param name="initRVA">Init routine RVA</param>
/// <param name="initArg">Init routine argument</param>
/// <param name="unlink">Unlink module after injection</param>
/// <param name="erasePE">Erase PE headers after injection</param>
/// <param name="wait">Wait for injection</param>
/// <returns>Status code</returns>
NTSTATUS DriverControl::InjectDll(
    DWORD pid,
    const std::wstring& path,
    InjectType itype,
    uint32_t initRVA /*= 0*/,
    const std::wstring& initArg /*= L""*/,
    bool unlink /*= false*/,
    bool erasePE /*= false*/,
    bool wait /*= true*/
)
{
    DWORD bytes = 0;
    INJECT_DLL data = { IT_Thread };

    // Not loaded
    if (_hDriver == INVALID_HANDLE_VALUE)
        return STATUS_DEVICE_DOES_NOT_EXIST;

    wcscpy_s( data.FullDllPath, path.c_str() );
    wcscpy_s( data.initArg, initArg.c_str() );
    data.type = itype;
    data.pid = pid;
    data.initRVA = initRVA;
    data.wait = wait;
    data.unlink = unlink;
    data.erasePE = erasePE;

    if (!DeviceIoControl( _hDriver, IOCTL_BLACKBONE_INJECT_DLL, &data, sizeof( data ), nullptr, 0, &bytes, NULL ))
        return LastNtStatus();

    return STATUS_SUCCESS;
}
Esempio n. 20
0
/// <summary>
/// Allocate virtual memory
/// </summary>
/// <param name="pid">Tarhet PID</param>
/// <param name="base">Desired base. If 0 address is chosed by the system</param>
/// <param name="size">Region size</param>
/// <param name="type">Allocation type - MEM_RESERVE/MEM_COMMIT</param>
/// <param name="protection">Memory protection</param>
/// <returns>Status code</returns>
NTSTATUS DriverControl::AllocateMem( DWORD pid, ptr_t& base, ptr_t& size, DWORD type, DWORD protection, bool physical /*= false*/ )
{
    DWORD bytes = 0;
    ALLOCATE_FREE_MEMORY allocMem = { 0 };
    ALLOCATE_FREE_MEMORY_RESULT result = { 0 };

    allocMem.pid = pid;
    allocMem.base = base;
    allocMem.size = size;
    allocMem.type = type;
    allocMem.protection = protection;
    allocMem.allocate = TRUE;
    allocMem.physical = physical;

    // Not loaded
    if (_hDriver == INVALID_HANDLE_VALUE)
        return STATUS_DEVICE_DOES_NOT_EXIST;

    if (!DeviceIoControl( _hDriver, IOCTL_BLACKBONE_ALLOCATE_FREE_MEMORY, &allocMem, sizeof( allocMem ), &result, sizeof( result ), &bytes, NULL ))
    {
        size = base = 0;
        return LastNtStatus();
    }

    base = result.address;
    size = result.size;

    return STATUS_SUCCESS;
}
Esempio n. 21
0
/// <summary>
/// Manually map PE image
/// </summary>
/// <param name="pid">Target PID</param>
/// <param name="address">Memory location of the image to map</param>
/// <param name="size">Image size</param>
/// <param name="asImage">Memory chunk has image layout</param>
/// <param name="flags">Mapping flags</param>
/// <param name="initRVA">Init routine RVA</param>
/// <param name="initArg">Init routine argument</param>
/// <returns>Status code</returns>
NTSTATUS DriverControl::MmapDll(
    DWORD pid,
    void* address,
    uint32_t size,
    bool asImage,
    KMmapFlags flags,
    uint32_t initRVA /*= 0*/,
    const std::wstring& initArg /*= L"" */
)
{
    DWORD bytes = 0;
    INJECT_DLL data = { IT_MMap };

    memset( data.FullDllPath, 0, sizeof( data.FullDllPath ) );
    wcscpy_s( data.initArg, initArg.c_str() );

    data.pid = pid;
    data.initRVA = initRVA;
    data.wait = true;
    data.unlink = false;
    data.erasePE = false;
    data.flags = flags;
    data.imageBase = (ULONGLONG)address;
    data.imageSize = size;
    data.asImage = asImage;

    if (!DeviceIoControl( _hDriver, IOCTL_BLACKBONE_INJECT_DLL, &data, sizeof( data ), nullptr, 0, &bytes, NULL ))
        return LastNtStatus();

    return STATUS_SUCCESS;
}
Esempio n. 22
0
/// <summary>
/// Manually map PE image
/// </summary>
/// <param name="pid">Target PID</param>
/// <param name="path">Full qualified image path</param>
/// <param name="flags">Mapping flags</param>
/// <param name="initRVA">Init routine RVA</param>
/// <param name="initArg">Init routine argument</param>
/// <returns>Status code</returns>
NTSTATUS DriverControl::MmapDll(
    DWORD pid,
    const std::wstring& path,
    KMmapFlags flags,
    uint32_t initRVA /*= 0*/,
    const std::wstring& initArg /*= L"" */
)
{
    DWORD bytes = 0;
    INJECT_DLL data = { IT_MMap };
    UNICODE_STRING ustr = { 0 };

    // Convert path to native format
    SAFE_NATIVE_CALL( RtlDosPathNameToNtPathName_U, path.c_str(), &ustr, nullptr, nullptr );
    wcscpy_s( data.FullDllPath, ustr.Buffer );
    SAFE_CALL( RtlFreeUnicodeString, &ustr );

    wcscpy_s( data.initArg, initArg.c_str() );

    data.pid = pid;
    data.initRVA = initRVA;
    data.wait = true;
    data.unlink = false;
    data.erasePE = false;
    data.flags = flags;
    data.imageBase = 0;
    data.imageSize = 0;
    data.asImage = false;

    if (!DeviceIoControl( _hDriver, IOCTL_BLACKBONE_INJECT_DLL, &data, sizeof( data ), nullptr, 0, &bytes, NULL ))
        return LastNtStatus();

    return STATUS_SUCCESS;
}
Esempio n. 23
0
/// <summary>
/// Free memory
/// </summary>
/// <param name="size">Size of memory chunk to free. If 0 - whole block is freed</param>
NTSTATUS MemBlock::Free( size_t size /*= 0*/ )
{
    if (_ptr != 0)
    {
        size = Align( size, 0x1000 );

        NTSTATUS status = _physical ? Driver().FreeMem( _memory->core().pid(), _ptr, size, MEM_RELEASE ) :
            _memory->Free( _ptr, size, size == 0 ? MEM_RELEASE : MEM_DECOMMIT );

        if (!NT_SUCCESS( status ))
            return LastNtStatus();

        if(size == 0)
        {
            _ptr  = 0;
            _size = 0;
            _protection = 0;
        }
        else
        {
            _ptr  += size;
            _size -= size;
        }
    }

    return STATUS_SUCCESS;
}
Esempio n. 24
0
/// <summary>
/// Add hardware breakpoint to thread
/// </summary>
/// <param name="addr">Breakpoint address</param>
/// <param name="type">Breakpoint type(read/write/execute)</param>
/// <param name="length">Number of bytes to include into breakpoint</param>
/// <returns>Index of used breakpoint; -1 if failed</returns>
int Thread::AddHWBP( ptr_t addr, HWBPType type, HWBPLength length )
{
    _CONTEXT64 context64 = { 0 };
    _CONTEXT32 context32 = { 0 };
    bool use64 = !_core->native()->GetWow64Barrier().x86OS;

    // CONTEXT_DEBUG_REGISTERS can be operated without thread suspension
    bool res = use64 ? GetContext( context64, CONTEXT64_DEBUG_REGISTERS, true ) : GetContext( context32, CONTEXT_DEBUG_REGISTERS, true );
    auto pDR7 = use64 ? reinterpret_cast<regDR7*>(&context64.Dr7) : reinterpret_cast<regDR7*>(&context32.Dr7);
    if (!res)
        return -1;

    // Get free DR
    int freeIdx = pDR7->getFreeIndex();

    // If all 4 registers are occupied - error
    if (freeIdx < 0)
    {
        LastNtStatus( STATUS_NO_MORE_ENTRIES );
        return -1;
    }

    // Enable corresponding HWBP and local BP flag

    pDR7->l_enable = 1;
    pDR7->setLocal( freeIdx, 1 );
    pDR7->setRW( freeIdx, static_cast<char>(type) );
    pDR7->setLen( freeIdx, static_cast<char>(length) );

    use64 ? *(&context64.Dr0 + freeIdx) = addr : *(&context32.Dr0 + freeIdx) = static_cast<DWORD>(addr);

    // Write values to registers
    res = use64 ? SetContext( context64, true ) : SetContext( context32, true );
    return res ? freeIdx : -1;
}
Esempio n. 25
0
/// <summary>
/// Generate assembly code for remote call.
/// </summary>
/// <param name="a">Underlying assembler object</param>
/// <param name="pfn">Remote function pointer</param>
/// <param name="args">Function arguments</param>
/// <param name="cc">Calling convention</param>
/// <param name="retType">Return type</param>
/// <returns>true on success</returns>
bool RemoteExec::PrepareCallAssembly( AsmHelperBase& a, 
                                      const void* pfn, 
                                      std::vector<AsmVariant>& args, 
                                      eCalligConvention cc, 
                                      eReturnType retType )
{
    size_t data_offset = ARGS_OFFSET;

    // Invalid calling convention
    if (cc < cc_cdecl || cc > cc_fastcall)
    {
        LastNtStatus( STATUS_INVALID_PARAMETER_3 );
        return false;
    }

    // Copy structures and strings
    for (auto& arg : args)
    {
        if (arg.type == AsmVariant::dataStruct || arg.type == AsmVariant::dataPtr)
        {
            _userData.Write( data_offset, arg.size, reinterpret_cast<const void*>(arg.imm_val) );
            arg.new_imm_val = _userData.ptr<size_t>() + data_offset;

            // Add some padding after data
            data_offset += arg.size + 0x10;
        }
    }

    // Insert hidden variable if return type is struct.
    // This variable contains address of buffer in which return value is copied
    if (retType == rt_struct)
    {
        args.emplace( args.begin(), AsmVariant( _userData.ptr<size_t>() + ARGS_OFFSET ) );
        args.front().new_imm_val = args.front().imm_val;
        args.front().type = AsmVariant::structRet;
    }
        
    a.GenPrologue();
    a.GenCall( pfn, args, cc );

    // Retrieve result from XMM0 or ST0
    if (retType == rt_float || retType == rt_double)
    {
        a->mov( asmjit::host::zax, _userData.ptr<size_t>() + RET_OFFSET );

#ifdef USE64
        if (retType == rt_double)
            a->movsd( asmjit::host::Mem( asmjit::host::zax, 0 ), asmjit::host::xmm0 );
        else
            a->movss( asmjit::host::Mem( asmjit::host::zax, 0 ), asmjit::host::xmm0 );
#else
        a->fstp( asmjit::host::Mem( asmjit::host::zax, 0, retType * sizeof(float) ) );
#endif
    }

    AddReturnWithEvent( a, mt_default, retType );
    a.GenEpilogue();

    return true;
}
Esempio n. 26
0
/// <summary>
/// Create environment for future remote procedure calls
///
/// _userData layout (x86/x64):
/// --------------------------------------------------------------------------------------------------------------------------
/// | Internal return value | Return value |  Last Status code  |  Event handle   |  Space for copied arguments and strings  |
/// -------------------------------------------------------------------------------------------------------------------------
/// |       8/8 bytes       |   8/8 bytes  |      8/8 bytes     |   16/16 bytes   |                                          |
/// --------------------------------------------------------------------------------------------------------------------------
/// </summary>
/// <param name="noThread">Create only codecave and sync event, without thread</param>
/// <returns>Status</returns>
NTSTATUS RemoteExec::CreateRPCEnvironment( bool noThread /*= false*/ )
{
    NTSTATUS dwResult = STATUS_SUCCESS;
    DWORD thdID = 0;
    bool status = true;

    //
    // Allocate environment codecave
    //
    if (!_workerCode.valid())
        _workerCode = _memory.Allocate( 0x1000 );

    if (!_userData.valid())
        _userData = _memory.Allocate( 0x4000, PAGE_READWRITE );

    if (!_userCode.valid())
        _userCode = _memory.Allocate( 0x1000 );

    // Create RPC thread and sync event
    if (noThread == false)
        thdID = CreateWorkerThread();
    else
    // Randomize thread id for event name
        thdID = GetTickCount();
             
    auto& barrier = _proc.core().native()->GetWow64Barrier();
    if (barrier.type != wow_32_64)
        status = CreateAPCEvent( thdID );

    if ((noThread == false && thdID == 0) || status == false)
        dwResult = LastNtStatus();

    return dwResult;
}
Esempio n. 27
0
/// <summary>
/// Query virtual memory
/// </summary>
/// <param name="lpAddress">Address to query</param>
/// <param name="lpBuffer">Retrieved memory info</param>
/// <returns>Status code</returns>
NTSTATUS Native::VirtualQueryExT( ptr_t lpAddress, MEMORY_INFORMATION_CLASS infoClass, LPVOID lpBuffer, size_t bufSize )
{
    SIZE_T retLen = 0;

    LastNtStatus( STATUS_SUCCESS );
    
    return SAFE_NATIVE_CALL(
        NtQueryVirtualMemory, _hProcess, reinterpret_cast<LPVOID>(lpAddress),
        infoClass, lpBuffer, bufSize, &retLen
        );
}
Esempio n. 28
0
/// <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;
}
Esempio n. 29
0
/// <summary>
/// Load arbitrary driver
/// </summary>
/// <param name="svcName">Driver service name</param>
/// <param name="path">Driver file path</param>
/// <returns>Status</returns>
NTSTATUS DriverControl::LoadDriver( const std::wstring& svcName, const std::wstring& path )
{
    UNICODE_STRING Ustr;

    // If no file provided, try to start existing service
    if (!path.empty() && PrepareDriverRegEntry( svcName, path ) != 0)
        return LastNtStatus();

    std::wstring regPath = L"\\registry\\machine\\SYSTEM\\CurrentControlSet\\Services\\" + svcName;
    SAFE_CALL( RtlInitUnicodeString, &Ustr, regPath.c_str() );

    return SAFE_NATIVE_CALL( NtLoadDriver, &Ustr );
}
Esempio n. 30
0
/// <summary>
/// Map pure IL image
/// Not supported yet
/// </summary>
/// <returns>Image base</returns>
module_t MMap::MapPureManaged( )
{
    /*if(!netImg.Init(_pTopImage->FilePath))
    {
        SetLastError(0x1337);
        return 0;
    }*/

    //netImg.Parse();

    LastNtStatus( STATUS_NOT_IMPLEMENTED );
    return 0;
}