parent
e9ad4d7bd3
commit
7fb4f9484c
@ -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));
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
Loading…
Reference in new issue