I want to work all winapi with standart c++. how to pass output with address? look o_processName. GetModuleFileNameExW function paremeter 3 need wchar_t type. i need to convert it to wstring type. as i search the possible is to pass memory address to GetModuleFileNameExW not the type.
void GetProcessNameById(DWORD i_processId, std::wstring *o_processName)
{
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, i_processId);
if (hProcess != NULL)
{
if (GetModuleFileNameExW(hProcess, NULL, &o_processName, MAX_PATH))
{
CloseHandle(hProcess);
}
}
}
You cannot pass a std::wstring (or any C++ container) directly to a Win32 API function. The Win32 API is written with a C interface, and so it knows nothing about C++ types. As such, you must use C semantics when calling the API.
In your example, you can allocate a C style WCHAR[] buffer to receive the filename, and then assign that buffer to your std::wstring:
void GetProcessNameById(DWORD i_processId, std::wstring *o_processName) {
WCHAR szFileName[MAX_PATH];
DWORD dwLength = 0;
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, i_processId);
if (hProcess != NULL) {
dwLength = GetModuleFileNameExW(hProcess, NULL, szFileName, MAX_PATH);
CloseHandle(hProcess);
}
o_processName->assign(szFileName, dwLength);
}
Alternatively, if you want to use a C++ container, you have to preallocate it and then pass its internal data buffer to the API:
void GetProcessNameById(DWORD i_processId, std::wstring *o_processName) {
std::wstring wFileName;
wFileName.resize(MAX_PATH);
DWORD dwLength = 0;
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, i_processId);
if (hProcess != NULL) {
dwLength = GetModuleFileNameExW(hProcess, NULL, &wFileName[0], MAX_PATH); // or wFileName.data() in C++17 and later
CloseHandle(hProcess);
}
o_processName->assign(wFileName.c_str(), dwLength);
}
void GetProcessNameById(DWORD i_processId, std::wstring *o_processName) {
std::vector<WCHAR> vecFileName(MAX_PATH, 0);
DWORD dwLength = 0;
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, i_processId);
if (hProcess != NULL) {
dwLength = GetModuleFileNameExW(hProcess, NULL, &vecFileName[0], MAX_PATH); // or vecFileName.data() in C++11 and later
CloseHandle(hProcess);
}
o_processName->assign(&vecFileName[0], dwLength); // or vecFileName.data()
}
void GetProcessNameById(DWORD i_processId, std::wstring *o_processName) {
std::array<WCHAR, MAX_PATH> arrFileName;
DWORD dwLength = 0;
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, i_processId);
if (hProcess != NULL) {
dwLength = GetModuleFileNameExW(hProcess, NULL, arrFileName.data(), MAX_PATH);
CloseHandle(hProcess);
}
o_processName->assign(arrFileName.data(), dwLength);
}
If you want, you can take this a step further by using std::unique_ptr in C++11 and later to ensure the HANDLE is closed automatically when it goes out of scope.
And lastly, you should be using GetProcessImageFileNameW() instead of GetModuleFileNameExW():
To retrieve the name of the main executable module for a remote process, use the GetProcessImageFileName or QueryFullProcessImageName function. This is more efficient and more reliable than calling the GetModuleFileNameEx function with a NULL module handle.
Also, because GetProcessImageFileName() requires only PROCESS_QUERY_LIMITED_INFORMATION access rights, which you are more likely to be able to obtain than PROCESS_QUERY_INFORMATION | PROCESS_VM_READ rights, especially for system/restricted processes.
Related
Despite the fact that memory allocation/write, finding LoadLibraryA address and creating a remote thread return valid (not NULL) results, absolutely nothing happens after that (mainly, the DllMain of the loaded DLL doesn't seem to get called).
#define PROC_NAME L"TestConsole.exe"
#define DLL_NAME "TestLib.dll\0"
HANDLE GetProcessByName(const wchar_t* name);
int main()
{
const char dllName[] = DLL_NAME;
int dllNameSize = strlen(dllName) + 1;
HANDLE process = GetProcessByName(PROC_NAME);
LPVOID allocMem = VirtualAllocEx(process, NULL, dllNameSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(process, allocMem, dllName, dllNameSize, NULL);
// Just to make sure
char buff[20];
ReadProcessMemory(process, allocMem, buff, dllNameSize, NULL);
printf("Data: %s\n", buff);
LPVOID libraryAddress =
(LPVOID)GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryA");
HANDLE remoteThread = CreateRemoteThread(process, NULL, NULL, (LPTHREAD_START_ROUTINE)libraryAddress, allocMem, NULL, NULL);
}
HANDLE GetProcessByName(const wchar_t* name)
{
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (Process32First(snapshot, &entry) == TRUE)
{
while (Process32Next(snapshot, &entry) == TRUE)
{
if (wcscmp(entry.szExeFile, name) == 0)
{
return OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ParentProcessID);
}
}
}
return NULL;
}
Things I know/checked:
The thread gets created and a valid (not null) handle is returned. Despite it nothing happens.
I'm pretty sure that it's not DLL's fault. It's extremely simple, simply prints to console when it gets loaded and it works correctly when used simply with CreateThread().
Injector, DLL and the app to which I'm injecting are all 64 bit. If I chose any other platform (for all 3) everything works the same except for CreateRemoteThread(), which now fails.
The entry.th32ParentProcessID is the identifier of the process that created this process (its parent process). which means you did inject into the parent process of the target process (explorer.exe in my test). You should use entry.th32ProcessID instead.
In addition, the open permission PROCESS_ALL_ACCESS used in OpenProcess is too large, you only need to use what the CreateRemoteThread document requires: PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ
I am trying to create a simple C++ console app which dump the memory space of a given process (e.g. calc.exe) So I use MiniDumpWriteDump function
Here is the code :
DWORD procID = 1150;
char* procName = "calc.exe";
// opens the dump file
HANDLE hFile = CreateFile( "calc.dmp", GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if(hFile)
{
// opens the process
HANDLE hProcToDump = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, procID);
if(hProcToDump)
{
// dumps via the API
BOOL rv = MiniDumpWriteDump(hProcToDump, GetProcessId(hProcToDump), hFile, MiniDumpNormal, NULL, NULL, NULL);
HRESULT hr = GetLastError();
if( !rv )
printf("MiniDumpWriteDump failed.");
else
printf("Minidump OK!");
CloseHandle( hFile );
CloseHandle( hProcToDump );
}
}
But I get the error :
GetLastError() = hresult 0x8007012b Only part of a ReadProcessMemory or WriteProcessMemory request was completed
Why ?
Note : I am admin on Win 7 x64.
Thank you for your help.
Try this, which is similar to your example. Usage of MiniDumpWriteDump.
I'm trying to add my software to registry, I have found some pieces of the codes I can use but not full working code C/C++ is new to me and can't create it on my own. But here is the basic idea: Check if reg key set if not create it.
I was able to get my program location using this code:
TCHAR szPath[MAX_PATH];
GetModuleFileName(NULL,szPath,MAX_PATH);
And was able to create the key with: (Not sure if it's the right way)
HKEY newValue;
RegOpenKey(HKEY_CURRENT_USER,"Software\\Microsoft\\Windows\\CurrentVersion\\Run",&newValue);
RegSetValueEx(newValue,"myprogram",0,REG_SZ,(LPBYTE)szPath,sizeof(szPath));
RegCloseKey(newValue);
return 0;
What is missing, A small check if the key isn't already there...
Thank you!
Here's some code that likely does what you want. Call RegisterProgram for your EXE to self-register itself for automatically being started when the user logs in. This function calls GetModuleFileName and then invokes another helper function called RegisterMyProgramForStartup that does the writing to the registry.
Call IsMyProgramRegisteredForStartup(L"My_Program") to detect if the registration actually exists and appears valid.
One quick note. The performance impact of checking to see if the key exists before actually writing it out again is negligible. You could just call RegisterProgram blindly and it will overwrite the key if it already exists. Detecting if the registration exists is useful for initializing your UI checkbox that enables or disables auto-start. (You are giving your users a choice, right? Because I hate apps that automatically install themselves to run automatically without giving me a choice.)
BOOL IsMyProgramRegisteredForStartup(PCWSTR pszAppName)
{
HKEY hKey = NULL;
LONG lResult = 0;
BOOL fSuccess = TRUE;
DWORD dwRegType = REG_SZ;
wchar_t szPathToExe[MAX_PATH] = {};
DWORD dwSize = sizeof(szPathToExe);
lResult = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_READ, &hKey);
fSuccess = (lResult == 0);
if (fSuccess)
{
lResult = RegGetValueW(hKey, NULL, pszAppName, RRF_RT_REG_SZ, &dwRegType, szPathToExe, &dwSize);
fSuccess = (lResult == 0);
}
if (fSuccess)
{
fSuccess = (wcslen(szPathToExe) > 0) ? TRUE : FALSE;
}
if (hKey != NULL)
{
RegCloseKey(hKey);
hKey = NULL;
}
return fSuccess;
}
BOOL RegisterMyProgramForStartup(PCWSTR pszAppName, PCWSTR pathToExe, PCWSTR args)
{
HKEY hKey = NULL;
LONG lResult = 0;
BOOL fSuccess = TRUE;
DWORD dwSize;
const size_t count = MAX_PATH*2;
wchar_t szValue[count] = {};
wcscpy_s(szValue, count, L"\"");
wcscat_s(szValue, count, pathToExe);
wcscat_s(szValue, count, L"\" ");
if (args != NULL)
{
// caller should make sure "args" is quoted if any single argument has a space
// e.g. (L"-name \"Mark Voidale\"");
wcscat_s(szValue, count, args);
}
lResult = RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, NULL, 0, (KEY_WRITE | KEY_READ), NULL, &hKey, NULL);
fSuccess = (lResult == 0);
if (fSuccess)
{
dwSize = (wcslen(szValue)+1)*2;
lResult = RegSetValueExW(hKey, pszAppName, 0, REG_SZ, (BYTE*)szValue, dwSize);
fSuccess = (lResult == 0);
}
if (hKey != NULL)
{
RegCloseKey(hKey);
hKey = NULL;
}
return fSuccess;
}
void RegisterProgram()
{
wchar_t szPathToExe[MAX_PATH];
GetModuleFileNameW(NULL, szPathToExe, MAX_PATH);
RegisterMyProgramForStartup(L"My_Program", szPathToExe, L"-foobar");
}
int _tmain(int argc, _TCHAR* argv[])
{
RegisterProgram();
IsMyProgramRegisteredForStartup(L"My_Program");
return 0;
}
To check whether or not the value exists, call RegQueryValueEx.
LONG retval = RegQueryValueEx(hKey, "myprogram", NULL, NULL, NULL, NULL);
Note that what you called newValue is actually a key rather than a value. To avoid confusion you should name it such. I used the name hKey.
Then to check whether or not the value exists, compare retval against ERROR_SUCCESS as described in the documentation.
The other problem with your code is that there is absolutely no error checking. I'll leave that to you to address.
You forget to write an argument about security access
I wrote this function to inject DLL into running process:
DLL_Results CDLL_Loader::InjectDll()
{
DWORD ThreadTeminationStatus;
LPVOID VirtualMem;
HANDLE hProcess, hRemoteThread;
HMODULE hModule;
if (!isInit())
return NOT_INIT;
if (isInjected())
return DLL_ALREADY_HOOKED;
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessID);
if (hProcess == NULL)
return PROCESS_ERROR_OPEN;
VirtualMem = VirtualAllocEx (hProcess, NULL, strlen(DllFilePath), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (VirtualMem == NULL)
return PROCESS_ERRORR_VALLOC;
if (WriteProcessMemory(hProcess, (LPVOID)VirtualMem, DllFilePath, strlen(DllFilePath), NULL) == 0)
{
VirtualFreeEx(hProcess, NULL, (size_t)strlen(DllFilePath), MEM_RESERVE|MEM_COMMIT);
CloseHandle(hProcess);
return PROCESS_ERROR_WRITE;
}
hModule = GetModuleHandle(L"kernel32.dll");
hRemoteThread = CreateRemoteThread(hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "LoadLibraryA"),
(LPVOID)VirtualMem, 0, NULL);
if (hRemoteThread == NULL)
{
FreeLibrary(hModule);
VirtualFreeEx(hProcess, NULL, (size_t)strlen(DllFilePath), MEM_RESERVE | MEM_COMMIT);
CloseHandle(hProcess);
return PROCESS_ERROR_CREATE_RTHREAD;
}
WaitForSingleObject(hRemoteThread, INFINITE);
GetExitCodeThread(hRemoteThread, &ThreadTeminationStatus);
FreeLibrary(hModule);
VirtualFreeEx(hProcess, NULL, (size_t)strlen(DllFilePath), MEM_RESERVE | MEM_COMMIT);
CloseHandle(hRemoteThread);
CloseHandle(hProcess);
injected = true;
return DLLHOOK_OK;
}
And It works great, but when i was trying to eject the dll i was unable to find information about unhooking.. i was trying to build some function to do it and i think i'm close
this is what i've got so far:
is that the right way? if so what parameter should i pass in createRemoteThread instade of VirtualMem (That was used in the injecting function)...
DLL_Results CDLL_Loader::EjectDll()
{
DWORD ThreadTeminationStatus;
HANDLE hProcess, hRemoteThread;
HMODULE hModule;
if (isInjected())
return DLLEJECT_OK;
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessID);
if (hProcess == NULL)
return PROCESS_ERROR_OPEN;
hModule = GetModuleHandle(L"kernel32.dll");
hRemoteThread = CreateRemoteThread(hProcess, NULL, 0,
(LPTHREAD_START_ROUTINE)GetProcAddress(hModule, "FreeLibrary"),
/*(LPVOID)VirtualMem <- What do i need to send here?*/, 0, NULL);
if (hRemoteThread != NULL)
{
WaitForSingleObject(hRemoteThread, INFINITE);
GetExitCodeThread(hRemoteThread, &ThreadTeminationStatus);
}
CloseHandle(hRemoteThread);
CloseHandle(hProcess);
injected = false;
return DLLEJECT_OK;
}
On 32-bit systems, the value of ThreadTeminationStatus after GetExitCodeThread contains the return value of LoadLibraryA in the remote process.
This is the module handle of the newly loaded dll.
You can use it as the parameter to FreeLibrary in the remote thread.
If you want to use the code on 64-bit Windows, the thread exit code is truncated to a 32-bit DWORD, so it's unusable.
You have to create a callable routine in the remote process (as Necrolis suggested) or resort to finding the module base of the DLL via psapi or the Toolhelp API (CreateToolhelp32Snapshot, Module32First, Module32Next).
You need to pass it the HANDLE of the dll you injected, else you can pass it VirtualMem but then your remote thread routine would need to be:
DWORD WINAPI UnloadDll(void* pMem)
{
FreeLibrary(GetModuleHandleA((const char*)pMem));
return 0;
}
However, generally the dll you inject should unload itself (see how DllMain works), either manually or automatically when the host is closed.
I have a process handle with
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, THE_PROCESS_ID);
How can I get the username of the user that is running the process?
I am using unmanaged code (no .NET).
Use OpenProcessToken to get the token (obviously), then GetTokenInformation with the TokenOwner flag to get the SID of the owner. Then you can use LookupAccountSid to get the username.
if WMI is not an option, then use GetUserFromProcess below that takes the process ID as an input parameter and returns the user name and domain:
#include <comdef.h>
#define MAX_NAME 256
BOOL GetLogonFromToken (HANDLE hToken, _bstr_t& strUser, _bstr_t& strdomain)
{
DWORD dwSize = MAX_NAME;
BOOL bSuccess = FALSE;
DWORD dwLength = 0;
strUser = "";
strdomain = "";
PTOKEN_USER ptu = NULL;
//Verify the parameter passed in is not NULL.
if (NULL == hToken)
goto Cleanup;
if (!GetTokenInformation(
hToken, // handle to the access token
TokenUser, // get information about the token's groups
(LPVOID) ptu, // pointer to PTOKEN_USER buffer
0, // size of buffer
&dwLength // receives required buffer size
))
{
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
goto Cleanup;
ptu = (PTOKEN_USER)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, dwLength);
if (ptu == NULL)
goto Cleanup;
}
if (!GetTokenInformation(
hToken, // handle to the access token
TokenUser, // get information about the token's groups
(LPVOID) ptu, // pointer to PTOKEN_USER buffer
dwLength, // size of buffer
&dwLength // receives required buffer size
))
{
goto Cleanup;
}
SID_NAME_USE SidType;
char lpName[MAX_NAME];
char lpDomain[MAX_NAME];
if( !LookupAccountSid( NULL , ptu->User.Sid, lpName, &dwSize, lpDomain, &dwSize, &SidType ) )
{
DWORD dwResult = GetLastError();
if( dwResult == ERROR_NONE_MAPPED )
strcpy (lpName, "NONE_MAPPED" );
else
{
printf("LookupAccountSid Error %u\n", GetLastError());
}
}
else
{
printf( "Current user is %s\\%s\n",
lpDomain, lpName );
strUser = lpName;
strdomain = lpDomain;
bSuccess = TRUE;
}
Cleanup:
if (ptu != NULL)
HeapFree(GetProcessHeap(), 0, (LPVOID)ptu);
return bSuccess;
}
HRESULT GetUserFromProcess(const DWORD procId, _bstr_t& strUser, _bstr_t& strdomain)
{
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,procId);
if(hProcess == NULL)
return E_FAIL;
HANDLE hToken = NULL;
if( !OpenProcessToken( hProcess, TOKEN_QUERY, &hToken ) )
{
CloseHandle( hProcess );
return E_FAIL;
}
BOOL bres = GetLogonFromToken (hToken, strUser, strdomain);
CloseHandle( hToken );
CloseHandle( hProcess );
return bres?S_OK:E_FAIL;
}
WMI is probably the path of least resistance. You should also be able to get the token using OpenProcessToken, then GetTokenInformation to get the SID of the owner. You can then turn the SID into a user name.
WMI should be able to tell you that information. Otherwise you need to rely on undocumented fun in ntdll.dll. It appears others have found solutions that don't use ntdll.dll -- use them rather than undocumented stuff.
Here a solution knowing the process id.
std::optional<std::wstring> GetUserNameFromProcess(DWORD id)
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id); // 1- OpenProcess
std::wstring endUser = L"";
std::wstring endDomain = L"";
if (hProcess != NULL)
{
HANDLE hToken = NULL;
if (OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) // 2- OpenProcessToken
{
DWORD tokenSize = 0;
GetTokenInformation(hToken, TokenUser, NULL, 0, &tokenSize);
if (tokenSize > 0)
{
BYTE* data = new BYTE[tokenSize];
GetTokenInformation(hToken, TokenUser, data, tokenSize, &tokenSize); // 3- GetTokenInformation
TOKEN_USER* pUser = (TOKEN_USER*)data;
PSID pSID = pUser->User.Sid;
DWORD userSize = 0;
DWORD domainSize = 0;
SID_NAME_USE sidName;
LookupAccountSid(NULL, pSID, NULL, &userSize, NULL, &domainSize, &sidName);
wchar_t* user = new wchar_t[userSize + 1];
wchar_t* domain = new wchar_t[domainSize + 1];
LookupAccountSid(NULL, pSID, user, &userSize, domain, &domainSize, &sidName); // 4- LookupAccountSid
user[userSize] = L'\0';
domain[domainSize] = L'\0';
endUser = user;
endDomain = domain;
delete[] domain;
delete[] user;
delete[] data;
}
CloseHandle(hToken);
}
CloseHandle(hProcess);
if (endUser != L"")
return endUser;
}
return {};
}