Вы вообще не обрабатываете ошибки. OpenProcess()
, VirtualAllocEx()
, WriteProcessMemory()
, CreateRemoteThread()
, все эти функции могут потерпеть неудачу, вы должны справиться с этим. И GetLastError()
имеет значение, только если они действительно терпят неудачу.
В CreateRemoteThreadInject()
, если CreateRemoteThread()
завершается успешно, вы не ждете завершения потока, прежде чем пытаться освободить выделенную память. И вы закрываете HANDLE
для процесса перед использованием этого HANDLE
для освобождения выделенной памяти. И вы не закрываете HANDLE
, возвращаемое CreateRemoteThread()
.
Вы делаете все в правильном порядке в Injectstuff()
, но вам все еще не хватает адекватной обработки ошибок, а также вы не выделяете достаточно памяти для нулевого терминатора в строке пути DLL.
Но почему у вас две функции, выполняющие по существу одно и то же? Единственная реальная разница между ними заключается в том, что Injectstuff()
запрашивает у OpenProcess()
больше разрешений, чем ему действительно нужно, тогда как CreateRemoteThreadInject()
запрашивает только те конкретные разрешения, которые ему действительно необходимы.
Кстати, использование system()
для выполнения echo
команд совершенно бесполезно. Вы должны просто написать std::cout
или std::cerr
вместо этого и flush
, если необходимо. Нет необходимости выкладывать системный командный процесс для выполнения его команды echo
.
Вместо этого попробуйте что-нибудь подобное:
void DisplayLastError(const char *operation, int err)
{
std::cerr << "Error ";
if (err) std::cerr << err << " ";
std::cerr << operation << std::endl;
}
void DisplayLastError(const char *operation)
{
DisplayLastError(operation, GetLastError());
}
bool CreateRemoteThreadInject(DWORD IDofproc, const char * dll)
{
if (!IDofproc)
return false;
LPVOID pLoadLibrary = (LPVOID) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "LoadLibraryA");
if (!pLoadLibrary)
{
DisplayLastError("getting LoadLibrary pointer");
return false;
}
HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, IDofproc);
if (!hProcess)
{
DisplayLastError("opening the process");
return false;
}
LPVOID pMemory = VirtualAllocEx(hProcess, NULL, strlen(dll) + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (!pMemory)
{
DisplayLastError("allocating memory");
CloseHandle(hProcess);
return false;
}
if (!WriteProcessMemory(hProcess, pMemory, dll, strlen(dll) + 1, NULL))
{
DisplayLastError("writing to allocated memory");
VirtualFreeEx(hProcess, pMemory, 0, MEM_RELEASE);
CloseHandle(hProcess);
return false;
}
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)pLoadLibrary, pMemory, 0, NULL);
if (!hThread)
{
DisplayLastError("creating remote thread");
VirtualFreeEx(hProcess, pMemory, 0, MEM_RELEASE);
CloseHandle(hProcess);
return false;
}
WaitForSingleObject(hThread, INFINITE);
DWORD dwExitCode = 0;
GetExitCodeThread(hThread, &dwExitCode);
CloseHandle(hThread);
VirtualFreeEx(hProcess, pMemory, 0, MEM_RELEASE);
CloseHandle(hProcess);
if (!dwExitCode)
{
DisplayLastError("loading dll", 0);
return false;
}
MessageBox(NULL, TEXT("Injected"), TEXT(""), MB_OK);
return true;
}
bool Injectstuff(DWORD processId, char* dllpath)
{
std::cout << "Process ID: " << processId << std::endl;
return CreateRemoteThreadInject(processId, dllpath);
}
Также обратите внимание, что код, необходимый для определения успешности LoadLibraryA()
или неправильной работы только в том случае, если целевой процесс является 32-разрядным. Функция, переданная в CreateRemoteThread()
, всегда должна возвращать 32-битную DWORD
, а LoadLibraryA()
возвращает 32-битную HMODULE
при вызове в 32-битном процессе, но она возвращает 64-битную HMODULE
при вызов в 64-битном процессе. Поток не может вернуть 64-битный код завершения, а GetExitCodeThread()
не может получить 64-битный код выхода, поэтому возвращенный HMODULE
будет усечен, что может привести к неточным результатам. Так что не совсем уместно использовать LoadLibraryA()
напрямую в качестве функции потока при внедрении в 64-битный процесс, если вы не заботитесь о результате загрузки. Если вам это нужно, вы можете вместо этого внедрить небольшой поток функций, который косвенно вызывает LoadLibrary()
и сохраняет результат в адрес памяти, который инжектор может затем прочитать с помощью ReadProcessMemory()
, когда поток завершится. Или используйте другой метод инъекции .