How remove a Callback Notify Routine of a determinated module?

Hello,

I’m newbie in kernel driver development and need remove a callback notify routine of a deteminated module (.sys file).

I searched on web and found this (incomplete) example: http://www.mengwuji.net/thread-2134-1-1.html in a chinese forum that show how make this, but my goal is remove only PsSetCreateProcessNotifyRoutine, then from this (incomplete) example i made some adjusts where resulted on following code, but not know if i’m on right direction.

Someone could give me a idea please?

Thank you very much in advance.

Here is my code, compiled with success using VS2010, Visual DDK and WDK 7600.16385.1

status returns: 0xc000007a and only “FIRST” condition block is executed


#include “stdafx.h”
#include “ntddk.h”
#include “WINDEF.H”

typedef struct EX_FAST_REF {
union {
PVOID Object;
ULONG RefCnt : 3;
ULONG Value;
};
}EX_FAST_REF, *PEX_FAST_REF;

typedef struct _EX_PUSH_LOCK
{
union
{
ULONG Locked: 1;
ULONG Waiting: 1;
ULONG Waking: 1;
ULONG MultipleShared: 1;
ULONG Shared: 28;
ULONG Value;
PVOID Ptr;
};
} EX_PUSH_LOCK, *PEX_PUSH_LOCK;

typedef struct _CM_CALLBACK_CONTEXT_BLOCK {
LARGE_INTEGER Cookie;
LIST_ENTRY ThreadListHead;
EX_PUSH_LOCK ThreadListLock;
PVOID CallerContext;
} CM_CALLBACK_CONTEXT_BLOCK, *PCM_CALLBACK_CONTEXT_BLOCK;

typedef struct _EX_CALLBACK_ROUTINE_BLOCK
{
EX_RUNDOWN_REF RundownProtect;
PEX_CALLBACK_FUNCTION Function;
PCM_CALLBACK_CONTEXT_BLOCK Context;
} EX_CALLBACK_ROUTINE_BLOCK, *PEX_CALLBACK_ROUTINE_BLOCK;

typedef struct _LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
WORD LoadCount;
WORD TlsIndex;
union
{
LIST_ENTRY HashLinks;
struct
{
PVOID SectionPointer;
ULONG CheckSum;
};
};
union
{
ULONG TimeDateStamp;
PVOID LoadedImports;
};
struct _ACTIVATION_CONTEXT * EntryPointActivationContext;
PVOID PatchInformation;
LIST_ENTRY ForwarderLinks;
LIST_ENTRY ServiceTagLinks;
LIST_ENTRY StaticLinks;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;

ULONG uMoudleSize = 0;
ULONG uProcessUnKnowTypeAddress = 0;

ULONG GetMoudleBase(PDRIVER_OBJECT pDriverObject, wchar_t *StrC, ULONG unKnowType)
{
LDR_DATA_TABLE_ENTRY *pDataTableEntry, *SectionBase;
PLIST_ENTRY pList;
UNICODE_STRING usString;
ULONG uMoudleBase = 0;

pDataTableEntry = (LDR_DATA_TABLE_ENTRY*)pDriverObject->DriverSection;

if (!pDataTableEntry)
return uMoudleBase;

pList = pDataTableEntry->InLoadOrderLinks.Flink;

while (pList != &pDataTableEntry->InLoadOrderLinks)
{

SectionBase = (LDR_DATA_TABLE_ENTRY*)pList;
RtlInitUnicodeString(&usString, StrC);

if (RtlCompareUnicodeString(&SectionBase->BaseDllName, &usString, TRUE) == 0)
{

uMoudleBase = (ULONG)SectionBase->DllBase;
uMoudleSize = (ULONG)SectionBase->SizeOfImage;
}

if (!(unKnowType > (ULONG)SectionBase->DllBase && unKnowType < (ULONG)SectionBase->SizeOfImage))
{
uProcessUnKnowTypeAddress = unKnowType;
}

pList = pList->Flink;
}
return uMoudleBase;
}

