mirror of
https://github.com/NomanNasirMinhas/Ringer
synced 2026-08-19 05:01:13 +00:00
246 lines
8.3 KiB
Go
246 lines
8.3 KiB
Go
package extract
|
|
|
|
import "fmt"
|
|
|
|
// An IOCTL code is a 32-bit value laid out by the CTL_CODE macro:
|
|
//
|
|
// (DeviceType << 16) | (Access << 14) | (Function << 2) | Method
|
|
//
|
|
// Bits 0-1 are the transfer method, bits 2-13 the function code, bits 14-15
|
|
// the access, and bits 16-31 the device type.
|
|
|
|
// IoctlCode is a decoded IOCTL control code.
|
|
type IoctlCode struct {
|
|
Code uint32
|
|
DeviceType uint16
|
|
Function uint16
|
|
Method uint8
|
|
Access uint8
|
|
Confidence string // "high", "medium", or "low"
|
|
Source string // "disasm" or "data"
|
|
RVA uint32 // where the value was found (0 if unknown)
|
|
Note string // optional annotation (e.g. "ambiguous: NTSTATUS range")
|
|
}
|
|
|
|
// DecodeIoctl splits a raw 32-bit value into its CTL_CODE components.
|
|
func DecodeIoctl(code uint32) (deviceType uint16, function uint16, method, access uint8) {
|
|
method = uint8(code & 0x3)
|
|
function = uint16((code >> 2) & 0xFFF)
|
|
access = uint8((code >> 14) & 0x3)
|
|
deviceType = uint16((code >> 16) & 0xFFFF)
|
|
return
|
|
}
|
|
|
|
// MethodName returns the human-readable name for a transfer method.
|
|
func MethodName(m uint8) string {
|
|
switch m {
|
|
case 0:
|
|
return "METHOD_BUFFERED"
|
|
case 1:
|
|
return "METHOD_IN_DIRECT"
|
|
case 2:
|
|
return "METHOD_OUT_DIRECT"
|
|
case 3:
|
|
return "METHOD_NEITHER"
|
|
default:
|
|
return fmt.Sprintf("METHOD_%d", m)
|
|
}
|
|
}
|
|
|
|
// AccessName returns the human-readable name for an access value.
|
|
func AccessName(a uint8) string {
|
|
switch a {
|
|
case 0:
|
|
return "FILE_ANY_ACCESS"
|
|
case 1:
|
|
return "FILE_READ_ACCESS"
|
|
case 2:
|
|
return "FILE_WRITE_ACCESS"
|
|
case 3:
|
|
return "FILE_READ_ACCESS|FILE_WRITE_ACCESS"
|
|
default:
|
|
return fmt.Sprintf("ACCESS_%d", a)
|
|
}
|
|
}
|
|
|
|
// deviceTypeNames maps common FILE_DEVICE_* values to their symbolic names.
|
|
var deviceTypeNames = map[uint16]string{
|
|
0x0001: "FILE_DEVICE_BEEP",
|
|
0x0002: "FILE_DEVICE_CD_ROM",
|
|
0x0003: "FILE_DEVICE_CD_ROM_FILE_SYSTEM",
|
|
0x0004: "FILE_DEVICE_CONTROLLER",
|
|
0x0005: "FILE_DEVICE_DATALINK",
|
|
0x0006: "FILE_DEVICE_DFS",
|
|
0x0007: "FILE_DEVICE_DISK",
|
|
0x0008: "FILE_DEVICE_DISK_FILE_SYSTEM",
|
|
0x0009: "FILE_DEVICE_FILE_SYSTEM",
|
|
0x000A: "FILE_DEVICE_INPORT_PORT",
|
|
0x000B: "FILE_DEVICE_KEYBOARD",
|
|
0x000C: "FILE_DEVICE_MAILSLOT",
|
|
0x000D: "FILE_DEVICE_MIDI_IN",
|
|
0x000E: "FILE_DEVICE_MIDI_OUT",
|
|
0x000F: "FILE_DEVICE_MOUSE",
|
|
0x0010: "FILE_DEVICE_MULTI_UNC_PROVIDER",
|
|
0x0011: "FILE_DEVICE_NAMED_PIPE",
|
|
0x0012: "FILE_DEVICE_NETWORK",
|
|
0x0013: "FILE_DEVICE_NETWORK_BROWSER",
|
|
0x0014: "FILE_DEVICE_NETWORK_FILE_SYSTEM",
|
|
0x0015: "FILE_DEVICE_NULL",
|
|
0x0016: "FILE_DEVICE_PARALLEL_PORT",
|
|
0x0017: "FILE_DEVICE_PHYSICAL_NETCARD",
|
|
0x0018: "FILE_DEVICE_PRINTER",
|
|
0x0019: "FILE_DEVICE_SCANNER",
|
|
0x001A: "FILE_DEVICE_SERIAL_MOUSE_PORT",
|
|
0x001B: "FILE_DEVICE_SERIAL_PORT",
|
|
0x001C: "FILE_DEVICE_SCREEN",
|
|
0x001D: "FILE_DEVICE_SOUND",
|
|
0x001E: "FILE_DEVICE_STREAMS",
|
|
0x001F: "FILE_DEVICE_TAPE",
|
|
0x0020: "FILE_DEVICE_TAPE_FILE_SYSTEM",
|
|
0x0021: "FILE_DEVICE_TRANSPORT",
|
|
0x0022: "FILE_DEVICE_UNKNOWN",
|
|
0x0023: "FILE_DEVICE_VIDEO",
|
|
0x0024: "FILE_DEVICE_VIRTUAL_DISK",
|
|
0x0025: "FILE_DEVICE_WAVE_IN",
|
|
0x0026: "FILE_DEVICE_WAVE_OUT",
|
|
0x0027: "FILE_DEVICE_8042_PORT",
|
|
0x0028: "FILE_DEVICE_NETWORK_REDIRECTOR",
|
|
0x0029: "FILE_DEVICE_BATTERY",
|
|
0x002A: "FILE_DEVICE_BUS_EXTENDER",
|
|
0x002B: "FILE_DEVICE_MODEM",
|
|
0x002C: "FILE_DEVICE_VDM",
|
|
0x002D: "FILE_DEVICE_MASS_STORAGE",
|
|
0x002E: "FILE_DEVICE_SMB",
|
|
0x002F: "FILE_DEVICE_KS",
|
|
0x0030: "FILE_DEVICE_CHANGER",
|
|
0x0031: "FILE_DEVICE_SMARTCARD",
|
|
0x0032: "FILE_DEVICE_ACPI",
|
|
0x0033: "FILE_DEVICE_DVD",
|
|
0x0034: "FILE_DEVICE_FULLSCREEN_VIDEO",
|
|
0x0035: "FILE_DEVICE_DFS_FILE_SYSTEM",
|
|
0x0036: "FILE_DEVICE_DFS_VOLUME",
|
|
0x0037: "FILE_DEVICE_SERENUM",
|
|
0x0038: "FILE_DEVICE_TERMSRV",
|
|
0x0039: "FILE_DEVICE_KSEC",
|
|
0x003A: "FILE_DEVICE_FIPS",
|
|
0x003B: "FILE_DEVICE_INFINIBAND",
|
|
0x003C: "FILE_DEVICE_VMBUS",
|
|
0x003D: "FILE_DEVICE_CRYPT_PROVIDER",
|
|
0x003E: "FILE_DEVICE_WPD",
|
|
0x003F: "FILE_DEVICE_BLUETOOTH",
|
|
0x0040: "FILE_DEVICE_MT_COMPOSITE",
|
|
0x0041: "FILE_DEVICE_MT_TRANSPORT",
|
|
0x0042: "FILE_DEVICE_BIOMETRIC",
|
|
0x0043: "FILE_DEVICE_PMI",
|
|
0x0044: "FILE_DEVICE_EHSTOR",
|
|
0x0045: "FILE_DEVICE_DEVAPI",
|
|
0x0046: "FILE_DEVICE_GPIO",
|
|
0x0047: "FILE_DEVICE_USBEX",
|
|
0x0048: "FILE_DEVICE_CONSOLE",
|
|
0x0049: "FILE_DEVICE_NFP",
|
|
0x004A: "FILE_DEVICE_SYSENV",
|
|
0x004B: "FILE_DEVICE_VIRTUAL_BLOCK",
|
|
0x004C: "FILE_DEVICE_POINT_OF_SERVICE",
|
|
0x004D: "FILE_DEVICE_STORAGE_REPLICATION",
|
|
0x004E: "FILE_DEVICE_TRUST_ENV",
|
|
0x004F: "FILE_DEVICE_UCM",
|
|
0x0050: "FILE_DEVICE_UCMTCPCI",
|
|
0x0051: "FILE_DEVICE_PERSISTENT_MEMORY",
|
|
0x0052: "FILE_DEVICE_NVDIMM",
|
|
0x0053: "FILE_DEVICE_HOLOGRAPHIC",
|
|
0x0054: "FILE_DEVICE_SDFXHCI",
|
|
0x0055: "FILE_DEVICE_HVDEV",
|
|
}
|
|
|
|
// DeviceTypeName returns the symbolic name for a device type, or "" if unknown.
|
|
func DeviceTypeName(dt uint16) string {
|
|
return deviceTypeNames[dt]
|
|
}
|
|
|
|
// knownNTSTATUS is a small set of common NTSTATUS values that frequently appear
|
|
// as CMP immediates in driver dispatch code. They are return-value comparisons,
|
|
// not IOCTL codes, and are filtered out to reduce false positives.
|
|
var knownNTSTATUS = map[uint32]bool{
|
|
0x00000000: true, // STATUS_SUCCESS
|
|
0x00000103: true, // STATUS_PENDING
|
|
0x40000003: true, // STATUS_OBJECT_NAME_EXISTS (informational)
|
|
0x80000005: true, // STATUS_BUFFER_OVERFLOW
|
|
0x8000000A: true, // STATUS_NO_MORE_FILES
|
|
0x8000001A: true, // STATUS_NO_MORE_ENTRIES
|
|
0xC0000001: true, // STATUS_UNSUCCESSFUL
|
|
0xC0000002: true, // STATUS_NOT_IMPLEMENTED
|
|
0xC0000004: true, // STATUS_INFO_LENGTH_MISMATCH
|
|
0xC0000005: true, // STATUS_ACCESS_VIOLATION
|
|
0xC0000008: true, // STATUS_INVALID_HANDLE
|
|
0xC000000D: true, // STATUS_INVALID_PARAMETER
|
|
0xC000000E: true, // STATUS_NO_SUCH_DEVICE
|
|
0xC000000F: true, // STATUS_NO_SUCH_FILE
|
|
0xC0000010: true, // STATUS_INVALID_DEVICE_REQUEST
|
|
0xC0000011: true, // STATUS_END_OF_FILE
|
|
0xC0000013: true, // STATUS_NO_MEDIA_IN_DEVICE
|
|
0xC0000017: true, // STATUS_NO_MEMORY
|
|
0xC000001C: true, // STATUS_BUFFER_TOO_SMALL
|
|
0xC0000022: true, // STATUS_ACCESS_DENIED
|
|
0xC0000023: true, // STATUS_BUFFER_TOO_SMALL (dup)
|
|
0xC0000024: true, // STATUS_OBJECT_TYPE_MISMATCH
|
|
0xC0000034: true, // STATUS_OBJECT_NAME_NOT_FOUND
|
|
0xC0000035: true, // STATUS_OBJECT_NAME_COLLISION
|
|
0xC0000039: true, // STATUS_OBJECT_PATH_INVALID
|
|
0xC000003A: true, // STATUS_OBJECT_PATH_NOT_FOUND
|
|
0xC0000043: true, // STATUS_SHARING_VIOLATION
|
|
0xC0000045: true, // STATUS_INVALID_PAGE_PROTECTION
|
|
0xC000007B: true, // STATUS_INVALID_IMAGE_FORMAT
|
|
0xC000009A: true, // STATUS_INSUFFICIENT_RESOURCES
|
|
0xC00000BB: true, // STATUS_NOT_SUPPORTED
|
|
0xC00000C0: true, // STATUS_DEVICE_NOT_CONNECTED
|
|
0xC00000CC: true, // STATUS_BAD_NETWORK_NAME
|
|
0xC00000D0: true, // STATUS_DRIVER_UNABLE_TO_LOAD
|
|
0xC000010E: true, // STATUS_IMAGE_ALREADY_LOADED
|
|
0xC0000135: true, // STATUS_DLL_NOT_FOUND
|
|
0xC0000142: true, // STATUS_DLL_INIT_FAILED
|
|
0xC000014B: true, // STATUS_PIPE_BROKEN
|
|
0xC0000205: true, // STATUS_INSUFFICIENT_RESOURCES
|
|
0xC0000225: true, // STATUS_NOT_FOUND
|
|
0xC00000E5: true, // STATUS_FLT_NO_HANDLER_DEFINED
|
|
}
|
|
|
|
// plausibleIoctl reports whether a raw 32-bit value is a plausible IOCTL code
|
|
// rather than a status code, flag, or size constant. It returns the reason for
|
|
// rejection (empty string means "plausible").
|
|
func plausibleIoctl(code uint32) (ok bool, note string) {
|
|
if code == 0 {
|
|
return false, "zero"
|
|
}
|
|
if code == 0xFFFFFFFF {
|
|
return false, "0xFFFFFFFF"
|
|
}
|
|
// A real IOCTL has a non-zero device type in bits 16-31, so the value is
|
|
// >= 0x10000. Smaller values are flags, sizes, or synthetic IDs (e.g. the
|
|
// nanga driver's SSNs 0x777/0x888/0x999), not IOCTLs.
|
|
if code < 0x10000 {
|
|
return false, "device type zero (< 0x10000)"
|
|
}
|
|
if knownNTSTATUS[code] {
|
|
return false, "known NTSTATUS"
|
|
}
|
|
dt, fn, m, a := DecodeIoctl(code)
|
|
// A value that is exactly device_type<<16 (function/method/access all zero)
|
|
// is a degenerate IOCTL and far more likely a size or alignment constant
|
|
// (e.g. 0x10000 = 64 KiB).
|
|
if fn == 0 && m == 0 && a == 0 {
|
|
return false, "degenerate (function/method/access all zero)"
|
|
}
|
|
// NTSTATUS error codes occupy 0xC0000000-0xFFFFFFFF. A value whose device
|
|
// type falls in 0xC000-0xFFFF is almost certainly a status code, not an
|
|
// IOCTL (custom vendor device types are conventionally 0x8000-0xBFFF).
|
|
if dt >= 0xC000 {
|
|
return false, "NTSTATUS error range"
|
|
}
|
|
if dt >= 0x8000 {
|
|
// Custom vendor device type. Genuinely ambiguous with NTSTATUS warning
|
|
// codes, so keep it but flag it.
|
|
return true, "ambiguous: vendor device type overlaps NTSTATUS warning range"
|
|
}
|
|
return true, ""
|
|
}
|