From 90256b20d9412b26c96e39af925b2e3e7ef04809 Mon Sep 17 00:00:00 2001 From: crazy hugsy Date: Tue, 21 Nov 2023 10:19:27 -0800 Subject: [PATCH] Fixing tests and Architecture lookup (#27) * minor fixes * added pwn::shellcode::patternfind * Fixed minor bugs when looking up architectures --- Modules/Assembly/Source/Disassembler.cpp | 6 +- Modules/Assembly/Tests/CMakeLists.txt | 4 +- Modules/Binary/Include/Win32/PE.hpp | 8 ++ Modules/Binary/Tests/CMakeLists.txt | 7 +- Modules/Common/Include/Architecture.hpp | 20 ++--- Modules/Common/Include/Common.hpp | 18 ++--- Modules/Common/Include/Context.hpp | 17 ++++- Modules/Common/Source/Architecture.cpp | 15 +++- Modules/Common/Source/Context.cpp | 14 +++- Modules/Common/Source/Utils.cpp | 4 +- Modules/Process/Source/Win32/Process.cpp | 10 +-- Modules/Shellcode/CMakeLists.txt | 6 +- Modules/Shellcode/Include/Pattern.hpp | 32 ++++++++ Modules/Shellcode/Source/Pattern.cpp | 74 +++++++++++++++++++ Modules/Shellcode/Tests/CMakeLists.txt | 1 + .../Shellcode/Tests/pwn_shellcode_pattern.cpp | 36 +++++++++ Modules/Symbols/Include/Win32/API.hpp | 43 +++++++++++ Modules/Symbols/Include/Win32/Resolver.hpp | 52 +++++++------ Modules/System/Include/Win32/System.hpp | 3 +- Modules/System/Source/Win32/System.cpp | 11 ++- Tools/Win32/BasicExample/main.cpp | 46 +++++++++++- .../Win32/ProcessGhosting/ProcessGhosting.cpp | 20 ++--- cmake/FindPhnt.cmake | 2 + pwn++/Source/Win32/dllmain.cpp | 13 +--- 24 files changed, 368 insertions(+), 94 deletions(-) create mode 100644 Modules/Shellcode/Include/Pattern.hpp create mode 100644 Modules/Shellcode/Source/Pattern.cpp create mode 100644 Modules/Shellcode/Tests/pwn_shellcode_pattern.cpp diff --git a/Modules/Assembly/Source/Disassembler.cpp b/Modules/Assembly/Source/Disassembler.cpp index 86dc9f14..f3a7419e 100644 --- a/Modules/Assembly/Source/Disassembler.cpp +++ b/Modules/Assembly/Source/Disassembler.cpp @@ -301,14 +301,14 @@ Disassembler::Print(std::vector const& bytes, std::optional ar void Disassembler::X64(std::vector const& bytes) { - Disassembler::Print(bytes, Architectures["x64"]); + Disassembler::Print(bytes, Architectures[ArchitectureType::x64]); } void Disassembler::X86(std::vector const& bytes) { - Disassembler::Print(bytes, Architectures["x86"]); + Disassembler::Print(bytes, Architectures[ArchitectureType::x86]); } #endif // PWN_DISASSEMBLE_X86 @@ -316,7 +316,7 @@ Disassembler::X86(std::vector const& bytes) void Disassembler::ARM64(std::vector const& bytes) { - Disassembler::Print(bytes, Architectures["arm64"]); + Disassembler::Print(bytes, Architectures[ArchitectureType::arm64]); } #endif diff --git a/Modules/Assembly/Tests/CMakeLists.txt b/Modules/Assembly/Tests/CMakeLists.txt index e583b433..2e4324c4 100644 --- a/Modules/Assembly/Tests/CMakeLists.txt +++ b/Modules/Assembly/Tests/CMakeLists.txt @@ -1,12 +1,12 @@ enable_testing() set(TEST_EXECUTABLE_NAME tests_pwn_${PROJECT_NAME}) -list(APPEND SOURCE_FILES +set(FILES ${TEST_DIR}/main.cpp ${TEST_DIR}/pwn_disasm.cpp ) -add_executable(${TEST_EXECUTABLE_NAME} ${SOURCE_FILES}) +add_executable(${TEST_EXECUTABLE_NAME} ${FILES}) add_executable(PWN::Tests::${PROJECT_NAME} ALIAS ${TEST_EXECUTABLE_NAME}) add_dependencies(${TEST_EXECUTABLE_NAME} PWN::Deps::Catch2 PWN::${PROJECT_NAME}) target_link_libraries(${TEST_EXECUTABLE_NAME} PUBLIC Catch2::Catch2WithMain PWN::${PROJECT_NAME}) diff --git a/Modules/Binary/Include/Win32/PE.hpp b/Modules/Binary/Include/Win32/PE.hpp index beb160ef..9c4688fb 100644 --- a/Modules/Binary/Include/Win32/PE.hpp +++ b/Modules/Binary/Include/Win32/PE.hpp @@ -213,6 +213,14 @@ class PE return m_PeHeader; } + uptr const + EntryPointAddress() const + { + auto const hdrs = Header(); + return Is64b() ? std::get(hdrs).OptionalHeader.AddressOfEntryPoint : + std::get(hdrs).OptionalHeader.AddressOfEntryPoint; + } + std::vector const& DataDirectories() const diff --git a/Modules/Binary/Tests/CMakeLists.txt b/Modules/Binary/Tests/CMakeLists.txt index 3f49a4ac..35af6647 100644 --- a/Modules/Binary/Tests/CMakeLists.txt +++ b/Modules/Binary/Tests/CMakeLists.txt @@ -1,15 +1,10 @@ enable_testing() set(TEST_BINARY_PE tests_pwn_${PROJECT_NAME}) -list(APPEND SOURCE_FILES - - ${TEST_DIR}/main.cpp - ${TEST_DIR}/pwn_binary_pe.cpp -) set(DEPS PWN::Common PWN::FileSystem) file(GLOB DLL_TEST_FILES "C:/Windows/System32/*.dll") -add_executable(${TEST_BINARY_PE} ${SOURCE_FILES}) +add_executable(${TEST_BINARY_PE} ${TEST_DIR}/main.cpp ${TEST_DIR}/pwn_binary_pe.cpp) add_executable(PWN::Tests::${PROJECT_NAME}::PE ALIAS ${TEST_BINARY_PE}) add_dependencies(${TEST_BINARY_PE} PWN::Deps::Catch2 PWN::${PROJECT_NAME} ${DEPS}) target_link_libraries(${TEST_BINARY_PE} PUBLIC Catch2::Catch2WithMain PWN::${PROJECT_NAME} ${DEPS}) diff --git a/Modules/Common/Include/Architecture.hpp b/Modules/Common/Include/Architecture.hpp index c030415a..f9743505 100644 --- a/Modules/Common/Include/Architecture.hpp +++ b/Modules/Common/Include/Architecture.hpp @@ -87,25 +87,27 @@ struct Architecture /// ///@brief Find an architecture by name. The function will throw `std::range_error` - // if not found + // if not found. + /// + ///@param architecture_name /// - ///@param sv ///@return Architecture + ///@throw range_error if not found /// - static Architecture - Find(std::string_view const& sv); + static Architecture const& + Find(std::string_view const& architecture_name); }; /// ///@brief Supported architecture declarations /// -static constexpr CMap Architectures { +static constexpr CMap Architectures { {{ - {"x64"sv, {"X86_64"sv, ArchitectureType::x64, 8, Endianess::little}}, - {"x86"sv, {"X86_32"sv, ArchitectureType::x86, 4, Endianess::little}}, - {"arm64"sv, {"ARM_AARCH64"sv, ArchitectureType::arm64, 8, Endianess::little}}, - {"arm"sv, {"ARM_AARCH64"sv, ArchitectureType::arm, 4, Endianess::little}}, + {ArchitectureType::x64, {"X86_64"sv, ArchitectureType::x64, 8, Endianess::little}}, + {ArchitectureType::x86, {"X86_32"sv, ArchitectureType::x86, 4, Endianess::little}}, + {ArchitectureType::arm64, {"ARM_AARCH64"sv, ArchitectureType::arm64, 8, Endianess::little}}, + {ArchitectureType::arm, {"ARM_AARCH64"sv, ArchitectureType::arm, 4, Endianess::little}}, }}, }; diff --git a/Modules/Common/Include/Common.hpp b/Modules/Common/Include/Common.hpp index 22c0aedf..5af5e949 100644 --- a/Modules/Common/Include/Common.hpp +++ b/Modules/Common/Include/Common.hpp @@ -33,10 +33,6 @@ // clang-format on #pragma warning(pop) -#ifndef UNREFERENCED_PARAMETER -#define UNREFERENCED_PARAMETER(x) ((void)x) -#endif // UNREFERENCED_PARAMETER - #elif defined(PWN_BUILD_FOR_LINUX) // @@ -62,11 +58,12 @@ #define MAX_PATH 260 #endif // MAX_PATH +#endif // defined(PWN_BUILD_FOR_LINUX) + #ifndef UNREFERENCED_PARAMETER #define UNREFERENCED_PARAMETER(x) ((void)x) #endif // UNREFERENCED_PARAMETER -#endif // defined(PWN_BUILD_FOR_LINUX) #ifndef UnusedParameter #define UnusedParameter UNREFERENCED_PARAMETER @@ -114,9 +111,6 @@ using usize = std::size_t; using ssize = std::intptr_t; using uptr = std::uintptr_t; -#ifndef UnreferencedParameter -#define UnreferencedParameter(x) ((void)(x)) -#endif // UnreferencedParameter using namespace std::literals::string_view_literals; using namespace std::literals::chrono_literals; @@ -150,7 +144,8 @@ constexpr_concat(std::string const& arg, Args... args) template struct CMap { - std::array, Size> data; + using CMapEntry = std::pair; + std::array data; [[nodiscard]] constexpr Value at(const Key& key) const @@ -166,10 +161,7 @@ struct CMap { return itr->second; } - else - { - throw std::range_error("Not Found"); - } + throw std::range_error("Not Found"); } [[nodiscard]] constexpr Value diff --git a/Modules/Common/Include/Context.hpp b/Modules/Common/Include/Context.hpp index 8e9888e4..ea5cd0e3 100644 --- a/Modules/Common/Include/Context.hpp +++ b/Modules/Common/Include/Context.hpp @@ -41,6 +41,12 @@ class GlobalContext return; } + if constexpr ( std::is_same_v ) + { + SetArchitecture(arg); + return; + } + if constexpr ( std::is_same_v ) { SetLogLevel(arg); @@ -65,7 +71,16 @@ class GlobalContext private: /// - ///@brief Set the Architecture object + /// @brief Set the Architecture object + /// + /// @param arch + /// + void + SetArchitecture(ArchitectureType const& arch); + + + /// + ///@brief Set the Architecture object from a string /// ///@param type /// diff --git a/Modules/Common/Source/Architecture.cpp b/Modules/Common/Source/Architecture.cpp index 460d6897..42ba1214 100644 --- a/Modules/Common/Source/Architecture.cpp +++ b/Modules/Common/Source/Architecture.cpp @@ -36,10 +36,21 @@ operator<<(std::wostream& wos, Endianess e) } -Architecture +const Architecture& Architecture::Find(std::string_view const& sv) { - return Architectures.at(sv); + auto entry = std::find_if( + Architectures.data.cbegin(), + Architectures.data.cend(), + [&](auto const& e) + { + return e.second.name == sv; + }); + if ( entry == Architectures.data.cend() ) + { + throw std::range_error("Architecture not found"); + } + return entry->second; } diff --git a/Modules/Common/Source/Context.cpp b/Modules/Common/Source/Context.cpp index 229ab6eb..8a415d08 100644 --- a/Modules/Common/Source/Context.cpp +++ b/Modules/Common/Source/Context.cpp @@ -13,14 +13,20 @@ GlobalContext::GlobalContext() Set("x64"); }; +void +GlobalContext::SetArchitecture(ArchitectureType const& archtype) +{ + architecture = Architectures.at(archtype); +} void GlobalContext::SetArchitecture(std::string_view const& type) { - architecture = Architecture::Find(type); - endianess = architecture.endian; - ptrsize = architecture.ptrsize; - dbg("Selecting '{}'", architecture); + auto arch = Architecture::Find(type); + architecture = arch; + endianess = arch.endian; + ptrsize = arch.ptrsize; + dbg("Selecting '{}'", arch); } diff --git a/Modules/Common/Source/Utils.cpp b/Modules/Common/Source/Utils.cpp index 0d048ef6..8d721497 100644 --- a/Modules/Common/Source/Utils.cpp +++ b/Modules/Common/Source/Utils.cpp @@ -209,7 +209,7 @@ Random::Next() -> u64 auto -Random::Next(u64 const max, u64 const min) noexcept -> u64 +Random::Next(u64 const min, u64 const max) noexcept -> u64 { return (XorShift64() + min) % max; } @@ -521,7 +521,7 @@ Pack::p8(u8 v, Endianess e) void Pause() { - dbg("Pausing, press enter to resume..."); + info("Pausing, press enter to resume..."); std::cin.get(); } diff --git a/Modules/Process/Source/Win32/Process.cpp b/Modules/Process/Source/Win32/Process.cpp index e8a27081..9918b093 100644 --- a/Modules/Process/Source/Win32/Process.cpp +++ b/Modules/Process/Source/Win32/Process.cpp @@ -94,9 +94,6 @@ Process::Process(u32 Pid) : m_ProcessId {Pid} throw std::runtime_error("Process initialization error"); } - xdbg("Process handle with {}", ProcessAccessToString(m_ProcessHandleAccessMask).c_str()); - - // Process PPID { auto BasicInfo = Value(Query(PROCESSINFOCLASS::ProcessBasicInformation)); @@ -107,7 +104,7 @@ Process::Process(u32 Pid) : m_ProcessId {Pid} // Full path { auto NativeFilePath = Value(Query(PROCESSINFOCLASS::ProcessImageFileName)); - m_NativePath = std::wstring {NativeFilePath->Buffer}; + m_NativePath = (NativeFilePath->Length) ? std::wstring {NativeFilePath->Buffer} : std::wstring {L""}; } } @@ -115,7 +112,8 @@ Process::Process(u32 Pid) : m_ProcessId {Pid} Process::Process(HANDLE&& hProcess) : Process(::GetProcessId(hProcess)) { m_ProcessHandle.reset(std::move(hProcess)); - m_ProcessHandleAccessMask = PROCESS_ALL_ACCESS; + // TODO: fix by querying existing access + m_ProcessHandleAccessMask = PROCESS_QUERY_LIMITED_INFORMATION; } @@ -525,6 +523,8 @@ Process::ReOpenProcessWith(const DWORD DesiredAccess) // m_ProcessHandle = UniqueHandle {hProcess}; m_ProcessHandleAccessMask = NewAccessMask; + + xdbg("Process handle with {}", ProcessAccessToString(m_ProcessHandleAccessMask).c_str()); return Ok(true); } diff --git a/Modules/Shellcode/CMakeLists.txt b/Modules/Shellcode/CMakeLists.txt index dadf3b02..27ba9e7a 100644 --- a/Modules/Shellcode/CMakeLists.txt +++ b/Modules/Shellcode/CMakeLists.txt @@ -7,8 +7,12 @@ set(SOURCE_DIR ${PROJECT_DIR}/Source) set(HEADER_DIR ${SOURCE_DIR}/Include) set(TEST_DIR ${PROJECT_DIR}/Tests) +set(SOURCE_FILES + ${SOURCE_DIR}/Pattern.cpp +) + if(WIN32) - set(SOURCE_FILES + list(APPEND SOURCE_FILES ${SOURCE_DIR}/Win32/Kernel.cpp $<$:${SOURCE_DIR}/Win32/asm/x64/copy_system_token.asm> diff --git a/Modules/Shellcode/Include/Pattern.hpp b/Modules/Shellcode/Include/Pattern.hpp new file mode 100644 index 00000000..3bb398e4 --- /dev/null +++ b/Modules/Shellcode/Include/Pattern.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include "Common.hpp" + + +namespace pwn::Shellcode +{ + +/// +///@brief +/// +///@param Bytes +///@param Needle +///@param NeedleMask +/// +///@return ssize +/// +ssize +PatternFind(std::vector const& Bytes, std::vector const& Needle, std::vector const& NeedleMask); + +/// +///@brief +/// +///@param Bytes +///@param Needle +/// +///@return ssize +/// +ssize +PatternFind(std::vector const& Bytes, std::vector const& Needle); + +} // namespace pwn::Shellcode diff --git a/Modules/Shellcode/Source/Pattern.cpp b/Modules/Shellcode/Source/Pattern.cpp new file mode 100644 index 00000000..64368a41 --- /dev/null +++ b/Modules/Shellcode/Source/Pattern.cpp @@ -0,0 +1,74 @@ +#include "Pattern.hpp" + +#include + +namespace pwn::Shellcode +{ + +// ssize PatternFind(Utils::MemoryView const& View, , std::vector const& Needle, std::vector const& NeedleMask) + +ssize +PatternFind(std::vector const& Bytes, std::vector const& Needle, std::vector const& NeedleMask) +{ + if ( Needle.size() > Bytes.size() ) + { + return -1; + } + + if ( Needle.size() != NeedleMask.size() ) + { + return -1; + } + + ssize i = 0; + ssize offset1 = 0; + ssize offset2 = 0; + usize match = 0; + + for ( auto byte : Bytes ) + { + // + // Compare the current byte + // + if ( (byte & NeedleMask[offset2]) == Needle[offset2] ) + { + offset2++; + match++; + } + else + { + offset1 = i + 1; + offset2 = 0; + match = 0; + } + + // + // Exit if found a complete sequence + // + if ( match == Needle.size() ) + { + return offset1; + } + + i++; + } + + return -1; +} + +ssize +PatternFind(std::vector const& Bytes, std::vector const& Needle) +{ + std::vector NeedleMask; + NeedleMask.resize(Needle.size()); + std::for_each( + NeedleMask.begin(), + NeedleMask.end(), + [](auto& c) + { + c = 0xff; + }); + return PatternFind(Bytes, Needle, NeedleMask); +} + +} // namespace pwn::Shellcode diff --git a/Modules/Shellcode/Tests/CMakeLists.txt b/Modules/Shellcode/Tests/CMakeLists.txt index 49c6e3d8..7879ba51 100644 --- a/Modules/Shellcode/Tests/CMakeLists.txt +++ b/Modules/Shellcode/Tests/CMakeLists.txt @@ -3,6 +3,7 @@ set(TEST_EXECUTABLE_NAME tests_pwn_${PROJECT_NAME}) list(APPEND SOURCE_FILES ${TEST_DIR}/main.cpp + ${TEST_DIR}/pwn_shellcode_pattern.cpp ) add_executable(${TEST_EXECUTABLE_NAME} ${SOURCE_FILES}) diff --git a/Modules/Shellcode/Tests/pwn_shellcode_pattern.cpp b/Modules/Shellcode/Tests/pwn_shellcode_pattern.cpp new file mode 100644 index 00000000..4a413915 --- /dev/null +++ b/Modules/Shellcode/Tests/pwn_shellcode_pattern.cpp @@ -0,0 +1,36 @@ +#include + +#include "Pattern.hpp" +#define NS "pwn::Shellcode" + +using namespace pwn; + +TEST_CASE("Pattern tests", "[" NS "]") +{ + SECTION("PatternFind(no mask)") + { + const std::vector bytes {0x01, 0x02, 0x03, 0x04}; + const std::vector needle1 {0x01, 0x02}; + const std::vector needle2 {0x03, 0x04}; + const std::vector needle3 {0x01, 0x04}; + + CHECK(Shellcode::PatternFind(bytes, needle1) == 0); + CHECK(Shellcode::PatternFind(bytes, needle2) == 2); + CHECK(Shellcode::PatternFind(bytes, needle3) == -1); + } + + SECTION("PatternFind(mask)") + { + const std::vector bytes {0x00, 0x11, 0x88, 0xff}; + const std::vector needle1 {0x00, 0x01}; + const std::vector mask1 {0x00, 0x0f}; + const std::vector needle2 {0x80, 0x80}; + const std::vector mask2 {0xf0, 0x80}; + const std::vector needle3 {0x88, 0xff}; + const std::vector mask3 {0x01, 0x00}; + + CHECK(Shellcode::PatternFind(bytes, needle1, mask1) == 0); + CHECK(Shellcode::PatternFind(bytes, needle2, mask2) == 2); + CHECK(Shellcode::PatternFind(bytes, needle3, mask3) == -1); + } +} diff --git a/Modules/Symbols/Include/Win32/API.hpp b/Modules/Symbols/Include/Win32/API.hpp index ba62a5fb..04514746 100644 --- a/Modules/Symbols/Include/Win32/API.hpp +++ b/Modules/Symbols/Include/Win32/API.hpp @@ -116,6 +116,19 @@ ExternalImport( ULONG ProcessInformationLength, PULONG ReturnLength); +ExternalImport( + "ntdll.dll", + NtCreateProcess, + NTSTATUS, + _Out_ PHANDLE ProcessHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE ParentProcess, + _In_ BOOLEAN InheritObjectTable, + _In_opt_ HANDLE SectionHandle, + _In_opt_ HANDLE DebugPort, + _In_opt_ HANDLE ExceptionPort); + ExternalImport( "ntdll.dll", NtCreateProcessEx, @@ -146,6 +159,20 @@ ExternalImport( _In_opt_ PUNICODE_STRING RuntimeData, _In_ ULONG Flags); + +ExternalImport( + "ntdll.dll", + NtCreateThread, + NTSTATUS, + _Out_ PHANDLE ThreadHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, + _In_ HANDLE ProcessHandle, + _Out_ PCLIENT_ID ClientId, + _In_ PCONTEXT ThreadContext, + _In_ PINITIAL_TEB InitialTeb, + _In_ BOOLEAN CreateSuspended); + ExternalImport( "ntdll.dll", NtCreateThreadEx, @@ -174,6 +201,22 @@ ExternalImport( IN ULONG SectionAttributes, IN HANDLE FileHandle OPTIONAL); + +ExternalImport( + "ntdll.dll", + NtCreateTransaction, + NTSTATUS, + PHANDLE TransactionHandle, + ACCESS_MASK DesiredAccess, + POBJECT_ATTRIBUTES ObjectAttributes, + LPGUID Uow, + HANDLE TmHandle, + ULONG CreateOptions, + ULONG IsolationLevel, + ULONG IsolationFlags, + PLARGE_INTEGER Timeout, + PUNICODE_STRING Description); + ExternalImport( "ntdll.dll", NtOpenFile, diff --git a/Modules/Symbols/Include/Win32/Resolver.hpp b/Modules/Symbols/Include/Win32/Resolver.hpp index e6ef3561..25541908 100644 --- a/Modules/Symbols/Include/Win32/Resolver.hpp +++ b/Modules/Symbols/Include/Win32/Resolver.hpp @@ -12,14 +12,19 @@ static std::unordered_map pwn_Modules {}; #define ExternalImport(Dll, Func, Ret, ...) \ typedef Ret(NTAPI* CONCAT(pwnFn_, Func))(__VA_ARGS__); \ template \ - static auto Func(Ts... Args)->Ret \ + static auto Func(Ts... Args) -> Ret \ { \ - if ( !pwn_Modules.contains(Dll) ) \ + if ( !pwn_Modules.contains(Dll) ) [[unlikely]] \ { \ - pwn_Modules[Dll] = ::LoadLibraryA(Dll); \ + HMODULE hMod = ::LoadLibraryA(Dll); \ + if ( !hMod ) \ + { \ + throw std::runtime_error("Missing library " Dll "!"); \ + } \ + pwn_Modules[Dll] = hMod; \ } \ static auto fnPtr = reinterpret_cast(::GetProcAddress(pwn_Modules[Dll], #Func)); \ - if ( !fnPtr ) \ + if ( !fnPtr ) [[unlikely]] \ { \ throw std::runtime_error("Missing import " Dll "!" #Func); \ } \ @@ -29,27 +34,32 @@ static std::unordered_map pwn_Modules {}; #if defined(PWN_BUILD_FOR_LINUX) -static std::unordered_map pwn_Modules {}; +static std::unordered_map pwn_Modules {}; -#define ExternalImport(Dll, Func, Ret, ...) \ - typedef Ret(NTAPI* CONCAT(pwnFn_, Func))(__VA_ARGS__); \ - template \ - auto Func(Ts... Args)->Ret \ - { \ - if ( !pwn_Modules.contains(Dll) ) \ - { \ - pwn_Modules[Dll] = ::::dlopen((Dll, RTLD_LAZY); \ - } \ - static auto fnPtr = ::dlsym(pwn_Modules[Dll], #Func)); \ - if ( !fnPtr ) \ - { \ - throw std::runtime_error("Missing import " Dll "!" #Func); \ - } \ - return fnPtr(std::forward(Args)...); \ +#define ExternalImport(Dll, Func, Ret, ...) \ + typedef Ret(NTAPI* CONCAT(pwnFn_, Func))(__VA_ARGS__); \ + template \ + auto Func(Ts... Args) -> Ret \ + { \ + if ( !pwn_Modules.contains(Dll) ) \ + { \ + void * hMod = ::::dlopen((Dll, RTLD_LAZY); \ + if ( !hMod ) \ + { \ + throw std::runtime_error("Missing library " Dll "!"); \ + } \ + pwn_Modules[Dll] = hMod; \ + } \ + static auto fnPtr = ::dlsym(pwn_Modules[Dll], #Func)); \ + if ( !fnPtr ) \ + { \ + throw std::runtime_error("Missing import " Dll "!" #Func); \ + } \ + return fnPtr(std::forward(Args)...); \ } #endif // PWN_BUILD_FOR_LINUX -}; // namespace pwn::Resolver +}; // namespace pwn::Resolver #define RestrictedType(...) const auto& __VA_OPT__(, RestrictedType(__VA_ARGS__)) diff --git a/Modules/System/Include/Win32/System.hpp b/Modules/System/Include/Win32/System.hpp index f4832eca..2fa2737b 100644 --- a/Modules/System/Include/Win32/System.hpp +++ b/Modules/System/Include/Win32/System.hpp @@ -44,7 +44,8 @@ PageSize() -> u32; ///@return u32 /// u32 -ProcessId(const HANDLE hProcess); +ProcessId(const HANDLE hProcess = ::GetCurrentProcess()); + /// ///@brief diff --git a/Modules/System/Source/Win32/System.cpp b/Modules/System/Source/Win32/System.cpp index 5f0584df..5f7795f9 100644 --- a/Modules/System/Source/Win32/System.cpp +++ b/Modules/System/Source/Win32/System.cpp @@ -30,9 +30,14 @@ namespace pwn::System auto PageSize() -> u32 { - SYSTEM_INFO siSysInfo {}; - ::GetSystemInfo(&siSysInfo); - return siSysInfo.dwPageSize; + static u32 __page_size {}; + if ( !__page_size ) [[unlikely]] + { + SYSTEM_INFO siSysInfo {}; + ::GetSystemInfo(&siSysInfo); + __page_size = siSysInfo.dwPageSize; + } + return __page_size; } diff --git a/Tools/Win32/BasicExample/main.cpp b/Tools/Win32/BasicExample/main.cpp index 3f7be87f..88852671 100644 --- a/Tools/Win32/BasicExample/main.cpp +++ b/Tools/Win32/BasicExample/main.cpp @@ -15,6 +15,17 @@ using namespace pwn; #endif // VARIABLE_ATTRIBUTE_NON_VOLATILE +DWORD +Test(PVOID Arg) +{ + while ( true ) + { + ok("hello"); + ::Sleep(1000); + } + return 0; +} + auto wmain(const int argc, const wchar_t** argv) -> int { @@ -22,10 +33,41 @@ wmain(const int argc, const wchar_t** argv) -> int Context.Set(Log::LogLevel::Debug); + auto self = Process::Current(); + self.ReOpenProcessWith(PROCESS_CREATE_PROCESS); + HANDLE h {}; + auto st = Resolver::ntdll::NtCreateProcessEx( + &h, + PROCESS_ALL_ACCESS, + nullptr, + self.Handle(), + 0, + nullptr, + nullptr, + nullptr, + false); + Log::ntperror("NtCreateProcess", st); + + Process::Process child(std::move(h)); + child.ReOpenProcessWith( + PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ); + ok("PID {} has {} threads", child.Id(), child.Threads().size()); + + DWORD tid {}; + bool b1 = ::CreateRemoteThread(child.Handle(), nullptr, 0, (LPTHREAD_START_ROUTINE)Test, nullptr, 0, &tid); + if ( !b1 ) + { + Log::perror("CreateRemoteThread"); + } + else + { + ok("CreateRemoteThread returned {}", b1); + } + + // // Get the current process and its token // - auto self = Process::Current(); Security::Token ProcessToken(self.Handle(), Security::Token::Granularity::Process); if ( Failed(ProcessToken.AddPrivilege(L"SeSystemEnvironmentPrivilege")) ) { @@ -56,7 +98,7 @@ wmain(const int argc, const wchar_t** argv) -> int UNICODE_STRING UnlockIdName; ::RtlInitUnicodeString(&UnlockIdName, L"UnlockIDCopy"); - Status = NtQuerySystemEnvironmentValueEx( + Status = Resolver::ntdll::NtQuerySystemEnvironmentValueEx( &UnlockIdName, (LPGUID)GuidUnlockId.data(), value.data(), diff --git a/Tools/Win32/ProcessGhosting/ProcessGhosting.cpp b/Tools/Win32/ProcessGhosting/ProcessGhosting.cpp index a47b9e91..ac078208 100644 --- a/Tools/Win32/ProcessGhosting/ProcessGhosting.cpp +++ b/Tools/Win32/ProcessGhosting/ProcessGhosting.cpp @@ -25,8 +25,7 @@ wmain(const int argc, const wchar_t** argv) -> int const auto GhostProcessPath = (argc >= 2) ? std::filesystem::path(argv[1]) : std::filesystem::path(L"\\\\?\\C:\\Windows\\System32\\winver.exe"); - const auto GhostedProcessPath = - (argc >= 3) ? std::filesystem::path(argv[2]) : std::filesystem::path(L"\\\\?\\c:\\temp\\ghost.exe"); + const auto GhostedProcessPath = std::filesystem::temp_directory_path() / Utils::Random::AlnumWideString(10); dbg("Ghosting '{}' as '{}'", GhostProcessPath.string(), GhostedProcessPath.string()); @@ -60,6 +59,7 @@ wmain(const int argc, const wchar_t** argv) -> int // 3. Write the payload executable to the file. The content isn’t persisted because the file is already // delete-pending. The delete-pending state also blocks external file-open attempts. // + uptr BaseAddress = 0; { auto const FileSize = ValueOr(PayloadFile.Size(), 0); auto hMap = Value(PayloadFile.Map(PAGE_READONLY)); @@ -134,14 +134,13 @@ wmain(const int argc, const wchar_t** argv) -> int // // 7. Assign process arguments and environment variables. // - Process::Memory GhostedProcessMemory(GhostedProcess); auto PebRaw = Value(GhostedProcessMemory.Read((uptr)GhostedProcess.ProcessEnvironmentBlock(), sizeof(PEB))); auto Peb = reinterpret_cast(PebRaw.data()); Binary::PE PeTarget {GhostProcessPath}; - Peb->ImageBaseAddress = - (PVOID)((uptr)(std::get(PeTarget.Header()).OptionalHeader.AddressOfEntryPoint)); + const uptr StartAddress = BaseAddress + PeTarget.EntryPointAddress(); + Peb->ImageBaseAddress = (PVOID)StartAddress; GhostedProcessMemory.Write((uptr)GhostedProcess.ProcessEnvironmentBlock(), PebRaw); dbg("Overwriting PEB in process PID={}", GhostedProcess.ProcessId()); @@ -149,11 +148,10 @@ wmain(const int argc, const wchar_t** argv) -> int // // 8. Create a thread to execute in the process. // - uptr StartAddress = 0; - UniqueHandle hThread { + const UniqueHandle hThread { [&StartAddress, &GhostedProcess]() -> HANDLE { - HANDLE h; + HANDLE h {}; return NT_SUCCESS(pwn::Resolver::ntdll::NtCreateThreadEx( &h, THREAD_ALL_ACCESS, @@ -161,7 +159,7 @@ wmain(const int argc, const wchar_t** argv) -> int GhostedProcess.Handle(), (LPTHREAD_START_ROUTINE)StartAddress, nullptr, - false, + 0, 0, 0, 0, @@ -175,12 +173,14 @@ wmain(const int argc, const wchar_t** argv) -> int return EXIT_FAILURE; } - ok("Started thread TID={} with start address @ {} in process PID={}", + ok("Started thread TID={} with start address @ {:#x} in process PID={}", hThread.get(), StartAddress, GhostedProcess.ProcessId()); Utils::Pause(); + ::WaitForSingleObject(hThread.get(), INFINITE); + return EXIT_SUCCESS; } diff --git a/cmake/FindPhnt.cmake b/cmake/FindPhnt.cmake index 4196fd54..6ce8f73c 100644 --- a/cmake/FindPhnt.cmake +++ b/cmake/FindPhnt.cmake @@ -1,3 +1,5 @@ +include(FetchContent) + FetchContent_Declare( Deps_PhNt GIT_REPOSITORY https://github.com/winsiderss/phnt.git diff --git a/pwn++/Source/Win32/dllmain.cpp b/pwn++/Source/Win32/dllmain.cpp index 92c0b492..90271167 100644 --- a/pwn++/Source/Win32/dllmain.cpp +++ b/pwn++/Source/Win32/dllmain.cpp @@ -1,15 +1,14 @@ #include + using namespace pwn; -#if PWN_BUILD_SHARED_LIB -#ifdef PWN_BUILD_FOR_WINDOWS void OnAttachRoutine() { // // Initialize the RNG // - utils::random::seed(); + Utils::Random::Seed(); } @@ -22,8 +21,8 @@ OnDetachRoutine() BOOL APIENTRY DllMain(_In_ HMODULE hModule, _In_ DWORD ul_reason_for_call, _In_ LPVOID lpReserved) { - UnreferencedParameter(hModule); - UnreferencedParameter(lpReserved); + UnusedParameter(hModule); + UnusedParameter(lpReserved); switch ( ul_reason_for_call ) { @@ -41,7 +40,3 @@ DllMain(_In_ HMODULE hModule, _In_ DWORD ul_reason_for_call, _In_ LPVOID lpReser } return true; } - -#endif // PWN_BUILD_FOR_WINDOWS - -#endif // PWN_BUILD_SHARED_LIB