Created
April 29, 2023 01:33
-
-
Save hfiref0x/847c42c0d641c806483cb4a681068993 to your computer and use it in GitHub Desktop.
F-Secure Blacklight fsbl.sys
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Infamous "antirootkit" from F-Secure. Driver contains few potential CVE's. | |
With such "functionallity" under the hood it was unable to detect anything more advanced then few PoC's from old rootkit.com | |
main.c | |
RtlCopyUnicodeString(&g_DriverRegEntry, RegistryPath); | |
DriverObject->MajorFunction[2] = fsblIrpCloseHandler; | |
DriverObject->MajorFunction[0xE] = fsblDriverDispatch; | |
DriverObject->MajorFunction[0x12] = fsblIrpCleanupHandler; | |
DriverObject->MajorFunction[0] = fsblIrpCreateHandler; | |
DriverObject->DriverUnload = fsblDriverUnload; | |
RtlInitUnicodeString(&DestinationString, L"\\Device\\fsblstandaloneDevice"); | |
if ( WdmlibIoCreateDeviceSecure( | |
DriverObject, | |
0x10u, | |
&DestinationString, | |
0x22u, | |
0x100u, | |
0, | |
&DefaultSDDLString, | |
&DeviceClassGuid, | |
&DeviceObject) < 0 ) | |
goto Exit2; | |
DeviceExtension = DeviceObject->DeviceExtension; | |
*DeviceExtension = 0i64; | |
DeviceExtension[1] = 0i64; | |
*DeviceExtension = DeviceObject; | |
DeviceObject->Flags |= 0x10u; | |
RtlInitUnicodeString(&SymbolicLinkName, L"\\??\\fsblstandaloneDevice"); | |
v6 = IoCreateSymbolicLink(&SymbolicLinkName, &DestinationString); | |
if ( v6 < 0 ) | |
{ | |
ExitDeleteDevice: | |
IoDeleteDevice(DeviceObject); | |
Exit2: | |
ExFreePoolWithTag(g_DriverRegEntry.Buffer, 'lbsf'); | |
g_DriverRegEntry.Buffer = 0i64; | |
return 0xE0010001i64; | |
} | |
if ( !fsblGetPsPointers() ) | |
{ | |
IoDeleteSymbolicLink(&SymbolicLinkName); | |
goto ExitDeleteDevice; | |
} | |
fsblReferenceFSHS1Device(); | |
dispatch.c | |
IoControlCode = CurrentStackLocation->Parameters.DeviceIoControl.IoControlCode; | |
InputBufferLength = CurrentStackLocation->Parameters.DeviceIoControl.InputBufferLength; | |
OutputBufferLength = CurrentStackLocation->Parameters.DeviceIoControl.OutputBufferLength; | |
switch ( IoControlCode ) | |
{ | |
case 0x80002014: | |
SystemBuffer = Irp->AssociatedIrp.MasterIrp; | |
v18 = fsblValidateInputAndRunCallback( | |
SystemBuffer, | |
InputBufferLength, | |
SystemBuffer, | |
OutputBufferLength, | |
&v20, | |
fsblReadDriverObjectIRPHandlerCode); | |
ntStatus = v18; | |
if ( v18 >= 0 ) | |
{ | |
v19 = v20; | |
Irp->IoStatus.Status = v18; | |
Irp->IoStatus.Information = v19; | |
goto LABEL_26; | |
} | |
goto LABEL_24; | |
case 0x80002018: | |
SystemBuffer = Irp->AssociatedIrp.MasterIrp; | |
v16 = fsblValidateInputAndRunCallback( | |
SystemBuffer, | |
InputBufferLength, | |
SystemBuffer, | |
OutputBufferLength, | |
&v20, | |
fsblReadDriverObjectIRPHandler); | |
ntStatus = v16; | |
if ( v16 >= 0 ) | |
{ | |
v17 = v20; | |
Irp->IoStatus.Status = v16; | |
Irp->IoStatus.Information = v17; | |
goto LABEL_26; | |
} | |
goto LABEL_24; | |
case 0x8000201C: | |
SystemBuffer = Irp->AssociatedIrp.MasterIrp; | |
v14 = fsblValidateInputAndRunCallback( | |
SystemBuffer, | |
InputBufferLength, | |
SystemBuffer, | |
OutputBufferLength, | |
&v20, | |
fsblModifyDriverObjectIRPHandler); | |
ntStatus = v14; | |
if ( v14 >= 0 ) | |
{ | |
v15 = v20; | |
Irp->IoStatus.Status = v14; | |
Irp->IoStatus.Information = v15; | |
goto LABEL_26; | |
} | |
goto LABEL_24; | |
case 0x80006010: | |
SystemBuffer = Irp->AssociatedIrp.SystemBuffer; | |
if ( !SystemBuffer || !fsblCallDriver ) | |
{ | |
LODWORD(v20) = 0; | |
ntStatus = 0xC000000D; | |
goto LABEL_24; | |
} | |
if ( OutputBufferLength <= 8 ) | |
{ | |
v12 = 0i64; | |
ntStatus = 0xC0000023; | |
LODWORD(v20) = 0; | |
goto LABEL_13; | |
} | |
if ( (OutputBufferLength & 7) != 0 ) | |
{ | |
v12 = 0i64; | |
ntStatus = 0xE0010002; | |
LODWORD(v20) = 0; | |
goto LABEL_13; | |
} | |
memset(Irp->AssociatedIrp.SystemBuffer, 0, OutputBufferLength); | |
ntStatus = fsblCallDriver((SystemBuffer + 8), OutputBufferLength - 8, &v20); | |
if ( ntStatus < 0 ) | |
goto LABEL_22; | |
*SystemBuffer = 0x12345678; | |
*(SystemBuffer + 4) = v20; | |
v13 = 8 - ((v20 + 8) & 7) + v20 + 8; | |
LODWORD(v20) = v13; | |
if ( v13 > OutputBufferLength - 8 ) | |
{ | |
v12 = 0i64; | |
ntStatus = 0xC0000023; | |
LODWORD(v20) = 0; | |
goto LABEL_13; | |
} | |
if ( fsblEncryptOutputBuffer(g_CurrentProcessId, SystemBuffer, v13) ) | |
{ | |
v12 = 0i64; | |
ntStatus = 0xE0010004; | |
LODWORD(v20) = 0; | |
} | |
else | |
{ | |
LABEL_22: | |
v12 = v20; | |
} | |
LABEL_13: | |
if ( ntStatus >= 0 ) | |
{ | |
Irp->IoStatus.Information = v12; | |
LABEL_25: | |
Irp->IoStatus.Status = ntStatus; | |
goto LABEL_26; | |
} | |
LABEL_24: | |
memset(SystemBuffer, 0, OutputBufferLength); | |
Irp->IoStatus.Information = 0i64; | |
goto LABEL_25; | |
} | |
if ( IoControlCode != 0x8000E00C ) | |
{ | |
Irp->IoStatus.Status = 0xC0000010; | |
IofCompleteRequest(Irp, 0); | |
return 0xC0000010i64; | |
} | |
SystemBuffer = Irp->AssociatedIrp.MasterIrp; | |
v9 = fsblValidateInputAndRunCallback( | |
SystemBuffer, | |
InputBufferLength, | |
SystemBuffer, | |
OutputBufferLength, | |
&v20, | |
fsblOpenProcessForReadVmByProcessId); | |
ntStatus = v9; | |
if ( v9 < 0 ) | |
goto LABEL_24; | |
v11 = v20; | |
Irp->IoStatus.Status = v9; | |
Irp->IoStatus.Information = v11; | |
LABEL_26: | |
IofCompleteRequest(Irp, 0); | |
return ntStatus; | |
} | |
stringxor.c | |
__int64 fsblDecodeString(_BYTE *InputBuffer, __int64 InputBufferLength, char *Key) | |
{ | |
char v3; | |
v3 = *Key; | |
if ( !InputBuffer ) | |
return 1001i64; | |
if ( !InputBufferLength || (InputBufferLength & 1) != 0 ) | |
return 1002i64; | |
InputBufferLength = InputBufferLength; | |
do | |
{ | |
*InputBuffer ^= v3; | |
v3 += Key[1]; | |
++InputBuffer; | |
--InputBufferLength; | |
} | |
while ( InputBufferLength ); | |
return 0i64; | |
} | |
fsblGetPsPointers | |
if ( fsblDecodeString(SourceString, 0x36i64, v1) ) | |
return 0; | |
RtlInitUnicodeString(&routineName, SourceString); | |
PsLookupProcessByProcessId = MmGetSystemRoutineAddress(&routineName); | |
if ( !PsLookupProcessByProcessId || fsblDecodeString(v3, 0x1Ci64, v1) ) | |
return 0; | |
RtlInitUnicodeString(&routineName, v3); | |
PsProcessType = MmGetSystemRoutineAddress(&routineName); | |
return PsProcessType != 0i64; | |
fsblOpenProcessForReadVmByProcessId | |
__int64 fsblOpenProcessForReadVmByProcessId( | |
unsigned int *ProcessId, | |
unsigned int InputBufferLength, | |
void **OutputBuffer, | |
unsigned int OutputBufferLength, | |
_DWORD *a5) | |
{ | |
_DWORD *v5; | |
char v8; | |
NTSTATUS ntStatus; | |
LUID AccessMode; | |
__int64 result; | |
void *Handle; | |
struct _SECURITY_SUBJECT_CONTEXT SubjectContext; | |
PVOID Object; | |
v5 = a5; | |
v8 = UserMode; | |
if ( !ProcessId || !InputBufferLength || !OutputBuffer || !OutputBufferLength || !a5 ) | |
goto LABEL_20; | |
if ( !PsProcessType || !PsLookupProcessByProcessId ) | |
{ | |
result = 0xE001000Ai64; | |
LABEL_21: | |
*a5 = 0; | |
return result; | |
} | |
if ( InputBufferLength < 4 ) | |
{ | |
LABEL_20: | |
result = 0xC000000Di64; | |
goto LABEL_21; | |
} | |
ntStatus = PsLookupProcessByProcessId(*ProcessId, &Object); | |
if ( ntStatus < 0 || !Object ) | |
goto LABEL_17; | |
memset(&SubjectContext, 0, sizeof(SubjectContext)); | |
AccessMode = SeExports->SeDebugPrivilege; | |
SeCaptureSubjectContext(&SubjectContext); | |
LOBYTE(AccessMode.LowPart) = SeSinglePrivilegeCheck(AccessMode, UserMode) == 0; | |
SeReleaseSubjectContext(&SubjectContext); | |
ntStatus = ObOpenObjectByPointer(Object, 0, 0i64, 0x410u, *PsProcessType, AccessMode.LowPart, &Handle);// PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | |
if ( ntStatus >= 0 ) | |
{ | |
*v5 = 8; | |
if ( OutputBufferLength < 8 ) | |
ntStatus = 0xC0000023; | |
else | |
*OutputBuffer = Handle; | |
v8 = 0; | |
} | |
ObfDereferenceObject(Object); | |
if ( v8 ) | |
LABEL_17: | |
*v5 = 0; | |
return ntStatus; | |
} | |
create.c | |
__int64 fsblIrpCreateHandler(DEVICE_OBJECT *a1, IRP *a2) | |
{ | |
volatile signed __int32 *DeviceExtension; | |
DeviceExtension = a1->DeviceExtension; | |
if ( _InterlockedIncrement(DeviceExtension + 2) <= 1 ) | |
{ | |
LODWORD(g_CurrentProcessId) = PsGetCurrentProcessId(); | |
a2->IoStatus.Information = 0i64; | |
a2->IoStatus.Status = 0; | |
IofCompleteRequest(a2, 0); | |
return 0i64; | |
} | |
else | |
{ | |
_InterlockedDecrement(DeviceExtension + 2); | |
a2->IoStatus.Status = 0xC0000043; | |
a2->IoStatus.Information = 0i64; | |
IofCompleteRequest(a2, 0); | |
return 3221225539i64; | |
} | |
} | |
Input/Output buffers are encrypted (and decrypted via versa) | |
1. id = GetCurrentProcessId() | |
2. hash = Sha1(id) | |
3. *Buffer[0] = 0x12345678 | |
4. Buffer = RC2(Buffer, sizeof(Buffer), hash) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment