内存写入

环境:winxp,编译器:vc++

一、

// 内存写入.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <windows.h> #include <malloc.h> #include <stdlib.h> #include <comdef.h> /********************************************************************/ /* */ /*1、获取自身句柄   */ /*2、得到ImageSize的大小,得到模块的ImageBuffer */ /*3、在当前空间申请空间存放自身代码 */ /*4、拷贝自身到缓存 */ /*5、打开要注入的进程 */ /*6、在远程进程申请空间 */ /*7、对模块中的代码进行重定位 */ /*8、得到模块中要运行的函数的地址    */ /*9、将模块在进程中的地址作为参数传递给入口函数    */ /*10、将修正后的模块 通过WriteProcessMemory写入远程进程的内存空间中    */ /*11、通过CreateRemoteThread启动刚写入的代码    */ /*12、释放内存 */ /* */ /********************************************************************/ void EDGSelfWriteMemeory();//出错原因,函数名与系统函数名重合// int main(int argc, char* argv[]) { EDGSelfWriteMemeory(); return 0; } DWORD GetImageSize(DWORD ImBuff) { 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; PIMAGE_DATA_DIRECTORY pDataDirectory =NULL; PIMAGE_IMPORT_DESCRIPTOR pImportDescri = NULL; PIMAGE_IMPORT_BY_NAME pImExortByName = NULL; PIMAGE_IMPORT_BY_NAME pImExortByNameOri = NULL; pDosHeader = (PIMAGE_DOS_HEADER)ImBuff; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)ImBuff+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+4); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER); pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader+pPEHeader->SizeOfOptionalHeader); pDataDirectory = (PIMAGE_DATA_DIRECTORY)((DWORD)pSectionHeader-16*sizeof(IMAGE_DATA_DIRECTORY)); pImportDescri =(PIMAGE_IMPORT_DESCRIPTOR)((DWORD)ImBuff + pDataDirectory[1].VirtualAddress); DWORD LocalImageSize = pOptionHeader->SizeOfImage; return LocalImageSize; } DWORD Correct_Base_Reloc2(IN LPVOID pImageBuffer,IN DWORD Size_of_Bechanged_Image) { 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; DWORD Size_Of_Base_Reloc = 0; if(!pImageBuffer) { free(pImageBuffer); return 0; } if(*(PWORD)(pImageBuffer)!=IMAGE_DOS_SIGNATURE) { free(pImageBuffer); return 0; } pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pImageBuffer+pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader+4); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER); pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader+pPEHeader->SizeOfOptionalHeader); if(*((PDWORD)((DWORD)pImageBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) { printf("不是有效的PE标志\n"); free(pImageBuffer); return 0; } PIMAGE_DATA_DIRECTORY pDataDirectory =NULL; pDataDirectory = (PIMAGE_DATA_DIRECTORY)((DWORD)pSectionHeader-16*sizeof(IMAGE_DATA_DIRECTORY)); PIMAGE_BASE_RELOCATION pBaseReloc =NULL; pBaseReloc = (PIMAGE_BASE_RELOCATION)((DWORD)pImageBuffer + pDataDirectory[5].VirtualAddress); //修改ImageBase// pOptionHeader->ImageBase = pOptionHeader->ImageBase + Size_of_Bechanged_Image; PWORD guodu = NULL; DWORD RVA_MEMBER = 0;int ans = 0; DWORD FOA_MEMBER = 0; DWORD bns = 0; DWORD cns = 0; while(pBaseReloc->SizeOfBlock!=0 &&pBaseReloc->VirtualAddress!=0) { guodu = (PWORD)((DWORD)pBaseReloc + IMAGE_SIZEOF_BASE_RELOCATION); if(pBaseReloc->SizeOfBlock<8) { pBaseReloc = (PIMAGE_BASE_RELOCATION)( (DWORD)pBaseReloc + pBaseReloc->SizeOfBlock );//核心代码// continue; } DWORD NumberOfRelocAddress = (pBaseReloc->SizeOfBlock - 8)/2; for(DWORD i = NumberOfRelocAddress;i>0;i--,guodu++) { DWORD qwq = *guodu>>12; if(qwq !=0) { RVA_MEMBER =(DWORD)(*guodu & 0xFFF) + (DWORD)pBaseReloc->VirtualAddress;//出错原因,偏移出错,原因还是数据类型出错,以后自己要是拿不准,建议全加括号// FOA_MEMBER = RVA_MEMBER; DWORD test = *(PDWORD)((DWORD)pImageBuffer+(DWORD)FOA_MEMBER); *(PDWORD)((DWORD)pImageBuffer+(DWORD)FOA_MEMBER) = *(PDWORD)((DWORD)pImageBuffer+(DWORD)FOA_MEMBER) + Size_of_Bechanged_Image; } } pBaseReloc = (PIMAGE_BASE_RELOCATION)( (DWORD)pBaseReloc + pBaseReloc->SizeOfBlock );//核心代码// } return 1; } DWORD testAddr() { while (TRUE) { MessageBox(NULL, 0, 0, NULL); Sleep(3000); } } DWORD WINAPI ThreadProcCorrectTable(LPVOID lpParam) { //修复导入表// 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; PIMAGE_IMPORT_DESCRIPTOR pIMPORT_DESCRIPTOR = NULL; PIMAGE_IMPORT_BY_NAME pImage_IMPORT_BY_NAME = NULL; PDWORD OriginalFirstThunk = NULL; PDWORD FirstThunk = NULL; PIMAGE_THUNK_DATA pImageThunkData = NULL; DWORD Original = 0; pDosHeader = (PIMAGE_DOS_HEADER)lpParam; pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)lpParam + pDosHeader->e_lfanew); pPEHeader = (PIMAGE_FILE_HEADER)((DWORD)pNTHeader + 4); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)((DWORD)pPEHeader + IMAGE_SIZEOF_FILE_HEADER); //每个导入表的相关信息占20个字节 pIMPORT_DESCRIPTOR = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)lpParam + pOptionHeader->DataDirectory[1].VirtualAddress); DWORD dwFuncAddr = 0; HMODULE hModule; while (pIMPORT_DESCRIPTOR->FirstThunk && pIMPORT_DESCRIPTOR->OriginalFirstThunk) { hModule = LoadLibrary((PCHAR)((DWORD)lpParam + (DWORD)pIMPORT_DESCRIPTOR->Name)); // FirstThunk 指向 IMAGE_THUNK_DATA 结构数组 OriginalFirstThunk = (PDWORD)((DWORD)lpParam + (DWORD)pIMPORT_DESCRIPTOR->OriginalFirstThunk); FirstThunk = (PDWORD)((DWORD)lpParam + (DWORD)pIMPORT_DESCRIPTOR->FirstThunk); while (*OriginalFirstThunk) { if (*OriginalFirstThunk & 0x80000000) { //高位为1 则 除去最高位的值就是函数的导出序号 Original = *OriginalFirstThunk & 0xFFF; //去除最高标志位。 dwFuncAddr = (DWORD)GetProcAddress(hModule, (PCHAR)Original); } else { // MessageBox(0,0,0,0); //高位不为1 则指向IMAGE_IMPORT_BY_NAME; pImage_IMPORT_BY_NAME = (PIMAGE_IMPORT_BY_NAME)((DWORD)lpParam + *OriginalFirstThunk); dwFuncAddr = (DWORD)GetProcAddress(hModule, (PCHAR)pImage_IMPORT_BY_NAME->Name); } *FirstThunk = dwFuncAddr; OriginalFirstThunk++; } pIMPORT_DESCRIPTOR++; } testAddr(); //若远程线程正确执行,那么将弹出MessageBox(0,0,0,0);// return 0; } void EDGSelfWriteMemeory() {//1// DWORD SelfImageBase = (DWORD)GetModuleHandle(NULL); //2// DWORD SelfImageSize = GetImageSize(SelfImageBase); //3////4// PVOID SelfImagebuff = VirtualAlloc(NULL,SelfImageSize,MEM_RESERVE | MEM_COMMIT,PAGE_READWRITE); memcpy(SelfImagebuff,(PVOID)SelfImageBase,SelfImageSize); //5// DWORD PID; printf("请输入要写入进程的16进制的PID,以便获取句柄...\n"); scanf("%x",&PID); HANDLE hProcess;//假定写入到飞鸽里// hProcess = OpenProcess(PROCESS_ALL_ACCESS,false,PID); if(!hProcess) {printf("OpenProcess函数失效,错误码是:%x",GetLastError());return ;} //6//在A进程里申请内存// DWORD OtherExMemAddress = (DWORD)VirtualAllocEx(hProcess,NULL,SelfImageSize,MEM_COMMIT,PAGE_READWRITE); if(!OtherExMemAddress) {printf("OtherExMemAddress 函数失效,错误码是:%x",GetLastError());return ;} DWORD Size_Change =OtherExMemAddress - SelfImageBase; Correct_Base_Reloc2(SelfImagebuff,Size_Change); //10////写入内存// DWORD realMemByte;//接受实际写入的字节数// BOOL ret = WriteProcessMemory(hProcess,(PVOID)OtherExMemAddress,SelfImagebuff,SelfImageSize,&realMemByte); if(!ret) {printf("WriteProcessMemory 函数失效,错误码是:%x",GetLastError());return ;} DWORD FixIATAddr = (DWORD)ThreadProcCorrectTable + OtherExMemAddress - SelfImageBase; //8////9////11//在别的进程中修复IAT表(通过线程来修复)。。。// //出错原因,我第一次是直接传函数的地址,而不是分步传的,这就导致我的重定位表已经修复了我的线程地址// HANDLE hThread = CreateRemoteThread(hProcess,NULL,0,(unsigned long (__stdcall *)(void *))FixIATAddr,(PVOID)OtherExMemAddress,0,&realMemByte);//最后一个参数是一个OUT类型的,无关参数,直接用前面所不使用的变量代替,第六个参数线程创建后立即运行// if (hThread == NULL) { printf("CreateRemoteThreadError,错误码是:%x\n",GetLastError()); return; } //第三个参数线程栈初始大小,以字节为单位,如果该值设为0,那么使用系统默认大小.//第二个参数该结构指定了线程的安全属性.//第四个参数是线程在A进程的地址,所以注意偏移// WaitForSingleObject(hThread, INFINITE); //12//释放远程申请的空间...// VirtualFreeEx(hProcess,(PVOID)OtherExMemAddress,SelfImageSize,MEM_DECOMMIT); CloseHandle(hThread); CloseHandle(hProcess); }

二、

 

 

用飞鸽做的实验...

三、坑点:创建远程线程的时候,注意一下地址的传递要考虑到偏移


__EOF__

本文作者_TLSN
本文链接https://www.cnblogs.com/lordtianqiyi/articles/15664929.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   TLSN  阅读(65)  评论(3编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示