BSOne.SFC/Tocsg.Module/Bs1Flt/bs1flt/bs1flt_bluetooth_port_hook.c

977 lines
28 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "precomp.h"
enum
{
bluetooth_btkrnl = 0,
bluetooth_rfcomm,
bluetooth_btwusb,
bluetooth_bthusb,
bluetooth_bthenum, //Å×½ºÆ® ÇÊ¿ä..
bluetooth_maximum
};
static WCHAR* s_bthname[] =
{
L"\\Driver\\BTKRNL",
L"\\Driver\\RFCOMM",
L"\\Driver\\BTWUSB",
L"\\Driver\\BTHUSB",
L"\\Driver\\BTHENUM",
NULL
};
static BOOLEAN enable_bluetoothhook = FALSE;
NTSTATUS BtkrnHookDispatch(PDEVICE_OBJECT deviceObject, PIRP irp);
NTSTATUS RfcommHookDispatch(PDEVICE_OBJECT deviceObject, PIRP irp);
NTSTATUS BtwusbHookDispatch(PDEVICE_OBJECT deviceObject, PIRP irp);
NTSTATUS BthusbHookDispatch(PDEVICE_OBJECT deviceObject, PIRP irp);
NTSTATUS BthEnumHookDispatch(PDEVICE_OBJECT deviceObject, PIRP irp);
static PDRIVER_DISPATCH s_ProxyDispatchers[bluetooth_maximum] =
{
BtkrnHookDispatch,
RfcommHookDispatch,
BtwusbHookDispatch,
BthusbHookDispatch,
BthEnumHookDispatch //Å×½ºÆ® ÇÊ¿ä
};
NTSTATUS BtkrnlDeviceIoControl(PDRIVER_DISPATCH dispath, PDEVICE_OBJECT deviceObject, PIRP irp);
NTSTATUS RfcommInternalDeviceIoControl(PDRIVER_DISPATCH dispath, PDEVICE_OBJECT deviceObject, PIRP irp);
NTSTATUS BtwusbDeviceIoControl(PDRIVER_DISPATCH dispath, PDEVICE_OBJECT deviceObject, PIRP irp);
NTSTATUS BthusbDeviceIoControl(PDRIVER_DISPATCH dispath, PDEVICE_OBJECT deviceObject, PIRP irp);
NTSTATUS BthEnumPnpControl(PDRIVER_DISPATCH dispath, PDEVICE_OBJECT deviceObject, PIRP irp);
#define BTKRNL_COMMON_HOOK_HANDLERS \
[IRP_MJ_DEVICE_CONTROL] = { NULL, IRP_MJ_DEVICE_CONTROL, TRUE, BtkrnlDeviceIoControl }, \
#define RFCOMM_COMMON_HOOK_HANDLERS \
[IRP_MJ_INTERNAL_DEVICE_CONTROL] = { NULL, IRP_MJ_INTERNAL_DEVICE_CONTROL, TRUE, RfcommInternalDeviceIoControl }, \
#define BTWUSB_COMMON_HOOK_HANDLERS \
[IRP_MJ_DEVICE_CONTROL] = { NULL, IRP_MJ_DEVICE_CONTROL, TRUE, BtwusbDeviceIoControl }, \
#define BTHUSB_COMMON_HOOK_HANDLERS \
[IRP_MJ_DEVICE_CONTROL] = { NULL, IRP_MJ_DEVICE_CONTROL, TRUE, BthusbDeviceIoControl }, \
#define BTHENUM_COMMON_HOOK_HANDLERS \
[IRP_MJ_PNP] = { NULL, IRP_MJ_PNP, TRUE, BthEnumPnpControl }, \
static HOOK_CONTEXT g_BlueToothHookContexts[] =
{
{ NULL, FALSE, 0, { BTKRNL_COMMON_HOOK_HANDLERS } },
{ NULL, FALSE, 0, { RFCOMM_COMMON_HOOK_HANDLERS } },
{ NULL, FALSE, 0, { BTWUSB_COMMON_HOOK_HANDLERS } },
{ NULL, FALSE, 0, { BTHUSB_COMMON_HOOK_HANDLERS } }
//{ NULL, FALSE, 0, { BTHENUM_COMMON_HOOK_HANDLERS } }
};
NTSTATUS BlueToothHookDispatch_Common(ULONG ContextIndex, PDEVICE_OBJECT deviceObject, PIRP irp)
{
NTSTATUS NtStatus = STATUS_SUCCESS;
PIO_STACK_LOCATION pCurrentIoStack = IoGetCurrentIrpStackLocation(irp);
ULONG id = pCurrentIoStack->MajorFunction;
PHOOK_CONTEXT hook = NULL;
PDRIVER_DISPATCH pOrgHandler = NULL;
if (ContextIndex >= ARRAYSIZE(g_BlueToothHookContexts))
return STATUS_UNSUCCESSFUL;
InterlockedIncrement((volatile LONG*)&g_BlueToothHookContexts[ContextIndex].IrpEnterCount);
hook = &g_BlueToothHookContexts[ContextIndex];
// 2. ÈÄÅ· À¯È¿¼º °Ë»ç
if (hook->IsHooked &&
hook->HookHandlers[id].IsHook &&
hook->HookHandlers[id].Work)
{
pOrgHandler = hook->HookHandlers[id].pOrgHandler;
NtStatus = hook->HookHandlers[id].Work(
pOrgHandler,
deviceObject,
irp
);
}
else
{
NtStatus = STATUS_UNSUCCESSFUL;
}
InterlockedDecrement((volatile LONG*)&g_BlueToothHookContexts[ContextIndex].IrpEnterCount);
return NtStatus;
}
NTSTATUS BthEnumHookDispatch(PDEVICE_OBJECT deviceObject, PIRP irp)
{
return BlueToothHookDispatch_Common(bluetooth_bthenum, deviceObject, irp);
}
NTSTATUS BtkrnHookDispatch(PDEVICE_OBJECT deviceObject, PIRP irp)
{
return BlueToothHookDispatch_Common(bluetooth_btkrnl, deviceObject, irp);
}
NTSTATUS RfcommHookDispatch(PDEVICE_OBJECT deviceObject, PIRP irp)
{
return BlueToothHookDispatch_Common(bluetooth_rfcomm, deviceObject, irp);
}
NTSTATUS BtwusbHookDispatch(PDEVICE_OBJECT deviceObject, PIRP irp)
{
return BlueToothHookDispatch_Common(bluetooth_btwusb, deviceObject, irp);
}
NTSTATUS BthusbHookDispatch(PDEVICE_OBJECT deviceObject, PIRP irp)
{
return BlueToothHookDispatch_Common(bluetooth_bthusb, deviceObject, irp);
}
// ¸ÅÇÎÀ» À§ÇÑ ±¸Á¶Ã¼ Á¤ÀÇ
typedef struct _BTH_UUID_MAPPING {
PWCHAR UuidLower; // ¼Ò¹®ÀÚ UUID
PWCHAR UuidUpper; // ´ë¹®ÀÚ UUID
PWCHAR ReadableName; // º¯È¯µÉ ÇѱÛ/¿µ¹® ¼³¸í
} BTH_UUID_MAPPING, * PBTH_UUID_MAPPING;
// ±âÁ¸ ¿Ï·á ·çƾÀÇ Á¤º¸¸¦ ¹é¾÷ÇØµÑ ±¸Á¶Ã¼ ¼±¾ð (Àü¿ª Çì´õ¿¡ ¼±¾ðÇϼ¼¿ä)
typedef struct _BTH_HOOK_CONTEXT {
PIO_COMPLETION_ROUTINE OldCompletionRoutine;
PVOID OldContext;
UCHAR OldControl;
char processName[50];
} BTH_HOOK_CONTEXT, * PBTH_HOOK_CONTEXT;
// ºí·çÅõ½º ÁÖ¿ä ÀåÄ¡ UUID ¸ÅÇÎ Å×À̺í (Àü¿ª ¹è¿­)
BTH_UUID_MAPPING g_BthUuidTable[] = {
// --- [º¸¾È À§Çù / µ¥ÀÌÅÍ À¯Ãâ (Â÷´Ü ±ÇÀå)] ---
{ L"1105", L"1105", L"ÆÄÀÏ Àü¼Û (OBEX Object Push)" },
{ L"1101", L"1101", L"½Ã¸®¾ó Åë½Å (Serial Port)" },
{ L"1115", L"1115", L"ºí·çÅõ½º Å×´õ¸µ/°øÀ¯ (PANU)" },
{ L"1116", L"1116", L"ºí·çÅõ½º ÇÖ½ºÆÌ (NAP)" },
{ L"1132", L"1132", L"¹®ÀÚ ¸Þ½ÃÁö Á¢±Ù (MAP)" },
// --- [¹Ìµð¾î / ¿Àµð¿À (¼±ÅÃÀû Â÷´Ü)] ---
{ L"110b", L"110B", L"¿Àµð¿À/Çìµå¼Â ½ºÇÇÄ¿ (A2DP Sink)" },
{ L"110a", L"110A", L"¿Àµð¿À ¼Ò½º (A2DP Source)" },
{ L"1108", L"1108", L"±¸Çü ¸ð³ë Çìµå¼Â (Headset)" },
{ L"111e", L"111E", L"ÇÚÁîÇÁ¸® ÅëÈ­ (Handsfree)" },
{ L"110c", L"110C", L"¹Ìµð¾î ¸®¸ðÄÁ (AVRCP)" },
// --- [ÀÔ·Â ÀåÄ¡ (Çã¿ë ±ÇÀå)] ---
{ L"1124", L"1124", L"¸¶¿ì½º/Űº¸µå (HID)" },
{ L"1812", L"1812", L"ÀúÀü·Â ¸¶¿ì½º/Űº¸µå (BLE HID)" },
// ¹è¿­ÀÇ ³¡À» ¾Ë¸®´Â ³Î(NULL) °ª
{ NULL, NULL, L"¾Ë ¼ö ¾ø´Â ºí·çÅõ½º ÀåÄ¡" }
};
/**
* Çϵå¿þ¾î ID ¹®ÀÚ¿­ ³»¿¡¼­ ƯÁ¤ UUID¸¦ ã¾Æ Àб⠽¬¿î À̸§À¸·Î ¹ÝȯÇÕ´Ï´Ù.
* @param HardwareIdString: °Ë»çÇÒ ¹®ÀÚ¿­ (¿¹: L"BTHENUM\\{0000110b-0000...}")
* @return ¸ÅĪµÈ ÀåÄ¡ÀÇ ÇÑ±Û ¼³¸í Æ÷ÀÎÅÍ
*/
PWCHAR GetReadableBluetoothName(PWCHAR HardwareIdString) {
int i = 0;
if (HardwareIdString == NULL) {
return L"À߸øµÈ ÀåÄ¡ Á¤º¸";
}
// ¹è¿­À» ¼øÈ¸ÇÏ¸ç ¸ÅĪµÇ´Â UUID°¡ ÀÖ´ÂÁö °Ë»ç
while (g_BthUuidTable[i].UuidLower != NULL) {
// ¼Ò¹®ÀÚ ¶Ç´Â ´ë¹®ÀÚ°¡ Æ÷ÇԵǾî ÀÖ´ÂÁö È®ÀÎ (wcsstr)
if (wcsstr(HardwareIdString, g_BthUuidTable[i].UuidLower) != NULL ||
wcsstr(HardwareIdString, g_BthUuidTable[i].UuidUpper) != NULL)
{
return g_BthUuidTable[i].ReadableName;
}
i++;
}
// ¸ÅĪµÇ´Â °ªÀÌ ¾øÀ¸¸é ±âº»°ª ¹Ýȯ
return L"¾Ë ¼ö ¾ø´Â ºí·çÅõ½º ÀåÄ¡ (±âŸ)";
}
#define TAG_LOG_STR 'goLB'
NTSTATUS GetAllHardwareIdsAsString(
_In_ PWCHAR MultiSzBuffer,
_Out_ PUNICODE_STRING CombinedString
)
{
PWCHAR currentString;
ULONG totalChars = 0;
USHORT maxLen = 0;
if (MultiSzBuffer == NULL || CombinedString == NULL)
{
return STATUS_INVALID_PARAMETER;
}
// 1. º´ÇÕ¿¡ ÇÊ¿äÇÑ Àüü ¹®ÀÚ¿­ ±æÀÌ °è»ê
currentString = MultiSzBuffer;
while (*currentString != L'\0')
{
// ÇöÀç ¹®ÀÚ¿­ ±æÀÌ + ±¸ºÐÀÚ("; ") 2±ÛÀÚ
totalChars += (ULONG)wcslen(currentString) + 2;
// ´ÙÀ½ ¹®ÀÚ¿­·Î Æ÷ÀÎÅÍ À̵¿ (ÇöÀç±æÀÌ + NULL)
currentString += wcslen(currentString) + 1;
}
if (totalChars == 0)
{
RtlInitUnicodeString(CombinedString, L"");
return STATUS_NOT_FOUND;
}
// UNICODE_STRINGÀÇ ÃÖ´ë Å©±â´Â 65535 ¹ÙÀÌÆ®(USHORT)·Î Á¦ÇѵÊ
if ((totalChars * sizeof(WCHAR) + sizeof(WCHAR)) > 0xFFFF)
{
return STATUS_BUFFER_OVERFLOW;
}
// 2. ¸Þ¸ð¸® ÇÒ´ç (NonPagedPool »ç¿ë - ¿Ï·á ·çƾ(DISPATCH_LEVEL)¿¡¼­ ¾ÈÀü)
maxLen = (USHORT)(totalChars * sizeof(WCHAR) + sizeof(WCHAR));
// ÃֽŠWDK¿¡¼­´Â NonPagedPoolNx¸¦ ±ÇÀåÇϳª, ±¸¹öÀü ȣȯ¼ºÀ» À§ÇØ NonPagedPool »ç¿ë
CombinedString->Buffer = (PWCHAR)ExAllocatePoolWithTag(NonPagedPool, maxLen, TAG_LOG_STR);
if (CombinedString->Buffer == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
// UNICODE_STRING ±¸Á¶Ã¼ ÃʱâÈ­
CombinedString->MaximumLength = maxLen;
CombinedString->Length = 0;
CombinedString->Buffer[0] = L'\0';
// 3. ¹®ÀÚ¿­ °áÇÕ (Concatenation)
currentString = MultiSzBuffer;
while (*currentString != L'\0')
{
UNICODE_STRING tempStr;
RtlInitUnicodeString(&tempStr, currentString);
// ÇöÀç ¹®ÀÚ¿­À» ºÙÀÓ
RtlAppendUnicodeStringToString(CombinedString, &tempStr);
currentString += (tempStr.Length / sizeof(WCHAR)) + 1;
// ´ÙÀ½ ¹®ÀÚ¿­ÀÌ Á¸ÀçÇÏ¸é ±¸ºÐÀÚ("; ") »ðÀÔ
if (*currentString != L'\0') {
RtlAppendUnicodeToString(CombinedString, L"; ");
}
}
return STATUS_SUCCESS;
}
// -----------------------------------------------------------------------
// IRP_MN_QUERY_ID ¿Ï·á ·çƾ (¿©±â¼­ ±â±â Á¾·ù¸¦ ÆÇº°Çϰí Â÷´ÜÇÕ´Ï´Ù)
// -----------------------------------------------------------------------
NTSTATUS PnpQueryIdCompletionRoutine(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
) {
UNREFERENCED_PARAMETER(DeviceObject);
UNREFERENCED_PARAMETER(Context);
PBTH_HOOK_CONTEXT hookCtx = (PBTH_HOOK_CONTEXT)Context;
ULONG state = GetPolicyState(BDC_BLUETOOTH);
ULONG policyLog = IsPolicyLog(BDC_BLUETOOTH);
WCHAR processName[50] = { 0, };
WCHAR notice[MAX_PATH] = { 0, };
NTSTATUS status = Irp->IoStatus.Status;
BOOLEAN bBlock = FALSE;
//if (Irp->PendingReturned) {
// IoMarkIrpPending(Irp);
//}
//PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
// ÇÏÀ§ µå¶óÀ̹ö°¡ 󸮸¦ ¼º°øÇß°í, ¿ì¸®°¡ ¿øÇÏ´Â Hardware IDs ¿äûÀÎ °æ¿ì
if (NT_SUCCESS(Irp->IoStatus.Status) /*&&
irpSp->MinorFunction == IRP_MN_QUERY_ID &&
irpSp->Parameters.QueryId.IdType == BusQueryHardwareIDs*/)
{
if (Irp->IoStatus.Information != 0)
{
UNICODE_STRING allHwIdsStr;
PWCHAR hwIds = (PWCHAR)Irp->IoStatus.Information;
status = GetAllHardwareIdsAsString(hwIds, &allHwIdsStr);
if (NT_SUCCESS(status))
{
PWCHAR name = GetReadableBluetoothName(allHwIdsStr.Buffer); // ·Î±×¿¡ »ç¶÷ÀÌ ÀÐÀ» ¼ö ÀÖ´Â À̸§À¸·Î ³²±â±â À§ÇØ º¯È¯ ½Ãµµ
KLogEx(DEBUG_TRACE_INFO, "btheunm connect : %S, %S", name, allHwIdsStr.Buffer);
if (wcsstr(allHwIdsStr.Buffer, L"110b") != NULL ||
wcsstr(allHwIdsStr.Buffer, L"110B") != NULL ||
wcsstr(allHwIdsStr.Buffer, L"1105") != NULL)
{
bBlock = TRUE;
}
//'1124', '1812', '110B', '1108'
if (policyLog)
{
if(hookCtx->processName)
RtlStringCbPrintfW(processName, sizeof(processName), L"%S", hookCtx->processName);
if (/*state == DISABLE &&*/ bBlock)
RtlStringCbPrintfW(notice, sizeof(notice), L"btheunm blocked(%s)(%s)", name, allHwIdsStr.Buffer);
else
RtlStringCbPrintfW(notice, sizeof(notice), L"btheunm allow(%s)(%s)", name, allHwIdsStr.Buffer);
SetLog(NULL, NULL, LOG_POLICY, BDC_BLUETOOTH, state, 0, processName, notice);
}
if (/*state == DISABLE &&*/ bBlock)
{
KLogEx(DEBUG_TRACE_INFO, "btheunm connect STATUS_ACCESS_DENIED !!!");
ExFreePool(hwIds); // BthEnumÀÌ ¸¸µé¾îÁØ ¿ø·¡ ¹öÆÛµµ ÇØÁ¦
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
}
else
{
}
if(allHwIdsStr.Buffer)
ExFreePoolWithTag(allHwIdsStr.Buffer, TAG_LOG_STR);
}
else
{
KLogEx(DEBUG_TRACE_ERROR, "GetAllHardwareIdsAsString Fail (%X)", status);
}
}
}
// »óÀ§ µå¶óÀ̹ö°¡ ¿ø·¡ µî·ÏÇØµÎ¾ú´ø ¿Ï·á ·çƾÀÌ ÀÖ´Ù¸é È£ÃâÇÏ¿© È帧 º¹¿ø
if (hookCtx->OldCompletionRoutine != NULL) {
BOOLEAN bInvoke = FALSE;
if (NT_SUCCESS(Irp->IoStatus.Status) && (hookCtx->OldControl & SL_INVOKE_ON_SUCCESS)) bInvoke = TRUE;
if (!NT_SUCCESS(Irp->IoStatus.Status) && (hookCtx->OldControl & SL_INVOKE_ON_ERROR)) bInvoke = TRUE;
if (Irp->Cancel && (hookCtx->OldControl & SL_INVOKE_ON_CANCEL)) bInvoke = TRUE;
if (bInvoke) {
status = hookCtx->OldCompletionRoutine(DeviceObject, Irp, hookCtx->OldContext);
}
else if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
}
else {
if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
}
// ÇÒ´çÇß´ø ÄÁÅØ½ºÆ® ¸Þ¸ð¸® ÇØÁ¦ (¸Þ¸ð¸® ¸¯ ¹æÁö)
ExFreePoolWithTag(hookCtx, 'kooH');
return status;
}
NTSTATUS BthEnumPnpControl(PDRIVER_DISPATCH dispath, PDEVICE_OBJECT deviceObject, PIRP irp)
{
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);
ULONG processId = 0;
char szProcessName[20] = { 0, };
if (!g_bs1Flt.IsAttached)
goto $BthEnumCleanup;
if (!enable_bluetoothhook)
goto $BthEnumCleanup;
processId = HandleToULong(PsGetCurrentProcessId());
UGetProcessName(szProcessName);
// IRP_MN_QUERY_ID (ÀåÄ¡ ½Äº°ÀÚ ¿äû) ÀÏ ¶§¸¸ ¿Ï·á ·çƾÀ» ´ä´Ï´Ù.
if (irpSp->MinorFunction == IRP_MN_QUERY_ID &&
irpSp->Parameters.QueryId.IdType == BusQueryHardwareIDs)
{
PBTH_HOOK_CONTEXT hookCtx = (PBTH_HOOK_CONTEXT)ExAllocatePoolWithTag(NonPagedPool, sizeof(BTH_HOOK_CONTEXT), 'kooH');
if (hookCtx != NULL) {
// ±âÁ¸ ½ºÅÃÀÇ ¿Ï·á ·çƾ ¹é¾÷
hookCtx->OldCompletionRoutine = irpSp->CompletionRoutine;
hookCtx->OldContext = irpSp->Context;
hookCtx->OldControl = irpSp->Control;
strcpy(hookCtx->processName, szProcessName);
// ¿ì¸®ÀÇ ¿Ï·á ·çƾÀ¸·Î ÇöÀç ½ºÅà À§Ä¡ µ¤¾î¾²±â (IoSetCompletionRoutine »ç¿ë ºÒ°¡)
irpSp->CompletionRoutine = PnpQueryIdCompletionRoutine;
irpSp->Context = hookCtx;
irpSp->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL;
}
// ¿ø·¡ÀÇ BthEnum ÇÔ¼ö È£Ãâ
return dispath(deviceObject, irp);
}
$BthEnumCleanup:
// ±× ¿ÜÀÇ PnP ¿äûÀº ¿ø·¡ÀÇ BthEnum ÇÔ¼ö·Î ±×´ë·Î ³Ñ°Ü¹ö¸²
return dispath(deviceObject, irp);
}
/**
@brief ºí·çÅõ½º µ¿±Û ÈÄÅ·ÇÔ¼ö
*/
NTSTATUS BtkrnlDeviceIoControl(PDRIVER_DISPATCH dispath, PDEVICE_OBJECT deviceObject, PIRP irp)
{
PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(irp);
ULONG buffSize = irpstack->Parameters.DeviceIoControl.InputBufferLength;
ULONG controlCode = irpstack->Parameters.DeviceIoControl.IoControlCode;
ULONG state = 0;
WCHAR processName[50] = { 0, };
ULONG processId = 0;
ULONG policyLog = 0;
char szProcessName[20] = { 0, };
if (!g_bs1Flt.IsAttached)
goto $BtkrnlCleanup;
if (!enable_bluetoothhook)
goto $BtkrnlCleanup;
processId = HandleToULong(PsGetCurrentProcessId());
UGetProcessName(szProcessName);
state = GetPolicyState(BDC_BLUETOOTH);
policyLog = IsPolicyLog(BDC_BLUETOOTH);
if (state == DISABLE)
{
// ¹öÆÛ Å©±â üũ µîÀº Çʿ信 µû¶ó ¼öÇà
if (buffSize > 4)
{
WCHAR notice[MAX_PATH] = { 0, };
KLogEx(DEBUG_TRACE_INFO, "btkrnl blocked(%X)(%d)", controlCode, buffSize);
if (policyLog)
{
RtlStringCbPrintfW(processName, sizeof(processName), L"%S", szProcessName);
RtlStringCbPrintfW(notice, sizeof(notice), L"btkrnl blocked(%X)(%d)", controlCode, buffSize);
SetLog(NULL, NULL, LOG_POLICY, BDC_BLUETOOTH, state, 0, processName, notice);
}
irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; // ¶Ç´Â STATUS_ACCESS_DENIED
irp->IoStatus.Information = 0;
IoCompleteRequest(irp, IO_NO_INCREMENT);
return STATUS_INVALID_DEVICE_REQUEST;
}
}
$BtkrnlCleanup:
return dispath(deviceObject, irp);
}
/**
@brief ³»Àå ºí·çÅõ½º ÀåÄ¡ ÈÄÅ· ÇÔ¼ö (RfComm / Microsoft Stack)
*/
PFILE_OBJECT gFileObject = NULL;
NTSTATUS RfcommInternalDeviceIoControl(PDRIVER_DISPATCH dispath, PDEVICE_OBJECT deviceObject, PIRP irp)
{
PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(irp);
NTSTATUS status = STATUS_SUCCESS;
PCHAR pBuffer = NULL;
PFILE_OBJECT pFileObject = irpstack->FileObject;
ULONG controlCode = irpstack->Parameters.DeviceIoControl.IoControlCode;
ULONG blueToothState = 0;
ULONG blueToothFileState = 0;
WCHAR processName[50] = { 0, };
ULONG processId = 0;
ULONG blueToothlog = 0;
ULONG blueToothFilelog = 0;
char szProcessName[20] = { 0, };
WCHAR notice[MAX_PATH] = { 0, };
if (!g_bs1Flt.IsAttached)
return dispath(deviceObject, irp);
if (!enable_bluetoothhook)
return dispath(deviceObject, irp);
processId = HandleToULong(PsGetCurrentProcessId());
UGetProcessName(szProcessName);
blueToothState = GetPolicyState(BDC_BLUETOOTH);
blueToothlog = IsPolicyLog(BDC_BLUETOOTH);
if (blueToothState == DISABLE)
{
KLogEx(DEBUG_TRACE_INFO, " blocked(%X)", controlCode);
if (blueToothlog)
{
RtlStringCbPrintfW(processName, sizeof(processName), L"%S", szProcessName);
RtlStringCbPrintfW(notice, sizeof(notice), L"rfcom blocked(%X)", controlCode);
SetLog(NULL, NULL, LOG_POLICY, BDC_BLUETOOTH, blueToothState, 0, processName, notice);
}
irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
irp->IoStatus.Information = 0;
IoCompleteRequest(irp, IO_NO_INCREMENT);
return STATUS_INVALID_DEVICE_REQUEST;
}
if (!irp->MdlAddress || !irp->MdlAddress->ByteCount ||!irpstack->FileObject)
return dispath(deviceObject, irp);
pBuffer = MmGetSystemAddressForMdl(irp->MdlAddress);
if (!pBuffer)
return dispath(deviceObject, irp);
__try
{
blueToothFileState = GetPolicyState(BDC_BLUETOOTH_FILE);
blueToothFilelog = IsPolicyLog(BDC_BLUETOOTH_FILE);
RtlStringCbPrintfW(processName, sizeof(processName), L"%S", szProcessName);
POBEX_COMMON_HEADER pCommon = (POBEX_COMMON_HEADER)pBuffer;
KLogEx(DEBUG_TRACE_INFO, "Opcode(%X)", pCommon->Opcode);
switch (pCommon->Opcode)
{
case OBEX_OPCODE_CONNECT:
{
KLogEx(DEBUG_TRACE_INFO, "OBEX_OPCODE_CONNECT(%p)", pFileObject);
POBEX_CONNECT_PACKET pConn = (POBEX_CONNECT_PACKET)pBuffer;
USHORT hostPacketLen = 0;
USHORT hostMaxPktSize = 0;
if (blueToothFilelog || blueToothlog)
{
if (irp->MdlAddress->ByteCount < sizeof(OBEX_CONNECT_PACKET))
{
KLogEx(DEBUG_TRACE_INFO, "Data too short for OBEX Connect");
break;
}
hostPacketLen = SWAP_USHORT(pConn->PacketLength);
hostMaxPktSize = SWAP_USHORT(pConn->MaxPacketSize);
RtlStringCbPrintfW(notice, sizeof(notice),
L"OBEX_OPCODE_CONNECT, hostPacketLen(%d), version(0x%x), flag(%d), hostMaxPktSize(%d)",
hostPacketLen, pConn->Version, pConn->Flags, hostMaxPktSize);
KLogEx(DEBUG_TRACE_INFO, "file blocked(%X), (%S)", controlCode, notice);
SetLog(NULL, NULL, LOG_POLICY, BDC_BLUETOOTH, blueToothFileState, 0, processName, notice);
}
gFileObject = pFileObject;
if (blueToothFileState == DISABLE)
{
KLogEx(DEBUG_TRACE_INFO, "Blocked OBEX Connect");
irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
irp->IoStatus.Information = 0;
IoCompleteRequest(irp, IO_NO_INCREMENT);
return STATUS_INVALID_DEVICE_REQUEST;
}
}
break;
case OBEX_OPCODE_DISCONNECT: // Disconnect
{
KLogEx(DEBUG_TRACE_INFO, "OBEX_OPCODE_DISCONNECT(%p)", pFileObject);
gFileObject = NULL;
if (blueToothFilelog || blueToothlog)
{
RtlStringCbPrintfW(notice, sizeof(notice),
L"OBEX_OPCODE_DISCONNECT, ByteCount(%d)", irp->MdlAddress->ByteCount);
KLogEx(DEBUG_TRACE_INFO, "(%S)", notice);
SetLog(NULL, NULL, LOG_POLICY, BDC_BLUETOOTH, blueToothFileState, 0, processName, notice);
}
}
break;
case OBEX_OPCODE_PUT: // Put
case OBEX_OPCODE_PUT_FINAL: // Put Final
{
KLogEx(DEBUG_TRACE_INFO, "OBEX_OPCODE_PUT,OBEX_OPCODE_PUT_FINAL(%p)", pFileObject);
if (gFileObject != pFileObject)
{
break;
}
ULONG currentOffset = 3;
WCHAR szFileName[260] = { 0 };
ULONG packetLen = irp->MdlAddress->ByteCount;
PUCHAR pData = (PUCHAR)pBuffer;
if (blueToothFilelog || blueToothlog)
{
while (currentOffset < packetLen)
{
UCHAR headerId = pData[currentOffset];
if (currentOffset + 3 > packetLen)
break;
// OBEX Çì´õ´Â »óÀ§ 2ºñÆ®¿¡ µû¶ó ÀÎÄÚµù ¹æ½ÄÀÌ ´Ù¸§
// 00xxxxxx: Unicode String (Length Æ÷ÇÔ) -> Name Çì´õ°¡ ¿©±â ¼ÓÇÔ
// 01xxxxxx: Byte Sequence (Length Æ÷ÇÔ)
// 10xxxxxx: 1 Byte Value (Length ÇÊµå ¾øÀ½)
// 11xxxxxx: 4 Byte Value (Length ÇÊµå ¾øÀ½)
if (headerId == OBEX_OPCODE_NAME) // 0x01: ÆÄÀÏ¸í ¹ß°ß!
{
USHORT headerLen = 0;
// Length Çʵå´Â Big Endian (2 bytes)
((PUCHAR)&headerLen)[1] = pData[currentOffset + 1];
((PUCHAR)&headerLen)[0] = pData[currentOffset + 2];
// ½ÇÁ¦ À̸§ ±æÀÌ = Çì´õ±æÀÌ - (ID 1byte + Length 2bytes)
// OBEX NameÀº Null-terminated UnicodeÀÓ (¸¶Áö¸· 2¹ÙÀÌÆ® 0x00 0x00 Æ÷ÇÔ)
if (headerLen > 5 && (currentOffset + headerLen <= packetLen))
{
ULONG nameByteLen = headerLen - 3; // ¼ø¼ö ¹®ÀÚ¿­ ¹ÙÀÌÆ® ¼ö (Çì´õ ¿À¹öÇìµå 3¹ÙÀÌÆ® Á¦¿Ü)
if (nameByteLen >= sizeof(szFileName))
nameByteLen = sizeof(szFileName) - 2;
// ÆÄÀÏ¸í º¹»ç (pData + offset + 3)
RtlCopyMemory(szFileName, &pData[currentOffset + 3], nameByteLen);
for (ULONG k = 0; k < nameByteLen / 2; k++)
szFileName[k] = SWAP_USHORT(szFileName[k]);
szFileName[nameByteLen/2] = 0;
KLogEx(DEBUG_TRACE_INFO, "File Name Found: %ws", szFileName);
RtlStringCbPrintfW(notice, sizeof(notice), L"File Transfer: %s, packetLen: %d", szFileName, packetLen);
}
break; // À̸§À» ã¾ÒÀ¸¸é ·çÇÁ Á¾·á (ÃÖÀûÈ­)
}
// ´ÙÀ½ Çì´õ·Î À̵¿Çϱâ À§ÇÑ ¿ÀÇÁ¼Â °è»ê
if ((headerId & 0xC0) == 0x00 || (headerId & 0xC0) == 0x40)
{
// Length Çʵ尡 Àִ ŸÀÔ (String, Sequence)
USHORT chunkLen = 0;
((PUCHAR)&chunkLen)[1] = pData[currentOffset + 1];
((PUCHAR)&chunkLen)[0] = pData[currentOffset + 2];
if (chunkLen == 0) break; // ¹«ÇÑ·çÇÁ ¹æÁö
currentOffset += chunkLen;
}
else if ((headerId & 0xC0) == 0x80)
{
// 1 Byte Value (ÃÑ 2¹ÙÀÌÆ®: ID + Value)
currentOffset += 2;
}
else if ((headerId & 0xC0) == 0xC0)
{
// 4 Byte Value (ÃÑ 5¹ÙÀÌÆ®: ID + Value 4bytes)
currentOffset += 5;
}
}
if(notice[0] == 0)
RtlStringCbPrintfW(notice, sizeof(notice), L"File Transfer: unknown, packetLen: %d", packetLen);
SetLog(NULL, NULL, LOG_POLICY, BDC_BLUETOOTH, blueToothFileState, 0, processName, notice);
}
if (blueToothFileState == DISABLE || blueToothFileState == READONLY)
{
KLogEx(DEBUG_TRACE_INFO, "Blocked File Transfer: %ws", szFileName);
irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
irp->IoStatus.Information = 0;
IoCompleteRequest(irp, IO_NO_INCREMENT);
return STATUS_INVALID_DEVICE_REQUEST;
}
}
break;
case OBEX_OPCODE_OK:
KLogEx(DEBUG_TRACE_INFO, "OBEX_OPCODE_OK");
break;
case OBEX_OPCODE_CONTINUE:
KLogEx(DEBUG_TRACE_INFO, "OBEX_OPCODE_CONTINUE");
break;
case OBEX_OPCODE_BODY:
KLogEx(DEBUG_TRACE_INFO, "OBEX_OPCODE_BODY");
break;
case OBEX_OPCODE_END_BODY:
KLogEx(DEBUG_TRACE_INFO, "OBEX_OPCODE_END_BODY");
break;
case OBEX_OPCODE_VERSION:
KLogEx(DEBUG_TRACE_INFO, "OBEX_OPCODE_VERSION");
break;
case OBEX_OPCODE_CONN_FLAGS:
KLogEx(DEBUG_TRACE_INFO, "OBEX_OPCODE_CONN_FLAGS");
break;
case OBEX_OPCODE_NAME:
KLogEx(DEBUG_TRACE_INFO, "OBEX_OPCODE_NAME");
break;
case OBEX_OPCODE_LENGTH:
KLogEx(DEBUG_TRACE_INFO, "OBEX_OPCODE_LENGTH");
break;
default:
KLogEx(DEBUG_TRACE_INFO, "default OBEX_OPCODE");
break;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
NTSTATUS exceptStatus = GetExceptionCode();
KLogEx(DEBUG_TRACE_ERROR, "Exception accessing buffer: 0x%X", exceptStatus);
}
status = dispath(deviceObject, irp);
return status;
}
/**
@brief ºí·çÅõ½º USB ÀåÄ¡ ÈÄÅ· ÇÔ¼ö (BTWUSB)
*/
NTSTATUS BtwusbDeviceIoControl(PDRIVER_DISPATCH dispath, PDEVICE_OBJECT deviceObject, PIRP irp)
{
PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(irp);
ULONG controlCode = irpstack->Parameters.DeviceIoControl.IoControlCode;
NTSTATUS ntStatus = STATUS_SUCCESS;
ULONG blueToothState = 0;
WCHAR processName[50] = { 0, };
ULONG processId = 0;
ULONG blueToothlog = 0;
char szProcessName[20] = { 0, };
WCHAR notice[MAX_PATH] = { 0, };
if (!g_bs1Flt.IsAttached)
return dispath(deviceObject, irp);
if (!enable_bluetoothhook)
return dispath(deviceObject, irp);
processId = HandleToULong(PsGetCurrentProcessId());
UGetProcessName(szProcessName);
blueToothState = GetPolicyState(BDC_BLUETOOTH);
blueToothlog = IsPolicyLog(BDC_BLUETOOTH);
if (blueToothState == DISABLE)
{
KLogEx(DEBUG_TRACE_INFO, " btwusb blocked(%X)", controlCode);
if (blueToothlog)
{
RtlStringCbPrintfW(processName, sizeof(processName), L"%S", szProcessName);
RtlStringCbPrintfW(notice, sizeof(notice), L"btwusb blocked(%X)", controlCode);
SetLog(NULL, NULL, LOG_POLICY, BDC_BLUETOOTH, blueToothState, 0, processName, notice);
}
irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
irp->IoStatus.Information = 0;
IoCompleteRequest(irp, IO_NO_INCREMENT);
return STATUS_INVALID_DEVICE_REQUEST;
}
ntStatus = dispath(deviceObject, irp);
if (blueToothlog == TRUE)
{
}
return ntStatus;
}
/**
@brief ºí·çÅõ½º USB ÀåÄ¡ ÈÄÅ· ÇÔ¼ö (BTHUSB)
*/
NTSTATUS BthusbDeviceIoControl(PDRIVER_DISPATCH dispath, PDEVICE_OBJECT deviceObject, PIRP irp)
{
PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(irp);
ULONG controlCode = irpstack->Parameters.DeviceIoControl.IoControlCode;
NTSTATUS ntStatus = STATUS_SUCCESS;
ULONG blueToothState = 0;
WCHAR processName[50] = { 0, };
ULONG processId = 0;
ULONG blueToothlog = 0;
char szProcessName[20] = { 0, };
WCHAR notice[MAX_PATH] = { 0, };
if (!g_bs1Flt.IsAttached)
return dispath(deviceObject, irp);
if (!enable_bluetoothhook)
return dispath(deviceObject, irp);
processId = HandleToULong(PsGetCurrentProcessId());
UGetProcessName(szProcessName);
blueToothState = GetPolicyState(BDC_BLUETOOTH);
blueToothlog = IsPolicyLog(BDC_BLUETOOTH);
if (blueToothState == DISABLE)
{
if (processId == 4)
return dispath(deviceObject, irp);
if (IsDefalutLocalDiskExceptProcess(szProcessName))
return dispath(deviceObject, irp);
if (_strnicmp(szProcessName, "SystemSettings", strlen(szProcessName)) == 0 ||
_strnicmp(szProcessName, "RuntimeBroker.", strlen(szProcessName)) == 0 )
return dispath(deviceObject, irp);
KLogEx(DEBUG_TRACE_INFO, " bthusb blocked(%s)(%X)", szProcessName, controlCode);
if (blueToothlog)
{
RtlStringCbPrintfW(processName, sizeof(processName), L"%S", szProcessName);
RtlStringCbPrintfW(notice, sizeof(notice), L"bthusb blocked(%X)", controlCode);
SetLog(NULL, NULL, LOG_POLICY, BDC_BLUETOOTH, blueToothState, 0, processName, notice);
}
irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
irp->IoStatus.Information = 0;
IoCompleteRequest(irp, IO_NO_INCREMENT);
return STATUS_INVALID_DEVICE_REQUEST;
}
ntStatus = dispath(deviceObject, irp);
if (blueToothlog == TRUE)
{
}
return ntStatus;
}
NTSTATUS BlueToothIrpHookInit()
{
WCHAR* name = NULL;
ULONG i, mi;
PDRIVER_OBJECT obj = NULL;
PHOOK_CONTEXT hook = NULL;
for (i = 0; i < ARRAYSIZE(g_BlueToothHookContexts); i++)
{
hook = &g_BlueToothHookContexts[i];
if (hook->IsHooked)
continue;
name = s_bthname[i];
if (name == NULL)
continue;
KLogEx(DEBUG_TRACE_INFO, "Target driver(%S)\n", name);
obj = SearchDriverObject(name);
if (!obj)
{
KLogEx(DEBUG_TRACE_ERROR, "Not found object (%S)\n", name);
continue;
}
hook->DriverObject = obj;
for (mi = 0; mi < IRP_MJ_MAXIMUM_FUNCTION + 1; mi++)
{
if (!hook->HookHandlers[mi].IsHook)
continue;
if (obj->MajorFunction[mi] == s_ProxyDispatchers[i])
continue;
hook->HookHandlers[mi].pOrgHandler = obj->MajorFunction[mi];
if (hook->HookHandlers[mi].pOrgHandler == NULL)
continue;
InterlockedExchangePointer((PVOID)&obj->MajorFunction[mi], (PVOID)s_ProxyDispatchers[i]);
KLogEx(DEBUG_TRACE_INFO, "[Hook] %S MJ:%d Org:%p New:%p\n",
name, mi, hook->HookHandlers[mi].pOrgHandler, s_ProxyDispatchers[i]);
}
hook->IsHooked = TRUE;
enable_bluetoothhook = TRUE;
}
KLogEx(DEBUG_TRACE_INFO, "complete\n");
return STATUS_SUCCESS;
}
NTSTATUS BlueToothIrpHookCleanup()
{
ULONG i, mi;
LARGE_INTEGER WaitTime;
PHOOK_CONTEXT hook = NULL;
PDRIVER_DISPATCH pCurrentHandler = NULL;
enable_bluetoothhook = FALSE;
KLogEx(DEBUG_TRACE_INFO, "Started...\n");
for (i = 0; i < ARRAYSIZE(g_BlueToothHookContexts); i++)
{
hook = &g_BlueToothHookContexts[i];
if (!hook->IsHooked || !hook->DriverObject)
continue;
KLogEx(DEBUG_TRACE_INFO, "Unhooking Driver Index: %d\n", i);
for (mi = 0; mi <= IRP_MJ_MAXIMUM_FUNCTION; mi++)
{
if (!hook->HookHandlers[mi].IsHook)
continue;
if (hook->HookHandlers[mi].pOrgHandler == NULL)
continue;
pCurrentHandler = (PDRIVER_DISPATCH)InterlockedExchangePointer(
(PVOID)&hook->DriverObject->MajorFunction[mi],
(PVOID)hook->HookHandlers[mi].pOrgHandler
);
hook->HookHandlers[mi].pOrgHandler = NULL;
}
WaitTime.QuadPart = -50 * 1000 * 10; // 50ms ´ÜÀ§·Î ´ë±â
while (hook->IrpEnterCount > 0)
{
KLogEx(DEBUG_TRACE_INFO, "(%d), Waiting for active IRPs... Count: %d\n", i, hook->IrpEnterCount);
KeDelayExecutionThread(KernelMode, FALSE, &WaitTime);
}
hook->IsHooked = FALSE;
hook->DriverObject = NULL;
//RtlZeroMemory(hook->HookHandlers, sizeof(hook->HookHandlers));
}
WaitTime.QuadPart = -500 * 1000 * 10;
KeDelayExecutionThread(KernelMode, FALSE, &WaitTime);
KLogEx(DEBUG_TRACE_INFO, "Complete.\n");
return STATUS_SUCCESS;
}