Click here to Skip to main content
Email Password   helpLost your password?

Introduction

API calls interception is the task that allows to get access to some parts of other's programs. Lots of programmers spend time on developing and describing various methods which allow that access. Such methods are used in many anti-viruses and anti-spyware. Besides, sometimes, intercepting can help you to find errors in your application. However, it is not a secret that some viruses use it too. I spent much time to find and understand the technique of interception. I would like to describe here the results of my research.

Method description

First of all, you need to read the following article to understand the basics of the interception mechanism: HookSys (written by Ivo Ivanov). It was very helpful for me, and I used the sample code from it. However, it does not solve all my problems because Ivo's samples sometimes miss very important API calls. It happens when the application starts up too fast and the intercepting service has no time to inject the DLL. After some research, I found the actual problem, and it was related to using the kernel mode function, SetCreateProcessNotificationRoutine. This function is used to receive notification events about any new process creation. Such a notification is often fired when the process has already been started. Therefore, I needed to find a way to improve Ivo's code.

As far as I know, the execution of all Windows processes consists of the following steps:

The step right before the main thread resuming looks like the most comfortable for injection because the process is in suspended state and none of its instructions have been executed yet.

Most of the work on the process creation is done in the kernel mode, so to change this algorithm, you need to intercept the kernel mode functions NtCreateProcess() and NtCreateThread(). The CONTEXT structure, the pointer to which is passed to the function NtCreateThread(), contains a member called EAX. I found that it equals to the process' start address in user mode, so if you can change it, then you can get the control right after process creation and before starting. To solve this task, I wrote a kernel mode driver. It starts while the system starts up.

There are some initialization steps:

  1. starting;
  2. receiving configuration from the user mode;
  3. intercepting kernel mode functions such as: NtCreateProcess(), NtCreateThread(), NtTerminateProcess(), NewNtCreateProcessEx() - for Windows 2003 Server.

A handler to the NtCreateThread() function contains code that will do most of the interesting jobs. Here is a brief description of its algorithm:

  1. allow access to the creating process by calling ObReferenceObjectByHandle();
  2. remember the main thread start address (ThreadContext->EAX);
  3. "jump" to the context of the creating process by calling KeAttachProcess();
  4. allocate memory for my code by calling ZwAllocateVirtualMemory(), similar to the well known technique for CreateRemoteThread() in user mode;
  5. copy the small code to the allocated memory that will load my DLL. This code looks like:
    push pszDllName
    mov  ebx, LoadLibraryAddr
    call [ebx]
    mov  eax, Win32StartAddr
    push eax
    ret
    pszDllName: db 'example.dll';
  6. "jump" to the initial process;
  7. change the thread start address (ThreadContext->EAX) so it will point to the allocated memory.

That is all. You can download and compile the complete source code for this article. Note: the sample is fully functional and quite enough for basic understanding, but for real usage, it might be rewritten.

Compiling the code

You need the NTDDK to be installed on your computer. I'm using MSVS 6.0 for compiling NtProcDrv, and MSVS 7.1 for the rest of the projects.

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
GeneralRe: How to get the executable name from the created process??
Andriy Oriekhov
12:32 25 Oct '06  
Unfortunately I don't know the answer and I have no time to find it.
GeneralRe: How to get the executable name from the created process??
ehaerim
11:32 5 Jan '07  
The code below will give you the process name within the NtProcDrv driver. But this will work only on Win XP or later.

I haven't found an answer for Win2K. If you have found, let me know.

haerim


typedef NTSTATUS (*QUERY_INFO_PROCESS) (
__in HANDLE ProcessHandle,
__in PROCESSINFOCLASS ProcessInformationClass,
__out_bcount(ProcessInformationLength) PVOID ProcessInformation,
__in ULONG ProcessInformationLength,
__out_opt PULONG ReturnLength
);

QUERY_INFO_PROCESS ZwQueryInformationProcess;

NTSTATUS GetProcessImageName(PUNICODE_STRING ProcessImageName)
{
NTSTATUS status;
ULONG returnedLength;
ULONG bufferLength;
PVOID buffer;
PUNICODE_STRING imageName;

PAGED_CODE(); // this eliminates the possibility of the IDLE Thread/Process
if (NULL == ZwQueryInformationProcess) {

UNICODE_STRING routineName;

RtlInitUnicodeString(&routineName, L"ZwQueryInformationProcess");

ZwQueryInformationProcess =
(QUERY_INFO_PROCESS) MmGetSystemRoutineAddress(&routineName);

if (NULL == ZwQueryInformationProcess) {
DbgPrint("Cannot resolve ZwQueryInformationProcess\n");
}
}
// // Step one - get the size we need
// status = ZwQueryInformationProcess( NtCurrentProcess(),
ProcessImageFileName,
NULL, // buffer
0, // buffer size
&returnedLength);

if (STATUS_INFO_LENGTH_MISMATCH != status) {

return status;

}

// // Is the passed-in buffer going to be big enough for us?
// This function returns a single contguous buffer model...
// bufferLength = returnedLength - sizeof(UNICODE_STRING);

if (ProcessImageName->MaximumLength < bufferLength) {

ProcessImageName->Length = (USHORT) bufferLength;

return STATUS_BUFFER_OVERFLOW;

}

