bypassed EAC (example)

master
xerox 4 years ago
parent e9ad4d7bd3
commit 7fb4f9484c

@ -1,3 +1,4 @@
#include <iostream>
#include "nozzle.hpp" #include "nozzle.hpp"
int main(const int argc, const char** argv) int main(const int argc, const char** argv)
@ -17,4 +18,5 @@ int main(const int argc, const char** argv)
std::printf("[+] module base => %p\n", module_base); std::printf("[+] module base => %p\n", module_base);
std::getchar(); std::getchar();
} }

@ -50,6 +50,46 @@ return false;\
// //
namespace util namespace util
{ {
inline void write(HANDLE target_handle, void* addr, void* buffer, std::size_t size)
{
SIZE_T bytes_written;
::WriteProcessMemory(
target_handle,
addr,
buffer,
size,
&bytes_written
);
}
inline void read(HANDLE target_handle, void* addr, void* buffer, std::size_t size)
{
SIZE_T bytes_read;
::ReadProcessMemory(
target_handle,
addr,
buffer,
size,
&bytes_read
);
}
template <class T>
inline T read(HANDLE target_handle, void* addr)
{
if (!addr) return {};
T buffer;
read(target_handle, addr, static_cast<void*>(&buffer), sizeof(T));
return buffer;
}
template <class T>
inline void write(HANDLE target_handle, void* addr, const T& data)
{
if (!addr) return;
write(target_handle, addr, static_cast<void*>(&data), sizeof(T));
}
using uq_handle = std::unique_ptr<void, decltype(&CloseHandle)>; using uq_handle = std::unique_ptr<void, decltype(&CloseHandle)>;
inline void open_binary_file(const std::string& file, std::vector<uint8_t>& data) inline void open_binary_file(const std::string& file, std::vector<uint8_t>& data)
{ {
@ -365,25 +405,20 @@ namespace nozzle
HANDLE target_handle; HANDLE target_handle;
void* alloc_base; void* alloc_base;
void write(void* addr, void* buffer, std::size_t size);
void read(void* addr, void* buffer, std::size_t size);
template <class T> template <class T>
T read(void* addr) T read(void* addr)
{ {
if (!addr) if (!addr) return {};
return {};
T buffer; T buffer;
read(addr, &buffer, sizeof(T)); read(target_handle, addr, static_cast<void*>(&buffer), sizeof(T));
return buffer; return buffer;
} }
template <class T> template <class T>
void write(void* addr, const T& data) void write(void* addr, const T& data)
{ {
if (!addr) if (!addr) return;
return; write(target_handle, addr, static_cast<void*>(&data), sizeof(T));
write(addr, (void*)&data, sizeof(T));
} }
}; };
@ -400,9 +435,8 @@ namespace nozzle
std::vector<std::uint8_t> image_buffer; std::vector<std::uint8_t> image_buffer;
util::open_binary_file(path, image_buffer); util::open_binary_file(path, image_buffer);
this->image_buffer = image_buffer; this->image_buffer = image_buffer;
std::printf("[+] enabled debug priv => %d\n", util::enable_privilege(L"SeDebugPrivilege")); util::enable_privilege(L"SeDebugPrivilege");
this->target_handle = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); this->target_handle = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
std::printf("[+] target handle => %p\n", target_handle);
} }
injector::injector(std::vector<std::uint8_t> image_buffer, unsigned pid) injector::injector(std::vector<std::uint8_t> image_buffer, unsigned pid)
@ -446,7 +480,7 @@ namespace nozzle
image.fix_imports(_get_module, _get_function); image.fix_imports(_get_module, _get_function);
image.map(); image.map();
image.relocate(reinterpret_cast<std::uintptr_t>(alloc_base)); image.relocate(reinterpret_cast<std::uintptr_t>(alloc_base));
write(alloc_base, image.data(), image.size()); util::write(this->target_handle, alloc_base, image.data(), image.size());
return alloc_base; return alloc_base;
} }
@ -457,7 +491,7 @@ namespace nozzle
std::uint8_t jmp_rip[14] = { 0xff, 0x25, 0x0, 0x0, 0x0, 0x0 }; std::uint8_t jmp_rip[14] = { 0xff, 0x25, 0x0, 0x0, 0x0, 0x0 };
*reinterpret_cast<std::uintptr_t*>(jmp_rip + 6) = reinterpret_cast<std::uintptr_t>(alloc_base) + image.entry_point(); *reinterpret_cast<std::uintptr_t*>(jmp_rip + 6) = reinterpret_cast<std::uintptr_t>(alloc_base) + image.entry_point();
static const auto rtl_alloc_heap = GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtClose"); static const auto rtl_alloc_heap = GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtClose");
write(rtl_alloc_heap, jmp_rip, sizeof(jmp_rip)); util::write(this->target_handle, rtl_alloc_heap, jmp_rip, sizeof(jmp_rip));
} }
void* injector::get_allocated_base() const void* injector::get_allocated_base() const
@ -484,28 +518,4 @@ namespace nozzle
{ {
return target_pid; return target_pid;
} }
void injector::write(void* addr, void* buffer, std::size_t size)
{
SIZE_T bytes_written;
::WriteProcessMemory(
target_handle,
addr,
buffer,
size,
&bytes_written
);
}
void injector::read(void* addr, void* buffer, std::size_t size)
{
SIZE_T bytes_read;
::ReadProcessMemory(
target_handle,
addr,
buffer,
size,
&bytes_read
);
}
} }

