воскресенье, 5 апреля 2020 г.

static code analysis

This cool article is good case to show how you can employ static code analysis for extracting some unexported symbols from binary code - in this case we need ExNPagedLookasideLock & ExNPagedLookasideListHead

Sure the first thing you need is disassembler. If you search at GitHub "x86 disasm" you will get something about 20 repositories, but we need one that satisfies some requirements:
  • disasm to some intermediate code and not in string output
  • can be used in kernel mode (just in case if you want to do it) which means that it must be written in C

So just choose the one with the most comprehensible code - bcs they all contains bugs and you anyway will fix them and/or add missed instructions

Lets start with exported function ExInitializeNPagedLookasideList. Simplest cases - xp 64bit:

четверг, 2 апреля 2020 г.


It seems that in w10 build 19569 new verifier table has appeared - VfDifThunks along with new exported function DifRegisterPlugin (which is used only in VerifierExt.sys for now). List of intercepted functions:

четверг, 26 марта 2020 г.


In windows 8 in fltmgr was introduced feature for filter operation Etw logging - structure WMI_FLTIO_NOTIFY_ROUTINES in GLOBALS:
 void  (TimeStampRoutine*)(struct _ETW_KERNEL_TRACE_TIMESTAMP*, unsigned long);
 void  (FailureNotifyRoutine*)(void*, unsigned long, unsigned long, unsigned short);
 void  (InitiationNotifyRoutine*)(void*, unsigned long, unsigned long, unsigned short);
 void  (CompletionNotifyRoutine*)(void*, unsigned long, unsigned long, unsigned short, struct _ETW_KERNEL_TRACE_TIMESTAMP*);

 void  (FastCompletionNotifyRoutine*)(void*, unsigned long, unsigned long, unsigned short, struct _ETW_KERNEL_TRACE_TIMESTAMP*);

in windows 10 new entry was added:
void  (IoRedirectionNotifyRoutine*)(struct _IRP*, struct _FILE_OBJECT*);

This structure initialized in DriverEntry - PerfTraceRoutines assigned address of GLOBALS.DummyPerfTraceRoutines and then called function WmiQueryTraceInformation with class FltIoNotifyRoutinesClass (where this structure filled with content of EtwpFltIoNotifyRoutines)
So patching this functions pointers you can have real-time info about operations in file filters (or perhaps disable Etw logging for them)

On freshly installed system only two pfns are initialized:

среда, 4 марта 2020 г.


since w8 Microsoft introduced for PnP devices management new structure with lots of function pointers - PiPnpRtlCtx

