void TestThreadList() { using ThreadListIterCat = std::iterator_traits<hadesmem::ThreadList::iterator>::iterator_category; HADESMEM_DETAIL_STATIC_ASSERT( std::is_base_of<std::input_iterator_tag, ThreadListIterCat>::value); using ThreadListConstIterCat = std::iterator_traits< hadesmem::ThreadList::const_iterator>::iterator_category; HADESMEM_DETAIL_STATIC_ASSERT( std::is_base_of<std::input_iterator_tag, ThreadListConstIterCat>::value); { hadesmem::detail::SmartHandle wait_thread_1( ::CreateThread(nullptr, 0, &SleepWrapper, nullptr, 0, nullptr)); hadesmem::detail::SmartHandle wait_thread_2( ::CreateThread(nullptr, 0, &SleepWrapper, nullptr, 0, nullptr)); } hadesmem::ThreadList const thread_list_1(::GetCurrentProcessId()); hadesmem::ThreadList thread_list_2(thread_list_1); hadesmem::ThreadList thread_list_3(std::move(thread_list_2)); thread_list_2 = std::move(thread_list_3); BOOST_TEST(std::begin(thread_list_2) != std::end(thread_list_2)); auto iter = std::begin(thread_list_1); BOOST_TEST(iter != std::end(thread_list_1)); BOOST_TEST(++iter != std::end(thread_list_1)); BOOST_TEST_NE(iter->GetId(), 0U); DWORD const second_id = iter->GetId(); BOOST_TEST(++iter != std::end(thread_list_1)); DWORD const third_id = iter->GetId(); BOOST_TEST_NE(second_id, third_id); }
void ReadStringEx(Process const& process, PVOID address, OutputIterator data, std::size_t chunk_len, void* upper_bound) { HADESMEM_DETAIL_STATIC_ASSERT(detail::IsCharType<T>::value); HADESMEM_DETAIL_STATIC_ASSERT(std::is_base_of< std::output_iterator_tag, typename std::iterator_traits<OutputIterator>::iterator_category>::value); HADESMEM_DETAIL_ASSERT(chunk_len != 0); for (;;) { detail::ProtectGuard protect_guard{ process, address, detail::ProtectGuardType::kRead}; MEMORY_BASIC_INFORMATION const mbi = detail::Query(process, address); PVOID const region_next_real = static_cast<PBYTE>(mbi.BaseAddress) + mbi.RegionSize; void* const region_next = upper_bound ? (std::min)(upper_bound, region_next_real) : region_next_real; T* cur = static_cast<T*>(address); while (cur + 1 <= region_next) { std::size_t const len_to_end = reinterpret_cast<DWORD_PTR>(region_next) - reinterpret_cast<DWORD_PTR>(cur); std::size_t const buf_len_bytes = (std::min)(chunk_len * sizeof(T), len_to_end); std::size_t const buf_len = buf_len_bytes / sizeof(T); std::vector<T> buf(buf_len); detail::ReadUnchecked(process, cur, buf.data(), buf.size() * sizeof(T)); auto const iter = std::find(std::begin(buf), std::end(buf), T()); std::copy(std::begin(buf), iter, data); if (iter != std::end(buf) || region_next == upper_bound) { protect_guard.Restore(); return; } cur += buf_len; } address = region_next; protect_guard.Restore(); if (upper_bound && cur >= upper_bound) { return; } } }
inline std::vector<T, Alloc> ReadVector(Process const& process, PVOID address, std::size_t count) { HADESMEM_DETAIL_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value); HADESMEM_DETAIL_STATIC_ASSERT(std::is_default_constructible<T>::value); HADESMEM_DETAIL_ASSERT(count ? address != nullptr : true); return ReadVectorEx<T, Alloc>(process, address, count, ReadFlags::kNone); }
explicit PatchDr(Process const& process, TargetFuncT target, DetourFuncT detour) : PatchVeh{process, target, detour} { HADESMEM_DETAIL_STATIC_ASSERT(detail::IsFunction<TargetFuncT>::value || std::is_pointer<TargetFuncT>::value); HADESMEM_DETAIL_STATIC_ASSERT(detail::IsFunction<DetourFuncT>::value || std::is_pointer<DetourFuncT>::value); }
inline void ReadVector(Process const& process, PVOID address, std::size_t count, OutputIterator out) { HADESMEM_DETAIL_STATIC_ASSERT(std::is_base_of< std::output_iterator_tag, typename std::iterator_traits<OutputIterator>::iterator_category>::value); HADESMEM_DETAIL_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value); HADESMEM_DETAIL_STATIC_ASSERT(std::is_default_constructible<T>::value); HADESMEM_DETAIL_ASSERT(count ? address != nullptr : true); return ReadVectorEx<T>(process, address, count, out, ReadFlags::kNone); }
void GetCallbacks(OutputIterator callbacks) const { using OutputIteratorCategory = typename std::iterator_traits<OutputIterator>::iterator_category; HADESMEM_DETAIL_STATIC_ASSERT( std::is_base_of<std::output_iterator_tag, OutputIteratorCategory>::value); auto const image_base = GetRuntimeBase(*process_, *pe_file_); auto callbacks_raw = reinterpret_cast<PIMAGE_TLS_CALLBACK*>( RvaToVa(*process_, *pe_file_, static_cast<DWORD>(GetAddressOfCallBacks() - image_base))); if (!callbacks_raw) { HADESMEM_DETAIL_THROW_EXCEPTION( Error{} << ErrorString{"TLS callbacks are invalid."}); } for (auto callback = Read<PIMAGE_TLS_CALLBACK>(*process_, callbacks_raw); callback; callback = Read<PIMAGE_TLS_CALLBACK>(*process_, ++callbacks_raw)) { auto const callback_offset = reinterpret_cast<ULONGLONG>(callback) - image_base; *callbacks = reinterpret_cast<PIMAGE_TLS_CALLBACK>( static_cast<ULONG_PTR>(callback_offset)); ++callbacks; } }
inline void Write(Process const& process, PVOID address, T const& data) { HADESMEM_DETAIL_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value); HADESMEM_DETAIL_ASSERT(address != nullptr); detail::WriteImpl(process, address, data); }
void WriteImpl(Process const& process, PVOID address, T const& data) { HADESMEM_DETAIL_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value); HADESMEM_DETAIL_ASSERT(address != nullptr); WriteImpl(process, address, std::addressof(data), sizeof(data)); }
inline void ReadVectorEx(Process const& process, PVOID address, std::size_t count, OutputIterator out, std::uint32_t flags) { HADESMEM_DETAIL_STATIC_ASSERT(std::is_base_of< std::output_iterator_tag, typename std::iterator_traits<OutputIterator>::iterator_category>::value); HADESMEM_DETAIL_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value); HADESMEM_DETAIL_STATIC_ASSERT(std::is_default_constructible<T>::value); HADESMEM_DETAIL_ASSERT(count ? address != nullptr : true); auto const data = ReadVectorEx<T>(process, address, count, flags); std::copy(std::begin(data), std::end(data), out); }
void TestRegionList() { using RegionListIterCat = std::iterator_traits<hadesmem::RegionList::iterator>::iterator_category; HADESMEM_DETAIL_STATIC_ASSERT( std::is_base_of<std::input_iterator_tag, RegionListIterCat>::value); using RegionListConstIterCat = std::iterator_traits< hadesmem::RegionList::const_iterator>::iterator_category; HADESMEM_DETAIL_STATIC_ASSERT( std::is_base_of<std::input_iterator_tag, RegionListConstIterCat>::value); hadesmem::Process const process(::GetCurrentProcessId()); hadesmem::RegionList const region_list_1(process); hadesmem::RegionList region_list_2(region_list_1); hadesmem::RegionList region_list_3(std::move(region_list_2)); region_list_2 = std::move(region_list_3); BOOST_TEST(std::begin(region_list_2) != std::end(region_list_2)); auto iter = std::begin(region_list_1); hadesmem::Region const first_region(process, nullptr); BOOST_TEST(iter != std::end(region_list_1)); BOOST_TEST_EQ(*iter, first_region); hadesmem::Region const second_region( process, static_cast<char const* const>(first_region.GetBase()) + first_region.GetSize()); BOOST_TEST(++iter != std::end(region_list_1)); BOOST_TEST_EQ(*iter, second_region); hadesmem::Region last(process, nullptr); do { hadesmem::Region current = *iter; BOOST_TEST(current > last); BOOST_TEST(current >= last); BOOST_TEST(last < current); BOOST_TEST(last <= current); last = current; } while (++iter != std::end(region_list_1)); BOOST_TEST_THROWS( hadesmem::Region( process, static_cast<char const* const>(last.GetBase()) + last.GetSize()), hadesmem::Error); }
inline std::vector<T, Alloc> ReadVectorEx(Process const& process, PVOID address, std::size_t count, std::uint32_t flags) { HADESMEM_DETAIL_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value); HADESMEM_DETAIL_STATIC_ASSERT(std::is_default_constructible<T>::value); HADESMEM_DETAIL_ASSERT(count ? address != nullptr : true); if (!count) { return {}; } std::vector<T, Alloc> data(count); detail::ReadImpl(process, address, data.data(), sizeof(T) * count, flags); return data; }
inline void WriteString(Process const& process, PVOID address, std::basic_string<T, Traits, Alloc> const& data) { HADESMEM_DETAIL_STATIC_ASSERT(detail::IsCharType<T>::value); HADESMEM_DETAIL_ASSERT(address != nullptr); return Write(process, address, data.c_str(), data.size() + 1); }
inline void WriteString(Process const& process, PVOID address, T const* const str) { HADESMEM_DETAIL_STATIC_ASSERT(detail::IsCharType<T>::value); HADESMEM_DETAIL_ASSERT(address != nullptr); HADESMEM_DETAIL_ASSERT(str != nullptr); WriteString(process, address, std::basic_string<T>(str)); }
inline void Read(Process const& process, PVOID address, OutputIterator out) { HADESMEM_DETAIL_STATIC_ASSERT(std::is_base_of< std::output_iterator_tag, typename std::iterator_traits<OutputIterator>::iterator_category>::value); HADESMEM_DETAIL_ASSERT(address != nullptr); auto const data = detail::ReadImpl<std::array<T, N>>(process, address); std::copy(&data[0], &data[0] + N, out); }
inline void WriteVector(Process const& process, PVOID address, std::vector<T, Alloc> const& data) { HADESMEM_DETAIL_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value); HADESMEM_DETAIL_ASSERT(address != nullptr); HADESMEM_DETAIL_ASSERT(!data.empty()); std::size_t const raw_size = data.size() * sizeof(T); detail::WriteImpl(process, address, data.data(), raw_size); }
inline void Write(Process const& process, PVOID address, T const* beg, T const* end) { HADESMEM_DETAIL_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value); HADESMEM_DETAIL_ASSERT(address != nullptr); HADESMEM_DETAIL_ASSERT(beg != nullptr); HADESMEM_DETAIL_ASSERT(end != nullptr); std::size_t const count = static_cast<std::size_t>(std::distance(beg, end)); Write(process, address, beg, count); }
inline void Write(Process const& process, PVOID address, T const* ptr, std::size_t count) { HADESMEM_DETAIL_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value); HADESMEM_DETAIL_ASSERT(address != nullptr); HADESMEM_DETAIL_ASSERT(ptr != nullptr); HADESMEM_DETAIL_ASSERT(count != 0); std::size_t const raw_size = static_cast<std::size_t>(std::distance(ptr, ptr + count)) * sizeof(T); detail::WriteImpl(process, address, ptr, raw_size); }
inline FARPROC GetProcAddressInternalFromPred(Process const& process, HMODULE module, Pred pred) { HADESMEM_DETAIL_STATIC_ASSERT(sizeof(FARPROC) == sizeof(void*)); PeFile const pe_file{process, module, PeFileType::Image, 0}; ExportList const exports{process, pe_file}; auto const iter = std::find_if(std::begin(exports), std::end(exports), pred); if (iter != std::end(exports)) { return GetProcAddressFromExport(process, *iter); } return nullptr; }
hadesmem::detail::Optional<Entry> Toolhelp32Enum(Func func, HANDLE snap, std::string const& error) { HADESMEM_DETAIL_STATIC_ASSERT(std::is_pod<Entry>::value); Entry entry{}; entry.dwSize = static_cast<DWORD>(sizeof(entry)); if (!func(snap, &entry)) { DWORD const last_error = ::GetLastError(); if (last_error == ERROR_NO_MORE_FILES) { return hadesmem::detail::Optional<Entry>(); } HADESMEM_DETAIL_THROW_EXCEPTION(Error{} << ErrorString{error.c_str()} << ErrorCodeWinLast{last_error}); } return hadesmem::detail::Optional<Entry>(entry); }