首页 > 代码库 > 源码解析一种无模块注入进程方法
源码解析一种无模块注入进程方法
对windows安全比较熟悉的同学对模块注入应该都比较了解,很多病毒、木马、外挂都会用到,无模块注入应用得则比较少。
无模块注入的好处是DLL注入进去后,确实已经不以模块的形式存在了,用任何进程模块查看工具,都找不到注入进去的DLL。因为它已经变为一块纯堆内存,跟EXE主模块里申请的堆没有任何差别。
这里讲的一种无模块注入的方法,能够让DLL自身实现这样的功能,无需外部注入工具帮助处理。当然如果进程内自行加载这样的DLL后,也是以无模块DLL形式存在。
注入完成后,进程内找不到注入的模块存在,用Dbgview每5秒可以看到"No Module Thread"消息打印出来,表示无模块DLL内进程的活动
之前这个方法有在看雪发表过,不过没有详细讲,有的同学不是很明白,这里把源码贴出来,加上注释,应该会比较清楚了。
LoadPE.CPP
"No Module Thread"//coded by 燕十二 #include "stdafx.h" #include <stdio.h> //将DLL文件读到内存 BOOL LoadDll2Mem(PVOID &pAllocMem,DWORD &dwMemSize,char* strFileName) { HANDLE hFile = CreateFileA(strFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) { return FALSE; } PVOID pFileBuff = NULL; int nFileSize = GetFileSize(hFile, NULL); if (nFileSize == 0) { return FALSE; } else { pFileBuff = VirtualAlloc(NULL,nFileSize,MEM_COMMIT,PAGE_EXECUTE_READWRITE); } DWORD dwReadSize = 0; if (!ReadFile(hFile, pFileBuff, nFileSize, &dwReadSize, NULL)) { return FALSE; } PVOID pBase = pFileBuff; //判断是否是PE PIMAGE_DOS_HEADER pIDH = (PIMAGE_DOS_HEADER)pFileBuff; if (IMAGE_DOS_SIGNATURE != pIDH->e_magic) { return FALSE; } PIMAGE_NT_HEADERS pINH = (PIMAGE_NT_HEADERS)((ULONG)pFileBuff + pIDH->e_lfanew); if (IMAGE_NT_SIGNATURE != pINH->Signature) { return FALSE; } dwMemSize = nFileSize; pAllocMem = pFileBuff; return TRUE; } //将DLL文件按section信息构建内存,重新对齐填充各section,并自行计算填充导入表 BOOL PELoader(char *lpStaticPEBuff, PVOID& pExecuMem) { long lPESignOffset = *(long *)(lpStaticPEBuff + 0x3c); IMAGE_NT_HEADERS *pINH = (IMAGE_NT_HEADERS *)(lpStaticPEBuff + lPESignOffset); long lImageSize = pINH->OptionalHeader.SizeOfImage; char *lpDynPEBuff = (char *)VirtualAlloc(NULL,lImageSize,MEM_COMMIT,PAGE_EXECUTE_READWRITE); if(lpDynPEBuff == NULL) { return FALSE; } memset(lpDynPEBuff, 0, lImageSize); long lSectionNum = pINH->FileHeader.NumberOfSections; IMAGE_SECTION_HEADER *pISH = (IMAGE_SECTION_HEADER *)((char *)pINH + sizeof(IMAGE_NT_HEADERS)); memcpy(lpDynPEBuff, lpStaticPEBuff, pISH->VirtualAddress); long lFileAlignMask = pINH->OptionalHeader.FileAlignment - 1; long lSectionAlignMask = pINH->OptionalHeader.SectionAlignment - 1; for(int nIndex = 0; nIndex < lSectionNum; nIndex++, pISH++) { memcpy(lpDynPEBuff + pISH->VirtualAddress, lpStaticPEBuff + pISH->PointerToRawData, pISH->SizeOfRawData); } if(pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size > 0) { IMAGE_IMPORT_DESCRIPTOR *pIID = (IMAGE_IMPORT_DESCRIPTOR *)(lpDynPEBuff + pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); for(; pIID->Name != NULL; pIID++) { IMAGE_THUNK_DATA *pITD = (IMAGE_THUNK_DATA *)(lpDynPEBuff + pIID->FirstThunk); char* pLoadName = lpDynPEBuff + pIID->Name; HINSTANCE hInstance = LoadLibrary(pLoadName); if(hInstance == NULL) { VirtualFree(lpDynPEBuff,lImageSize,MEM_DECOMMIT); return FALSE; } for(; pITD->u1.Ordinal != 0; pITD++) { FARPROC fpFun; if(pITD->u1.Ordinal & IMAGE_ORDINAL_FLAG32) { fpFun = GetProcAddress(hInstance, (LPCSTR)(pITD->u1.Ordinal & 0x0000ffff)); } else { IMAGE_IMPORT_BY_NAME * pIIBN = (IMAGE_IMPORT_BY_NAME *)(lpDynPEBuff + pITD->u1.Ordinal); fpFun = GetProcAddress(hInstance, (LPCSTR)pIIBN->Name); } if(fpFun == NULL) { delete lpDynPEBuff; return false; } pITD->u1.Ordinal = (long)fpFun; } } } if(pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size > 0) { IMAGE_BASE_RELOCATION *pIBR = (IMAGE_BASE_RELOCATION *)(lpDynPEBuff + pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); long lDifference = (long)lpDynPEBuff - pINH->OptionalHeader.ImageBase; for(; pIBR->VirtualAddress != 0; ) { char *lpMemPage = lpDynPEBuff + pIBR->VirtualAddress; long lCount = (pIBR->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) >> 1; short int *pRelocationItem = (short int *)((char *)pIBR + sizeof(IMAGE_BASE_RELOCATION)); for(int nIndex = 0; nIndex < lCount; nIndex++) { int nOffset = pRelocationItem[nIndex] & 0x0fff; int nType = pRelocationItem[nIndex] >> 12; if(nType == 3) { *(long *)(lpMemPage + nOffset) += lDifference; } else if(nType == 0) { } } pIBR = (IMAGE_BASE_RELOCATION *)(pRelocationItem + lCount); } } pExecuMem = lpDynPEBuff; return true; } typedef BOOL (WINAPI *DLL_MAIN)( HMODULE hModule,DWORD ul_reason_for_call,LPVOID lpReserved); //通过PE信息获取EP作为入口函数,并运行,这里把dwReaseon设置为NO_MODULE_MARK,保留参数设置为模块的路径 //相当于再次以(hModule,NO_MODULE_MARK,pModuleName)为参数,调用一次原始的DllMain函数 bool CallDllMain(PVOID pExecMem,DWORD dwReaseon,char* pModuleName) { PIMAGE_NT_HEADERS pINH = (PIMAGE_NT_HEADERS)((ULONG)pExecMem + ((PIMAGE_DOS_HEADER)pExecMem)->e_lfanew); DWORD dwEP = pINH->OptionalHeader.AddressOfEntryPoint; DLL_MAIN lpDllMain = (DLL_MAIN)((DWORD)pExecMem + dwEP); lpDllMain((HMODULE)pExecMem,dwReaseon,pModuleName); return TRUE; } BOOL LaunchDll(char *strName,DWORD dwReason) { PVOID pRelocMem = NULL; PVOID pExecuMem = NULL; DWORD dwMemSize = 0; if (LoadDll2Mem(pRelocMem,dwMemSize,strName)) { PELoader((char *)pRelocMem,pExecuMem); CallDllMain(pExecuMem,dwReason,strName); ZeroMemory(pRelocMem,dwMemSize); VirtualFree(pRelocMem,dwMemSize,MEM_DECOMMIT); } return TRUE; }
TestDll.cpp
// TestDll.cpp : Defines the entry point for the DLL application. //Coded by 燕十二 #include "stdafx.h" #include "LoadPE.h" //防止无模块DLL多次注入 BOOL IsMutexExist(char* pstrMutex) { BOOL bRet = FALSE; HANDLE hMutex = NULL; hMutex = CreateMutexA(NULL, TRUE, pstrMutex); if ( hMutex ) { if ( GetLastError() == ERROR_ALREADY_EXISTS ) bRet = TRUE; ReleaseMutex(hMutex); CloseHandle(hMutex); } else { bRet = TRUE; } return bRet; } //调用LoadPE.cpp里的函数,自行处理PE加载,把DLL在新申请的内存加载起来,并执行入口函数 void LaunchNoModule() { LaunchDll(dllModuleName,NO_MODULE_MARK); } unsigned int __stdcall NoModuleThread(void* lpParameter) { while (TRUE) { Sleep(5000); OutputDebugString("No Module Thread"); } return TRUE; } //开启一个线程,调用实际的DLL功能代码 void NoModuleEntryCall(HMODULE hModule, DWORD ul_reason_for_call, char* pstrModuleName) { char szMutexName[MAX_PATH]; wsprintf(szMutexName,"yanshier2013nomoduleinject%d",GetCurrentProcessId()); g_hMutex = CreateMutex(NULL, TRUE, szMutexName); char szLog[MAX_PATH] = {0}; wsprintf(szLog,"NoModuleEntryCall Module Start:%p",hModule); OutputDebugString(szLog); //下面为正常Dll功能代码 CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)NoModuleThread,NULL,NULL,NULL); } BOOL ChooseSub(HMODULE hModule, DWORD ul_reason_for_call, char* pstrModuleName) { BOOL bRet = FALSE; GetModuleFileNameA(NULL, exeModuleName, MAX_PATH); if ( ul_reason_for_call == NO_MODULE_MARK ) strcpy(dllModuleName, pstrModuleName); else GetModuleFileName(hModule, dllModuleName, MAX_PATH); if ( ul_reason_for_call == NO_MODULE_MARK ) { NoModuleEntryCall(hModule, DLL_PROCESS_ATTACH, 0); bRet = TRUE; } else { LaunchNoModule(); bRet = FALSE; } return bRet; } //ul_reason_for_call等于NO_MODULE_MARK时,DllMain已经是在新申请的内存中运行 //DllMain返回值是个很关键的地方,可能平常写DLLMain的时候不会注意到,都是直接返回TRUE,没有去关注FALSE的情况 //ul_reason_for_call等于DLL_PROCESS_ATTACH时,DllMain返回FALSE会使DLL自行卸载 //利用这一点再结合PE自行加载,就可以实现无模块注入了 //当然,这样的DLL,如果由程序内部加载,也是以无模块的形式存在的 BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { BOOL bRet = FALSE; if ( ul_reason_for_call == DLL_PROCESS_ATTACH || ul_reason_for_call == NO_MODULE_MARK ) { char szMutexName[MAX_PATH]; wsprintf(szMutexName,"yanshier2013nomoduleinject%d",GetCurrentProcessId()); if ( IsMutexExist(szMutexName)) return FALSE; bRet = ChooseSub(hModule, ul_reason_for_call, (char *)lpReserved); } else { if ( ul_reason_for_call == DLL_PROCESS_DETACH) { ReleaseMutex(g_hMutex); CloseHandle(g_hMutex); bRet = TRUE; } } return bRet; }
源码下载见附件
本文出自 “燕十二” 博客,请务必保留此出处http://chenjava.blog.51cto.com/374566/1574442
源码解析一种无模块注入进程方法
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。