Well as we know on Windows NT there is no callback function ( From user mode ) to do this task,
although there are implementations that can do it.
For example, we can use the callback that Windows OS provides us to monitor all the windows that are created
then obtain their handles, get the process ID belonging to that window and compare the PID
with previously obtained list, which will have all the IDs of processes that have been created in
the system, but I think this technique is more resource-intensive than the one I will show you today.
Well, on Windows NT, explorer.exe is one of the most important processes, that is responsible for many tasks
including the initiation of all programs the user requests (not processes created by other programs, services, drivers), assigning a token, priority and so on.
Our the task is to set a hook on CreateProcessInternal function in explorer to ensure that
any process started is first passed through our hook. We can set a hook in one more Internal
function, but that is not necessary, because explorer specifically calls this Function.
Usually CreateProcessInternalW looks like this:
PUSH 624
PUSH 76084980
CALL 7607417C
MOV EAX,DWORD PTR SS:[EBP+8]
MOV DWORD PTR SS:[EBP-360],EAX
MOV EDX,DWORD PTR SS:[EBP+C]
MOV DWORD PTR SS:[EBP-334],EDX
MOV ESI,DWORD PTR SS:[EBP+10]
MOV DWORD PTR SS:[EBP-33C],ESI
MOV EAX,DWORD PTR SS:[EBP+14]
MOV DWORD PTR SS:[EBP-464],EAX
...
But this could change according to the windows version or service pack, but don't think we can just add these instructions
and hope for everything to work by itself.
Ok, because we need the first 5 bytes for our hook, we must copy these bytes to overwrite and
then execute them, luckily this instruction:
PUSH 624
has an exact size of 5 bytes, the hooking function will be this
( passing function address as the first parameter of CreateProcessInternal and the new function address as the second parameter):
jump to the rest of the original function and a return address to the rest of the function hook.
Then we can use any API to display a string (unicode)
WINDOWS 8
Apparently, on Windows 8 things have not changed either. Now the main module is KernelBase.dll.
Actually kernelbase and kernel32 have the definition of CreateProcessInternal but Kernel32@CreateProcessInternal
is just a wrapper because it will always jump to KernelBase@CreateProcessInternal.
Futhermore, Windows 8 doesn't call CreateProcessInternal directly, it is first calling a undocumented
function on the SHELL module. CreateProcessInternal on Windows 8 looks like this:
CreateProcessInternal:
MOV EDI,EDI
PUSH EBP
MOV EBP,ESP
PUSH 0x0FFFFFFFE
PUSH 74e824e8
...
Our program can work on windows 8 too, just change the name of the module to "kernelbase".
Now we just need to inject our code into explorer.exe, doing that we can :
[*] Block initialization of any program
[*] Obtain information about any process
[*] Inject code to every process ran by the user
[*] Use your imagination :)
For example: To block an application from being run, just change the input arguments to invalid and the process will fail.
And here's the unhook function to clean everything up:
code was tested on:
Windows XP + SP2 (x86)
Windows XP + SP3 (x86)
Windows Vista (x86)
WIndows 7 (x86)
WIndows 7 + SP1 (x86)
Windows 8 Developer preview (x86)
64-bit Version:
In attached as well.
although there are implementations that can do it.
For example, we can use the callback that Windows OS provides us to monitor all the windows that are created
then obtain their handles, get the process ID belonging to that window and compare the PID
with previously obtained list, which will have all the IDs of processes that have been created in
the system, but I think this technique is more resource-intensive than the one I will show you today.
Well, on Windows NT, explorer.exe is one of the most important processes, that is responsible for many tasks
including the initiation of all programs the user requests (not processes created by other programs, services, drivers), assigning a token, priority and so on.
Our the task is to set a hook on CreateProcessInternal function in explorer to ensure that
any process started is first passed through our hook. We can set a hook in one more Internal
function, but that is not necessary, because explorer specifically calls this Function.
Usually CreateProcessInternalW looks like this:
PUSH 624
PUSH 76084980
CALL 7607417C
MOV EAX,DWORD PTR SS:[EBP+8]
MOV DWORD PTR SS:[EBP-360],EAX
MOV EDX,DWORD PTR SS:[EBP+C]
MOV DWORD PTR SS:[EBP-334],EDX
MOV ESI,DWORD PTR SS:[EBP+10]
MOV DWORD PTR SS:[EBP-33C],ESI
MOV EAX,DWORD PTR SS:[EBP+14]
MOV DWORD PTR SS:[EBP-464],EAX
...
But this could change according to the windows version or service pack, but don't think we can just add these instructions
and hope for everything to work by itself.
Ok, because we need the first 5 bytes for our hook, we must copy these bytes to overwrite and
then execute them, luckily this instruction:
PUSH 624
has an exact size of 5 bytes, the hooking function will be this
( passing function address as the first parameter of CreateProcessInternal and the new function address as the second parameter):
Code: Select all
the new function will jump this:ULONG Hook(LPBYTE lpCreateProcessInternal,LPBYTE JMPAddress)
{
DWORD PrevProtect;
if(lpCreateProcessInternal)
{
if(VirtualProtect((LPVOID)lpCreateProcessInternal,5,PAGE_EXECUTE_READWRITE,&PrevProtect))
{
// Get Old bytes
OldBytes[0] = lpCreateProcessInternal[0];
*(PDWORD)&OldBytes[1] = *(PDWORD)&lpCreateProcessInternal[1];
// calculating relative address
*(PDWORD)&NewBytes[1] = (DWORD)((ULONG)JMPAddress - (ULONG)lpCreateProcessInternal - 5);
// Set hook
lpCreateProcessInternal[0] = NewBytes[0];
*(PDWORD)&lpCreateProcessInternal[1] = *(PDWORD)&NewBytes[1];
// restore protection
VirtualProtect((LPVOID)lpCreateProcessInternal,5,PrevProtect,NULL);
// get relative JMP to Function+5 ( will be optimized by the compiler )
*(PDWORD)&OldBytes[6] = (DWORD)((ULONG)(lpCreateProcessInternal + 5) - ((ULONG)&OldBytes[5]) - 5 );
// disable DEP
VirtualProtect((LPVOID)OldBytes,10,PAGE_EXECUTE_READWRITE,&PrevProtect);
// success
return 1;
}
}
return 0;
}
Code: Select all
In this function, we simply call the stub which contains the original 5 bytes from the hooked function and a ULONG WINAPI HookCreateProcessInternal(
HANDLE hToken,
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation,
PHANDLE hNewToken)
{
ULONG RetStatus;
DefCreateProcessInternal CreateProcessInternal;
/* We can modify the parameters */
CreateProcessInternal = (DefCreateProcessInternal) &OldBytes[0];
RetStatus = CreateProcessInternal( hToken,
lpApplicationName,
lpCommandLine,
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
lpCurrentDirectory,
lpStartupInfo,
lpProcessInformation,
hNewToken);
/* Check the success */
if(RetStatus)
{
/* We can modify/show the Results */
MessageBoxW(0,lpApplicationName,lpApplicationName,MB_OK);
}
else
{
/* Error, */
MessageBoxW(0,"ERROR","ERROR",MB_OK);
}
return RetStatus;
}
jump to the rest of the original function and a return address to the rest of the function hook.
Then we can use any API to display a string (unicode)
WINDOWS 8
Apparently, on Windows 8 things have not changed either. Now the main module is KernelBase.dll.
Actually kernelbase and kernel32 have the definition of CreateProcessInternal but Kernel32@CreateProcessInternal
is just a wrapper because it will always jump to KernelBase@CreateProcessInternal.
Futhermore, Windows 8 doesn't call CreateProcessInternal directly, it is first calling a undocumented
function on the SHELL module. CreateProcessInternal on Windows 8 looks like this:
CreateProcessInternal:
MOV EDI,EDI
PUSH EBP
MOV EBP,ESP
PUSH 0x0FFFFFFFE
PUSH 74e824e8
...
Our program can work on windows 8 too, just change the name of the module to "kernelbase".
Now we just need to inject our code into explorer.exe, doing that we can :
[*] Block initialization of any program
[*] Obtain information about any process
[*] Inject code to every process ran by the user
[*] Use your imagination :)
For example: To block an application from being run, just change the input arguments to invalid and the process will fail.
And here's the unhook function to clean everything up:
Code: Select all
Full source code inattachedULONG UnHook(LPBYTE lpFunctionAddress)
{
DWORD PrevProtect;
if(VirtualProtect((LPVOID)lpFunctionAddress,5,PAGE_EXECUTE_READWRITE,&PrevProtect))
{
lpFunctionAddress[0] = OldBytes[0];
*(PDWORD)&lpFunctionAddress[1] = *(PDWORD)&OldBytes[1];
VirtualProtect((LPVOID)lpFunctionAddress,5,PrevProtect,NULL);
}
return 0;
}
code was tested on:
Windows XP + SP2 (x86)
Windows XP + SP3 (x86)
Windows Vista (x86)
WIndows 7 (x86)
WIndows 7 + SP1 (x86)
Windows 8 Developer preview (x86)
64-bit Version:
In attached as well.
Attachments
src
(3.6 KiB) Downloaded 74 times
(3.6 KiB) Downloaded 74 times