Skip to content

Commit

Permalink
[Driver] Fix failure after first IRP captured (#27)
Browse files Browse the repository at this point in the history
Fixed by 6b8e9c1

The bug was coming from an unused `Status` variable initialized to
`UNSUCCESSFUL` that was (almost) always returned in
`CapturedIrp::CaptureIrpPreHook`.

As a consequence the first IRP with input data would simply fail,
resulting in the disabling the monitoring of the driver.
  • Loading branch information
hugsy authored Mar 23, 2024
1 parent 110b4eb commit c95be06
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 74 deletions.
5 changes: 0 additions & 5 deletions Common/Headers/IoctlCodes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,6 @@ enum class Ioctl : u32
///
DisableMonitoring = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, METHOD_BUFFERED, FILE_ANY_ACCESS),

///
///@brief StoreTestCase
///
StoreTestCase = CTL_CODE(FILE_DEVICE_UNKNOWN, 0x809, METHOD_BUFFERED, FILE_ANY_ACCESS),

// clang-format on
};

Expand Down
106 changes: 47 additions & 59 deletions Driver/Client/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ ToggleMonitoring(HANDLE hFile, std::string const& arg, bool enable)


bool
SendData(std::string const& device_name, const u32 ioctl)
SendData(std::string const& device_name, const u32 ioctl, std::vector<u8>& buffer_in)
{
wil::unique_handle hFile(::CreateFileA(
device_name.c_str(),
Expand All @@ -160,61 +160,44 @@ SendData(std::string const& device_name, const u32 ioctl)
}

DWORD nbBytesReturned = 0;
const usize sz = 0x20;
auto buffer_in = std::make_unique<u8[]>(sz);
::memset(buffer_in.get(), 'A', sz);

bool bSuccess = ::DeviceIoControl(hFile.get(), ioctl, buffer_in.get(), sz, nullptr, 0, &nbBytesReturned, nullptr);
info("SendData('%s', %dB) returned %s", device_name.c_str(), sz, boolstr(bSuccess));
bool bSuccess = ::DeviceIoControl(
hFile.get(),
ioctl,
buffer_in.data(),
buffer_in.size(),
nullptr,
0,
&nbBytesReturned,
nullptr);
info("SendData('%s', %dB) returned %s", device_name.c_str(), buffer_in.size(), boolstr(bSuccess));

return bSuccess;
}

std::optional<u32>
ReceiveData(HANDLE hFile)
{
//
// Try read into empty buffer to probe the size
//
DWORD expectedDataLength = 0;
{
u8* data = nullptr;
bool bRes = ::ReadFile(hFile, data, 0, &expectedDataLength, nullptr);
info("ReceiveData(nullptr) = %s", boolstr(bRes));
if ( bRes )
{
ok(" -> expectedDataLength = %d", expectedDataLength);
}
else
{
err("stopping");
return std::nullopt;
}
}

if ( expectedDataLength == 0 )
{
return 0;
}
DWORD expectedDataLength = 1024;

//
// Get read content
//
while ( true )
{
const DWORD dataLength = expectedDataLength;
auto data = std::make_unique<u8[]>(dataLength);
bool bRes = ::ReadFile(hFile, data.get(), dataLength, &expectedDataLength, nullptr);
info("ReceiveData(data, %d) = %s", dataLength, boolstr(bRes));
if ( bRes )
if ( bRes == false )
{
CFB::Utils::Hexdump(data.get(), dataLength);
return dataLength;
}
else
{
err("stopping");
if ( ::GetLastError() == ERROR_INSUFFICIENT_BUFFER )
{
expectedDataLength = dataLength * 2;
continue;
}
err("ReadFile() failed, GLE %#x", ::GetLastError());
return std::nullopt;
}

CFB::Utils::Hexdump(data.get(), dataLength);
return dataLength;
}
}

Expand All @@ -227,7 +210,7 @@ main(int argc, const char** argv)
argparse::ArgumentParser program("DriverClient");

const std::vector<std::string> valid_actions =
{"hook", "hook-unhook", "unhook", "size", "set-capturing", "send-data", "read-data", "session"};
{"hook", "unhook", "size", "monitor", "unmonitor", "send", "recv", "session"};

program.add_argument("--action")
.default_value(std::string("hook"))
Expand All @@ -244,7 +227,6 @@ main(int argc, const char** argv)
program.add_argument("--driver").default_value(std::string("\\driver\\hevd"));
program.add_argument("--device").default_value(std::string("\\\\.\\HackSysExtremeVulnerableDriver"));
program.add_argument("--ioctl").scan<'i', int>().default_value(0x222003); // BUFFER_OVERFLOW_STACK
program.add_argument("--enable").default_value(false).implicit_value(true);

try
{
Expand All @@ -257,11 +239,10 @@ main(int argc, const char** argv)
std::exit(1);
}

auto action = program.get<std::string>("--action");
auto driver_name = program.get<std::string>("--driver");
auto device_name = program.get<std::string>("--device");
auto ioctl = program.get<int>("--ioctl");
auto enable = program.get<bool>("--enable");
const auto action = program.get<std::string>("--action");
const auto driver_name = program.get<std::string>("--driver");
const auto device_name = program.get<std::string>("--device");
const auto ioctl = program.get<int>("--ioctl");

wil::unique_handle hEvent;

Expand All @@ -271,7 +252,7 @@ main(int argc, const char** argv)
if ( !hFile )
{
err("Failed to open '%S'", CFB_DEVICE_NAME);
// return -1;
return -1;
}

if ( action == "hook" )
Expand All @@ -282,24 +263,26 @@ main(int argc, const char** argv)
{
Driver::Unhook(hFile.get(), driver_name);
}
else if ( action == "hook-unhook" )
{
Driver::Hook(hFile.get(), driver_name);
Driver::Unhook(hFile.get(), driver_name);
}
else if ( action == "size" )
{
Driver::GetNumberOfDrivers(hFile.get());
}
else if ( action == "set-capturing" )
else if ( action == "monitor" )
{
Driver::ToggleMonitoring(hFile.get(), driver_name, enable);
Driver::ToggleMonitoring(hFile.get(), driver_name, true);
}
else if ( action == "send-data" )
else if ( action == "unmonitor" )
{
Driver::SendData(device_name, ioctl);
Driver::ToggleMonitoring(hFile.get(), driver_name, false);
}
else if ( action == "read-data" )
else if ( action == "send" )
{
const usize sz {0x100};
auto buffer_in = std::vector<u8>(sz);
::memset(buffer_in.data(), 'A', sz);
Driver::SendData(device_name, ioctl, buffer_in);
}
else if ( action == "recv" )
{
Driver::ReceiveData(hFile.get());
}
Expand All @@ -315,7 +298,12 @@ main(int argc, const char** argv)

for ( int i = 0; i < 2; i++ )
{
Driver::SendData(device_name, ioctl);
const usize sz {0x100};
auto buffer_in = std::vector<u8>(sz);
auto buffer_out = std::vector<u8>(sz);
::memset(buffer_in.data(), 'A', sz);

Driver::SendData(device_name, ioctl, buffer_in);

u32 Status = ::WaitForSingleObject(hEvent.get(), 1 * 1000);
switch ( Status )
Expand Down
5 changes: 2 additions & 3 deletions Driver/Source/CapturedIrp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@ CapturedIrp::CapturePreCallData(_In_ PIRP Irp)
return STATUS_ACCESS_DENIED;
}

NTSTATUS Status = STATUS_UNSUCCESSFUL;
const ULONG Flags = m_DeviceObject->Flags;
const PIO_STACK_LOCATION Stack = ::IoGetCurrentIrpStackLocation(Irp);

Expand Down Expand Up @@ -240,7 +239,7 @@ CapturedIrp::CapturePreCallData(_In_ PIRP Irp)
}
}

