 |
|
 |
Is this driver Vista compatible? I am asking this question because I can not see NtCreateThreadEx hooked.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi, I also ran into the "0x431" problem. Could you please possibly tell me your solution? Thanks in advance!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
It's pretty simple - I've just found the registry hive responsible for services (HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services) and deleted the key matching our kernel-intercepting service (I don't remember it's name, but it's inside the code of NTProcDrv). Then it works totally fine.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hey Guys,
I also am receiving the same error . i am trying to understand your solution but can't....
What exactly did you do to solve the problem.
Michael
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Hi
Every time I run your demo, I receive the following error:
Cannot create service. ErrorCode = 0x431 I've built the demo from source code (using Visual C++ Express Codename Orcas), both Release and Debug, but the error still appears, every time. I executed the app step by step with VC++ debugger, but it doesn't show me any satisfying results. How do I deal with this problem?
Thanks in Advance.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I must have had an error in my Registry - I've removed the wrong entry, and now the app works fine. BTW, did you forget to close a handle to the Service Manager?
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
 |
I want to modify source code for Vista O.S., a handler to NtCreateThreadEx() function, I don't know the parameter type of this function. Please help me, thanks!!!
|
| Sign In·View Thread·PermaLink | 1.00/5 (3 votes) |
|
|
|
 |
|
 |
I've modified the dllhookapi.cpp to see 1) if I can subclass Notepad.exe successfully within DllMain. 2) if I can subclass multiple instances of Notepad.exe successfully.
The code works this way: 1) Call EnumProcesses to find out all the running processes. 2) Call Subclass with the process id array obtained above and the name of notepad for subclassing. 3) For each process id, Subclass will call EnumProcessModules and GetModuleFileNameEx to get the full module name and repeat this until we find notepad. 4) Now if we have found notepad, call EnumThreadWindows with current thread id to find out the main window to subclass.
Here the problem rises. EnumThreadWindows returns successfully, but EnumThreadWindowsProc NEVER get called. I couldn't understand why. Now I guess it is because somehow the current thread did not create any windows yet. So EnumThreadWindows return TRUE but no EnumThreadWindowsProc call!
But then, how can I subclass notepad right after the creation?
haerim
// dllhookapi.cpp : Defines the entry point for the DLL application. // /////////////////////////////////////////////////////// // Andriy Oriekhov. 2006. Toleron Sofware. // www.toleron.com ///////////////////////////////////////////////////////
#include "stdafx.h" #include "windows.h"
#include
HWND g_hwnd = NULL; BOOL CALLBACK EnumThreadWindowsProc(HWND hwnd, LPARAM lParam); // New & old window procedure of the subclassed window WNDPROC OldProc = NULL; LRESULT CALLBACK NewProc(HWND, UINT, WPARAM, LPARAM);
void Subclass(DWORD* paProcess, DWORD nCount, LPCTSTR pName);
BOOL WINAPI DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: { WriteLogDebug("Before starting process.");
// Get the list of process identifiers. DWORD aProcesses[1024], cbNeeded, cProcesses; if (EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded) == 0) { DWORD dwErr = GetLastError(); WriteLogDebug("DllMain: dwErr=%d", dwErr); return TRUE; }
// Find the matching process and subclass it. cProcesses = cbNeeded / sizeof(DWORD); Subclass(aProcesses, cProcesses, "C:\\Windows\\System32\\notepad.exe");
break; } case DLL_PROCESS_DETACH: { WriteLogDebug("Before ending process."); if (::SetWindowLongPtr(g_hwnd, GWL_WNDPROC, (long)OldProc) == 0) { WriteLogDebug("Failed to unsubclass back from NewProc(0x%X) to OldProc(0x%X)", GetWindowLongPtr(g_hwnd, GWL_WNDPROC), (long)OldProc); } break; }}
return TRUE; }
void Subclass(DWORD* paProcess, DWORD nCount, LPCTSTR pName) { WriteLogDebug("Subclass: nCount=%d, pName=%s", nCount, pName); char szProcessName[MAX_PATH] = ""; unsigned int i; for (i = 0; i < nCount; i++) { // Get a handle to the process. DWORD dwPID = paProcess[i]; HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, dwPID);
if (NULL == hProcess) { WriteLogDebug("Subclass: dwPID=0x%X(%d), OpenProcess failed!", dwPID, dwPID); CloseHandle(hProcess); continue; } // Get modules for this process DWORD cbNeeded = 0; HMODULE hMod; if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded) == 0) // { WriteLogDebug("Subclass: hProcess=0x%X, EnumProcessModules failed!", hProcess); continue; } DWORD nModCount = cbNeeded / sizeof(HMODULE); WriteLogDebug("Subclass: nModCount=%d", nModCount);
// Get the process name. GetModuleFileNameEx(hProcess, hMod, szProcessName, sizeof(szProcessName)); WriteLogDebug("Subclass: dwPID=0x%X(%u), cbNeeded=%d, %s\n", dwPID, dwPID, cbNeeded, szProcessName); if (strcmpi(szProcessName, pName) != 0) { CloseHandle(hProcess); continue; } /* // Go through with all the windows for the current thread // => There is no windows for dwPID yet. So, EnumWindowsProc will NEVER be called for dwPID. EnumWindows(EnumWindowsProc, (LPARAM)dwPID); */ DWORD dwTID = GetCurrentThreadId(); WriteLogDebug("Subclass: dwTID=0x%X", dwTID); // Now, let's subclass the main window. => This seems not working. See comments below. // The below EnumThreadWindows seems to NEVER call EnumThreadWindowsProc because there is no windows for the current thread created yet. // So, EnumThreadWindows call succeeds returning TRUE but no EnumThreadWindowsProc gets called at all. // Then how can I subclass the main window of this thread? I don't know the answer yet. if (EnumThreadWindows(dwTID, EnumThreadWindowsProc, (LPARAM)dwPID) == 0) { DWORD dwErr = GetLastError(); WriteLogDebug("Subclass: dwTID=0x%X, dwErr=%d, EnumThreadWindows failed!", dwTID, dwErr); CloseHandle(hProcess); continue; }
CloseHandle(hProcess); } }
BOOL CALLBACK EnumThreadWindowsProc(HWND hwnd, LPARAM lParam) { WriteLogDebug("EnumThreadWindowsProc(0x%X, %d)", hwnd, lParam);
// Let's find hwnd's process is the same as DllMain's calling process DWORD dwPID_hwnd = 0, dwTID_hwnd = 0; dwTID_hwnd = GetWindowThreadProcessId(hwnd, &dwPID_hwnd);
TCHAR wmfn[MAX_PATH + 1] = {0}; UINT nLen = GetWindowModuleFileName(hwnd, wmfn, MAX_PATH); // Huh, this does not work for other processes, but only for the calling process!!! WriteLogDebug("EnumThreadWindowsProc: hwnd=0x%X, dwPID_hwnd =0x%X(%d), dwTID_hwnd=0x%X(%d)\n" " nLen=%d, wmfn=%s", hwnd, dwPID_hwnd, dwPID_hwnd, dwTID_hwnd, dwTID_hwnd, nLen, wmfn); return TRUE; // // Finally, let's subclass hwnd // WNDPROC OldProc = (WNDPROC)::SetWindowLongPtr(hwnd, GWL_WNDPROC, (long)NewProc); // if (OldProc == 0) // WriteLogDebug("EnumThreadWindowsProc: Failed to subclass hwnd(0x%X)", hwnd); // else // WriteLogDebug("EnumThreadWindowsProc: Succeeded in subclassing hwnd(0x%X)'s OldProc(0x%X) to NewProc(0x%X)", // hwnd, (long)OldProc, (long)NewProc); // // return FALSE; }
//------------------------------------------------------------- // NewProc // Notice: - new window procedure for the START button; // - it just swaps the left & right muse clicks; // LRESULT CALLBACK NewProc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ) { // WriteLogDebug("wParam=%d, lParam)=%d", wParam, lParam); switch (uMsg) { //WM_COMMAND nNotifyCode (Menu) wID:34795 case WM_COMMAND: WriteLogDebug("wParam=%d, lParam, HIWORD(wParam)(nNotifyCode)=%d, LOWORD(lParam)(id)=%d=%d", wParam, lParam, HIWORD(wParam), LOWORD(lParam)); if (HIWORD(wParam) == 0) { // WriteLogDebug("2,HIWORD(wParam)(nNotifyCode)=%d, LOWORD(lParam)(id)=%d", HIWORD(wParam), LOWORD(lParam)); switch(LOWORD(wParam)) { case 34795: // display main dialog ::MessageBox(NULL,"NULL","hStart",MB_OK); return S_OK; case 34796: return S_OK; case 34797: return S_OK; default: break; } } } return CallWindowProc(OldProc,hwnd,uMsg,wParam,lParam); }
// Usage //WriteLog("int value=%d \n str value=%s", 19, "test"); #include void inline WriteLog(char *ch, ...) { char buf[1024]; va_list arg_list; va_start( arg_list, ch ); wvsprintf( buf, ch, arg_list ); va_end( arg_list ); FILE *file; file = fopen("dllhookapi.log", "a+"); fprintf(file, "%s", buf); fclose(file); }
void inline WriteLogDebug(char *ch, ...) { char buf[1024]; va_list arg_list; va_start( arg_list, ch ); wvsprintf( buf, ch, arg_list ); va_end( arg_list ); OutputDebugString(buf); }
-- modified at 17:11 Friday 5th January, 2007
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
There is an executable, A.exe. It can be run multiple times resulting in multiple processes shown in TaskManager's process list.
I care about those processes created by running A.exe only and need to inject dll into them. No other processes should be injected.
The problem is how to filter those processes?
Since NewNtCreateThread is given as
NTSTATUS NewNtCreateThread( OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN HANDLE ProcessHandle, OUT PCLIENT_ID ClientId, IN PCONTEXT ThreadContext, IN PINITIAL_TEB InitialTeb, IN BOOLEAN CreateSuspended);
and there is ProcessHandle, somehow we should be able to get necessary information about the current process and filter out unwanted ones.
ObjectAttributes parameter is always passed as NULL, so ObjectAttributes->ObjectName can't be used at all.
This is the first time in kernel programming, and it is too hard for me to find how.
Please someone help me on this.
haerim
-- modified at 14:07 Sunday 31st December, 2006
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
The code below works for WinXP or later to find out the name of full process image name.
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; }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
The below is log after hooking.
As you see, ProcessHandle was 0x240 when it was created by NtCreateProcessEx. But, when it was terminated by NtTerminateProcess it was NULL. Why? and How does the kernel terminate a process with a NULL handle?
Can anyone explain?
haerim
========= Log by DBGPRINT ===================
In DriverEntry Memory for Pool successfully initialized receiving IOCTL_NTPROCDRV_SET_ADDRNFO ok! Trying to hook srvices Setting hook on SSTIndexNtCreateProcess = 0x0000002F Setting hook on SSTIndexNtCreateThread = 0x00000035 Setting hook on SSTIndexNtTerminateProcess = 0x00000101 Setting hook on pfnLoadLibrary = 0x7C80AE4B Setting hook on SSTIndexNtCreateProcessEx = 0x00000030 In NtCreateProcessEx Kernel successfully create NtCreateProcessEx. ----->ProcessHandle = 0x240 Successfully added process handle to Queue ObjectAttributes = 0x00000000Kernel trying to CreateThread(from User Mode) for ProcessHandle = 0x240 Address of LoadLibraryW = 0x7C80AE4B ---------------Memory allocation OK! BaseAddr = 0x80000 ---------------Old EAX Value = 0x0100739d Kernel sucessfully create new thread. ----->ThreadHandle = 0x1fch for ProcessHandle = 0x240 Called NtTerminateProcess, ProcessHandle=0x00000000 Kernel sucessfully terminate Process. ----->ProcessHandle = 0x00000000 Called NtTerminateProcess, ProcessHandle=0x00000000 ObjectAttributes = 0x00000000 Kernel sucessfully create new thread. ----->ThreadHandle = 0x2d4h for ProcessHandle = 0xffffffff ObjectAttributes = 0x00000000 Kernel sucessfully create new thread. ----->ThreadHandle = 0x1e0h for ProcessHandle = 0xffffffff In NtCreateProcessEx Kernel successfully create NtCreateProcessEx. ----->ProcessHandle = 0x14c Successfully added process handle to Queue ObjectAttributes = 0x00000000 Kernel trying to CreateThread(from User Mode) for ProcessHandle = 0x14C Address of LoadLibraryW = 0x7C80AE4B ---------------Memory allocation OK! BaseAddr = 0x130000 ---------------Old EAX Value = 0x004034af Kernel sucessfully create new thread. ----->ThreadHandle = 0x150h for ProcessHandle = 0x14c ObjectAttributes = 0x00000000 Kernel sucessfully create new thread. ----->ThreadHandle = 0x470h for ProcessHandle = 0xffffffff ObjectAttributes = 0x00000000 Kernel sucessfully create new thread. ----->ThreadHandle = 0x470h for ProcessHandle = 0xffffffff
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
BOOL WINAPI DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: MessageBox(NULL,"Before starting process.","Hello",0); break; case DLL_PROCESS_DETACH: MessageBox(NULL,"Before ending.","Hello",0); break; }
return TRUE; }
When a Notepad process is created there certaily a "Hello" messagebox saying "Before starting process." shows up along with a bell sound. I have to press OK to continue. And, when it is terminated, I expected to see another "Hello" messagebox saying "Before ending." along with a bell sound, too. When I close NotePad.exe, however, no messagebox was shown but only a bell sound.
Why didn't the second messagebox show up but only a bell sound? How did it disappear without me pressing OK button at all?
haerim
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
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.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I've been playing around with HookInjEx(http://www.codeproject.com/threads/winspy.asp?df=100&forumid=16291&select=1784407&msg=1784407[^]) which worked fine for a single instance of Notepad.exe. However, when I run two Notepad instances, the injection worked for only one instance and not for the other one.
Is there any nice and clean way to make hooking work for all the instances?
One possible way is to use PsSetCreateProcessNotifyRoutine mentioned in this article.
Please provide a good working example if possible.
haerim
-- modified at 12:37 Friday 1st December, 2006
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
 |
