Sometimes when you want to hook a function, you don’t know what parameter to use. For example XxOpenProcess (I know I always use the same API, but thats because its an easy one and useful)
NtOpenProcess(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK AccessMask,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PCLIENT_ID ClientId );
In my other article we were using “ClientID”, but you may also use other parameters like the first one “ProcessHandle”
The goal of this article is not to deny process termination, but to stop memory editors attaching* to our process.
Before we start, I’m going to show you 2 “custom” made functions.
ULONG gProcessNameOffset;
ULONG GetProcessNameOffset()
{PEPROCESS curproc;
int i;curproc = PsGetCurrentProcess();
// This will fail if the EPROCESS grows larger
// than a page size.
for( i = 0; i < 3*PAGE_SIZE; i++ )
{
if( !strncmp( “System”, (PCHAR)curproc + i, strlen(“System”) ))
{
gProcessNameOffset = i;
}
}
return 0;
}
GetProcessNameOffset returns the offset within the EPROCESS structure of the process name
BOOL GetProcessName( PCHAR theName )
{
PEPROCESS curproc;
char *nameptr;if( gProcessNameOffset )
{
curproc = PsGetCurrentProcess();
nameptr = (PCHAR) curproc + gProcessNameOffset;
strncpy( theName, nameptr, NT_PROCNAMELEN );
theName[NT_PROCNAMELEN] = 0; /* NULL at end */
return TRUE;
}
return FALSE;
}
GetProcessName copy the process name into the specified buffer. This is very useful, you can use it like this:
CHAR ProcessName[PROCNAMELEN];
DbgPrint(“ZwOpenProcess() called from %s\n”, ProcessName);
Okay 1 more thing before we start.
// Length of process name (rounded up to next DWORD)
#define PROCNAMELEN 20
// Maximum length of NT process name
#define NT_PROCNAMELEN 16
Okay, let’s start! First lets make our function prototype. The parameters must be the same as the original function.
NTSTATUS NewZwOpenProcess(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PCLIENT_ID ClientId OPTIONAL
) {
Then let’s add this (OldZwOpenProcess points to the original function)
NTSTATUS ntStatus;
NTSTATUS ntStatus2;
CHAR CallerProcessName[PROCNAMELEN];GetProcessName(CallerProcessName);
ntStatus = ((ZWOPENPROCESS)(OldZwOpenProcess)) ( //Original ZwOpenProcess()
ProcessHandle,
DesiredAccess,
ObjectAttributes,
ClientId OPTIONAL);if( NT_SUCCESS(ntStatus))
{
Now we are going to use ObReferenceObjectByHandle to get the EPROCESS from the handle.
ntStatus = ObReferenceObjectByHandle(
*ProcessHandle,
PROCESS_ALL_ACCESS,
NULL,
KernelMode,
&Process, //Will hold the EPROCESS
NULL);if(NT_SUCCESS(ntStatus))
{
Now that we got the EPROCESS address (“Process” is holding it), we want to get the name. We do that like this (If you noticed, it almost does the same thing as GetProcessName):
//DbgPrint(“EPROCESS: 0x%08lX\n”, Process);
nameptr = (PCHAR)Process + gProcessNameOffset;
strncpy(Target, nameptr, NT_PROCNAMELEN);
Target[NT_PROCNAMELEN] = 0; /* NULL at end */
//DbgPrint(“Targeted Process %s”,Target);
Now we do some comparing (ProtectedProcess, is a buffer holding the name of the protected process) We check if the targeted process is our process, if it is, we close the handle and make it return STATUS_INVALID_HANDLE
if(!strncmp(Target,ProtectedProcess,NT_PROCNAMELEN)==0)
{
ZwClose(ProcessHandle); //Close Handle
DbgPrint(“OpenProcess called by %s\n”,CallerProcessName);
DbgPrint(“Targeting %s\n”,Target);
DbgPrint(“Returning STATUS_INVALID_HANDLE”);
ntStatus = STATUS_INVALID_HANDLE; //Return invalid handle
ProcessHandle = 0; //Handle = 0;
}
The full prototype code:
NTSTATUS NewZwOpenProcess(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PCLIENT_ID ClientId OPTIONAL
)
{NTSTATUS ntStatus;
NTSTATUS ntStatus2;
CHAR Target[PROCNAMELEN];
CHAR CallerProcessName[PROCNAMELEN];
PEPROCESS EProcess;
char *nameptr;GetProcessName(CallerProcessName);
ntStatus = ((ZWOPENPROCESS)(OldZwOpenProcess)) ( //Original ZwOpenProcess()
ProcessHandle,
DesiredAccess,
ObjectAttributes,
ClientId OPTIONAL);if( NT_SUCCESS(ntStatus))
{
ntStatus = ObReferenceObjectByHandle(
*ProcessHandle,
PROCESS_ALL_ACCESS,
NULL,
KernelMode,
&EProcess, //Will hold the EPROCESS
NULL);if(NT_SUCCESS(ntStatus))
{
//DbgPrint(”EPROCESS: 0x%08lX\n”, EProcess);
nameptr = (PCHAR)EProcess + gProcessNameOffset;
strncpy(Target, nameptr, NT_PROCNAMELEN);
Target[NT_PROCNAMELEN] = 0; /* NULL at end */
//DbgPrint(“Targeted Process %s”,Target);if(!strncmp(Target,ProtectedProcess,NT_PROCNAMELEN)==0)
{
ZwClose(ProcessHandle); //Close Handle
DbgPrint(“OpenProcess called by %s\n”,CallerProcessName);
DbgPrint(“Targeting %s\n”,Target);
DbgPrint(“Returning STATUS_INVALID_HANDLE”);
ntStatus = STATUS_INVALID_HANDLE; //Return invalid handle
ProcessHandle = 0; //Handle = 0;
}
}
}
return ntStatus; //STATUS_INVALID_HANDLE
}

Well thats it for this post, if you like that kind of stuff, you may want to visit Dual’s blog. He has some interesting advanced articles.
Now you may be asking why we did all of this when we could of used “ClientID” parameter. Thats because not every function has multiple useful parameters.
For example XxReadVirtualMemory As you see, only the first parameter is really useful to us, therefor you are going to use the method described in this article. Thanks for reading and visiting, if you find any errors or bugs, leave a comment =)
*Memory editors such as CheatEngine, can still open your process, since it uses it’s own routine of OpenProcess (Must be enabled in options -> Extra)
Posted by unlmtd 
Posted by unlmtd 
Posted by unlmtd 