size_t Native::EnumModulesT( Native::listModules& result ) { typename _PEB_T2<T>::type peb = { { { 0 } } }; _PEB_LDR_DATA2<T> ldr = { 0 }; result.clear(); if (getPEB( &peb ) != 0 && ReadProcessMemoryT( peb.Ldr, &ldr, sizeof(ldr), 0 ) == STATUS_SUCCESS) { for (T head = ldr.InLoadOrderModuleList.Flink; head != (peb.Ldr + FIELD_OFFSET( _PEB_LDR_DATA2<T>, InLoadOrderModuleList )); ReadProcessMemoryT( static_cast<ptr_t>(head), &head, sizeof(head), 0 )) { ModuleData data; wchar_t localPath[512] = { 0 }; _LDR_DATA_TABLE_ENTRY_BASE<T> localdata = { { 0 } }; ReadProcessMemoryT( head, &localdata, sizeof(localdata), 0 ); ReadProcessMemoryT( localdata.FullDllName.Buffer, localPath, localdata.FullDllName.Length, 0 ); data.baseAddress = localdata.DllBase; data.size = localdata.SizeOfImage; data.fullPath = Utils::ToLower( localPath ); data.name = Utils::StripPath( data.fullPath ); data.manual = false; data.type = std::is_same<T, DWORD>::value ? mt_mod32 : mt_mod64; result.emplace_back( data ); } } return result.size(); }
std::vector<ModuleDataPtr> Native::EnumModulesT() { NTSTATUS status = STATUS_SUCCESS; _PEB_T<T> peb = { }; _PEB_LDR_DATA2_T<T> ldr = { }; std::vector<ModuleDataPtr> result; if (getPEB( &peb ) != 0 && ReadProcessMemoryT( peb.Ldr, &ldr, sizeof( ldr ), 0 ) == STATUS_SUCCESS) { for (T head = ldr.InLoadOrderModuleList.Flink; NT_SUCCESS( status ) && head != (peb.Ldr + FIELD_OFFSET( _PEB_LDR_DATA2_T<T>, InLoadOrderModuleList )); status = ReadProcessMemoryT( static_cast<ptr_t>(head), &head, sizeof( head ) )) { ModuleData data; wchar_t localPath[512] = { 0 }; _LDR_DATA_TABLE_ENTRY_BASE_T<T> localdata = { { 0 } }; ReadProcessMemoryT( head, &localdata, sizeof( localdata ), 0 ); ReadProcessMemoryT( localdata.FullDllName.Buffer, localPath, localdata.FullDllName.Length ); data.baseAddress = localdata.DllBase; data.size = localdata.SizeOfImage; data.fullPath = Utils::ToLower( localPath ); data.name = Utils::StripPath( data.fullPath ); data.type = (sizeof( T ) < sizeof( uint64_t )) ? mt_mod32 : mt_mod64; data.ldrPtr = static_cast<ptr_t>(head); data.manual = false; result.emplace_back( std::make_shared<const ModuleData>( data ) ); } } else { BLACKBONE_TRACE( L"NativeModules: Failed to get PEB/LDR address. Not yet initialized" ); } return result; }
/// <summary> /// Enum pages containing valid PE headers /// </summary> /// <param name="result">Found modules</param> /// <returns>Sections count</returns> std::vector<ModuleDataPtr> Native::EnumPEHeaders() { MEMORY_BASIC_INFORMATION64 mbi = { 0 }; uint8_t buf[0x1000]; ptr_t lastBase = 0; std::vector<ModuleDataPtr> result; for (ptr_t memptr = minAddr(); memptr < maxAddr(); memptr = mbi.BaseAddress + mbi.RegionSize) { auto status = VirtualQueryExT( memptr, &mbi ); if (status == STATUS_INVALID_PARAMETER || status == STATUS_ACCESS_DENIED || status == STATUS_PROCESS_IS_TERMINATING) break; else if (status != STATUS_SUCCESS) continue; // Filter regions if (mbi.State != MEM_COMMIT || mbi.AllocationProtect == PAGE_NOACCESS || mbi.AllocationProtect & PAGE_GUARD || lastBase == mbi.AllocationBase) { continue; } ModuleData data; IMAGE_DOS_HEADER* phdrDos = reinterpret_cast<PIMAGE_DOS_HEADER>(buf); IMAGE_NT_HEADERS32 *phdrNt32 = nullptr; IMAGE_NT_HEADERS64 *phdrNt64 = nullptr; if (ReadProcessMemoryT( mbi.AllocationBase, buf, 0x1000 ) != STATUS_SUCCESS) continue; phdrNt32 = reinterpret_cast<PIMAGE_NT_HEADERS32>(buf + phdrDos->e_lfanew); phdrNt64 = reinterpret_cast<PIMAGE_NT_HEADERS64>(phdrNt32); if (phdrDos->e_magic != IMAGE_DOS_SIGNATURE || phdrNt32->Signature != IMAGE_NT_SIGNATURE) continue; if (phdrNt32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) { data.size = phdrNt32->OptionalHeader.SizeOfImage; data.type = mt_mod32; } else if (phdrNt32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { data.size = phdrNt64->OptionalHeader.SizeOfImage; data.type = mt_mod64; } data.baseAddress = mbi.AllocationBase; data.ldrPtr = 0; data.manual = false; // Try to get section name _UNICODE_STRING_T<DWORD64>* ustr = (decltype(ustr))buf; status = VirtualQueryExT( mbi.AllocationBase, MemorySectionName, ustr, sizeof(buf) ); if (status == STATUS_SUCCESS) { // Hack for x86 OS if (_wowBarrier.x86OS == true) { _UNICODE_STRING_T<DWORD>* ustr32 = reinterpret_cast<_UNICODE_STRING_T<DWORD>*>(ustr); data.fullPath = Utils::ToLower( reinterpret_cast<wchar_t*>((uintptr_t)ustr32->Buffer) ); } else data.fullPath = Utils::ToLower( reinterpret_cast<wchar_t*>((uintptr_t)ustr->Buffer) ); data.name = Utils::StripPath( data.fullPath ); } else { wchar_t name[64] = { 0 }; wsprintfW( name, L"Unknown_0x%I64x", data.baseAddress ); data.fullPath = name; data.name = data.fullPath; } result.emplace_back( std::make_shared<const ModuleData>( data ) ); lastBase = mbi.AllocationBase; } return result; }
/// <summary> /// Enum process section objects /// </summary> /// <param name="result">Found modules</param> /// <returns>Sections count</returns> std::vector<ModuleDataPtr> Native::EnumSections() { MEMORY_BASIC_INFORMATION64 mbi = { 0 }; ptr_t lastBase = 0; std::vector<ModuleDataPtr> result; for (ptr_t memptr = minAddr(); memptr < maxAddr(); memptr = mbi.BaseAddress + mbi.RegionSize) { auto status = VirtualQueryExT( memptr, &mbi ); if (status == STATUS_INVALID_PARAMETER || status == STATUS_ACCESS_DENIED || status == STATUS_PROCESS_IS_TERMINATING) break; else if (status != STATUS_SUCCESS) continue; // Filter non-section regions if (mbi.State != MEM_COMMIT || mbi.Type != SEC_IMAGE || lastBase == mbi.AllocationBase) continue; uint8_t buf[0x1000] = { 0 }; _UNICODE_STRING_T<uint64_t>* ustr = (decltype(ustr))(buf + 0x800); status = VirtualQueryExT( mbi.AllocationBase, MemorySectionName, ustr, sizeof(buf) / 2 ); // Get additional if (NT_SUCCESS( status )) { ModuleData data; IMAGE_DOS_HEADER* phdrDos = reinterpret_cast<PIMAGE_DOS_HEADER>(buf); IMAGE_NT_HEADERS32 *phdrNt32 = nullptr; IMAGE_NT_HEADERS64 *phdrNt64 = nullptr; if (ReadProcessMemoryT( mbi.AllocationBase, buf, 0x800 ) != STATUS_SUCCESS) continue; phdrNt32 = reinterpret_cast<PIMAGE_NT_HEADERS32>(buf + phdrDos->e_lfanew); phdrNt64 = reinterpret_cast<PIMAGE_NT_HEADERS64>(phdrNt32); // If no PE header present if (phdrDos->e_magic != IMAGE_DOS_SIGNATURE || phdrNt32->Signature != IMAGE_NT_SIGNATURE) { // Iterate until region end MEMORY_BASIC_INFORMATION64 mbi2 = { 0 }; for (ptr_t memptr2 = mbi.AllocationBase; memptr2 < maxAddr(); memptr2 = mbi2.BaseAddress + mbi2.RegionSize) if (!NT_SUCCESS( VirtualQueryExT( memptr2, &mbi2 ) ) || mbi2.Type != SEC_IMAGE) { data.size = static_cast<uint32_t>(mbi2.BaseAddress - mbi.AllocationBase); break; } data.type = mt_unknown; } else if( phdrNt32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC ) { data.size = phdrNt32->OptionalHeader.SizeOfImage; data.type = mt_mod32; } else if (phdrNt32->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { data.size = phdrNt64->OptionalHeader.SizeOfImage; data.type = mt_mod64; } else continue; // Hack for x86 OS if (_wowBarrier.x86OS == true) { _UNICODE_STRING_T<DWORD>* ustr32 = reinterpret_cast<_UNICODE_STRING_T<DWORD>*>(ustr); data.fullPath = Utils::ToLower( reinterpret_cast<wchar_t*>((uintptr_t)ustr32->Buffer) ); } else data.fullPath = Utils::ToLower( reinterpret_cast<wchar_t*>((uintptr_t)ustr->Buffer) ); data.name = Utils::StripPath( data.fullPath ); data.baseAddress = mbi.AllocationBase; data.ldrPtr = 0; data.manual = false; result.emplace_back( std::make_shared<const ModuleData>( data ) ); } lastBase = mbi.AllocationBase; } return result; }