我正在尝试制作DLL注入器,但是函数中存在参数错误。
我尝试将变量更改为char *,我已经确认进程ID是正确的,因为使用的是代码块,但是我正在尝试的程序无法在x64或x86中进行编译上是使用代码块创建的,该DLL可与其他注入器一起使用,我已确认dll路径正确。
{{1}}
第一个功能在VirtualFreeEx上打印87,第二个功能在VirtualFreeEx上打印6。我该如何解决?我正在使用GNU GCC编译器。
答案 0 :(得分:1)
您根本不执行任何错误处理。 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);
}
此外,请注意,仅当目标进程为32位时,才能检测LoadLibraryA()
是否成功所需的代码。传递给CreateRemoteThread()
的函数必须始终返回32位的DWORD
,并且在32位进程中调用时,LoadLibraryA()
返回32位的HMODULE
,但是返回在64位进程中进行调用时,使用64位HMODULE
。线程无法返回64位退出代码,并且GetExitCodeThread()
无法检索64位退出代码,因此返回的HMODULE
将被截断,这可能导致错误的结果。因此,在注入64位进程时,直接使用LoadLibraryA()
作为线程函数并不是真正合适的,除非您不关心加载的结果。如果需要的话,可以注入一个小的函数thunk,它间接调用LoadLibrary()
并将结果保存到一个内存地址,当线程完成时,注入器可以使用ReadProcessMemory()
从中读取该内存地址。或使用different injection technique。