VOID DeletePsSetCreateProcessNotifyRoutineCallBack(PDRIVER_OBJECT pDriverObject)
{

NTSTATUS status;
UNICODE_STRING szCreateProcess = { 0 };
PVOID pCreateProcess = NULL;
ULONG uMoudleBase = 0;
PEX_FAST_REF pRef = NULL;
PEX_CALLBACK_ROUTINE_BLOCK Point = NULL;
int i;

RtlInitUnicodeString(&szCreateProcess, L"PsSetCreateProcessNotifyRoutine");
pCreateProcess = MmGetSystemRoutineAddress(&szCreateProcess);

if( (pCreateProcess != 0) && MmIsAddressValid(pCreateProcess) ) {

pRef = (PEX_FAST_REF)pCreateProcess;

for (i = 0; i < 100 ; i++)
{

Point = (PEX_CALLBACK_ROUTINE_BLOCK)(pRef->Value);

if ( MmIsAddressValid((PVOID)Point) )
{

uMoudleBase = GetMoudleBase(pDriverObject, L"\SystemRoot\system32\drivers\aswSP.sys", (ULONG)Point->Function);

if (uProcessUnKnowTypeAddress == (ULONG)Point->Function)
{
status = PsSetCreateProcessNotifyRoutine((PCREATE_PROCESS_NOTIFY_ROUTINE)Point->Function, TRUE);
DbgPrint(“FIRST - %08x\n”, status);
}

if (uMoudleBase < (ULONG)Point->Function && (uMoudleBase + uMoudleSize) > (ULONG)Point->Function)
{
status = PsSetCreateProcessNotifyRoutine((PCREATE_PROCESS_NOTIFY_ROUTINE)Point->Function, TRUE);
DbgPrint(“SECOND - %08x\n”, status);
}

}
pRef++;
}

}
}

void CallbackNotifyRemoveUnload(IN PDRIVER_OBJECT DriverObject);

#ifdef __cplusplus
extern “C” NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
#endif

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{

DbgPrint(“Hello from CallbackNotifyRemove!\n”);

DeletePsSetCreateProcessNotifyRoutineCallBack(DriverObject);

DriverObject->DriverUnload = CallbackNotifyRemoveUnload;

return STATUS_SUCCESS;
}

void CallbackNotifyRemoveUnload(IN PDRIVER_OBJECT DriverObject)
{
DbgPrint(“Goodbye from CallbackNotifyRemove!\n”);
}

xxxxx@hotmail.com wrote:

I’m newbie in kernel driver development and need remove a callback notify routine of a deteminated module (.sys file).

Why?  There are damned few legitimate reasons for doing this, but it’s a
common malware technique, and we do not support malware authors here. 
Tell us what overall goal you are trying to achieve, and we can decide
whether to move forward.

I searched on web and found this (incomplete) example: http://www.mengwuji.net/thread-2134-1-1.html in a chinese forum that show how make this, but my goal is remove only PsSetCreateProcessNotifyRoutine, then from this (incomplete) example i made some adjusts where resulted on following code, but not know if i’m on right direction.

status returns: 0xc000007a and only “FIRST” condition block is executed

Right, as it should.  You removed a bunch of code, presumably because
you didn’t understand it.  As a result, you fetch the address of the
PsSetCreateProcessNotifyRoutine API, and then you pass the low 32 bits
of that address to PsSetCreateProcessNotifyRoutine.  Naturally, it’s not
going to be in its own list.

I hope you understand this code is 32-bit only.  If you’re running on a
64-bit system, none of this code will work.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

@Tim Roberts,

The part removed was exactly the incomplete part, and the structures that was missed i added. My goal not is a malware, but yes a anti malware (anti rootkit).

