I'm currently trying to implement a Process Evasion method named Process Doppelgänging in Rust.
I've successfully created the NTFS transaction, the process, I've written the new parameters in the PEB of the process but I can't create the main thread.
When I attempt to create the main thread my program crash.
When I use NtCreateThreadEx the function returns 0xC0000022 (STATUS_ACCESS_DENIED).
(I created the process with the PROCESS_ALL_ACCESS constant and I'm running as administrator).
ntstatus = NtCreateThreadEx(
&mut thread,
THREAD_ALL_ACCESS,
null_mut(),
process,
transmute::<u64, *mut c_void>(va_entrypoint),
null_mut(),
0, 0, 0, 0,
null_mut()
);
And when I use CreateRemoteThreadEx the program (my program not the created process) crash with error 0xC0000005 (STATUS_ACCESS_VIOLATION).
let thread = CreateRemoteThreadEx(
process,
THREAD_ALL_ACCESS,
0,
transmute::<u64, *mut c_void>(va_entrypoint),
null_mut(),
0,
null_mut(), &mut id
);
The va_entrypoint variable is equal to the ImageBaseAddress from the PEB of the created process + the AddressOfEntryPoint from the Optional Headers of the PE file that I loaded in memory.
I checked if the process is running and it's running, but I can only recognize it by it's PID in tasklist.exe output because the program doesn't have any name...
I guess it's normal because I didn't created the main thread, but I'm not sure as well.
I manually checked the address of the PEB, the Image Base address etc...With some process analysis tools and everything is ok.
I think I'm missing something when I'm trying to create the main thread — when I try to create the main thread, the process actually dies.
Related
I try to get the name of executable name of all of my launched windows and my problem is that:
I use the method
UINT GetWindowModuleFileName(
HWND hwnd,
LPTSTR lpszFileName,
UINT cchFileNameMax);
And I don't understand why it doesn't work.
Data which I have about a window are: -HWND AND PROCESSID
The error is:
e.g:
HWND: 00170628
ProcessId: 2336
WindowTitle: C:\test.cpp - Notepad++
GetWindowModuleFileName(): C:\test.exe
HWND: 00172138
ProcessId: 2543
WindowTitle: Firefox
GetWindowModuleFileName(): C:\test.exe
HWND: 00120358
ProcessId: 2436
WindowTitle: Mozilla Thunderbird
GetWindowModuleFileName(): C:\test.exe
Note: test.exe is the name of my executable file, but it is not the fullpath of Notepad++... and it make this for Mozilla Thunderbird too... I don't understand why
I use the function like this:
char filenameBuffer[4000];
if (GetWindowModuleFileName(hWnd, filenameBuffer, 4000) > 0)
{
std::cout << "GetWindowModuleFileName(): " << filenameBuffer << std::endl;
}
Thank you for your response.
The GetWindowModuleFileName function works for windows in the current process only.
You have to do the following:
Retrieve the window's process with GetWindowThreadProcessId.
Open the process with PROCESS_QUERY_INFORMATION and PROCESS_VM_READ access rights using OpenProcess.
Use GetModuleFileNameEx on the process handle.
If you really want to obtain the name of the module with which the window is registered (as opposed to the process executable), you can obtain the module handle with GetWindowLongPtr with GWLP_HINSTANCE. The module handle can then be passed to the aforementioned GetModuleFileNameEx.
Example:
TCHAR buffer[MAX_PATH] = {0};
DWORD dwProcId = 0;
GetWindowThreadProcessId(hWnd, &dwProcId);
HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ , FALSE, dwProcId);
GetModuleFileName((HMODULE)hProc, buffer, MAX_PATH);
CloseHandle(hProc);
Aaah. I read the MSDN page at the bottom.
From http://support.microsoft.com/?id=228469 (archive.org link):
GetWindowModuleFileName and GetModuleFileName correctly retrieve information about windows and modules in the calling process. In Windows 95 and 98, they return information about windows and modules in other processes. However, in Windows NT 4.0 and Windows 2000, since module handles are no longer shared by all processes as they were on Windows 95 and 98, these APIs do not return information about windows and modules in other processes.
To get more information on Windows 2000, use the Process Status Helper set of APIs (known as PSAPI, see Psapi.h include file), available since Windows NT 4.0. APIs such as GetModuleFileNameEx and GetModuleBaseName offer equivalent functionality.
Try using GetModuleFileNameEx instead.
http://support.microsoft.com/?id=228469 (archive.org link)
The executive summary is, GetWindowModuleFileName() doesn't work for windows in other processes in NT-based Windows.
Instead, you can use QueryFullProcessImageName() once you have a handle to the process. You can get a handle to the process with OpenProcess(), which you can use once you have a process id. You can get the process id from the HWND by using GetWindowThreadProcessId()
This is an example of how get the name of executable that creates window, hope it can give you some ideas about:
while(true)
{
Sleep(250);//reduce cpu usage
CHAR __name[MAX_PATH];//name buffer
HWND hwnd;//window handle
DWORD pid;//process pid
hwnd=FindWindow(NULL,NULL);//find any window
PROCESSENTRY32 entry;//process structure containing info about processes
entry.dwSize=sizeof(PROCESSENTRY32);
HANDLE snapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);//get processes
if(hwnd!=0)
{
GetWindowThreadProcessId(hwnd,&pid);//get found window pid
}
if (Process32First(snapshot,&entry)==TRUE)//start listing processes
{
while (Process32Next(snapshot,&entry)==TRUE)
{
if (stricmp(entry.szExeFile,"explorer.exe")==0)
{
if(pid!=entry.th32ProcessID)//if found window pid is explorers one, skip it
{
HANDLE hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);//open processusing PROCESS_ALL_ACCESS to get handle
if(hProcess!=NULL)
{
GetModuleFileNameEx(hProcess,NULL,__name,MAX_PATH);//get executable path
cout<<"Found: "<<__name<<endl;
}
}
}
}
}
To use GetModuleFileNameEx() you probably will need to set linker settings to link library psapi. Also include psapi.h.
I have a problem with DuplicateHandle (Win32). I try to duplicate a named pipe handle and I always get the Error 183 "file already exists". I do not understand this error message, because I try to create a copy of a file handle and the new file handle does not exist before. (Is there a start value required to overwrite?) This is my call:
return DuplicateHandle (MeshellProcessHandle, sourcehandle, HelperProcess, targethandle, 0, TRUE, DUPLICATE_SAME_ACCESS) != 0;
To understand what I am doing, I have to explain more extensively: I am working on a convenient editor frontend for the command line program cmd.exe. This project already works fine on the OS/2 Operating System which is very familiar with Win32, because from a historical point of view, the two OS were developed together until one year before finishing, where Microsoft and IBM went different ways.
The implementation of this program was quite tricky: There's a windowed front end editor program. This program creates named pipes for stderr, stdout and stderr, but from the reverse point of view (output from cmd.exe is input for the editor). Because of limited communication between different sessions, I had to program a "cmd helper program" which is a tiny commandline program holding several API calls and running in the same session as the cmd.exe program. The helper gets the editor process ID via commandline parameter and opens the existing pipes created by the windowed editor program and then redirects stdin/stdout/stderr to the pipes. The helper gets the process handle of the editor from the editor process ID via "OpenProcess" API call. Then the helper executes cmd.exe which automatically inherits the stdin/stdout/stderr handles and now cmd.exe writes to and reads from the pipe.
Another option would be to parse the full pipe names to cmd.exe without using DuplicateHandle, but I would prefer to be as close as to my solution which already works fine on the OS/2 Operating System.
I am still not sure why I have no access rights to duplicate the pipe handles. But I have found another solution: My helper console program starts the child process (cmd.exe) and within this child process, I want to use the named pipes instead of stdin/stdout/stderr - this is the reason why I want to use DuplicateHandle. Windows offers a convenient solution when starting the child process by using
CreateProcess (...)
With CreateProcess, you have always to hold parameters in the STARTUPINFO structure. And there are three handle variables you can set to redirect stdin/stdout/stderr to the three named pipes cmd_std*:
STARTUPINFO StartupInfo;
HFILE cmd_stdout, cmd_stdin, cmd_stderr;
//Open the existing pipes with CreateFile
//Start child process program
StartupInfo.hStdOutput = &cmd_stdout;
StartupInfo.hStdInput = &cmd_stdin;
StartupInfo.hStdError = &cmd_stderr;
CreateProcess (..., &StartupInfo, ...);
This solution has much less code than the variant with DuplicateHandle, because I also have to save and to restore the original file handles, so this way replaces 9 DuplicateHandle calls.
I did program the changes now but my new code described above does not work. If I set the "handle inheritance flag" in CreateProcess to TRUE, cmd.exe does not get executed, but CreateProcess returns TRUE (=OK). Here's my detailed code:
STARTUPINFO StartupInfo;
PROCESS_INFORMATION ProcessInformation;
HFILE cmd_stdout, cmd_stdin, cmd_stderr;
char *pprogstr, *pargstr;
//Open the existing pipes with CreateFile
//Start child process program cmd.exe
StartupInfo.hStdOutput = &cmd_stdout;
StartupInfo.hStdInput = &cmd_stdin;
StartupInfo.hStdError = &cmd_stderr;
StartupInfo.dwFlags = STARTF_USESTDHANDLES;
pprogstr = "C:\\WINDOWS\\system32\\cmd.exe";
pargstr = "/K";
CreateProcess (
pprogstr, // pointer to name of executable module
pargstr, // pointer to command line string
NULL, // pointer to process security attributes
NULL, // pointer to thread security attributes
TRUE, // handle inheritance flag
0, // creation flags
NULL, // pointer to new environment block
NULL, // pointer to current directory name
&StartupInfo, // pointer to STARTUPINFO
&ProcessInformation) // pointer to PROCESS_INFORMATION
Any idea?
What would cause WriteFile to return error 38 (ERROR_HANDLE_EOF, Reached the end of the file)? The "file" in this case is a mailslot. The way my program works is I have a process (running as a Windows service) that creates multiple child processes. Each child opens a mailslot of the same name in order to send status information back to its parent. In my small scale testing this works fine, but I am seeing cases where when I have several processes
running (like 16) I am getting this error. The code below shows how I am opening and writing to the mailslot in the child process.
Is it perhaps because the parent is not reading the mailslot fast enough? Is there a way to increase capacity of a mailslot so that end of file never gets reached? I really don't see how a mailslot can get full anyway, as long
as there is disk space (which there is plenty of).
char gLocalSlotName[256]="\\\\.\\mailslot\\TMAgentSlot-ComputerName";
gAgentSlot = CreateFile(gLocalSlotName, GENERIC_WRITE, FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES) NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE) NULL);
fResult = WriteFile(gAgentSlot, (char *)&ProcStat, sizeof(PROCSTAT), &cbWritten, (LPOVERLAPPED) NULL);
if (!fResult) {
derr = GetLastError();
printf("WriteFile error=%d", derr);
}
WriteFile is thin shell over NtWriteFile. if NtWriteFile return error NTSTATUS - it will be converted to its equivalent win32 error code (via RtlNtStatusToDosError) and WriteFile return false. win32 error code you can got via GetLastError(). however original NTSTATUS you can got via RtlGetLastNtStatus() exported by ntdll.dll api. problem with win32 errors codes - some time several different NTSTATUS values converted to the same win32 error.
in case ERROR_HANDLE_EOF - 2 different NTSTATUS converted to it:
STATUS_END_OF_FILE and STATUS_FILE_FORCED_CLOSED. the STATUS_END_OF_FILE never (look like) returned by msfs.sys (driver which handle mailslots). from another side - STATUS_FILE_FORCED_CLOSED (The specified file has been closed by another process.) can be returned when you write data to mailslot (by msfs.MsCommonWrite) if server end of the mailslot (end which you create via CreateMailslot call) already closed.
formally when last server handle was closed - all connecting clients marked as in closing state (inside MsFsdCleanup) and then if you call WriteFile for such client - the STATUS_FILE_FORCED_CLOSED is returned.
so -
What causes WriteFile to return error 38 (ERROR_HANDLE_EOF)?
the server process by some reason close self mailslot handle. you need search in this direction - when and why you close mailsot handle in parent process
Are forking() and CreateProcess(with all required arguments), the same thing for Linux and WinXP, respectively?
If they are different, then could someone explain the difference in terms of what happens in each of the two cases?
Thanks
They do different things, and on different systems. CreateProcess is a Windows-only function, while fork is only on POSIX (e.g. Linux and Mac OSX) systems.
The fork system call creates a new process and continue execution in both the parent and the child from the point where the fork function was called. CreateProcess creates a new process and load a program from disk. The only similarity is that the end result is a new process is created.
For more information, read the respective manual page on CreateProcess and fork.
To summarize: CreateProcess is similar to fork() followed by one of the exec() functions.
CreateProcess takes the following steps:
Create and initialize the process control block (PCB) in the kernel.
Create and initialize a new address space.
Load the program prog into the address space.
Copy arguments args into memory in the address space.
Initialize the hardware context to start execution at “start”.
Inform the scheduler that the new process is ready to run.
Unix's fork takes the following steps:
Create and initialize the process control block (PCB) in the kernel
Create a new address space
Initialize the address space with a copy of the entire contents of
the address space of the parent
Inherit the execution context of the parent (e.g., any open files)
Inform the scheduler that the new process is ready to run
It creates a complete copy of the parent process, and the parent doesn't set up the runtime environment for the child, because the parent process trusts its own set up. The child is a complete copy of the parent except for its process id (what fork returns). A forked process continues to run the same program as its parent until it performs an explicit exec. When the child calls exec which, the new executable image into memory and runs.
How is it efficient to make a complete copy? copy-on-write. It really only copies the virtual memory map. All of the segments in the segment table are read only. If the parent or child edits the data in a segment, an exception is thrown and the kernel creates a full memory copy of that. This is explained nicely in this answer
There are several benefits to shared resources between parent and child:
- intuitively, resource management: less memory is needed to maintain the states of the processes
- Cache resources are shared means greater temporal locality of data when data is not over written, which improves performance because retrieving data from larger caches/disk is time consuming.
Disadvantages to shared resources:
- when writes are common, it puts the data in an invalid state for the other process, and this leads to coherency misses which is costly if the child process is running on a separate core, because the changes will have to propagate up to the L3 cache.
In general though, programs read a heck of a lot more than writes, typically the child/parent will only need to make writes to its stack, and that's a small portion of the their program block.
Additionally Unix fork is different because it returns twice, once in the parent (the process id of its child), once in the child (0, congrats you're a new baby process), which is how we distinguish in our code if we are the child or parent.
Unix Exec does the following:
Load the program prog into the current address space.
Copy arguments args into memory in the address space.
Initialize the hardware context to start execution at “start.”
the parent has the option to wait for the child to finish. When the child finishes, when exit is called is when the parent's wait is notified.
I will give two examples to show the difference:
fork():
#include "stdio.h"
#include "stdlib.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int fac(int);
int main(void)
{
int child_ret,input_num=-1;
pid_t pid1;
while(input_num<0){
printf("\nPlease input a non-negative number: ");
scanf("%d",&input_num);
}
if((pid1=fork())<0){
printf("fork error");
}
else if(pid1==0){
printf("\nI am the child process,my PID is %d.\n\nThe first %d numbers of fibonacci sequence is:\n", getpid(),input_num);
for (int i=0;i<input_num;i++)
{printf("%d\n", fac(i+1));}
}
else{
wait(&child_ret);
printf("\nI am the parent process,my PID is %d.\n\n", getpid());
}
return 0;
}
int fac(int n)
{
if (n<=2) return n-1;
else
{
return fac(n-1)+fac(n-2);
}
}
In this program, fork will do a copy and return two values. We called the copied process parent process and the other one child process.If we call the exec() function, the whole process will be replaced by a new program except the PID.
CreateProcess():
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
void _tmain( VOID )
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
LPTSTR szCmdline=_tcsdup(TEXT("MyChildProcess"));
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line)
szCmdline, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d)./n", GetLastError() );
return;
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
This is an example from MSDN. What we call to create a new process must be a separate *.exe program in Windows system. The new process is a whole new one which just has the only connection of return value with the older one.
In conclusion, we often see fork()+exec() as CreateProcess(). In fact, fork() is more similar with CreateThread() in Windows.
I have a DLL that's loaded into a 3rd party parent process as an extension. From this DLL I instantiate external processes (my own) by using CreateProcess API. This works great in 99.999% of the cases but sometimes this suddenly fails and stops working permanently (maybe a restart of the parent process would solve this but this is undesirable and I don't want to recommend that until I solve the problem.) The failure is symptomized by external process not being invoked any more even though CreteProcess() doesn't report an error and by GetExitCodeProcess() returning 128. Here's the simplified version of what I'm doing:
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
if(!CreateProcess(
NULL, // No module name (use command line).
"<my command line>",
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
FALSE, // Set handle inheritance to FALSE.
CREATE_SUSPENDED, // Create suspended.
NULL, // Use parent's environment block.
NULL, // Use parent's starting directory.
&si, // Pointer to STARTUPINFO structure.
&pi)) // Pointer to PROCESS_INFORMATION structure.
{
// Handle error.
}
else
{
// Do something.
// Resume the external process thread.
DWORD resumeThreadResult = ResumeThread(pi.hThread);
// ResumeThread() returns 1 which is OK
// (it means that the thread was suspended but then restarted)
// Wait for the external process to finish.
DWORD waitForSingelObjectResult = WaitForSingleObject(pi.hProcess, INFINITE);
// WaitForSingleObject() returns 0 which is OK.
// Get the exit code of the external process.
DWORD exitCode;
if(!GetExitCodeProcess(pi.hProcess, &exitCode))
{
// Handle error.
}
else
{
// There is no error but exitCode is 128, a value that
// doesn't exist in the external process (and even if it
// existed it doesn't matter as it isn't being invoked any more)
// Error code 128 is ERROR_WAIT_NO_CHILDREN which would make some
// sense *if* GetExitCodeProcess() returned FALSE and then I were to
// get ERROR_WAIT_NO_CHILDREN with GetLastError()
}
// PROCESS_INFORMATION handles for process and thread are closed.
}
External process can be manually invoked from Windows Explorer or command line and it starts just fine on its own. Invoked like that it, before doing any real work, creates a log file and logs some information about it. But invoked like described above this logging information doesn't appear at all so I'm assuming that the main thread of the external process never enters main() (I'm testing that assumption now.)
There is at least one thing I could do to try to circumvent the problem (not start the thread suspended) but I would first like to understand the root of the failure first. Does anyone has any idea what could cause this and how to fix it?
Quoting from the MSDN article on GetExitCodeProcess:
The following termination statuses can be returned if the process has terminated:
The exit value specified in the
ExitProcess or TerminateProcess
function
The return value from the
main or WinMain function of the
process
The exception value for an
unhandled exception that caused the
process to terminate
Given the scenario you described, I think the most likely cause ist the third: An unhandled exception. Have a look at the source of the processes you create.
Have a look at Desktop Heap memory.
Essentially the desktop heap issue comes down to exhausted resources (eg starting too many processes). When your app runs out of these resources, one of the symptoms is that you won't be able to start a new process, and the call to CreateProcess will fail with code 128.
Note that the context you run in also has some effect. For example, running as a service, you will run out of desktop heap much faster than if you're testing your code in a console app.
This post has a lot of good information about desktop heap
Microsoft Support also has some useful information.
There are 2 issues that i could think of from your code sample
1.Get yourusage of the first 2 paramaters to the creatprocess command working first. Hard code the paths and invoke notepad.exe and see if that comes up. keep tweaking this until you have notepad running.
2.Contrary to your comment, If you have passed the currentdirectory parameter for the new process as NULL, it will use the current working directory of the process to start the new process from and not the parent' starting directory.
I assume that your external process exe cannot start properly due to dll dependencies that cannot be resolved in the new path.
ps : In the debugger watch for #err,hr which will tell you the explanation for the last error code,