隐藏模块(无模块注入)实现
// memoryLoad.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "stdlib.h"
#include "PeTools.h"
DWORD WINAPI InjectEntry(LPVOID lpParam)
{
//RepairIAT(lpParam);
//定义PE头的信息
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
if(!lpParam)
{
printf("读取到内存的pfilebuffer无效!\n");
return 0;
}
//判断是不是exe文件
if(*((PWORD)lpParam) != IMAGE_DOS_SIGNATURE)
{
printf("不含MZ标志,不是exe文件!\n");
return 0;
}
pDosHeader = (PIMAGE_DOS_HEADER)lpParam;
if(*((PDWORD)((BYTE *)lpParam + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE){
printf("无有效的PE标志\n");
return 0;
}
//读取pFileBuffer 获取DOS头,PE头,节表等信息
pDosHeader =(PIMAGE_DOS_HEADER)lpParam;
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)lpParam + pDosHeader->e_lfanew);
//打印NT头
pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4); //加4个字节到了标准PE头
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); //标准PE头+标准PE头的大小 20
//1000
PIMAGE_IMPORT_DESCRIPTOR ImportExtable = (PIMAGE_IMPORT_DESCRIPTOR)((char*)lpParam + pOptionHeader->DataDirectory[1].VirtualAddress);
DbgPrintf("%x",ImportExtable->FirstThunk);
while(ImportExtable->OriginalFirstThunk !=0 && ImportExtable->FirstThunk !=0){
char *DllName =(char*)lpParam + ImportExtable->Name;
DbgPrintf("加载的DLL名称:%s\n",DllName);
//这个时候的INT表已经找不到函数了,要先遍历INT表找到序号和名称,然后利用LoadLibrary获取函数的地址然后修复
DWORD* pThunkData_INT = (DWORD*)((char*)lpParam + ImportExtable->OriginalFirstThunk);
DWORD* pThunkData_IAT = (PDWORD)(((PBYTE)lpParam + ImportExtable->FirstThunk));
while(*pThunkData_INT){
if (*pThunkData_INT & 0x80000000)
{
DbgPrintf("按序号导入序号%x\n",(*pThunkData_INT & 0xFFFF));
(*pThunkData_IAT) = (DWORD)GetProcAddress(LoadLibrary(DllName),(char*)(*pThunkData_INT & 0xFFFF));
printf("--%x\n",*pThunkData_IAT);
}else{
PIMAGE_IMPORT_BY_NAME FirstThunkNames = (_IMAGE_IMPORT_BY_NAME*)((char*)lpParam + *pThunkData_INT);
DbgPrintf("按名称导入HIT/NAME-%x-%s\n",FirstThunkNames->Hint,FirstThunkNames->Name);
(*pThunkData_IAT) = (DWORD)GetProcAddress(LoadLibrary(DllName),(char*)FirstThunkNames->Name);
DbgPrintf("--%x\n",*pThunkData_IAT);
}
pThunkData_IAT++,pThunkData_INT++;
}
ImportExtable = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)ImportExtable+sizeof(IMAGE_IMPORT_DESCRIPTOR));
}
while (TRUE)
{
MessageBoxA(0,TEXT("注入成功"),0,0);
Sleep(10000);
}
return 0;
}
BOOL EnableDebugPrivilege()
{
HANDLE hToken;
BOOL fOk=FALSE;
if(OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&hToken))
{
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount=1;
LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&tp.Privileges[0].Luid);
tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken,FALSE,&tp,sizeof(tp),NULL,NULL);
fOk=(GetLastError()==ERROR_SUCCESS);
CloseHandle(hToken);
}
return fOk;
}
int main(int argc, char* argv[])
{
//1、获取自身句柄
EnableDebugPrivilege();
HMODULE pImageBuffer = GetModuleHandle(NULL);
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + pDosHeader->e_lfanew);
PIMAGE_FILE_HEADER pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pDosHeader + pDosHeader->e_lfanew + 4);
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + sizeof(IMAGE_FILE_HEADER));
//获取自身sizeofimage
DWORD sizeOfImage = pOptionHeader->SizeOfImage;
//3、在当前空间申请空间存放自身代码
LPVOID pNewImagebuffer = malloc(sizeOfImage);
//4、拷贝自身到缓存
memset(pNewImagebuffer, 0, sizeOfImage);
memcpy(pNewImagebuffer, pImageBuffer, sizeOfImage);
//5、打开要注入的进程
//先获取进程句柄
DWORD pid = 0;
printf("PID:");
scanf("%d", &pid);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid); //参数一,选择所有权限,参数二,不继承给false,参数三,给我们上面获得的pid的值
if(NULL == hProcess)
{
printf("打开进程失败\n");
return 0;
}
//6、在远程进程申请空间
LPVOID pImageBase = VirtualAllocEx(hProcess, NULL, sizeOfImage, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (!pImageBase)
{
printf("申请内存失败!\n");
return false;
}
//7、对模块中的代码进行重定位
RestoreRelocation(pNewImagebuffer,(DWORD)pImageBase);
//8、得到模块中要运行的函数的地址
//9、将模块在进程中的地址作为参数传递给入口函数
//10、将修正后的模块 通过WriteProcessMemory写入远程进程的内存空间中
DWORD byteWritten = 0;
BOOL Write = WriteProcessMemory(hProcess, pImageBase, pNewImagebuffer, sizeOfImage, &byteWritten);
if (!Write)
{
printf("can not write process memory!");
return -1;
}
DWORD dwProcOffset = (DWORD)InjectEntry - (DWORD)pImageBuffer + (DWORD)pImageBase;
//11、通过CreateRemoteThread启动刚写入的代码
//创建行程线程,执行相应函数.
HANDLE pThread = CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)dwProcOffset, pImageBase, NULL, NULL);
WaitForSingleObject(pThread, -1);
//12、释放内存
return 0;
}
重定位表修复代码:
void RestoreRelocation(IN LPVOID pImageBuffer, IN DWORD newImageBase){
//定义PE头的信息
PIMAGE_DOS_HEADER pDosHeader = NULL;
PIMAGE_NT_HEADERS pNTHeader = NULL;
PIMAGE_FILE_HEADER pPEHeader = NULL;
PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
LPVOID pTempBuffer = NULL;
bool Ssize = false;
if(!pImageBuffer)
{
printf("读取到内存的pfilebuffer无效!\n");
return;
}
//判断是不是exe文件
if(*((PWORD)pImageBuffer) != IMAGE_DOS_SIGNATURE)
{
printf("不含MZ标志,不是exe文件!\n");
return;
}
pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer;
if(*((PDWORD)((BYTE *)pImageBuffer + pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE){
printf("无有效的PE标志\n");
return;
}
//读取pFileBuffer 获取DOS头,PE头,节表等信息
pDosHeader =(PIMAGE_DOS_HEADER)pImageBuffer;
pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer + pDosHeader->e_lfanew);
//打印NT头
pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pNTHeader) + 4); //加4个字节到了标准PE头
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); //标准PE头+标准PE头的大小 20
pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + pPEHeader->SizeOfOptionalHeader);
DWORD oldImagebase = pOptionHeader->ImageBase;
pOptionHeader->ImageBase = newImageBase;
//定位重定位表
PIMAGE_BASE_RELOCATION ReloCation = (_IMAGE_BASE_RELOCATION*)((char*)pImageBuffer + pOptionHeader->DataDirectory[5].VirtualAddress);
PWORD pItem; //重定向表块中的项指针,2字节不断移动
int NumberOfItems; //重定向表一块中的项数
//这里pRelocationTable已经是当前绝对地址了
while (ReloCation->VirtualAddress && ReloCation->SizeOfBlock)
{
NumberOfItems = (ReloCation->SizeOfBlock - 8) / 2;
pItem = (PWORD)((DWORD)ReloCation + 8); //这里取出来的是还没加上重定向块中的VirtualAddress的Rva
for (int j = 0; j < NumberOfItems; j++)
{
WORD* offset = (WORD*)((char*)ReloCation+8+2*j); //每个数据项的地址
if (*offset >= 0x3000)
{
//低12位加上x就是要修改的地方
PDWORD RVA = (PDWORD)((DWORD)pImageBuffer + (ReloCation->VirtualAddress + (*offset-0x3000))); //变为FOA再变为绝对地址才能找到真正的值
*RVA = *RVA - oldImagebase + pOptionHeader->ImageBase;
}
}
ReloCation = (PIMAGE_BASE_RELOCATION)(ReloCation->SizeOfBlock + (DWORD)ReloCation);
}
}
stdafx.h
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#if !defined(AFX_STDAFX_H__A359ADEE_2268_4545_9688_6E6BB264B3B3__INCLUDED_)
#define AFX_STDAFX_H__A359ADEE_2268_4545_9688_6E6BB264B3B3__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#include
#include
#include
#include
void __cdecl OutputDebugStringF(const char *format, ...);
#ifdef _DEBUG
#define DbgPrintf OutputDebugStringF
#else
#define DbgPrintf
#endif
void __cdecl OutputDebugStringF(const char *format, ...)
{
va_list vlArgs;
char *strBuffer = (char*)GlobalAlloc(GPTR, 4096);
va_start(vlArgs, format);
_vsnprintf(strBuffer, 4096 - 1, format, vlArgs);
va_end(vlArgs);
strcat(strBuffer, "\n");
OutputDebugStringA(strBuffer);
GlobalFree(strBuffer);
return;
}
// TODO: reference additional headers your program requires here
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__A359ADEE_2268_4545_9688_6E6BB264B3B3__INCLUDED_)
petools.h可以删除,最终实现效果;