The error Error status: 0xc000007a, based in this site (http://cloud365.in/c00002e2-directory-services-could-not-start-error-status-0xc000007a/), mean that procedure not was found, in this case here could also be that the rootkit had applied a hook on PsSetCreateProcessNotifyRoutine (http://www.kernelmode.info/forum/viewtopic.php?f=14&t=4823) and also resulted in this same status code.

And about x32 or x64 code: - Yes, i need of a x32 code for this moment.

Then, what i must make to remove a callback notification routine of a determinated module?

If you print Point->Function as hex, will see that none corresponds to current entry ( based on result of a anti rootkit software like PC Hunter for example) https://image.prntscr.com/image/IFnk67ZfSIO4EmoV4FzcfQ.png.

Then, what’s next step to make my example work?

I hope that you or some other member here can help.

xxxxx@hotmail.com wrote:

The part removed was exactly the incomplete part, and the structures that was missed i added. My goal not is a malware, but yes a anti malware (anti rootkit).

Absolutely hopeless.  Once the malware is present in the kernel, it can
override or bypass anything you do.  Those guys are smart.

 

The error Error status: 0xc000007a, based in this site (http://cloud365.in/c00002e2-directory-services-could-not-start-error-status-0xc000007a/), mean that procedure not was found, in this case here could also be that the rootkit had applied a hook on PsSetCreateProcessNotifyRoutine (http://www.kernelmode.info/forum/viewtopic.php?f=14&t=4823) and also resulted in this same status code.

No, the error is because your code is wrong, because you removed
IMPORTANT code.  You fetch the address of
PsSetCreateProcessNotifyRoutine, and treat that as if it was the table
of registered callbacks, but (obviously, I hope) it’s not.  It’s a
function.  The table of callbacks is in an internal array called
PspCreateProcessNotifyRoutine.  Because that symbol is not exported, the
only way to find PspCreateProcessNotifyRoutine is to scan through the
disassembled code of PsSetCreateProcessNotifyRoutine to locate the first
instruction that loads it.  That’s what the code you removed does. 
That’s always going to be a delicate operation, because the assembler
code changes based on compiler versions and optimizations.

https://www.fireeye.com/blog/threat-research/2012/06/bypassing-process-monitoring.html

Then, what i must make to remove a callback notification routine of a determinated module?

You have to find the table of registered callbacks.  You aren’t looking
for that in your code.

If you print Point->Function as hex, will see that none corresponds to current entry

No, because you aren’t looking at the callback table.  You’re looking at
random data.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Even if you find a way to do this, think about what you are doing. The Malware is expecting this function to be called and has likely built up a table it is doing something with or has modified the processes that it has seen, to do anything useful you have to understand what the specific malware is doing and figure out how to undo it. As Tim pointed out this is a stupid design, it could easily lead to a situation that really corrupts the system in a bad way (yes I know malware is bad, but this design can be worse than a lot of malware).

Don Burn
Windows Driver Consulting
Website: http://www.windrvr.com

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@probo.com
Sent: Friday, December 22, 2017 5:47 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] How remove a Callback Notify Routine of a determinated module?

xxxxx@hotmail.com wrote:
> The part removed was exactly the incomplete part, and the structures that was missed i added. My goal not is a malware, but yes a anti malware (anti rootkit).

Absolutely hopeless. Once the malware is present in the kernel, it can override or bypass anything you do. Those guys are smart.

> The error Error status: 0xc000007a, based in this site (http://cloud365.in/c00002e2-directory-services-could-not-start-error-status-0xc000007a/), mean that procedure not was found, in this case here could also be that the rootkit had applied a hook on PsSetCreateProcessNotifyRoutine (http://www.kernelmode.info/forum/viewtopic.php?f=14&amp;t=4823) and also resulted in this same status code.

No, the error is because your code is wrong, because you removed IMPORTANT code. You fetch the address of PsSetCreateProcessNotifyRoutine, and treat that as if it was the table of registered callbacks, but (obviously, I hope) it’s not. It’s a function. The table of callbacks is in an internal array called PspCreateProcessNotifyRoutine. Because that symbol is not exported, the only way to find PspCreateProcessNotifyRoutine is to scan through the disassembled code of PsSetCreateProcessNotifyRoutine to locate the first instruction that loads it. That’s what the code you removed does. That’s always going to be a delicate operation, because the assembler code changes based on compiler versions and optimizations.

https://www.fireeye.com/blog/threat-research/2012/06/bypassing-process-monitoring.html

> Then, what i must make to remove a callback notification routine of a determinated module?

You have to find the table of registered callbacks. You aren’t looking for that in your code.

> If you print Point->Function as hex, will see that none corresponds to
> current entry

No, because you aren’t looking at the callback table. You’re looking at random data.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.


NTDEV is sponsored by OSR

Visit the list online at: http:

MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers!
Details at http:

To unsubscribe, visit the List Server section of OSR Online at http:</http:></http:></http:>

@Tim Roberts,

what part is important on incomplete code(http://www.mengwuji.net/thread-2134-1-1.html) for example?

this? =>

uPspCreateProcessNotifyRoutineAddr = SearchFeatureCode(uCreateProcessNotifyRoutineAddr,(char*)sCode,5);

if yes, i’m not have idea about how was implemented this method.

xxxxx@hotmail.com wrote:

what part is important on incomplete code(http://www.mengwuji.net/thread-2134-1-1.html) for example?

this? =>

uPspCreateProcessNotifyRoutineAddr = SearchFeatureCode(uCreateProcessNotifyRoutineAddr,(char*)sCode,5);

Exactly.

 

if yes, i’m not have idea about how was implemented this method.

Do you understand what it has to do, and why removing that code does not
work?  If not, then you cannot possibly hope to achieve your goal.  Do
you understand x86 assembly language?  You’re digging into the internals
of the Windows kernel here.  You can’t do that as a casual programmer. 
You’re going to be disassembling functions to figure out how they
operate, and that requires knowledge in several detailed areas.

Did you even look at the link I sent you?


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

“Did you even look at the link I sent you?”

Answer: - Yes, very useful. I also already had saw this article :slight_smile:

> what i must make to remove a callback notification routine of a determinated module?

The only thing that truly amazes me is that you haven’t, up to this point, been requested
(apparently, in capitals) to publish the name of your company so that the usual suspects may advise their clients to avoid its crappy products. OTOH, it is not all THAT bad - after all,the very suggestion that a software product may be worse than a piece of malware seems to be …ugh,“exciting”, don’t you think…

Anton Bassov

The source code you’ve been trying to copy-paste into your project (likely so you can then boast about what you’ve accomplished despite not even understanding the code properly) relies on finding the address to PspCreateProcessNotifyRoutine, an undocumented and non-exported routine which is called by PsSetCreateProcessNotifyRoutine, PsSetCreateProcessNotifyRoutineEx and PsSetCreateProcessNotifyRoutineEx2.

The reason the source code is trying to locate the address of PspCreateProcessNotifyRoutine is because this allows you to find an array which holds entries to the registered callback routines by other drivers, for the PsSetCreateProcessNotifyRoutine/Ex/Ex2 callbacks. Once the array has been found, after additional validation and searching of the correct data, it can be used to unregister the callback routine which another device driver had registered, by calling the unregister routine for that specific callback. Most of these Ps* callback routines share common similarities with this functionality.

What you are trying to do is highly unrecommended, undocumented and unstable. Microsoft don’t want people to access such data which is why it isn’t accessible via a documented interface, and you’re going to cause more harm than good trying to do this, especially since we can all see you do not actually know what you are doing. Such tasks can be justified in some situations, and I do know of security software which possesses the ability to do such, but they are developed and maintained by developers with more than enough experience to handle it correctly and keep it updated, and they’ll at-least check the environment characteristics to prevent deploying such a task on an environment which has been untested for it (to prevent bug-checks after an update which ruins the functionality). It is clear and evident that you don’t really understand how the source code you found even works, and the fact that you are trying to regularly copy-paste code from external, unknown sources, and implement them into your project and expect it to work right off-the-bat (not to mention the given circumstances of it all being undocumented and unstable and that most of these third-party hidden source code examples are environment-dependent due to many factors such as hard-coding off offsets or simply put, bad programming with bad functionality) tells me that maybe you should not even be developing kernel-mode software.

I am certain I have seen you ask questions like these before somewhere else. I re-call someone just like you over on the MSDN forum, asking how to use ZwQueryDirectoryFile from kernel-mode… I also remember someone spamming across multiple forums, asking how to remove window hooks set by other running software, via accessing non-exported and undocumented structures held under win32k.sys.

You’re completely wasting your time with the anti-rootkit project you’ve been working on for, it would seem around 12+ months. Rootkits are not prevalent in the wild, they haven’t been for a very long time. Most people are using 64-bit environments nowadays on updated machines, and anyone who isn’t is unlikely to touch your project with a barge-pole. If your developing all of this for experimental, educational purposes, then you could at-least try to actually develop the project yourself because using other people’s experimental, bad and compatibility-bad source code isn’t going to be very educational. Don’t say I didn’t warn you once you finish your project and are unable to fix bug-checks on people’s machines, or when no one actually takes an interest in it.

https://www.osronline.com/ShowThread.cfm?link=282419
https://www.osronline.com/ShowThread.cfm?link=281700
https://www.osronline.com/ShowThread.cfm?link=284212
https://www.osronline.com/ShowThread.cfm?link=281787

“I’m newbie in kernel driver development” - yet you’re trying to take on a task which is highly undocumented and unstable. I can’t believe this. You’ve been working on this anti-rootkit project for 12+ months it would appear after locating threads you’ve made across this forum and others alone for kernel-mode development, yet if you had taken the time to actually buckle down and study kernel-mode development before jumping into a project which was way over your head from the start, you’d probably be good enough to make some real progress with anti-rootkit by yourself by now.