尝试注入 dll 时如何正确使用 VirtualFreeEx
How to correctly use VirtualFreeEx when trying to inject a dll
我正在尝试制作 DLL 注入器,但函数中存在参数错误。
我已经尝试将变量更改为 char*,我已经确认进程 ID 是正确的,但我无法在 x64 或 x86 中编译它,因为我使用的是代码块,但我正在使用的程序试用它是用代码块创建的,DLL 可以与其他注入器一起使用,我已经确认 dll 路径是正确的。
void EchoLastError()
{
std::string ToExecute;
std::stringstream Command;
Command << "echo " << GetLastError();
ToExecute = Command.str();
system(ToExecute.c_str());
Command.str(std::string());
}
BOOL CreateRemoteThreadInject(DWORD IDofproc, const char * dll)
{
HANDLE Process;
LPVOID Memory, LoadLibrary;
if (!IDofproc)
{
return false;
}
Process = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, IDofproc);
EchoLastError();
system("pause");
LoadLibrary = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
Memory = (LPVOID)VirtualAllocEx(Process, NULL, strlen(dll) + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(Process, (LPVOID)Memory, dll, strlen(dll) + 1, NULL);
CreateRemoteThread(Process, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibrary, (LPVOID)Memory, NULL, NULL);
EchoLastError();
CloseHandle(Process);
VirtualFreeEx(Process, (LPVOID)Memory, 0, MEM_RELEASE);
EchoLastError();
MessageBox(NULL, "Injected", "", MB_OK);
return true;
}
//other
bool Injectstuff(DWORD processId, char* dllpath)
{
std::stringstream kds;
kds << "echo Process ID: " << processId;
std::string dl = kds.str();
system(dl.c_str());
EchoLastError();
HANDLE hTargetProcess = OpenProcess(PROCESS_ALL_ACCESS, false, processId);
EchoLastError();
system("pause");
if (hTargetProcess)
{
LPVOID LoadLibAddress = (LPVOID)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
EchoLastError();
system("pause");
LPVOID LoadPath = VirtualAllocEx(hTargetProcess, 0, strlen(dllpath), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
EchoLastError();
system("pause");
HANDLE RemoteThread = CreateRemoteThread(hTargetProcess, 0, 0, (LPTHREAD_START_ROUTINE)LoadLibAddress, LoadPath, 0, 0);
EchoLastError();
system("pause");
WaitForSingleObject(RemoteThread, INFINITE);
EchoLastError();
system("pause");
VirtualFreeEx(hTargetProcess, LoadPath, strlen(dllpath), MEM_RELEASE);
EchoLastError();
system("pause");
CloseHandle(RemoteThread);
CloseHandle(hTargetProcess);
return true;
}
return false;
}
第一个函数在 VirtualFreeEx 上打印 87,第二个函数在 VirtualFreeEx 上打印 6。我该如何解决这些问题?我正在使用 GNU GCC 编译器。
您根本没有进行任何错误处理。 OpenProcess()
、VirtualAllocEx()
、WriteProcessMemory()
、CreateRemoteThread()
,所有这些函数都可能失败,你需要处理它。而 GetLastError()
只有在它们确实失败时才有意义。
在 CreateRemoteThreadInject()
中,如果 CreateRemoteThread()
成功,则您在尝试释放分配的内存之前没有等待线程完成。在使用 HANDLE
释放分配的内存之前,您正在关闭进程的 HANDLE
。而且您没有关闭 HANDLE
return 编辑 CreateRemoteThread()
.
您在 Injectstuff()
中以正确的顺序执行操作,但您仍然缺乏足够的错误处理,而且您没有为 DLL 路径字符串上的空终止符分配足够的内存。
但是,为什么有两个函数在本质上做同样的事情?它们之间唯一真正的区别是 Injectstuff()
要求 OpenProcess()
获得比实际需要更多的权限,而 CreateRemoteThreadInject()
只要求它实际需要的特定权限。
附带说明一下,您使用 system()
执行 echo
命令是完全没用的。你应该只写 std::cout
或 std::cerr
,如果需要的话 flush
。根本不需要 shell 出一个系统命令进程来执行它的 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()
的函数必须始终 return 是 32 位的 DWORD
,而 LoadLibraryA()
return 是 32 位的 HMODULE
在调用时32 位进程,但在 64 位进程中调用时 return 是 64 位 HMODULE
。线程无法 return 64 位退出代码,并且 GetExitCodeThread()
无法检索 64 位退出代码,因此 returned HMODULE
将被截断,这可能导致到不准确的结果。所以,直接LoadLibraryA()
作为注入64位进程的线程函数是不太合适的,除非你不关心加载的结果.如果需要,您可以注入一个小函数 thunk,它间接调用 LoadLibrary()
并将结果保存到一个内存地址,然后注入器可以在线程完成时使用 ReadProcessMemory()
从中读取该地址。或者使用 different injection technique.
我正在尝试制作 DLL 注入器,但函数中存在参数错误。
我已经尝试将变量更改为 char*,我已经确认进程 ID 是正确的,但我无法在 x64 或 x86 中编译它,因为我使用的是代码块,但我正在使用的程序试用它是用代码块创建的,DLL 可以与其他注入器一起使用,我已经确认 dll 路径是正确的。
void EchoLastError()
{
std::string ToExecute;
std::stringstream Command;
Command << "echo " << GetLastError();
ToExecute = Command.str();
system(ToExecute.c_str());
Command.str(std::string());
}
BOOL CreateRemoteThreadInject(DWORD IDofproc, const char * dll)
{
HANDLE Process;
LPVOID Memory, LoadLibrary;
if (!IDofproc)
{
return false;
}
Process = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, IDofproc);
EchoLastError();
system("pause");
LoadLibrary = (LPVOID)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
Memory = (LPVOID)VirtualAllocEx(Process, NULL, strlen(dll) + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(Process, (LPVOID)Memory, dll, strlen(dll) + 1, NULL);
CreateRemoteThread(Process, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibrary, (LPVOID)Memory, NULL, NULL);
EchoLastError();
CloseHandle(Process);
VirtualFreeEx(Process, (LPVOID)Memory, 0, MEM_RELEASE);
EchoLastError();
MessageBox(NULL, "Injected", "", MB_OK);
return true;
}
//other
bool Injectstuff(DWORD processId, char* dllpath)
{
std::stringstream kds;
kds << "echo Process ID: " << processId;
std::string dl = kds.str();
system(dl.c_str());
EchoLastError();
HANDLE hTargetProcess = OpenProcess(PROCESS_ALL_ACCESS, false, processId);
EchoLastError();
system("pause");
if (hTargetProcess)
{
LPVOID LoadLibAddress = (LPVOID)GetProcAddress(GetModuleHandleA("kernel32.dll"), "LoadLibraryA");
EchoLastError();
system("pause");
LPVOID LoadPath = VirtualAllocEx(hTargetProcess, 0, strlen(dllpath), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
EchoLastError();
system("pause");
HANDLE RemoteThread = CreateRemoteThread(hTargetProcess, 0, 0, (LPTHREAD_START_ROUTINE)LoadLibAddress, LoadPath, 0, 0);
EchoLastError();
system("pause");
WaitForSingleObject(RemoteThread, INFINITE);
EchoLastError();
system("pause");
VirtualFreeEx(hTargetProcess, LoadPath, strlen(dllpath), MEM_RELEASE);
EchoLastError();
system("pause");
CloseHandle(RemoteThread);
CloseHandle(hTargetProcess);
return true;
}
return false;
}
第一个函数在 VirtualFreeEx 上打印 87,第二个函数在 VirtualFreeEx 上打印 6。我该如何解决这些问题?我正在使用 GNU GCC 编译器。
您根本没有进行任何错误处理。 OpenProcess()
、VirtualAllocEx()
、WriteProcessMemory()
、CreateRemoteThread()
,所有这些函数都可能失败,你需要处理它。而 GetLastError()
只有在它们确实失败时才有意义。
在 CreateRemoteThreadInject()
中,如果 CreateRemoteThread()
成功,则您在尝试释放分配的内存之前没有等待线程完成。在使用 HANDLE
释放分配的内存之前,您正在关闭进程的 HANDLE
。而且您没有关闭 HANDLE
return 编辑 CreateRemoteThread()
.
您在 Injectstuff()
中以正确的顺序执行操作,但您仍然缺乏足够的错误处理,而且您没有为 DLL 路径字符串上的空终止符分配足够的内存。
但是,为什么有两个函数在本质上做同样的事情?它们之间唯一真正的区别是 Injectstuff()
要求 OpenProcess()
获得比实际需要更多的权限,而 CreateRemoteThreadInject()
只要求它实际需要的特定权限。
附带说明一下,您使用 system()
执行 echo
命令是完全没用的。你应该只写 std::cout
或 std::cerr
,如果需要的话 flush
。根本不需要 shell 出一个系统命令进程来执行它的 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()
的函数必须始终 return 是 32 位的 DWORD
,而 LoadLibraryA()
return 是 32 位的 HMODULE
在调用时32 位进程,但在 64 位进程中调用时 return 是 64 位 HMODULE
。线程无法 return 64 位退出代码,并且 GetExitCodeThread()
无法检索 64 位退出代码,因此 returned HMODULE
将被截断,这可能导致到不准确的结果。所以,直接LoadLibraryA()
作为注入64位进程的线程函数是不太合适的,除非你不关心加载的结果.如果需要,您可以注入一个小函数 thunk,它间接调用 LoadLibrary()
并将结果保存到一个内存地址,然后注入器可以在线程完成时使用 ReadProcessMemory()
从中读取该地址。或者使用 different injection technique.