// // If we get here, the buffer IS going to be big enough for us, so
// let's allocate some storage.
// buffer = ExAllocatePoolWithTag(PagedPool, returnedLength, 'ipgD');

if (NULL == buffer) {

return STATUS_INSUFFICIENT_RESOURCES;

}

// // Now lets go get the data
// status = ZwQueryInformationProcess( NtCurrentProcess(),
ProcessImageFileName,
buffer,
returnedLength,
&returnedLength);

if (NT_SUCCESS(status)) {
// // Ah, we got what we needed
// imageName = (PUNICODE_STRING) buffer;

RtlCopyUnicodeString(ProcessImageName, imageName);

}

// // free our buffer
// ExFreePool(buffer);

// // And tell the caller what happened.
//
return status;

}

GeneralDoesn`t work
Cold-Fire
11:16 16 Aug '06  
I downloaded the demo and started the program....pressed enter to set the hook, then started any app without seein` any messagebox Confused ....

the files (.sys,.dll,.exe) were in the same folder so program didn`t reported any errors...I executed the program on the administrator account...

any answers ? I`m a bit confused about the functionality
GeneralRe: Doesn`t work
Andriy Oriekhov
4:44 22 Aug '06  
You have to copy file tunew20.dll to the windows/system32/ folder.
QuestionNow it works but...
Cold-Fire
4:40 23 Aug '06  
Now it works Big Grin ..but another question..what`s the difference between your method and using a CBT hook and processing HC_CREATEWND ? 10x in advance Cool
AnswerRe: Now it works but...
Andriy Oriekhov
13:01 23 Aug '06  
Only GUI application can be hooked with CBT technique.
GeneralRe: Now it works but...
Cold-Fire
2:49 24 Aug '06  
Oh..10x...I`m really new to hooking and using DLLs but I`m tryin` to gather all the information I can get about themBig Grin Poke tongue
QuestionWhy the "ParentProcess" is 0xFFFFFFFF?
Fu Hao
21:33 5 Jul '06  
Hi,mate

Your HookDemo is cool.
But there is one thing I can't understand.
In this Function:
NTSTATUS NewNtCreateProcessEx(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ParentProcess,
IN BOOLEAN InheritObjectTable,
IN HANDLE SectionHandle OPTIONAL,
IN HANDLE DebugPort OPTIONAL,
IN HANDLE ExceptionPort OPTIONAL,
IN HANDLE Unknown )
{
NTSTATUS ResultStatus;

//I Modified Here!
DBGPRINT(("In NtCreateProcessEx, ParentProcess =
0x%Xn",ParentProcess));

...

}

But the value of ParentProcess is 0xFFFFFFFF whatever process be created.

I just want to kown which session create the process.

Can you help me?

Thank you!




GeneralHow about non x86 ?
leandrobecker
13:31 5 Jun '06  
Hi

This code is awesome, but with Windows supporting x64 and IA64, the code is not portable.

Did you had worked on those platforms ?

Congratulations
GeneralRe: How about non x86 ?
Andriy Oriekhov
1:05 7 Jun '06  
No, I didn't.
GeneralReboot computer
nhthiemsvt
22:58 4 May '06  
Computer is rebooted when run HookDemo.exe??? is there idear to solve?
GeneralRe: Reboot computer
Andriy Oriekhov
0:55 26 May '06  
Did you place tunew20.dll to windows\system32?

Andriy Oriekhov
Generalnon-admin
ep
22:21 19 Mar '06  
can it be used when the user is using "user" account?


GeneralRe: non-admin
Andriy Oriekhov
7:36 20 Mar '06  
no, user should have "administrator" rights.
GeneralRe: non-admin
ricardo fernandes
14:28 11 May '06  
Hello,

I am running the sample with administrator rigths on xp pro service pack2
and i am getting the message cannot create service.
Can you give me a solution for this?

Thanks in advanced
Ricardo Fernandes



GeneralRe: non-admin
Andriy Oriekhov
1:01 26 May '06  
You can use GetLastError() function right after service creation to determine error number.

Andriy Oriekhov
GeneralRe: non-admin
girm
8:46 28 Jun '06  
Hi,

I did have problems(..because of my own code I'm afraid..) too , while adapting the code to my needs.
The kernel mode driver was not stopped in case of a crash (I get that from the error number, as suggested)

so I add some code before calling CreateService :

//we try open & close the service to be sure we will restart it properly
schService = ::OpenService(hServiceDB,"NTProcDrv",SERVICE_ALL_ACCESS);
if (schService!=NULL)
{
SERVICE_STATUS ServiceStatus;
ControlService(schService,SERVICE_CONTROL_STOP,&ServiceStatus);
DeleteService(schService);
CloseServiceHandle(schService);
}

hope it helps
Marc
GeneralThumbs up
Ivo Ivanov
9:38 15 Mar '06  
Hi Andriy,

Very nice article! Got my 5.

Thanks,

Ivo Ivanov, MCP(.NET/C#)
Author of "API Hooking Revealed" http://www.codeproject.com/system/hooksys.asp AntiHook 2.5, HookTool.NET SDK v3.6: http://www.infoprocess.com.au
GeneralAwesome!
yafan
15:44 6 Mar '06  

Thanks,

-y


Last Updated 31 May 2006 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010