return Status;
return STATUS_SUCCESS;
}


Expand Down Expand Up @@ -310,7 +309,7 @@ CapturedIrp::CapturePostCallData(_In_ PIRP Irp, _In_ NTSTATUS ReturnedIoctlStatu
RtlCopyMemory(m_OutputBuffer.get() + Offset, UserBuffer, Count);

#ifdef _DEBUG
ok("Capturing output data:");
dbg("Capturing output data:");
CFB::Utils::Hexdump(m_OutputBuffer.get(), MIN(m_OutputBuffer.size(), CFB_MAX_HEXDUMP_BYTE));
#endif // _DEBUG

Expand Down
37 changes: 30 additions & 7 deletions Driver/Source/Entry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,11 +220,6 @@ _Function_class_(DRIVER_DISPATCH) DriverDeviceControlRoutine(_In_ PDEVICE_OBJECT
break;
}

case CFB::Comms::Ioctl::GetDriverInfo:
warn("TODO");
Status = STATUS_NOT_IMPLEMENTED;
break;

default:
err("Received invalid IOCTL code 0x%08x", IoctlCode);
Status = STATUS_INVALID_DEVICE_REQUEST;
Expand Down Expand Up @@ -290,7 +285,6 @@ _Function_class_(DRIVER_DISPATCH) DriverReadRoutine(_In_ PDEVICE_OBJECT DeviceOb
}

NT_ASSERT(Irp->MdlAddress);

PVOID Buffer = ::MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
if ( Buffer == nullptr )
{
Expand All @@ -308,6 +302,8 @@ _Function_class_(DRIVER_DISPATCH) DriverReadRoutine(_In_ PDEVICE_OBJECT DeviceOb

for ( usize i = 0; i < DumpableIrpNumber; i++ )
{
dbg("Popping IRP %d/%d", i + 1, DumpableIrpNumber);

//
// Pop front the captured IRP
//
Expand All @@ -331,6 +327,13 @@ _Function_class_(DRIVER_DISPATCH) DriverReadRoutine(_In_ PDEVICE_OBJECT DeviceOb

RtlCopyMemory((PVOID)BufferPointer, &Header, DataSize);
BufferPointer += DataSize;

dbg("IRP %d/%d - Copied header: Process='%S', PID=%d, TID=%d",
i + 1,
DumpableIrpNumber,
Header.ProcessName,
Header.Pid,
Header.Tid);
}

//
Expand All @@ -347,6 +350,15 @@ _Function_class_(DRIVER_DISPATCH) DriverReadRoutine(_In_ PDEVICE_OBJECT DeviceOb
RtlCopyMemory((PVOID)BufferPointer, CurrentIrp->InputBuffer(), DataSize);
BufferPointer += DataSize;
}


dbg("IRP %d/%d - Copied input buffer (%d bytes)",
i + 1,
DumpableIrpNumber,
CurrentIrp->InputDataSize());
#ifdef _DEBUG
CFB::Utils::Hexdump(Buffer, MIN(CurrentIrp->InputDataSize(), CFB_MAX_HEXDUMP_BYTE));
#endif // _DEBUG
}

//
Expand All @@ -363,7 +375,17 @@ _Function_class_(DRIVER_DISPATCH) DriverReadRoutine(_In_ PDEVICE_OBJECT DeviceOb
RtlCopyMemory((PVOID)BufferPointer, CurrentIrp->OutputBuffer(), DataSize);
BufferPointer += DataSize;
}

dbg("IRP %d/%d - Copied output buffer (%d bytes)",
i + 1,
DumpableIrpNumber,
CurrentIrp->OutputDataSize());
#ifdef _DEBUG
CFB::Utils::Hexdump(Buffer, MIN(CurrentIrp->OutputDataSize(), CFB_MAX_HEXDUMP_BYTE));
#endif // _DEBUG
}

dbg("IRP %d/%d returned to client", i + 1, DumpableIrpNumber);
}
}

Expand Down Expand Up @@ -467,7 +489,8 @@ DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
Globals->DeviceObject = DeviceObject;
Globals->DriverObject = DriverObject;

err("Device initialization for '%S' done, use `%s` for debug logs",
warn(
"Device initialization for '%S' successful, use `%s` for debug logs",
CFB_DEVICE_NAME,
DML("ed nt !Kd_IHVDRIVER_Mask f"));
return Status;
Expand Down

0 comments on commit c95be06

Please sign in to comment.