@ -0,0 +1,129 @@
#pragma once
#include <Windows.h>
#include <cstdint>
#include <atomic>
// would use std::pair but that requires #include <map> which causes unresolved externals...
using ioctl_data = struct { HANDLE drv_handle; void* return_addr; };
#define READ_IOCTL 0x0222000
#define WRITE_IOCTL 0x0222004
namespace bedaisy
{
struct beioctl
{
void* ret_addr;
void* handle;
std::uintptr_t base_addr;
void* buffer;
size_t buffer_size;
size_t* bytes_read;
};
inline ioctl_data get_ioctl_data()
{
const auto wpm =
reinterpret_cast<std::uint8_t*>(
GetProcAddress(GetModuleHandleA("ntdll.dll"),
"NtWriteVirtualMemory"));
// ensure inline jump is installed...
if (*reinterpret_cast<std::uint8_t*>(wpm) == 0xFF)
{
// + 6 into jump code is the address of where the jump goes to.
const auto shellcode_ptr = *reinterpret_cast<std::uint8_t**>(wpm + 6);
// + 50 into the shellcode is the HARDCODED file handle used for DeviceIoControl...
const auto ioctl_handle = *reinterpret_cast<HANDLE*>(shellcode_ptr + 0x50);
// return address should be landing in this module
// (its not actually spoofing return address, just informational, used in ioctl data...)
const auto lsasrv =
reinterpret_cast<std::uintptr_t>(
GetModuleHandleA("lsasrv.dll"));
// 0f 1f 44 00 ? 8b f0 48 8b 0d ? ? ? ? 49 3b cd (proper return)
return { ioctl_handle, reinterpret_cast<void*>(lsasrv + 0x36E3B) }; // windows 10 2004 RVA you will need to update for your winver! :)
}
return { {}, {} };
}
inline void read(HANDLE proc_handle, std::uintptr_t addr, void* buffer, std::size_t size)
{
if (!addr || !buffer || !size)
return;
const auto [daisy_handle, return_addr] = get_ioctl_data();
const beioctl ioctl_data
{
return_addr,
proc_handle,
addr,
buffer,
size,
nullptr
};
DWORD bytes_read;
DeviceIoControl
(
daisy_handle,
READ_IOCTL,
(void*)&ioctl_data,
sizeof ioctl_data,
nullptr,
NULL,
&bytes_read,
nullptr
);
}
void write(HANDLE proc_handle, std::uintptr_t addr, void* buffer, std::size_t size)
{
if (!proc_handle || !addr)
return;
const auto [daisy_handle, return_addr] = get_ioctl_data();
const beioctl ioctl_data
{
return_addr,
proc_handle,
addr,
buffer,
size,
nullptr
};
DWORD bytes_read;
DeviceIoControl
(
daisy_handle,
WRITE_IOCTL,
(void*)&ioctl_data,
sizeof ioctl_data,
nullptr,
NULL,
&bytes_read,
nullptr
);
}
template <class T>
inline T read(HANDLE proc_handle, std::uintptr_t addr)
{
if (!addr || !proc_handle)
return {};
T buffer{};
read(proc_handle, addr, static_cast<void*>(&buffer), sizeof(T));
return buffer;
}
template <class T>
inline void write(HANDLE proc_handle, std::uintptr_t addr, const T& data)
{
if (!proc_handle || !addr)
return;
write(proc_handle, addr, static_cast<void*>(&data), sizeof(T));
}
}

