HMODULE CRemoteLoader::LoadLibraryByPathA( PCHAR Path ) { WCHAR Module[ MAX_PATH ] = { 0 }; mbstowcs( Module, Path, MAX_PATH ); DebugShout( "[LoadLibraryByPathA] ( %S <- %s )", Module, Path ); return LoadLibraryByPathW( Module ); }
HMODULE CRemoteLoader::LoadLibraryByPathIntoMemoryW( PWCHAR Path, BOOL PEHeader ) { CHAR PathAnsi[ MAX_PATH ] = { 0 }; wcstombs( PathAnsi, Path, MAX_PATH ); DebugShout( "[LoadLibraryByPathIntoMemoryW]( %S -> %s )( 0x%X )", Path, PathAnsi, PEHeader ); return LoadLibraryByPathIntoMemoryA( PathAnsi, PEHeader ); }
bool CRemoteCode::ExecuteRemoteThreadBuffer( remote_thread_buffer_t thread_data, bool async ) { unsigned long ulMemorySize = ( unsigned long )thread_data.size(); void *vRemoteMemory = RemoteAllocateMemory( ulMemorySize ); if( vRemoteMemory == NULL ) return false; unsigned char *newBuffer = new unsigned char[ thread_data.size() ]; for( int i = 0; i < (int)thread_data.size(); i++ ) { memcpy( &newBuffer[i], &thread_data[i], sizeof( unsigned char ) ); } BOOL bWriteProcess = WriteProcessMemory( m_hProcess, vRemoteMemory, newBuffer, thread_data.size(), NULL ); if( bWriteProcess == FALSE ) return false; DebugShout( "Memory written to process" ); HANDLE hThreadHandle = CreateRemoteThreadInProcess( ( LPTHREAD_START_ROUTINE )vRemoteMemory, NULL ); if( hThreadHandle == INVALID_HANDLE_VALUE ) return false; DebugShout( "Remote Buffer Executed in process 0x%X", m_hProcess ); if( async == true ) { WaitForSingleObject( hThreadHandle, INFINITE ); } RemoteFreeMemory( vRemoteMemory, ulMemorySize ); memset( &m_CurrentInvokeInfo, 0, sizeof( m_CurrentInvokeInfo ) ); m_CurrentRemoteThreadBuffer.clear(); return true; }
void CRemoteCode::PushParameter( parameter_type_t param_type, void *param ) { parameter_info_t pi; pi.ptype = param_type; pi.pparam = param; DebugShout( "Adding parameter to function [%i][0x%X]", pi.ptype, pi.pparam ); m_CurrentInvokeInfo.params.push_back( pi ); }
BOOL CRemoteLoader::ProcessTlsEntries( PVOID BaseAddress, PVOID RemoteAddress ) { IMAGE_NT_HEADERS* ImageNtHeaders = ToNts( BaseAddress ); if( ImageNtHeaders == NULL ) return FALSE; if( ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_TLS ].Size == 0 ) return TRUE; // Success when there is no Tls Entries DebugShout( "[ProcessTlsEntries] Tls Data detected!" ); IMAGE_TLS_DIRECTORY* TlsDirectory = ( IMAGE_TLS_DIRECTORY* ) RvaToPointer( ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_TLS ].VirtualAddress, BaseAddress ); if( TlsDirectory == NULL ) return TRUE; // Success when there is no Tls entries / broken data? DebugShout( "[ProcessTlsEntries] TlsDirectory (0x%X)", TlsDirectory ); if( TlsDirectory->AddressOfCallBacks == NULL ) return TRUE; // Success when there is no Tls entries / broken data? DebugShout( "[ProcessTlsEntries] TlsDirectory->AddressOfCallBacks (0x%X)", TlsDirectory->AddressOfCallBacks ); PIMAGE_TLS_CALLBACK TLSCallbacks[ 0xFF ]; if( ReadProcessMemory( GetProcess(), ( LPCVOID ) TlsDirectory->AddressOfCallBacks, TLSCallbacks, sizeof( TLSCallbacks ), NULL ) == FALSE ) { DebugShout( "[ProcessTlsEntries] Failed ReadProcessMemory" ); return FALSE; } BOOL SuccessValue = TRUE; for( int i = 0; TLSCallbacks[i]; i++ ) { DebugShout( "[ProcessTlsEntries] TLSCallbacks[%i] = 0x%X (0x%X)", i, TLSCallbacks[i], RemoteAddress ); // As a consequence of the relocation stuff mentioned above, pCallbacks[i] is already fixed if( CallEntryPoint( RemoteAddress, ( FARPROC ) TLSCallbacks[i] ) == false ) { DebugShout( "[ProcessTlsEntries] Failed to execute Tls Entry [%i]", i ); } else { DebugShout( "[ProcessTlsEntries] Called Tls Callback (0x%X)", TLSCallbacks[i] ); } } return SuccessValue; }
BOOL CRemoteLoader::ProcessSection( BYTE* Name, PVOID BaseAddress, PVOID RemoteAddress, ULONG RawData, ULONG VirtualAddress, ULONG RawSize, ULONG VirtualSize, ULONG ProtectFlag ) { DebugShout( "[ProcessSection] ProcessSection( %s, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X )", Name, BaseAddress, RemoteAddress, RawData, VirtualAddress, RawSize, VirtualSize, ProtectFlag ); HANDLE hProcess = GetProcess(); if( hProcess == INVALID_HANDLE_VALUE ) { hProcess = GetCurrentProcess(); } if( WriteProcessMemory( hProcess, MakePtr( PVOID, RemoteAddress, VirtualAddress ), MakePtr( PVOID, BaseAddress, RawData ), RawSize, NULL ) == FALSE ) { DebugShout( "[ProcessSection] Failed to write memory for (%s) -> (%s)", Name, LastErrorString() ); return FALSE; } DWORD dwOldProtect = NULL; if( VirtualProtectEx( hProcess, MakePtr( PVOID, RemoteAddress, VirtualAddress ), VirtualSize, ProtectFlag, &dwOldProtect ) == FALSE ) { DebugShout( "[ProcessSection] Failed to protect memory for (%s) -> (%s)", Name, LastErrorString() ); return FALSE; } return TRUE; }
HMODULE CRemoteLoader::LoadLibraryByPathIntoMemoryA( PCHAR Path, BOOL PEHeader ) { HMODULE hReturnValue = NULL; DebugShout( "[LoadLibraryByPathIntoMemoryA] %s (0x%X)", Path, PEHeader ); ModuleFile File = InitModuleFile( Path ); if( File.IsValid() == FALSE ) { DebugShout( "[LoadLibraryByPathIntoMemoryA] Failed to open file handle!" ); return NULL; } hReturnValue = LoadLibraryFromMemory( File.Buffer, File.Size, PEHeader, Path ); if( FreeModuleFile( File ) == FALSE ) { DebugShout( "[LoadLibraryByPathIntoMemoryA] Failed to free file handle..." ); } return hReturnValue; }
void CRemoteCode::PushAllParameters( bool right_to_left ) { if( m_CurrentInvokeInfo.params.size() == 0 ) return; DebugShout( "Parameters for function [%i]", m_CurrentInvokeInfo.params.size() ); vector<parameter_info_t> currentParams = m_CurrentInvokeInfo.params; vector<parameter_info_t> pushOrder; if( right_to_left == false ) { //left-to-right for( int i = 0; i < (int)m_CurrentInvokeInfo.params.size(); i++ ) { pushOrder.push_back( m_CurrentInvokeInfo.params.at( i ) ); DebugShout( "Parameter found [%i][%i]", i, m_CurrentInvokeInfo.params.at( i ).ptype ); } } else { //right-to-left if( m_CurrentInvokeInfo.params.size() == 1 ) { pushOrder.push_back( m_CurrentInvokeInfo.params.at( 0 ) ); } else { int iBegin = (int)m_CurrentInvokeInfo.params.size() - 1; while( iBegin != -1 ) { pushOrder.push_back( m_CurrentInvokeInfo.params.at( iBegin ) ); DebugShout( "Parameter found [%i][%s]", iBegin, ParameterTypeToString( m_CurrentInvokeInfo.params.at( iBegin ).ptype ).c_str() ); iBegin--; } } } for( int p = 0; p < (int)pushOrder.size(); p++ ) { parameter_info_t *paraminfo = &pushOrder[p]; if( paraminfo == NULL ) continue; DebugShout( "Function Iter [%i]", p ); DebugShout( "Function Parameter [%s]", ParameterTypeToString( paraminfo->ptype ).c_str() ); if( paraminfo->pparam == NULL ) { AddByteToBuffer( 0x68 ); AddLongToBuffer( 0 ); continue; } switch( paraminfo->ptype ) { case PARAMETER_TYPE_SHORT: case PARAMETER_TYPE_POINTER: case PARAMETER_TYPE_INT: case PARAMETER_TYPE_FLOAT: { if( paraminfo->pparam ) { unsigned long ulParam = *(unsigned long *)paraminfo->pparam; AddByteToBuffer( 0x68 ); AddLongToBuffer( ulParam ); } else { //if it is PARAMETER_TYPE_POINTER with a NULL pointer //we don't want to crash AddByteToBuffer( 0x68 ); AddLongToBuffer( NULL ); } break; } case PARAMETER_TYPE_BYTE: { unsigned char ucParam = *(unsigned char *)paraminfo->pparam; AddByteToBuffer( 0x6A ); AddByteToBuffer( ucParam ); break; } case PARAMETER_TYPE_BOOL: { bool bParam = *(bool *)paraminfo->pparam; unsigned char ucParam = (bParam) ? 1 : 0; AddByteToBuffer( 0x6A ); AddByteToBuffer( ucParam ); break; } case PARAMETER_TYPE_STRING: { char *szParameter = (char *)paraminfo->pparam; void *AllocatedString = CommitMemory( szParameter, strlen( szParameter ) + 1 ); if( AllocatedString == NULL ) { DebugShout( "NULL Allocated ANSI string pointer...." ); continue; //bad beans } DebugShout( "Allocated string pointer at [0x%X]", AllocatedString ); AddByteToBuffer( 0x68 ); AddLongToBuffer( ( unsigned long ) AllocatedString ); break; } case PARAMETER_TYPE_WSTRING: { wchar_t *szParameter = (wchar_t *)paraminfo->pparam; void *AllocatedString = CommitMemory( szParameter, (wcslen( szParameter ) * 2) + 1 ); if( AllocatedString == NULL ) { DebugShout( "NULL Allocated UNICODE string pointer...." ); continue; //bad beans } AddByteToBuffer( 0x68 ); AddLongToBuffer((unsigned long)AllocatedString); break; } default: { DebugShout( "Unable to locate parameter type %i", paraminfo->ptype ); break; } } } }
void CRemoteCode::AddByteToBuffer( unsigned char in ) { DebugShout( "Byte opcode added to buffer: 0x%02X", in ); m_CurrentRemoteThreadBuffer.push_back( in ); }
HMODULE CRemoteLoader::LoadLibraryFromMemory( PVOID BaseAddress, DWORD SizeOfModule, BOOL PEHeader, PCHAR OptionalPath ) { DebugShout( "[LoadLibraryFromMemory] BaseAddress (0x%X) - SizeOfModule (0x%X)", BaseAddress, SizeOfModule ); IMAGE_NT_HEADERS* ImageNtHeaders = ToNts( BaseAddress ); if( ImageNtHeaders == NULL ) { DebugShout( "[LoadLibraryFromMemory] Invalid Image: No IMAGE_NT_HEADERS" ); return NULL; } DebugShout( "[LoadLibraryFromMemory] SizeOfImage (0x%X)", ImageNtHeaders->OptionalHeader.SizeOfImage ); if( ImageNtHeaders->FileHeader.NumberOfSections == 0 ) { DebugShout( "[LoadLibraryFromMemory] Invalid Image: No Sections" ); return NULL; } if( ( ImageNtHeaders->OptionalHeader.ImageBase % 4096 ) != 0 ) { DebugShout( "[LoadLibraryFromMemory] Invalid Image: Not Page Aligned" ); return NULL; } if( ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR ].Size ) { if( ImageDirectoryEntryToData( BaseAddress, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR ) ) { DebugShout( "[LoadLibraryFromMemory] This method is not supported for Managed executables!" ); return NULL; } } DebugShout( "[LoadLibraryFromMemory] No COM/CLR data found!" ); // SizeOfImage NOT the same as module size M**********R // http://www.youtube.com/watch?v=pele5vptVgc PVOID AllocatedRemoteMemory = RemoteAllocateMemory( ImageNtHeaders->OptionalHeader.SizeOfImage ); if( AllocatedRemoteMemory == NULL ) { DebugShout( "[LoadLibraryFromMemory] Failed to allocate remote memory for module!" ); return NULL; } DebugShout( "[LoadLibraryFromMemory] Allocated remote module at [0x%X]!", AllocatedRemoteMemory ); if( ProcessImportTable( BaseAddress, AllocatedRemoteMemory, OptionalPath ) == FALSE ) { DebugShout( "[LoadLibraryFromMemory] Failed to fix imports!" ); return NULL; } DebugShout( "[LoadLibraryFromMemory] Fixed Imports!" ); if( ProcessRelocations( BaseAddress, AllocatedRemoteMemory ) == FALSE ) { DebugShout( "[LoadLibraryFromMemory] Failed to process relocations!" ); RemoteFreeMemory( AllocatedRemoteMemory, SizeOfModule ); return NULL; } DebugShout( "[LoadLibraryFromMemory] Fixed Relocations!" ); if( ProcessSections( BaseAddress, AllocatedRemoteMemory, PEHeader ) == FALSE ) { DebugShout( "[LoadLibraryFromMemory] Failed to process sections!" ); } DebugShout( "[LoadLibraryFromMemory] Processed sections!" ); if( ProcessTlsEntries( BaseAddress, AllocatedRemoteMemory ) == FALSE ) { DebugShout( "[LoadModuleFromMemory] ProcessTlsEntries Failed!" ); // we can also choose to continue here.. return NULL; } DebugShout( "[LoadModuleFromMemory] Processed Tls Entries!" ); if( ImageNtHeaders->OptionalHeader.AddressOfEntryPoint ) { FARPROC DllEntryPoint = MakePtr( FARPROC, AllocatedRemoteMemory, ImageNtHeaders->OptionalHeader.AddressOfEntryPoint ); DebugShout( "[LoadModuleFromMemory] DllEntrypoint = 0x%X", DllEntryPoint ); if( CallEntryPoint( AllocatedRemoteMemory, DllEntryPoint ) == false ) { DebugShout( "[LoadModuleFromMemory] Failed to execute remote thread buffer" ); } else { DebugShout( "[LoadModuleFromMemory] Executed the remote thread buffer successfully [0x%X]", DllEntryPoint ); } } else { DebugShout( "[LoadModuleFromMemory] AddressOfEntryPoint is NULL" ); } DebugShout( "[LoadModuleFromMemory] Returning Pointer (0x%X)", AllocatedRemoteMemory ); return ( HMODULE ) AllocatedRemoteMemory; }
void CRemoteCode::PushCall( calling_convention_t cconv, FARPROC CallAddress ) { DebugShout( "PushCall [0x%X][0x%X]", cconv, CallAddress ); int iFunctionBegin = (int)m_CurrentInvokeInfo.params.size(); m_CurrentInvokeInfo.calladdress = reinterpret_cast<unsigned long>( CallAddress ); m_CurrentInvokeInfo.cconv = cconv; switch( cconv ) { case CCONV_CDECL: { DebugShout( "Entering __cdecl" ); int iCalculateAddEsp = (iFunctionBegin * 4); PushAllParameters( true ); AddByteToBuffer( MOV_EAX_VALUE ); AddLongToBuffer( m_CurrentInvokeInfo.calladdress ); AddByteToBuffer( CALL_EXTERNAL ); AddByteToBuffer( 0xD0 ); //eax if( iCalculateAddEsp != 0 ) { bool bUseByte = (iCalculateAddEsp <= 0xFF); if( bUseByte ) { //add esp, [BYTE] AddByteToBuffer( 0x83 ); AddByteToBuffer( 0xC4 ); AddByteToBuffer((unsigned char)iCalculateAddEsp); } else { //add esp, [LONG] AddByteToBuffer( 0x81 ); AddByteToBuffer( 0xC4 ); AddLongToBuffer( iCalculateAddEsp ); } } break; } case CCONV_STDCALL: { DebugShout( "Entering __stdcall" ); PushAllParameters( true ); AddByteToBuffer( MOV_EAX_VALUE ); AddLongToBuffer( m_CurrentInvokeInfo.calladdress ); AddByteToBuffer( CALL_EXTERNAL ); AddByteToBuffer( 0xD0 ); //eax break; } case CCONV_THISCALL: { DebugShout( "Entering __thiscall" ); if( iFunctionBegin == 0 ) //no params... { DebugShout( "No parameters passed for __thiscall, requires at least one parameter (ECX)" ); break; } //first parameter of __thiscall is ALWAYS ECX. ALWAYS. //the parameter type should also be PARAMETER_TYPE_POINTER if( m_CurrentInvokeInfo.params[0].ptype != PARAMETER_TYPE_POINTER ) { DebugShout( "\"THIS\" parameter type invalid [%i]", m_CurrentInvokeInfo.params[0].ptype ); } void *pThis = m_CurrentInvokeInfo.params[0].pparam; if( pThis == NULL ) { DebugShout( "\"THIS\" parameter NULL for __thiscall function (ECX)" ); } AddByteToBuffer( 0x8B ); AddByteToBuffer( 0x0D ); AddLongToBuffer((unsigned long)pThis); //now we need to remove the first parameter from the vector, so when we execute the //parameter iteration function it is not included..... m_CurrentInvokeInfo.params.erase( m_CurrentInvokeInfo.params.begin() ); PushAllParameters( true ); AddByteToBuffer( MOV_EAX_VALUE ); AddLongToBuffer( m_CurrentInvokeInfo.calladdress ); AddByteToBuffer( CALL_EXTERNAL ); AddByteToBuffer( 0xD0 ); //eax break; } case CCONV_FASTCALL: { DebugShout( "Entering __fastcall" ); if( iFunctionBegin == 0 ) { PushCall( CCONV_STDCALL, CallAddress ); return; } else if( iFunctionBegin == 1 ) { unsigned long ulEdxParam = *(unsigned long *)m_CurrentInvokeInfo.params[0].pparam; AddByteToBuffer( 0xBA ); AddLongToBuffer( ulEdxParam ); m_CurrentInvokeInfo.params.erase( m_CurrentInvokeInfo.params.begin() ); PushCall( CCONV_STDCALL, CallAddress ); return; } else { unsigned long ulEdxParam = *(unsigned long *)m_CurrentInvokeInfo.params[0].pparam; unsigned long ulEaxParam = *(unsigned long *)m_CurrentInvokeInfo.params[1].pparam; AddByteToBuffer( 0xBA ); AddLongToBuffer( ulEdxParam ); AddByteToBuffer( MOV_EAX_VALUE ); AddLongToBuffer( ulEaxParam ); m_CurrentInvokeInfo.params.erase( m_CurrentInvokeInfo.params.begin() ); m_CurrentInvokeInfo.params.erase( m_CurrentInvokeInfo.params.begin() ); PushAllParameters( true ); AddByteToBuffer( 0xBB ); AddLongToBuffer( m_CurrentInvokeInfo.calladdress ); AddByteToBuffer( CALL_EXTERNAL ); AddByteToBuffer( 0xD3 ); //ebx } break; } } //clear data m_CurrentInvokeInfo.params.clear(); m_CurrentInvokeInfo.calladdress = NULL; }
ModuleFile CRemoteLoader::InitModuleFile( PCHAR FileName ) { ModuleFile r; r.Buffer = 0; r.Size = 0; HANDLE hFile = CreateFileA( FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if( hFile == INVALID_HANDLE_VALUE ) { DebugShout( "[InitModuleFile] CreateFileA Failed" ); return r; } DebugShout( "[InitModuleFile] File opened" ); if( GetFileAttributesA( FileName ) & FILE_ATTRIBUTE_COMPRESSED ) { r.Size = GetCompressedFileSizeA( FileName, NULL ); DebugShout( "[InitModuleFile] File is compressed!" ); } else { r.Size = GetFileSize( hFile, NULL ); } DebugShout( "[InitModuleFile] Size [0x%X]", r.Size ); if( r.Size == 0 ) { CloseHandle( hFile ); return r; } unsigned char *AllocatedFile = ( unsigned char* ) VirtualAlloc( NULL, r.Size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE ); if( AllocatedFile == NULL ) { DebugShout( "[InitModuleFile] Failed to allocate buffer!" ); r.Size = 0; CloseHandle( hFile ); return r; } DebugShout( "[InitModuleFile] Buffer allocated" ); DWORD NumberOfBytesRead = 0; if( ReadFile( hFile, AllocatedFile, r.Size, &NumberOfBytesRead, FALSE ) == FALSE ) { DebugShout( "[InitModuleFile] Read file failed.." ); r.Buffer = 0; r.Size = 0; } else { DebugShout( "[InitModuleFile] Read file complete (0x%X)", NumberOfBytesRead ); r.Buffer = AllocatedFile; } DebugShout( "[InitModuleFile] Buffer [0x%X]", r.Buffer ); CloseHandle( hFile ); return r; }
BOOL CRemoteLoader::ProcessSections( PVOID BaseAddress, PVOID RemoteAddress, BOOL MapPEHeader ) { IMAGE_NT_HEADERS* ImageNtHeaders = ToNts( BaseAddress ); if( ImageNtHeaders == NULL ) return FALSE; // Write PE header if( MapPEHeader ) { if( WriteProcessMemory( GetProcess(), RemoteAddress, BaseAddress, ImageNtHeaders->OptionalHeader.SizeOfHeaders, NULL ) == FALSE ) { DebugShout( "[ProcessSections] Failed to map PE header!" ); } else { DebugShout( "[ProcessSections] Mapped PE Header successfully!" ); } } else { DebugShout( "[ProcessSections] PE Header mapping disabled, skipping." ); } // Write individual sections PIMAGE_SECTION_HEADER ImageSectionHeader = ( PIMAGE_SECTION_HEADER ) ( ( ( ULONG_PTR ) &ImageNtHeaders->OptionalHeader ) + ImageNtHeaders->FileHeader.SizeOfOptionalHeader ); for( DWORD i = 0; i < ImageNtHeaders->FileHeader.NumberOfSections; i++ ) { ULONG Protection = GetSectionProtection( ImageSectionHeader[ i ].Characteristics ); if( !_stricmp( ".reloc", ( CHAR* ) ImageSectionHeader[ i ].Name ) ) { DebugShout( "[ProcessSections] Skipping \".reloc\" section." ); continue; // NOPE } if( ProcessSection( ImageSectionHeader[ i ].Name, BaseAddress, RemoteAddress, ImageSectionHeader[ i ].PointerToRawData, ImageSectionHeader[ i ].VirtualAddress, ImageSectionHeader[ i ].SizeOfRawData, ImageSectionHeader[ i ].Misc.VirtualSize, Protection ) == FALSE ) { DebugShout( "[ProcessSections] Failed %s", ImageSectionHeader[ i ].Name ); } else { DebugShout( "[ProcessSections] Success %s", ImageSectionHeader[ i ].Name ); } } return TRUE; }
HMODULE CRemoteLoader::LoadLibraryByPathW( PWCHAR Path ) { if( Path == NULL ) { DebugShout( "[LoadLibraryByPathW] szString is NULL" ); return NULL; } FARPROC RemoteLoadLibraryW = GetRemoteProcAddress( "kernel32.dll", "LoadLibraryW" ); if( RemoteLoadLibraryW == NULL ) { DebugShout( "[LoadLibraryByPathW] LoadLibraryW Resolve Failure" ); return NULL; } DebugShout( "[LoadLibraryByPathW] LoadLibraryW = 0x%X", RemoteLoadLibraryW ); PVOID ReturnPointerValue = RemoteAllocateMemory( sizeof( DWORD ) ); PushUNICODEString( Path ); PushCall( CCONV_STDCALL, RemoteLoadLibraryW ); //mov ptr, eax AddByteToBuffer( 0xA3 ); AddLongToBuffer( ( DWORD ) ReturnPointerValue ); //xor eax, eax AddByteToBuffer( 0x33 ); AddByteToBuffer( 0xC0 ); //retn 4 AddByteToBuffer( 0xC2 ); AddByteToBuffer( 0x04 ); AddByteToBuffer( 0x00 ); if( ExecuteRemoteThreadBuffer( m_CurrentRemoteThreadBuffer, true ) == false ) { DebugShout( "[LoadLibraryByPathW] ExecuteRemoteThreadBuffer failed" ); RemoteFreeMemory( ReturnPointerValue, sizeof( DWORD ) ); return NULL; } DebugShout( "[LoadModuleByNameW] ExecuteRemoteThreadBuffer succeeded" ); DWORD RemoteModuleHandle = 0; if( ReadProcessMemory( GetProcess(), ReturnPointerValue, &RemoteModuleHandle, sizeof( DWORD ), NULL ) == TRUE ) { RemoteFreeMemory( ReturnPointerValue, sizeof( DWORD ) ); } else { RemoteFreeMemory( ReturnPointerValue, sizeof( DWORD ) ); if( RemoteModuleHandle == 0 ) { RemoteModuleHandle = ( DWORD ) GetRemoteModuleHandleW( Path ); } } return ( HMODULE ) RemoteModuleHandle; }
BOOL CRemoteLoader::ProcessRelocations( PVOID BaseAddress, PVOID RemoteAddress ) { IMAGE_NT_HEADERS* ImageNtHeaders = ToNts( BaseAddress ); if( ImageNtHeaders == NULL ) return FALSE; if( ImageNtHeaders->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED ) { DebugShout( "[ProcessRelocations] Relocations have been stripped from this executable, continuing.." ); return TRUE; } else { DWORD ImageBaseDelta = MakeDelta( DWORD, RemoteAddress, ImageNtHeaders->OptionalHeader.ImageBase ); DebugShout( "[ProcessRelocations] VirtualAddress (0x%X)", ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ].VirtualAddress ); DWORD RelocationSize = ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ].Size; DebugShout( "[ProcessRelocations] Relocation Size [0x%X]", RelocationSize ); if( RelocationSize ) { IMAGE_BASE_RELOCATION* RelocationDirectory = ( IMAGE_BASE_RELOCATION* ) RvaToPointer( ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ].VirtualAddress, BaseAddress ); if( RelocationDirectory ) { DebugShout( "[ProcessRelocations] RelocationDirectory (0x%X)", RelocationDirectory ); PVOID RelocationEnd = reinterpret_cast< PBYTE >( RelocationDirectory ) + RelocationSize; while( RelocationDirectory < RelocationEnd ) { PBYTE RelocBase = static_cast< PBYTE >( RvaToPointer( RelocationDirectory->VirtualAddress, BaseAddress ) ); DWORD NumRelocs = ( RelocationDirectory->SizeOfBlock - sizeof( IMAGE_BASE_RELOCATION ) ) / sizeof( WORD ); PWORD RelocationData = reinterpret_cast< PWORD >( RelocationDirectory + 1 ); DebugShout( "[ProcessRelocations] RelocationDirectory (0x%X)", RelocationDirectory ); DebugShout( "[ProcessRelocations] RelocationData (0x%X)", RelocationData ); for( DWORD i = 0; i < NumRelocs; ++i, ++RelocationData ) { if( ProcessRelocation( ImageBaseDelta, *RelocationData, RelocBase ) == FALSE ) { DebugShout( "[ProcessRelocations] Unable to process relocation (%i)", i ); } } RelocationDirectory = reinterpret_cast< PIMAGE_BASE_RELOCATION >( RelocationData ); } } else { DebugShout( "[ProcessRelocations] Relocations have a size, but the pointer is invalid" ); return FALSE; } } else { DebugShout( "[ProcessRelocations] Relocations have have not been found in this executable, continuing.." ); return TRUE; } } return TRUE; }
BOOL CRemoteLoader::ProcessRelocation( INT ImageBaseDelta, WORD Data, PBYTE RelocationBase ) { BOOL bReturn = TRUE; switch( IMR_RELTYPE( Data ) ) { case IMAGE_REL_BASED_ABSOLUTE: { DebugShout( "[ProcessRelocation] IMAGE_REL_BASED_ABSOLUTE" ); break; } case IMAGE_REL_BASED_HIGH: { SHORT* Raw = reinterpret_cast< SHORT* >( RelocationBase + IMR_RELOFFSET( Data ) ); SHORT Backup = *Raw; *Raw += HIWORD( ImageBaseDelta ); DebugShout( "[ProcessRelocation] IMAGE_REL_BASED_HIGH (0x%X) -> (0x%X)", Backup, *Raw ); break; } case IMAGE_REL_BASED_LOW: { SHORT* Raw = reinterpret_cast< SHORT* >( RelocationBase + IMR_RELOFFSET( Data ) ); SHORT Backup = *Raw; *Raw += LOWORD( ImageBaseDelta ); DebugShout( "[ProcessRelocation] IMAGE_REL_BASED_LOW (0x%X) -> (0x%X)", Backup, *Raw ); break; } case IMAGE_REL_BASED_HIGHLOW: { DWORD32* Raw = reinterpret_cast< DWORD32* >( RelocationBase + IMR_RELOFFSET( Data ) ); DWORD32 Backup = *Raw; *Raw += ImageBaseDelta; DebugShout( "[ProcessRelocation] IMAGE_REL_BASED_HIGHLOW (0x%X) -> (0x%X)", Backup, *Raw ); break; } case IMAGE_REL_BASED_DIR64: { DWORD64* Raw = reinterpret_cast< DWORD64* >( RelocationBase + IMR_RELOFFSET( Data ) ); DWORD64 Backup = *Raw; *Raw += ImageBaseDelta; DebugShout( "[ProcessRelocation] IMAGE_REL_BASED_DIR64 (0x%X) -> (0x%X)", Backup, *Raw ); break; } case IMAGE_REL_BASED_HIGHADJ: { DebugShout( "[ProcessRelocation] IMAGE_REL_BASED_HIGHADJ" ); break; } default: { DebugShout( "[ProcessRelocation] UNKNOWN RELOCATION (0x%X)", IMR_RELTYPE( Data ) ); bReturn = FALSE; break; } } return bReturn; }
BOOL CRemoteLoader::ProcessImportTable( PVOID BaseAddress, PVOID RemoteAddress, PCHAR OptionalPath ) { IMAGE_NT_HEADERS* ImageNtHeaders = ToNts( BaseAddress ); if( ImageNtHeaders == NULL ) return FALSE; if( ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ].Size ) { IMAGE_IMPORT_DESCRIPTOR* ImageImportDescriptor = ( IMAGE_IMPORT_DESCRIPTOR* ) RvaToPointer( ImageNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ].VirtualAddress, BaseAddress ); if( ImageImportDescriptor ) { for( ; ImageImportDescriptor->Name; ImageImportDescriptor++ ) { PCHAR ModuleName = ( PCHAR ) RvaToPointer( ImageImportDescriptor->Name, BaseAddress ); if( ModuleName == NULL ) { DebugShout( "[ProcessImportTable] Module name for entry NULL" ); continue; } DebugShout( "[ProcessImportTable] Module Name [%s]", ModuleName ); HMODULE ModuleBase = GetRemoteModuleHandleA( ModuleName ); if( ModuleBase == NULL ) { ModuleBase = LoadLibraryByPathA( ModuleName ); } if( ModuleBase == NULL ) { DebugShout( "[ProcessImportTable] Failed to obtain module handle [%s]", ModuleName ); continue; } IMAGE_THUNK_DATA *ImageThunkData = NULL; IMAGE_THUNK_DATA *ImageFuncData = NULL; if( ImageImportDescriptor->OriginalFirstThunk ) { ImageThunkData = ( IMAGE_THUNK_DATA* ) RvaToPointer( ImageImportDescriptor->OriginalFirstThunk, BaseAddress ); ImageFuncData = ( IMAGE_THUNK_DATA* ) RvaToPointer( ImageImportDescriptor->FirstThunk, BaseAddress ); } else { ImageThunkData = ( IMAGE_THUNK_DATA* ) RvaToPointer( ImageImportDescriptor->FirstThunk, BaseAddress ); ImageFuncData = ( IMAGE_THUNK_DATA* ) RvaToPointer( ImageImportDescriptor->FirstThunk, BaseAddress ); } if( ImageThunkData == NULL ) { DebugShout( "[ProcessImportTable] Image Thunk Data is NULL" ); } if( ImageFuncData == NULL ) { DebugShout( "[ProcessImportTable] Image Func Data is NULL" ); } for( ; ImageThunkData->u1.AddressOfData; ImageThunkData++, ImageFuncData++ ) { FARPROC FunctionAddress = NULL; if( IMAGE_SNAP_BY_ORDINAL( ImageThunkData->u1.Ordinal ) ) { SHORT Ordinal = ( SHORT ) IMAGE_ORDINAL( ImageThunkData->u1.Ordinal ); FunctionAddress = ( FARPROC ) GetRemoteProcAddress( ModuleName, Ordinal ); DebugShout( "[ProcessImportTable] Processed (%s -> %i) -> (0x%X)", ModuleName, Ordinal, FunctionAddress ); if( this->GetProcess() == INVALID_HANDLE_VALUE ) { DebugShout( "[ProcessImportTable] Normal Value (0x%X)", GetProcAddress( GetModuleHandleA( ModuleName ), ( LPCSTR ) Ordinal ) ); } } else { IMAGE_IMPORT_BY_NAME* ImageImportByName = ( IMAGE_IMPORT_BY_NAME* ) RvaToPointer( *( DWORD* ) ImageThunkData, BaseAddress ); PCHAR NameOfImport = ( PCHAR ) ImageImportByName->Name; FunctionAddress = ( FARPROC ) GetRemoteProcAddress( ModuleName, NameOfImport ); DebugShout( "[ProcessImportTable] Processed (%s -> %s) -> (0x%X)", ModuleName, NameOfImport, FunctionAddress ); if( this->GetProcess() == INVALID_HANDLE_VALUE ) { DebugShout( "[ProcessImportTable] Normal Value (0x%X)", GetProcAddress( GetModuleHandleA( ModuleName ), NameOfImport ) ); } } ImageFuncData->u1.Function = ( DWORD ) FunctionAddress; } } return TRUE; } else { DebugShout( "[ProcessImportTable] Size of table confirmed but pointer to data invalid!" ); return FALSE; } } else { DebugShout( "[ProcessImportTable] No Imports" ); return TRUE; } return FALSE; }