I'm using the following code to try to get the PID of notepad.exe, but it doesn't find the process.
I'm currently running on Windows 10 and compiling using VS Studio 19 as Release x64.
Also tried to find other processes, like chrome.exe, calculator.exe, etc, but couldn't find anything.
DWORD GetProcessId(LPCTSTR ProcessName)
{
PROCESSENTRY32 pt;
HANDLE hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
std::wcout << "Error: " << GetLastError() << std::endl; // Error: 0
pt.dwSize = sizeof(PROCESSENTRY32);
std::wcout << "Error: " << GetLastError() << std::endl; // Error: 0
if (Process32First(hsnap, &pt)) { // must call this first
do {
if (!lstrcmpi(pt.szExeFile, ProcessName)) {
CloseHandle(hsnap);
return pt.th32ProcessID;
}
} while (Process32Next(hsnap, &pt));
}
std::wcout << "Error: " << GetLastError() << std::endl; // Error: 24
CloseHandle(hsnap); // close handle on failure
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
DWORD processId;
processId = GetProcessId(TEXT("notepad.exe"));
std::wcout << "processId: " << processId << std::endl;
return 0;
}
While debugging, I see the code is skipping the do while and jumping directly to CloseHandle(hsnap)
GetLastError() returns 24 at this line.
The image you posted of your debug output window shows pt.dwSize is set to 2168. This looks wrong. pt.dwSize is important, it used by Windows for version control.
On my computer sizeof(PROCESSENTRY32) is 556 (it depends on Windows version, I am using Windows 10). If project is not Unicode, the size should about half that. In VS, you can right click on PROCESSENTRY32 and it takes you to this definition:
typedef struct tagPROCESSENTRY32W
{
DWORD dwSize;
DWORD cntUsage;
DWORD th32ProcessID; // this process
ULONG_PTR th32DefaultHeapID;
DWORD th32ModuleID; // associated exe
DWORD cntThreads;
DWORD th32ParentProcessID; // this process's parent process
LONG pcPriClassBase; // Base priority of process's threads
DWORD dwFlags;
WCHAR szExeFile[MAX_PATH]; // Path
} PROCESSENTRY32W;
MAX_PATH should be 260. My guess is that you have redefined MAX_PATH or you have put the wrong #pragma statement somewhere. Or there is something weird happening. Try restarting Windows (use Restart instead of shutdown/start)
Also, zero the memory with PROCESSENTRY32 pt = {0}
PROCESSENTRY32 pt = { 0 };
pt.dwSize = sizeof(PROCESSENTRY32);
if (!Process32First(hsnap, &pt))
{
DWORD err = GetLastError();
std::cout << "Process32First failed\n";
std::cout << pt.dwSize << " GetLastError : " << err << "\n";
CloseHandle(hsnap);
return DWORD(-1);
}
The only expected GetLastError is ERROR_NO_MORE_FILES as shown in Windows documentation. If the error is something else, it means the function has totally failed.
If your project is Unicode, as it should be, consider avoiding those T macros. Just use GetProcessId(L"notepad.exe"); and LPCWSTR etc.
Ps, I ran your code and it was fine in my computer. The only difference was sizeof(PROCESSENTRY32)
Related
Trying to retrieve the running directory of a process using the PID. I am obtaining the PID using FindWindow() and GetWindowThreadProcessId() which results in the same process ID as shown in task manager, so I assume it to be correct.
When using GetModuleFileNameEx(), instead of resulting in a path, I get what seems to be a memory address.
auto wnd = FindWindow(nullptr, L"prog");
while (wnd == nullptr)
{
wnd = FindWindow(nullptr, L"prog");
}
TCHAR fBuf[MAX_PATH]; // buffer for path
DWORD procId; // process id
GetWindowThreadProcessId(wnd, &procId); // get process id
std::cout << procId << std::endl; // results in correct pid
auto procHdl = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, procId); // create handle for process
if (procHdl != NULL) {
if (GetModuleFileNameEx(procHdl, 0, fBuf, MAX_PATH) == 0) {
std::cerr << "Failed to get module filename." << std::endl;
}
else {
std::cout << "Module filename is: " << fBuf << std::endl;
}
CloseHandle(procHdl);
}
Sample output is:
10488
Module filename is: 008CF93C
I have had the same result using GetProcessImageFileNname() too.
To get the directory of a program, first use GetModuleFileNameEx to get the program path, and your directory will start from the first character to the last backslash found.
Example:
Program is: "C:\Windows\notepad.exe";
Directory is: "C:\Windows";
In code:
DWORD pid = 104;
CHAR ProgramFile[MAX_PATH];
std::string DirectoryPath;
HANDLE hProcess = OpenProcess(PROCESS_VM_READ|PROCESS_QUERY_INFORMATION, FALSE, pid);
GetModuleFileNameExA(hProcess, NULL, ProgramFile, MAX_PATH);
DirectoryPath = ProgramFile;
DirectoryPath = DirectoryPath.substr(0, DirectoryPath.find_last_of('\\'));
std::cout << "ProgramFile: " << ProgramFile << endl;
std::cout << "Directory: " << DirectoryPath.c_str();
Background:
I'm trying to write a C++ application that can scan for and attempt to restore deleted files from a WinPE environment, mostly as a learning exercise. This app utilizes the FMAPI library (fmapi.dll), which is a scarcely-documented library that only works in a WinPE environment (does not work in a full Windows OS). I've been using the ScanRestorableFiles example released by MS (available here) as a starting point.
Now, I've done a LOT of digging and have found next to nothing when it comes to FMAPI documentation - just the sample noted above and some basic MSDN docs here. The MSDN pages provide the definitions for the API functions and a few extra notes on a couple of the functions that provide a hint or two, but that's it. So I thought I'd come here in hopes of finding some assistance.
Also please note, as far as development languages go, C++ is not my strong point - I would consider myself novice at best.
Now to the issue at hand:
My app is able to successfully load the library, create the file restore context and scan for restorable files. However, once I try to call the RestoreFile() function on one of the restorable items that was returned by the ScanRestorableFiles() call, I get an Invalid Handle error. The "restored file" ends up being a 0-byte file (it does get created successfully in the proper place) with no data in it.
Interestingly, even after returning the Invalid Handle error code, my app holds a handle open on the file until the file restore context is closed (I know this because if I try to read the restored file immediately after attempting to restore it, I get a "file is in use by another process" error).
Posted below is the entire code for my app (its just a single source file, not counting headers and such) - since this seems to be a rarely-used API, I feel like I should post the whole thing to add context to each function call (and also because I'm not quite sure exactly what may or may not be relevant to the issue I'm having).
Code:
#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <sstream>
#include <stdlib.h>
#define SCAN_PATH L"\\"
//
//Define the needed FMAPI structures as documented in FMAPI
//
#define FILE_RESTORE_MAJOR_VERSION_2 0x0002
#define FILE_RESTORE_MINOR_VERSION_2 0x0000
#define FILE_RESTORE_VERSION_2 ((FILE_RESTORE_MAJOR_VERSION_2 << 16) | FILE_RESTORE_MINOR_VERSION_2)
using namespace std;
//External API function declarations
//We don't have an import library or
//header for the FMAPI functions, so
//we must dynamically link to them at
//runtime.
typedef PVOID PFILE_RESTORE_CONTEXT;
typedef enum {
ContextFlagVolume = 0x00000001,
ContextFlagDisk = 0x00000002,
FlagScanRemovedFiles = 0x00000004,
FlagScanRegularFiles = 0x00000008,
FlagScanIncludeRemovedDirectories = 0x00000010
} RESTORE_CONTEXT_FLAGS;
typedef enum {
FileRestoreProgressInfo = 100,
FileRestoreFinished = 101
} FILE_RESTORE_PACKET_TYPE, *PFILE_RESTORE_PACKET_TYPE;
typedef BOOL (WINAPI *FuncCreateFileRestoreContext) (
_In_ PCWSTR Volume,
_In_ RESTORE_CONTEXT_FLAGS Flags,
_In_ LONGLONG StartSector,
_In_ LONGLONG BootSector,
_In_ DWORD Version,
_Out_ PFILE_RESTORE_CONTEXT* Context
);
typedef BOOL (WINAPI *FuncCloseFileRestoreContext) (
_In_ PFILE_RESTORE_CONTEXT Context
);
typedef struct _RESTORABLE_FILE_INFO
{
ULONG Size;
DWORD Version;
ULONGLONG FileSize;
FILETIME CreationTime;
FILETIME LastAccessTime;
FILETIME LastWriteTime;
DWORD Attributes;
BOOL IsRemoved;
LONGLONG ClustersUsedByFile;
LONGLONG ClustersCurrentlyInUse;
ULONG RestoreDataOffset;
WCHAR FileName[1]; // Single-element array indicates a variable-length structure
} RESTORABLE_FILE_INFO, *PRESTORABLE_FILE_INFO;
typedef struct _FILE_RESTORE_PROGRESS_INFORMATION {
LONGLONG TotalFileSize;
LONGLONG TotalBytesCompleted;
LONGLONG StreamSize;
LONGLONG StreamBytesCompleted;
PVOID ClbkArg;
} FILE_RESTORE_PROGRESS_INFORMATION, *PFILE_RESTORE_PROGRESS_INFORMATION;
typedef struct _FILE_RESTORE_FINISHED_INFORMATION {
BOOL Success;
ULONG FinalResult;
PVOID ClbkArg;
} FILE_RESTORE_FINISHED_INFORMATION, *PFILE_RESTORE_FINISHED_INFORMATION;
typedef BOOL (WINAPI *FuncScanRestorableFiles) (
_In_ PFILE_RESTORE_CONTEXT Context,
_In_ PCWSTR Path,
_In_ ULONG FileInfoSize,
_Out_bytecap_(FileInfoSize) PRESTORABLE_FILE_INFO FileInfo,
_Out_ PULONG FileInfoUsed
);
typedef BOOLEAN (*FILE_RESTORE_CALLBACK) (
_In_ FILE_RESTORE_PACKET_TYPE PacketType,
_In_ ULONG PacketLength,
_In_ PVOID PacketData
);
typedef BOOL (WINAPI *FuncRestoreFile) (
_In_ PFILE_RESTORE_CONTEXT Context,
_In_ PRESTORABLE_FILE_INFO RestorableFile,
_In_ PCWSTR DstFile,
_In_opt_ FILE_RESTORE_CALLBACK Callback,
_In_opt_ PVOID ClbkArg
);
HMODULE hLib;
wchar_t VOLUME[255];
BOOLEAN FuncRestoreCallback(_In_ FILE_RESTORE_PACKET_TYPE pType, _In_ ULONG pLength, _In_ PVOID pData)
{
// This is the callback that is passed to RestoreFile(), which
// returns data about the status of an attempted restoration.
if (pType == FileRestoreProgressInfo)
{
wcout << L"FILE RESTORE PROGRESS INFO:" << L"\n";
wprintf(L"Length of status data: %lu\n", pLength);
wcout << L"Location of data: " << pData << L"\n";
PFILE_RESTORE_PROGRESS_INFORMATION restoreProgressInfo = static_cast<PFILE_RESTORE_PROGRESS_INFORMATION>(pData);
wprintf(L"Total file size: %lld\n", restoreProgressInfo->TotalFileSize);
wprintf(L"Total bytes completed: %lld\n", restoreProgressInfo->TotalBytesCompleted);
wprintf(L"Stream size: %lld\n", restoreProgressInfo->StreamSize);
wprintf(L"Stream bytes completed: %lld\n", restoreProgressInfo->StreamBytesCompleted);
//wcout << L"Callback arg data: " << restoreProgressInfo->ClbkArg << L"\n";
wprintf(L"Callback arg: %p\n", restoreProgressInfo->ClbkArg);
}
else if (pType == FileRestoreFinished)
{
wcout << L"FILE RESTORE FINISHED INFO:" << L"\n";
wprintf(L"Length of status data: %lu\n", pLength);
wcout << L"Location of data: " << pData << L"\n";
// Obtain the struct
PFILE_RESTORE_FINISHED_INFORMATION restoreFinishedInfo = static_cast<PFILE_RESTORE_FINISHED_INFORMATION>(pData);
// Try to read some data from it
wprintf(L"Success data: %d\n", restoreFinishedInfo->Success);
wprintf(L"Final result data: %lu\n", restoreFinishedInfo->FinalResult);
wprintf(L"Callback arg: %p\n", restoreFinishedInfo->ClbkArg);
}
return TRUE;
}
void Scan(_In_ PFILE_RESTORE_CONTEXT context, _In_ LPCWSTR path)
{
// This is the main function that scans the files
// Dynamically link to the needed FMAPI functions
FuncScanRestorableFiles ScanRestorableFiles;
ScanRestorableFiles = reinterpret_cast<FuncScanRestorableFiles>( GetProcAddress( hLib, "ScanRestorableFiles" ) );
ULONG neededBufferSize = 0;
BOOL success = TRUE;
RESTORABLE_FILE_INFO tempFileInfo;
// Call ScanRestorableFiles the first time with a size of 0 to get the required buffer size
if ( ! ScanRestorableFiles(context, path, 0, &tempFileInfo, &neededBufferSize) )
{
wprintf(L"Failed to retrieve required buffer size, Error: #%u\n", GetLastError());
return;
}
// Create the buffer needed to hold restoration information
BYTE *buffer = new BYTE[neededBufferSize];
wcout << L"Initial buffer size is: " << neededBufferSize << L"\n";
// Loops until an error occurs or no more files found
while (success)
{
// Cast the byte buffer pointer into a structure pointer
PRESTORABLE_FILE_INFO fileInfo = reinterpret_cast<PRESTORABLE_FILE_INFO>(buffer);
#pragma warning( push )
#pragma warning( disable : 6386 ) /* warning is ignored since fileInfo grows in size by design */
success = ScanRestorableFiles(context, path, neededBufferSize, fileInfo, &neededBufferSize);
#pragma warning( pop )
wcout << L"Current buffer size is: " << neededBufferSize << L"\n";
if (success)
{
wcout << L"Call returned success! Required buffer size from latest call is " << neededBufferSize <<
L" bytes." L"\n";
if (fileInfo->IsRemoved)
{
// Found restorable file
wprintf(L"Restorable file found: %s\n", fileInfo->FileName);
// Echo size of char array containing file name
wcout << L"Restorable file name size: " <<
(sizeof(fileInfo->FileName) / sizeof(fileInfo->FileName[0])) << L"\n";
// Echo RESTORABLE_FILE_INFO structure info to console
wcout << L"Restorable file info structure memory address: " << fileInfo << L"\n";
wcout << L"Restorable file info structure size (returned via RESTORABLE_FILE_INFO): " << fileInfo->Size << L"\n";
wcout << L"Restorable file info structure size (returned via sizeof()): " << sizeof(*fileInfo) << L"\n";
// Echo restorable file (FMAPI) version to console
wcout << L"Restorable file version: " << fileInfo->Version << L"\n";
// Retrieve creation, write and access times for the file
// Define temp FILETIME, SYSTEMTIME and TIME_ZONE_INFORMATION
// structure vars
// All of these types and functions are defined in windows.h
FILETIME tmpFT;
SYSTEMTIME tmpST;
TIME_ZONE_INFORMATION tmpTZI;
// Initialize empty char arrays
wchar_t szLocalDate[255] = {0}, szLocalTime[255] = {0};
// Get local time zone info
SetTimeZoneInformation(&tmpTZI);
// Get file creation time
FileTimeToLocalFileTime(&(fileInfo->CreationTime), &tmpFT);
FileTimeToSystemTime(&tmpFT, &tmpST);
// Format to readable output and store in char arrays
GetDateFormatEx(LOCALE_NAME_SYSTEM_DEFAULT, DATE_LONGDATE, &tmpST, NULL, szLocalDate, 255, NULL);
GetTimeFormatEx(LOCALE_NAME_SYSTEM_DEFAULT, 0, &tmpST, NULL, szLocalTime, 255);
wcout << L"Restorable file created: " << szLocalDate << " " << szLocalTime << L"\n";
// Clear array for re-use
fill(begin(szLocalDate), end(szLocalDate), 0);
// Get last write time
FileTimeToLocalFileTime(&(fileInfo->LastWriteTime), &tmpFT);
FileTimeToSystemTime(&tmpFT, &tmpST);
// Format to readable output and store in char arrays
GetDateFormatEx(LOCALE_NAME_SYSTEM_DEFAULT, DATE_LONGDATE, &tmpST, NULL, szLocalDate, 255, NULL);
GetTimeFormatEx(LOCALE_NAME_SYSTEM_DEFAULT, 0, &tmpST, NULL, szLocalTime, 255);
wcout << L"Restorable file last written: " << szLocalDate << " " << szLocalTime << L"\n";
// Clear array for re-use
fill(begin(szLocalDate), end(szLocalDate), 0);
// Get last access time
FileTimeToLocalFileTime(&(fileInfo->LastAccessTime), &tmpFT);
FileTimeToSystemTime(&tmpFT, &tmpST);
// Format to readable output and store in char arrays
GetDateFormatEx(LOCALE_NAME_SYSTEM_DEFAULT, DATE_LONGDATE, &tmpST, NULL, szLocalDate, 255, NULL);
GetTimeFormatEx(LOCALE_NAME_SYSTEM_DEFAULT, 0, &tmpST, NULL, szLocalTime, 255);
wcout << L"Restorable file last accessed: " << szLocalDate << " " << szLocalTime << L"\n";
// Output the rest of the file info
wcout << L"Restorable file attributes: " << fileInfo->Attributes << L"\n";
wcout << L"Restorable file size: " << fileInfo->FileSize << L"\n";
wcout << L"Restorable file ClustersUsedByFile: " << fileInfo->ClustersUsedByFile << L"\n";
wcout << L"Restorable file ClustersCurrentlyInUse: " << fileInfo->ClustersCurrentlyInUse << L"\n";
wcout << L"Restorable file RestoreDataOffset: " << fileInfo->RestoreDataOffset << L"\n";
// Attempt to restore the file
wstring tmpStr;
getline(wcin, tmpStr);
// Convert input to uppercase
for (wstring::size_type i = 0; i < tmpStr.size(); i++)
{
towupper(tmpStr[i]);
}
wcout << L"tmpStr is: " << tmpStr << L"\n";
if (tmpStr == L"RESTORE")
{
// Attempt to restore the file
wcout << L"Attempting to restore file " << fileInfo->FileName << L"..." << L"\n";
FuncRestoreFile RestoreFile;
//RestoreFile = (FuncRestoreFile)GetProcAddress( hLib, "RestoreFile" );
RestoreFile = reinterpret_cast<FuncRestoreFile>(GetProcAddress(hLib, "RestoreFile"));
wcout << L"RestoreFile address: " << RestoreFile << L"\n";
BOOL tmpRetVal = false;
PCWSTR restoredFileName = L"X:\\testfile.txt";
wcout << L"New file name: " << restoredFileName << L"\n";
PVOID cbArg = NULL;
tmpRetVal = RestoreFile(context, fileInfo, restoredFileName, &FuncRestoreCallback, cbArg);
wcout << L"Return value: " << tmpRetVal << L" ; cbArg: " << cbArg << L"\n";
if (tmpRetVal == 0)
{
wcout << L"Error was: " << GetLastError() << L"\n";
}
}
else if (tmpStr == L"CLOSE")
{
// Abort the scanning process and close the file restore context
wcout << L"Aborting scan and closing file restore context..." << L"\n";
success = false;
}
}
}
else
{
DWORD err = GetLastError();
if (ERROR_INSUFFICIENT_BUFFER == err)
{
wcout << L"Insufficient buffer size! Current size is " << sizeof(buffer) << L" bytes; " <<
L" required size is " << neededBufferSize << L" bytes. Resizing..." << L"\n";
delete [] buffer;
buffer = new BYTE[neededBufferSize];
success = true;
}
else if (ERROR_NO_MORE_FILES == err)
{
wprintf(L"Scanning Complete.\n");
success = false;
}
else
{
wprintf(L"ScanRestorableFiles, Error #%u.\n", err);
}
}
}
delete [] buffer;
buffer = NULL;
}
//
// Program entry point
//
void __cdecl wmain(int argc, wchar_t *argv[])
{
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
// Load the FMAPI DLL
hLib = ::LoadLibraryEx(L"fmapi.dll", NULL, NULL);
if ( !hLib )
{
wprintf(L"Could not load fmapi.dll. Error #%u.\n", GetLastError());
return;
}
// Dynamically link to the needed FMAPI functions
FuncCreateFileRestoreContext CreateFileRestoreContext;
CreateFileRestoreContext = reinterpret_cast<FuncCreateFileRestoreContext>( GetProcAddress( hLib, "CreateFileRestoreContext" ) );
FuncCloseFileRestoreContext CloseFileRestoreContext;
CloseFileRestoreContext = reinterpret_cast<FuncCloseFileRestoreContext>( GetProcAddress( hLib, "CloseFileRestoreContext" ) );
// Set the flags value for which kind of items we want to scan for
RESTORE_CONTEXT_FLAGS flags;
flags = (RESTORE_CONTEXT_FLAGS)(ContextFlagVolume | FlagScanRemovedFiles);
switch (argc)
{
case 2:
{
if (wcslen(argv[1]) < (sizeof(VOLUME) / sizeof(VOLUME[0]))) // ensure that argv[1] is not >255 chars long
{
wcscpy_s(VOLUME, argv[1]);
}
else
{
wcscpy_s(VOLUME, 255, argv[1]);
}
wcout << L"Volume set to: " << VOLUME << L"\n";
wcout << L"Defaulting to VOLUME search type; setting flags accordingly..." << L"\n";
flags = (RESTORE_CONTEXT_FLAGS)(ContextFlagVolume | FlagScanRemovedFiles);
break;
}
case 3:
{
if (wcslen(argv[1]) < (sizeof(VOLUME) / sizeof(VOLUME[0]))) // ensure that argv[1] is not >255 chars long
{
wcscpy_s(VOLUME, argv[1]);
}
else // if it is, only copy the first 255 chars
{
wcscpy_s(VOLUME, 255, argv[1]);
}
int len;
// Get length of second argument passed by the user
len = wcslen(argv[2]);
// Allocate new wchar_t array big enough to hold it
wchar_t *tmpArg = new (nothrow) wchar_t[len + 1];
// Ensure that the memory was allocated successfully
if (tmpArg == nullptr)
{
// Error allocating memory - bail out
wcout << L"Error allocating memory! Bailing out..." << L"\n";
return;
}
// Copy the argument string from argv to tmpArg
wcscpy_s(tmpArg, len + 1, argv[2]);
// Convert to uppercase
_wcsupr_s(tmpArg, len + 1);
// Check whether VOLUME or DISK search type was specified and set flags accordingly
if (wcscmp(tmpArg, L"VOLUME") == 0)
{
wcout << L"Volume set to: " << VOLUME << L"\n";
if (wcschr(VOLUME, L':') != NULL)
{
wcout << L"VOLUME search type specified; setting flags accordingly..." << L"\n";
flags = (RESTORE_CONTEXT_FLAGS)(ContextFlagVolume | FlagScanRemovedFiles);
}
else
{
wcout << L"VOLUME search type specified, but the volume identifier given doesn't appear " <<
L"to be a valid mounted volume! Please check your arguments and try again." << L"\n";
delete [] tmpArg;
return;
}
}
else if (wcscmp(tmpArg, L"DISK") == 0)
{
wcout << L"Disk set to: " << VOLUME << L"\n";
if (wcschr(VOLUME, L':') == NULL)
{
wcout << L"DISK search type specified; setting flags accordingly..." << L"\n";
flags = (RESTORE_CONTEXT_FLAGS)(ContextFlagDisk | FlagScanRemovedFiles);
}
else
{
wcout << L"DISK search type specified, but the disk identifier given doesn't appear " <<
L"to be a valid physical disk! Please check your arguments and try again." << L"\n";
delete [] tmpArg;
return;
}
}
else
{
wcout << L"UNKNOWN search type specified! Defaulting to VOLUME; setting flags accordingly..." << L"\n";
flags = (RESTORE_CONTEXT_FLAGS)(ContextFlagVolume | FlagScanRemovedFiles);
}
delete [] tmpArg;
break;
}
default:
{
// Set the default volume to scan here
wcscpy_s(VOLUME, L"\\\\.\\D:");
wcout << L"No arguments specified! Defaulting to VOLUME search of \\\\.\\D:" << L"\n";
break;
}
}
// Create the FileRestoreContext
PFILE_RESTORE_CONTEXT context = NULL;
if ( ! CreateFileRestoreContext(VOLUME, flags, 0, 0, FILE_RESTORE_VERSION_2, &context) )
{
DWORD err = GetLastError();
wprintf(L"Failed to Create FileRestoreContext, Error #%u.\n", err);
return;
}
else
{
wcout << L"Success! File restore context created! Value of context is: " << context << L"\n";
}
// Find restorable files starting at the given directory
Scan(context, SCAN_PATH);
// Close the context
if (context)
{
CloseFileRestoreContext(context);
context = NULL;
}
}
Please note this is still a very rudimentary app in its beginning stages. It basically begins a scan, defaulting (if no args are given) to scanning the D:\ drive and attempting to restore a deleted file to X:\testfile.txt. For those that may not be familiar with WinPE, X: is the system drive in a WinPE environment, and D: is usually the letter assigned to the OS drive of the machine that is booted to PE while in the PE environment, depending on the setup, with C: being the system reserved partition.
For each restorable file found, it pauses, and if the user enters the text "RESTORE" and hits ENTER, it will attempt to restore the file (this takes place around line 247). The callback function that indicates status for the restoration returns error code 6 (via FinalResult), as does GetLastError().
Any help on this is very much appreciated!
I have written DLL injector. I used CreateRemoteThread to inject my DLL to process and all was good.
Now i am trying inject DLL to process by undocumented function - NtCreateThreadEx. I have written injector but he is not working.
When i use 32 bit injector to inject 32 bit DLL to 32 bit process
all working good.
Problem is when i use 64 bit injector to inject 64 bit DLL to 64 bit process.
My DLL code:
#include <windows.h>
///Compilation with option -m64
extern "C" BOOL __stdcall DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved)
{
MessageBox( NULL, "MESSAGE FROM 64 BIT DLL", "Lorem ipsum", MB_ICONINFORMATION | MB_OKCANCEL );
return 0;
}
My TestApp code
#include <iostream>
#include <windows.h>
int main()
{
std::cout << " Lorem IPSUM" << std::endl;
//HMODULE HDLL = LoadLibraryA("dll64.dll");
//std::cout << "Error: " << GetLastError() << std::endl;
while(1)
{
std::cout << "petla" << std::endl;
Sleep(5000);
}
return 0;
}
My injector code:
#include <iostream>
#include <string>
#include <windows.h>
/// 64 bit OS - Windows 7
///=====================
///* In this same user context ("User")
///TYPE OF(32/64 bits)
///INJECTOR===DLL===PROCESS===RESULT
/// 32 32 32 -SUCESS
/// 64 64 64 -FALIED (error: 1300)
//Handle to process,Address of'LoadLibraryA',see DllAdr
///TO DO
///* Inject DLL to process from normal user context ("User") to higher user context (Zarzadca)
///* Inject DLL to process from normal user context ("User") to other normal user context (User1)
HANDLE NtCreateThreadEx(HANDLE hProcess,LPVOID lpBaseAddress, LPVOID lpSpace);
int privileges();
int main()
{
int PIDOfProcess = 0;
std::string pathToDLL = "dll64.dll\0"; ///find DLL in local directory
DWORD PID = (DWORD)PIDOfProcess; ///PID
HANDLE HProcess = NULL; ///Handle to process
LPVOID LibAddr = NULL; ///Address of procedure 'LoadLibraryA'
LPVOID DllAdr = NULL; ///Address of memory in other process
HANDLE hThread = NULL; ///Handle to remote thread
int WirteStatus = 0; ///Status of writing to memory of other process
std::cout << "ptr size = " << sizeof(void *) << std::endl;
std::cout << "Get PID of process" << std::endl;
std::cin >> PIDOfProcess;
PID = (DWORD)PIDOfProcess;
///std::cout << "Get path to DLL" << std::endl;
///std::cin >> pathToDLL;
if( privileges() != 0 )
{
std::cout << "Cannot get the right privileges" << std::endl;
}
HProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PID);
if(HProcess == NULL)
{
std::cout << "Could not find process" << std::endl;
std::cout << GetLastError() << std::endl;
system("pause");
return GetLastError();
}
DllAdr = (LPVOID)VirtualAllocEx(HProcess, NULL, pathToDLL.size() +1, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if(DllAdr == NULL)
{
std::cout <<"Can not allocate memory." << std::endl;
std::cout << GetLastError() << std::endl;
system("pause");
return GetLastError();
}
WirteStatus = WriteProcessMemory(HProcess, (LPVOID)DllAdr, pathToDLL.c_str() ,pathToDLL.size()+1, NULL);
if(WirteStatus == 0)
{
std::cout << "Could not write to process's address space" << std::endl;
std::cout << GetLastError() << std::endl;
system("pause");
return GetLastError();
}
LibAddr = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
if(LibAddr == NULL)
{
std::cout << "Unable to locate LoadLibraryA" << std::endl;
std::cout << GetLastError() << std::endl;
system("pause");
return GetLastError();
}
hThread = NtCreateThreadEx(HProcess,LibAddr,DllAdr);
///DWORD threadId = 0;
///hThread = CreateRemoteThread(HProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LibAddr, DllAdr, 0, &threadId);
if(hThread == NULL)
{
std::cout << "Error: ";
std::cout << GetLastError() << std::endl;
system("pause");
return GetLastError();
}
system("pause");
}
HANDLE NtCreateThreadEx(HANDLE hProcess,LPVOID lpBaseAddress,LPVOID lpSpace)
{
///The prototype of NtCreateThreadEx from undocumented.ntinternals.com
typedef DWORD (WINAPI * functypeNtCreateThreadEx)(
PHANDLE ThreadHandle,
ACCESS_MASK DesiredAccess,
LPVOID ObjectAttributes,
HANDLE ProcessHandle,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
BOOL CreateSuspended,
DWORD dwStackSize,
DWORD Unknown1,
DWORD Unknown2,
LPVOID Unknown3
);
HANDLE hRemoteThread = NULL;
HMODULE hNtDllModule = NULL;
functypeNtCreateThreadEx funcNtCreateThreadEx = NULL;
//Get handle for ntdll which contains NtCreateThreadEx
hNtDllModule = GetModuleHandle( "ntdll.dll" );
if ( hNtDllModule == NULL )
{
std::cout << "Cannot get module ntdll.dll error: " << GetLastError() << std::endl;
return NULL;
}
funcNtCreateThreadEx = (functypeNtCreateThreadEx)GetProcAddress( hNtDllModule, "NtCreateThreadEx" );
if ( !funcNtCreateThreadEx )
{
std::cout << "Cannot get procedure address error: " << GetLastError() << std::endl;
return NULL;
}
funcNtCreateThreadEx( &hRemoteThread, /*GENERIC_ALL*/0x1FFFFF, NULL, hProcess, (LPTHREAD_START_ROUTINE)lpBaseAddress, lpSpace, FALSE, NULL, NULL, NULL, NULL );
std::cout << "Status NtCreateThreadEx " << GetLastError() << std::endl;
std::cout << "hRemoteThread: " << hRemoteThread << std::endl;
std::cout << "hNtDllModule: " << hNtDllModule << std::endl;
std::cout << "funcNtCreateThreadEx: " << funcNtCreateThreadEx << std::endl;
return hRemoteThread;
}
int privileges()
{
HANDLE Token;
TOKEN_PRIVILEGES tp;
if(OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&Token)) ///It opens the access token associated with a process.
{
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);///Function retrieves the locally unique identifier (LUID)
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (AdjustTokenPrivileges(Token, false, &tp, sizeof(tp), NULL, NULL) != 0)///Function enables or disables privileges in the specified access token.
{
return 0; //OK
}
}
return 1;
}
When i use 64 bit injector to inject 64 bit DLL to 64 bit process, function NtCreateThreadEx return code of error 1300 and my DLL doesn't execute.
I use to compile on 64 bit architecture: g++ (tdm64-1) 5.1.0
I am working on Virus Windows 7 64 bit as normal user. Run as administrator doesn't help.
I dont know why it doesn't work, what i doing wrong.
PS: When i use 32 bit injector to inject 32 bit DLL to 32 bit process, function NtCreateThreadEx return code of error 1300 but my DLL execute.
In 32 bit version TestApp GetLastError return code 1114.
I use to compile on 32 bit architecture: g++ (tdm-2) 4.8.1
I include image
I based on:
http://www.p-programowanie.pl/cpp/dll-injection/ - Dll Injection (polish)
====
http://www.codeproject.com/Questions/369890/Ask-about-NtCreateThreadEx-in-Window-x
- Ask about NtCreateThreadEx in Window 7 x64!
=====
http://www.rohitab.com/discuss/topic/39535-code-injections-beginner-and-advanced/ Code Injections [beginner and advanced]
=====
http://securityxploded.com/ntcreatethreadex.php Remote Thread Execution in System Process using NtCreateThreadEx for Vista & Windows7
=====
http://cpp0x.pl/dokumentacja/WinAPI/Systemowe-kody-bledow-1300-1699/1470 Systemowe kody błędów (1300-1699) (polish)
Link to my topic on other forum (polish): http://forum.4programmers.net/C_i_C++/267735-dll_injection_w_windows_za_pomoca_nieudokumentowanej_funkcji_w_winapi?p=1234215#id1234215
My injector is working when i use him to inject DLL to other process in my user space (i am working as normal user)
but it is not working when
i am injecting to csrss.exe (or other system's process).
I get code of error 5 - Access Denied, when i run injector as Administrator i get code of error 0 (SUCCESS?) but my DLL not aborting process
( abort() - i try do BSoD).
I read about Session Separation and i think it is reason of my problem so i have one question: How i can hacking Windows :)
If it is imposibble can i inject DLL as normal user to proces in Administrator context (or other normal user's process) ?
Been stuck for a few hours making a (simple) dll injector that takes a .dll file and a process as arguments and then injects said .dll into the process, and I'm about to start tearing my hair out.
It doesn't function properly, and for no obvious reason either. The dll simply won't load into the process, but without any error messages being displayed. I did the exact same thing but with ANSI functions instead of Unicode and it worked like a charm, which after some testing is leading me to believe it's PROBABLY a problem with the file path not being loaded properly but I have no idea why.
I've attached my entire source code below and added some comments to hopefully clarify somewhat. And like I said, if I'm right, then the important part should start somewhere around:
//Get the full path of our dll and store it in a variable
Help a bro out.
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
using namespace std;
int main()
{
HANDLE hSnapshot, hProc = NULL;
PROCESSENTRY32 PE32;
PE32.dwSize = sizeof(PROCESSENTRY32);
WCHAR injProcName[100] = {NULL}, injDllName[100] = {NULL};
//Let user input options
cout << "Dll injector started!" << endl << "Please enter the name of the dll you would like to inject: ";
wcin >> injDllName;
cout << "Enter the name of the target process: ";
wcin >> injProcName;
//Create snapshot
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
Process32First(hSnapshot, &PE32);
//Load the first process into PE32 and loop to see if target process is running
do {
if(wcscmp(PE32.szExeFile, injProcName) == 0) {
wcout << PE32.szExeFile << " found!" << endl;
wcout << "Attempting to open " << injProcName << ".." << endl;
hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, PE32.th32ProcessID);
if(!hProc)
{
cout << "Failed to open process!" << endl;
return 1;
}
break;
}
}
while(Process32Next(hSnapshot, &PE32));
if(!hProc) {
cout << "Unable to locate process!" << endl;
return 1;
}
cout << "Process successfully opened!" << endl;
//Get the full path of our dll and store it in a variable
WCHAR DllPath[MAX_PATH] = {NULL};
GetFullPathName(injDllName, MAX_PATH, DllPath, NULL);
wcout << DllPath << endl;
//Allocate memory in target process
cout << "Allocating memory.." << endl;
LPVOID DllMemAddr = VirtualAllocEx(hProc,
NULL,
wcslen(DllPath),
MEM_COMMIT|MEM_RESERVE,
PAGE_READWRITE);
//Write our path into target process memory
wcout << "Writing dll to target process.." << endl;
WriteProcessMemory(hProc,
DllMemAddr,
DllPath,
wcslen(DllPath),
NULL);
//Get the memory address of LoadLibraryW
LPVOID LoadAddr = GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");
//Finally, start a new thread with the address of LoadLibraryW and our dll path as argument
cout << "Executing dll in remote process.." << endl;
CreateRemoteThread(hProc,
NULL,
NULL,
(LPTHREAD_START_ROUTINE)LoadAddr,
DllMemAddr,
NULL,
NULL);
cout << "Dll sucessfully injected!" << endl;
cin.get();
return 0;
}
wcslen returns length in wchar_t units. But VirtualAllocEx and WriteProcessMemory receive a length in byte units. So you only write half the string, because wchar_t is two bytes wide. And you did not write the null terminator.
You need to pass (wcslen(DllPath)+1)*sizeof(wchar_t).
Incidentally, your ANSI code was probably broken too because, presumably, it also missed the null terminator. But you probably got away with it by chance.
A little error checking would not go amis, while we are in the business of looking at your code. And initialising DllPath is a little pointless when you follow it with the call to GetFullPathName.
I am trying to do some dll injection. I think I tried everything I could but cound not solve the problem unfortunately. I always get ERROR CODE 127 which means ERROR_PROC_NOT_FOUND. I am using Windows 7 64 bit.
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
using namespace std;
char FileToInject[] = "theDll.dll";
char ProcessName[] = "calc.exe";
typedef HINSTANCE (*fpLoadLibrary)(char*);
bool InjectDLL(DWORD processId);
int main() {
DWORD processId = NULL;
PROCESSENTRY32 pre32 = {sizeof(PROCESSENTRY32)};
HANDLE hProcSnap;
cout << "BEFORECreateToolhelo32Snapshot:" << GetLastError() <<endl;
while(!processId) {
system("CLS");
cout << "Searching..." << endl;
hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
cout << "CreateToolhelo32Snapshot:" << GetLastError() <<endl;
if(Process32First(hProcSnap, &pre32)) {
do {
if(!(strcmp(pre32.szExeFile, ProcessName))) {
processId = pre32.th32ProcessID;
break;
}
}
while(Process32Next(hProcSnap, &pre32));
}
Sleep(1000);
}
cout << GetLastError() <<endl;
while(!InjectDLL(processId)) {
cout << "DLL Injection failed" << endl;
Sleep(1000);
}
cout << "DLL Injected successfully" << endl;
getchar();
CloseHandle(hProcSnap);
return 0;
}
bool InjectDLL(DWORD processId) {
HANDLE hProc;
LPVOID paramAddr;
cout << "START:" << GetLastError() <<endl;
HINSTANCE hDll = LoadLibrary("KERNEL32");
cout << "LoadLibrary:" << GetLastError() <<endl;
fpLoadLibrary LoadLibraryAddr = (fpLoadLibrary)GetProcAddress(hDll, "LibraryLoadA");
cout << "LoadLibraryArr:" << GetLastError() <<endl;
hProc = OpenProcess(PROCESS_ALL_ACCESS, false, processId);
cout << "OpenProcess:" << GetLastError() <<endl;
char DllPath[250] = "C:\\Hacks\test.dll";
paramAddr = VirtualAllocEx(hProc, 0, strlen(DllPath) + 1, MEM_COMMIT, PAGE_READWRITE);
cout << "VirtualAlloxEx:" <<GetLastError() <<endl;
bool MemoryWritten = WriteProcessMemory(hProc, paramAddr, DllPath, strlen(DllPath) + 1, NULL);
cout << "WriteProcessMemory:" << GetLastError() <<endl;
CreateRemoteThread(hProc, 0, 0, (LPTHREAD_START_ROUTINE)LoadLibraryAddr, paramAddr, 0, 0);
cout << "CreateRemoteThread:" <<GetLastError() <<endl;
CloseHandle(hProc);
return MemoryWritten;
}
The output is the following:
Searching...
CreateToolhelp32Snapshot: 18 ERROR_NO_MORE_FILES
LoadLibrary:18 ERROR_NO_MORE_FILES
LoadLibraryArr:127 ERROR_PROC_NOT_FOUND
OpenProcess:127 ERROR_PROC_NOT_FOUND
VirtualAlloxEx:127 ERROR_PROC_NOT_FOUND
WriteProcessMemory:127 ERROR_PROC_NOT_FOUND
CreateRemoteThread:5 ACCESS DENIED
DLL Injected successfully
The program finds the calc.exe as a process with no problem, but after that something goes wrong. Could someone please help me with this?
Thank you,
Tamas
This is one problem:
char DllPath[250] = "C:\\Hacks\test.dll";
The last backslash is not escaped. Change to:
char DllPath[250] = "C:\\Hacks\\test.dll";
The function is called LoadLibraryA(), not LibraryLoadA():
fpLoadLibrary LoadLibraryAddr =
(fpLoadLibrary)GetProcAddress(hDll, "LibraryLoadA");
A few other suggestions:
Only check GetLastError() if the previous WINAPI function failed.
Only continue processing if the previous WINAPI code (or other code) succeeded.
In
fpLoadLibrary LoadLibraryAddr = (fpLoadLibrary)GetProcAddress(hDll, "LibraryLoadA");
you should rather resolve the string LoadLibraryA. The
OpenProcess:127 ERROR_PROC_NOT_FOUND
VirtualAlloxEx:127 ERROR_PROC_NOT_FOUND (<-- sic)
WriteProcessMemory:127 ERROR_PROC_NOT_FOUND
errors are caused because you're using GetLastError even though these functions maybe didn't even fail. So before calling GetLastError, make sure that these functions yield an error return value (NULL or the like).