It`s called from lots of exported functions, but I think most comfortable for RE are IoOpenDeviceRegistryKeyIoOpenDeviceInterfaceRegistryKey. You can gather address of PiPnpRtlCtx with one pass of disassembling - it will be first loaded address in .data section after call to ExAcquireResourceExclusiveLite

This structure allocating and partially initializing in function PnpCtxOpenMachine. There are at least 3 version with different size:
  • 0xac for 32 bit/0x158 for x64 - used in w8, w8.1 and in w10 up to est.build 14279
  • 0xb0 for 32 bit/0x160 for x64 - used in w10 up to est. build 16299
  • 0x10c for 32 bit/0x210 for x64 - used in w10 since est. build 17134
This struct has lots of pointer to functions (see also PiPnpRtlInit):

вторник, 14 января 2020 г.

using devm_kcalloc unchecked result in linux kernel

Part I
This time I add references to linux kernel github - although I ran my naive code analyzer on version 4.18 - all found bugs have long and happy life in current source tree

gb_generate_enum_strings in drivers/staging/greybus/audio_topology.c:
strings = devm_kcalloc(gb->dev, items, sizeof(char *), GFP_KERNEL);
data = gbenum->names;

for (i = 0; i < items; i++) {
  strings[i] = (const char *)data;

rt2880_pinmux_pins in drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c:  
p->func[i]->pins = devm_kcalloc(p->dev,
for (j = 0; j < p->func[i]->pin_count; j++)
  p->func[i]->pins[j] = p->func[i]->pin_first + j;

Using unchecked result from devm_kmalloc_array:
ti_sci_scan_clocks_from_fw in drivers/clk/keystone/sci-clk.c:
tmp_clks = devm_kmalloc_array(dev, max_clks + 64,
memcpy(tmp_clks, clks, max_clks * sizeof(sci_clk));

Doubtful case (I think is has delayed effects bcs no checks for ports field) - function mscc_ocelot_probe in drivers/net/ethernet/mscc/ocelot_board.c
ocelot->ports = devm_kcalloc(&pdev->dev, ocelot->num_phys_ports,
                     sizeof(struct ocelot_port *), GFP_KERNEL);

понедельник, 13 января 2020 г.

using devm_kzalloc unchecked result in linux kernel 4.18

Managed Device Resource (described in Documentation/driver-model/devres.txt) is witty technique for lazy developers. Unfortunately it does not exempt from the need to check results. I decided to see if there are such places in linux kernel (which can lead to null address dereference). Right way to do it is use Static Analyzer like clang, coverity or PVS Studio. But I am too lazy so I wrote simple and naive perl script and run it on linux kernel 4.18 source tree. It found 56 cases (from total 4173 where devm_kzalloc was used) - not too much for manual checking. So lets see what we have

impd1_probe in arch/arm/mach-integrator/impd1.c:
            lookup = devm_kzalloc(&dev->dev,
                          sizeof(*lookup) + 3 * sizeof(struct gpiod_lookup),
            chipname = devm_kstrdup(&dev->dev, devname, GFP_KERNEL);
            mmciname = kasprintf(GFP_KERNEL, "lm%x:00700", dev->id);
            lookup->dev_id = mmciname;

st_sensors_of_probe in drivers/iio/common/st_sensors/st_sensors_core.c (still not fixed):
    pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
    if (!of_property_read_u32(np, "st,drdy-int-pin", &val) && (val <= 2))
        pdata->drdy_int_pin = (u8) val;
        pdata->drdy_int_pin = defdata ? defdata->drdy_int_pin : 0;

    pdata->open_drain = of_property_read_bool(np, "drive-open-drain");

sm501_register_gpio_i2c_instance in drivers/mfd/sm501.c:
    lookup = devm_kzalloc(&pdev->dev,
                  sizeof(*lookup) + 3 * sizeof(struct gpiod_lookup),
    lookup->dev_id = "i2c-gpio";
    if (iic->pin_sda < 32)
        lookup->table[0].chip_label = "SM501-LOW";
        lookup->table[0].chip_label = "SM501-HIGH";
    lookup->table[0].chip_hwnum = iic->pin_sda % 32;
    lookup->table[0].con_id = NULL;
    lookup->table[0].idx = 0;
    lookup->table[0].flags = GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN;

rt2880_pinmux_index in drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c (still not fixed):
            f[c]->groups = devm_kzalloc(p->dev, sizeof(int), GFP_KERNEL);
            f[c]->groups[0] = i;

rt2880_pinmux_probe in drivers/staging/mt7621-pinctrl/pinctrl-rt2880.c

        range = devm_kzalloc(p->dev, sizeof(struct pinctrl_gpio_range) + 4, GFP_KERNEL);
        range->name = name = (char *) &range[1];
        sprintf(name, "pio");
        range->npins = __be32_to_cpu(*ngpio);
        range->base = __be32_to_cpu(*gpiobase);
        range->pin_base = range->base;

rt5514_spi_pcm_probe in sound/soc/codecs/rt5514-spi.c:
    rt5514_dsp = devm_kzalloc(component->dev, sizeof(*rt5514_dsp),

    rt5514_dsp->dev = &rt5514_spi->dev;

rt5663_parse_dp in sound/soc/codecs/rt5663.c (still not fixed):
        rt5663->imp_table = devm_kzalloc(dev, table_size, GFP_KERNEL);
            (u32 *)rt5663->imp_table, table_size);

perl script used to find this bugs: