做edr的同学大概都晓得edr中经常需要监控windows服务以及windows驱动模块的加载的监控,windows驱动的加载的监控的方法通常使用和windows模块加载监控的方法一样,在内核驱动里使用PsSetLoadImageNotifyRoutine设置模块加载回调例程来监控ring3模块以及ring0模块的加载,回调函数 PsSetLoadImageNotifyRoutine的第二个参数判断,如果 Process Id是0 ,则表示加载驱动,如果Process Id非零,则表示加载DLL。但是这种方法监控驱动加载通常的进程Id是0,因为驱动加载的时候使用的是APC线程,当前上下文在系统线程内,所以得不到具体的进程id.
堆栈如下

所以在当到达PsSetLoadImageNotifyRoutine的时候加载驱动模块的加载的时候pid就是0了,是否有其他方法可以监控到具体的进程?答案是肯定的, 那就是ETW。
ETW是个windows日志事件Trace,每个Trace日志都有他自己的Guid,要监控服务以及驱动加载的日志就得找到对应的GUID,这个GUID是多少呢,下面我们就来具体分析。
最好的方式就是逆向调试分析,打开一个安装驱动服务的软件,比如我们这次使用的是


接下来就是上调试器附加这个进程

在调试器里找到CreateServiceW函数,发现这个函数会调用sechost.dll的sechost.CreateServiceW的函数

发现最终的实现是在这个sechost模块的CreateServiceW,在windows/system32的目录下找到对应的模块,在IDA下以及调试器看到,在运行到最后会调用NdrClientCall4



注意该函数的第一个参数是pStubDescriptor,它的类型是PMIDL_STUB_DESC pStubDescriptor,是一个结构体
typedef struct _MIDL_STUB_DESC {
void *RpcInterfaceInformation;
void * )(size_t) *(pfnAllocate;
void()(void *) * pfnFree;
union {
handle_t *pAutoHandle;
handle_t *pPrimitiveHandle;
PGENERIC_BINDING_INFO pGenericBindingInfo;
} IMPLICIT_HANDLE_INFO;
const NDR_RUNDOWN *apfnNdrRundownRoutines;
const GENERIC_BINDING_ROUTINE_PAIR *aGenericBindingRoutinePairs;
const EXPR_EVAL *apfnExprEval;
const XMIT_ROUTINE_QUINTUPLE *aXmitQuintuple;
const unsigned char *pFormatTypes;
int fCheckBounds;
unsigned long Version;
MALLOC_FREE_STRUCT *pMallocFreeStruct;
long MIDLVersion;
const COMM_FAULT_OFFSETS *CommFaultOffsets;
const USER_MARSHAL_ROUTINE_QUADRUPLE *aUserMarshalQuadruple;
const NDR_NOTIFY_ROUTINE *NotifyRoutineTable;
ULONG_PTR mFlags;
const NDR_CS_ROUTINES *CsRoutineTables;
void *ProxyServerInfo;
const NDR_EXPR_DESC *pExprInfo;
} MIDL_STUB_DESC;

最主要的是结构体中的第一个字段RpcInterfaceInformation,这个结构是RPC接口的信息,定义这RPC的GUID,当前对应的是全局内存是dword_10008F38,所以它对应的是RPC的GUIID

可以看出GUID是 367ABB81-9844-35F1-AD32-98F038001003
5a4K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6V1L8$3y4K6i4K6u0W2L8h3W2U0M7X3!0K6L8$3k6@1i4K6u0W2j5$3!0E0i4K6u0r3k6h3&6Q4x3X3c8#2M7#2)9J5c8X3!0H3k6h3&6K6M7r3g2U0M7#2)9J5c8Y4N6A6L8X3c8G2N6%4y4Q4y4h3k6H3M7X3!0@1L8$3y4G2L8s2y4Q4x3V1k6E0M7#2)9J5k6s2y4U0L8i4u0Q4x3V1j5@1j5K6S2T1y4K6M7H3x3g2)9J5k6r3t1H3y4o6y4Q4x3X3b7@1x3o6m8U0i4K6u0V1z5e0x3#2x3q4)9J5k6r3c8U0x3U0W2U0k6X3q4S2y4h3f1%4j5b7`.`.
意思就是说说这个GUID的RPC对应的名字是\PIPE\svcctl,而且它是在server.exe的这个服务进程里创建的。
接下来的工作就是去逆向service.exe这个进程。
在server.exe的程序里我们可以找到对应的RPC 接口函数是RCreateServiceW

接着会调用ScCreateServiceRpc

在下面的地方我们会看到一个函数
I_RpcBindingInqLocalClientPID(0i64, &Pid);,这个函数会获取当前RPC的客户端进程id

接着就是输出日志,当然前提是这个日志已经开启并且有人去接收它,
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课