Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Before Posting... Please check out the Community Guidelines in the
Announcements and Administration Category.

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");
}

Comments

  • Tim_RobertsTim_Roberts Posts: 12,622
    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, [email protected]
    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.
  • Tim_RobertsTim_Roberts Posts: 12,622
    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.

    Tim Roberts, [email protected]
    Providenza & Boekelheide, Inc.

  • Don_BurnDon_Burn Posts: 1,623
    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 <xxxxx@lists.osr.com>
    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&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://www.osronline.com/showlists.cfm?list=ntdev>;

    MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers!
    Details at <http://www.osr.com/seminars>;

    To unsubscribe, visit the List Server section of OSR Online at <http://www.osronline.com/page.cfm?name=ListServer>;
  • @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.
  • Tim_RobertsTim_Roberts Posts: 12,622
    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.

    Tim Roberts, [email protected]
    Providenza & Boekelheide, Inc.

  • "Did you even look at the link I sent you?"

    Answer: - Yes, very useful. I also already had saw this article :-)
  • > 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.
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!