@ -1,128 +1,31 @@
#include <Windows.h> #include "bedaisy.hpp"
#include <atomic> #include "utils.hpp"
#include <cstdint>
// would use std::pair but that requires #include <map> which causes unresolved externals... void read_demo()
using ioctl_data = struct { HANDLE drv_handle; void* return_addr; };
#define READ_IOCTL 0x0222000
#define WRITE_IOCTL 0x0222004
namespace bedaisy
{ {
struct beioctl OutputDebugStringA("[lsass] main thread created!");
{ const auto rust_handle =
void* ret_addr; OpenProcess(
void* handle; PROCESS_QUERY_INFORMATION, FALSE,
std::uintptr_t base_addr; utils::get_pid(L"RustClient.exe")
void* buffer;
size_t buffer_size;
size_t* bytes_read;
};
inline ioctl_data get_ioctl_data()
{
const auto wpm =
reinterpret_cast<std::uint8_t*>(
GetProcAddress(GetModuleHandleA("ntdll.dll"),
"NtWriteVirtualMemory"));
// ensure inline jump is installed...
if (*reinterpret_cast<std::uint8_t*>(wpm) == 0xFF)
{
const auto shellcode_ptr = *reinterpret_cast<std::uint8_t**>(wpm + 6);
const auto ioctl_handle = *reinterpret_cast<HANDLE*>(shellcode_ptr + 0x50);
const auto lsasrv =
reinterpret_cast<std::uintptr_t>(
GetModuleHandleA("lsasrv.dll"));
// 0f 1f 44 00 ? 8b f0 48 8b 0d ? ? ? ? 49 3b cd (proper return)
return { ioctl_handle, reinterpret_cast<void*>(lsasrv + 0x36E3B) }; // windows 10 2004 RVA you will need to update for your winver! :)
}
return { {}, {} };
}
template <class T>
inline T read(HANDLE proc_handle, std::uintptr_t addr)
{
if (!addr || !proc_handle)
return {};
T buffer;
const auto [daisy_handle, return_addr] = get_ioctl_data();
const beioctl ioctl_data
{
return_addr,
proc_handle,
addr,
&buffer,
sizeof(T),
nullptr
};
DWORD bytes_read;
DeviceIoControl
(
daisy_handle,
READ_IOCTL,
(void*)&ioctl_data,
sizeof ioctl_data,
nullptr,
NULL,
&bytes_read,
nullptr
); );
return buffer;
}
template <class T> if (rust_handle)
inline void write(HANDLE proc_handle, std::uintptr_t addr, const T& data)
{ {
if (!proc_handle || !addr) const auto game_base = utils::get_proc_base(rust_handle);
return; if (bedaisy::read<std::uint16_t>(rust_handle, game_base) == 0x5A4D)
OutputDebugStringA("[lsass] read rust MZ!");
const auto [daisy_handle, return_addr] = get_ioctl_data(); else
const beioctl ioctl_data OutputDebugStringA("[lsass] didnt read rust MZ!");
{
return_addr, const auto asm_base = utils::get_module_base(rust_handle, L"GameAssembly.dll");
proc_handle, if (bedaisy::read<std::uint16_t>(rust_handle, asm_base) == 0x5A4D)
addr, OutputDebugStringA("[lsass] read game assembly MZ!");
(void*)&data, else
sizeof(T), OutputDebugStringA("[lsass] didnt game assembly MZ!");
nullptr
};
DWORD bytes_read;
DeviceIoControl
(
daisy_handle,
WRITE_IOCTL,
(void*)&ioctl_data,
sizeof ioctl_data,
nullptr,
NULL,
&bytes_read,
nullptr
);
} }
} }
void read_demo()
{
OutputDebugStringA("[lsass] main thread created!");
// pid 4 is system process....
const auto system_process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, 4);
// global mapped... gunna be the same addr in system proc....
const auto ntdll = reinterpret_cast<std::uintptr_t>(GetModuleHandleA("ntdll.dll"));
if(bedaisy::read<std::uint16_t>(system_process, ntdll) == 0x5A4D)
OutputDebugStringA("[lsass] read MZ!");
else
OutputDebugStringA("[lsass] didnt read MZ!");
}
std::atomic<bool> init = false; std::atomic<bool> init = false;
extern "C" NTSTATUS nt_close(void* handle) extern "C" NTSTATUS nt_close(void* handle)
{ {

@ -137,7 +137,7 @@
<ClCompile> <ClCompile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>false</IntrinsicFunctions>
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;HELLOWORLD_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>NDEBUG;HELLOWORLD_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode> <ConformanceMode>true</ConformanceMode>
@ -156,13 +156,17 @@
<EnableUAC>false</EnableUAC> <EnableUAC>false</EnableUAC>
<EntryPointSymbol>nt_close</EntryPointSymbol> <EntryPointSymbol>nt_close</EntryPointSymbol>
<NoEntryPoint>false</NoEntryPoint> <NoEntryPoint>false</NoEntryPoint>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>ntdll.lib;libvcruntime.lib;libucrt.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries> <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="dllmain.cpp" /> <ClCompile Include="dllmain.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ClInclude Include="bedaisy.hpp" />
<ClInclude Include="utils.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" /> <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />

@ -5,10 +5,21 @@
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions> <Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter> </Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{daf3b77a-fcd2-4fca-bcf0-7da17ed41da6}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="dllmain.cpp"> <ClCompile Include="dllmain.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup>
<ClInclude Include="bedaisy.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="utils.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project> </Project>

@ -0,0 +1,101 @@
#pragma once
#include <Windows.h>
#include <TlHelp32.h>
#include <winternl.h>
#include <string>
#include "bedaisy.hpp"
char print_buffer[0x1000];
namespace utils
{
struct nt_peb
{
std::uintptr_t res[2];
std::uintptr_t image_base;
std::uintptr_t ldr;
std::uintptr_t proc_params;
};
inline uint32_t get_pid(const std::wstring_view process_name)
{
const auto handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (handle == INVALID_HANDLE_VALUE)
return !CloseHandle(handle);
PROCESSENTRY32W process_entry{ sizeof(PROCESSENTRY32W) };
for (Process32FirstW(handle, &process_entry); Process32NextW(handle, &process_entry); )
{
if (std::wcscmp(process_name.data(), process_entry.szExeFile) == NULL)
{
CloseHandle(handle);
return process_entry.th32ProcessID;
}
}
CloseHandle(handle);
return NULL;
}
inline PPEB get_process_peb(const HANDLE process_handle)
{
PROCESS_BASIC_INFORMATION process_info{};
ULONG bytes_returned;
if (NtQueryInformationProcess
(
process_handle,
ProcessBasicInformation,
&process_info,
sizeof(process_info),
&bytes_returned
) != ERROR_SUCCESS)
return nullptr;
return process_info.PebBaseAddress;
}
// could do a snapshot but i have this code handy atm...
inline std::uintptr_t get_proc_base(const HANDLE proc_handle)
{
if (!proc_handle) return {};
const auto ppeb = reinterpret_cast<std::uintptr_t>(get_process_peb(proc_handle));
const auto peb = bedaisy::read<nt_peb>(proc_handle, ppeb);
return peb.image_base;
}
// could do a snapshot but i have this code handy atm...
inline std::uintptr_t get_module_base(const HANDLE proc_handle, const wchar_t* module_handle)
{
const auto ppeb = reinterpret_cast<std::uintptr_t>(get_process_peb(proc_handle));
const auto peb = bedaisy::read<nt_peb>(proc_handle, ppeb);
wchar_t full_file_name[MAX_PATH];
std::uintptr_t module_base, file_name_ptr;
const auto module_list_entry =
bedaisy::read<PEB_LDR_DATA>(proc_handle, peb.ldr);
const auto first_entry =
reinterpret_cast<std::uintptr_t>(
module_list_entry.InMemoryOrderModuleList.Flink);
auto current_entry = bedaisy::read<std::uintptr_t>(proc_handle, first_entry);
while (current_entry != first_entry)
{
// read full module unicode_string structure.
file_name_ptr = bedaisy::read<ULONGLONG>(proc_handle, current_entry + 0x40);
// read full file path.
bedaisy::read
(
proc_handle,
file_name_ptr,
full_file_name,
MAX_PATH
);
module_base = bedaisy::read<ULONGLONG>(proc_handle, current_entry + 0x20);
if (std::wcsstr(full_file_name, module_handle))
return module_base;
current_entry = bedaisy::read<std::uintptr_t>(proc_handle, current_entry);
}
return NULL;
}
}
Loading…
Cancel
Save