Lets take
PsSetCreateProcessNotifyRoutine and old NT5 as example because it's simpler.
Internally it looks like
Code: Select allfor (i=0; i < PSP_MAX_CREATE_PROCESS_NOTIFY; i++) {
if (Remove) {
if (PspCreateProcessNotifyRoutine[i] == NotifyRoutine) {
PspCreateProcessNotifyRoutine[i] = NULL;
PspCreateProcessNotifyRoutineCount -= 1;
return STATUS_SUCCESS;
}
} else {
if (PspCreateProcessNotifyRoutine[i] == NULL) {
PspCreateProcessNotifyRoutine[i] = NotifyRoutine;
PspCreateProcessNotifyRoutineCount += 1;
return STATUS_SUCCESS;
}
}
}
where PSP_MAX_CREATE_PROCESS_NOTIFY = 8, this value valid up to current time.
So to operate with callbacks of this type (for example to list them) you need to read
PspCreateProcessNotifyRoutine array,
Code: Select allPCREATE_PROCESS_NOTIFY_ROUTINE PspCreateProcessNotifyRoutine[ PSP_MAX_CREATE_PROCESS_NOTIFY ];
(which is not exported of course) from kernel memory. How to do this? Obviously by finding a valid pointer to this data. And this can be done by disassembling owner
PsSetCreateProcessNotifyRoutine function body and looking for a specific pattern describing that array. There you need LDE (of course if you not plan to do any kind of hardcode - BSOD generator).
LoadImage, ThreadCreate also uses similar arrays (valid for NT5 kernels).
CmRegistryCallback introduced in Windows XP and it's internals also varies from NT5 to NT6 versions. There is no generic way to get what you want. You need a separate callback handling code for two different kernels and data signatures also can depends from service pack version.