|
 |
Hi Andriy,
Thanks for this usefull information. I've been trying it since this morning. The hookdemo.exe is running in the background and I get start and end messages for applications.
However I encountered some problems with some programs.
Excel: Whenever I try to open an Excel document by double-clicking on the file, Excel cannot open the document. It starts with an empty screen.
Visual studio: Try to open a *.cs file by double clicking. It shows process start messagebox. Just after this another messagebox pops up saying that it could not find the file. However I didn't click on the first messagebox coming from the hooking dll and theoretically there is no way that the application continues before I press OK on the first messagebox. How does this happen?
Adobe Acrobat reader: Open a pdf file by double clicking. Acrobat reader gives a memory error on exit.
There seems to be a problem in starting programs with parameters. Do you have any idea?
Thanks in advance
oky
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I haven't had time for exploring the problem. Try to change MessageBoxes in DLL with some kind of logging. In that case sample code will work fine.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Awesome article !!
I am trying to figure out how to adapt it to the "API Hooking revealed" from Mr Ivanov ... and since I am very new to kernel driver programing ... its ... well .. painfull.
I need to be able to know the executable name in order to know if I need to inject a dll in it or not.
I guess this information is to be grabbed from the process handle ... but since all this is in the driver code all my attemps failed.
Could you help me
thxs
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
 |
|
 |
Thanks for your answer, Yes I did think about doing it in DLLMain (I did it in fact it works fine)
But this is not an answer to my original question : I need to know the process name before injecting the dll ... otherwhile it means that I will inject the DLL in any process that starts : and this is what i would like avoid.
thanks in advance Marc
PS: I've previously forgotten to rate you a deserved 5, now its done , PPS: didn't get notified of your answer by CP , sorry it tooks so much time to post again
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
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; }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I downloaded the demo and started the program....pressed enter to set the hook, then started any app without seein` any messagebox ....
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
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|