PE文件入门(一)
Shellcode直接注入代码块
使用代码,在文件中将shellcode注入进程序的text节中,也就是代码块中
条件:代码块有足够的空间存下shellcode
思路:获取shellcode的注入位置,然后再通过计算把硬编码应该跳转的地址计算出来 其公式为:要跳转的地址=当前指令的下一条指令地址+5+X——>就可以推出X=要跳转的地址-(当前指令的下一条指令地址+5)
在通过指针将其值修改
在最后修改OEP,并使shellcode最后跳回原来的程序入口
#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<Windows.h> #define SHELLCODELENGTH 0x12 BYTE shellCode[] = { 0x6a,00,0x6a,00,0x6a,00,0x6a,00, 0xe8,00,00,00,00, 0xe9,00,00,00,00 }; PVOID FileToFileBuffer(LPSTR lpszFile) { FILE* file=NULL; PVOID FileBuffer=NULL; size_t FileOfSize=0; file = fopen(lpszFile, "rb+"); if (!file) { printf("文件打开错误"); return NULL; } fseek(file, NULL,SEEK_END); FileOfSize=ftell(file); fseek(file, NULL, SEEK_SET); FileBuffer = malloc(FileOfSize); if (!FileBuffer) { printf("内存分配错误"); fclose(file); return NULL; } if (!fread(FileBuffer, FileOfSize, 1, file)) { printf("文件读取错误"); fclose(file); return NULL; } fclose(file); return FileBuffer; } PVOID FileBufferToMemBuffer(LPVOID FileBuffer) { PVOID MemBuffer = NULL; PIMAGE_DOS_HEADER pFileDosHeader = NULL; PIMAGE_NT_HEADERS pFileNTHeader = NULL; PIMAGE_FILE_HEADER pFilePEHeader = NULL; PIMAGE_OPTIONAL_HEADER pFileOptionHeader = NULL; PIMAGE_SECTION_HEADER pFileSectionHeader = NULL; pFileDosHeader = (PIMAGE_DOS_HEADER)FileBuffer; pFilePEHeader = (PIMAGE_FILE_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4); pFileOptionHeader = (PIMAGE_OPTIONAL_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4 + IMAGE_SIZEOF_FILE_HEADER); pFileSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pFileOptionHeader+ pFilePEHeader->SizeOfOptionalHeader); size_t size = pFileOptionHeader->SizeOfImage; MemBuffer = malloc(size); memset(MemBuffer, 0, size); memcpy(MemBuffer, pFileDosHeader, pFileOptionHeader->SizeOfHeaders); for (int i = 0; i < pFilePEHeader->NumberOfSections; i++) { memcpy((PVOID)((DWORD)MemBuffer + pFileSectionHeader->VirtualAddress), (PVOID)((DWORD)FileBuffer + pFileSectionHeader->PointerToRawData), pFileSectionHeader->Misc.VirtualSize); pFileSectionHeader++; } return MemBuffer; } PVOID MemBufferToFile(LPVOID MemBuffer) { FILE* file=NULL; PVOID FileBuffer = NULL; PIMAGE_DOS_HEADER pFileDosHeader = NULL; PIMAGE_NT_HEADERS pFileNTHeader = NULL; PIMAGE_FILE_HEADER pFilePEHeader = NULL; PIMAGE_OPTIONAL_HEADER pFileOptionHeader = NULL; PIMAGE_SECTION_HEADER pFileSectionHeader = NULL; file = fopen("cpyj.exe", "wb+"); pFileDosHeader = (PIMAGE_DOS_HEADER)MemBuffer; pFilePEHeader = (PIMAGE_FILE_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4); pFileOptionHeader = (PIMAGE_OPTIONAL_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4 + IMAGE_SIZEOF_FILE_HEADER); pFileSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pFileOptionHeader + pFilePEHeader->SizeOfOptionalHeader); size_t size = pFileOptionHeader->SizeOfHeaders; for (int i = 0; i < pFilePEHeader->NumberOfSections; i++) { size += pFileSectionHeader->SizeOfRawData; pFileSectionHeader++; } pFileSectionHeader= (PIMAGE_SECTION_HEADER)((DWORD)pFileOptionHeader + pFilePEHeader->SizeOfOptionalHeader); FileBuffer = malloc(size); memset(FileBuffer, 0, size); memcpy(FileBuffer, MemBuffer, pFileOptionHeader->SizeOfHeaders); for (int i = 0; i < pFilePEHeader->NumberOfSections; i++) { memcpy((PVOID)((DWORD)FileBuffer+pFileSectionHeader->PointerToRawData), (PVOID)((DWORD)MemBuffer + pFileSectionHeader->VirtualAddress), pFileSectionHeader->SizeOfRawData); pFileSectionHeader++; } fwrite(FileBuffer, size, 1, file); return FileBuffer; } PVOID TestAddCodeInCodeSec(LPVOID ImageBuffer) { HMODULE AddressOfDll = GetModuleHandle((LPCWSTR)"user32.dll");//这里本机代码我没有求出来,所以messagebox传出来的值为NULL,所以什么都没变 FARPROC AddressOfMessage = GetProcAddress(AddressOfDll, (LPCSTR)"MessageBox"); PIMAGE_DOS_HEADER pFileDosHeader = NULL; PIMAGE_NT_HEADERS pFileNTHeader = NULL; PIMAGE_FILE_HEADER pFilePEHeader = NULL; PIMAGE_OPTIONAL_HEADER pFileOptionHeader = NULL; PIMAGE_SECTION_HEADER pFileSectionHeader = NULL; pFileDosHeader = (PIMAGE_DOS_HEADER)ImageBuffer; pFilePEHeader = (PIMAGE_FILE_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4); pFileOptionHeader = (PIMAGE_OPTIONAL_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4 + IMAGE_SIZEOF_FILE_HEADER); pFileSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pFileOptionHeader + pFilePEHeader->SizeOfOptionalHeader); if (((pFileSectionHeader->SizeOfRawData) - (pFileSectionHeader->Misc.VirtualSize)) < SHELLCODELENGTH) { printf("代码区空间不够"); return NULL; } PVOID codeBegin = (PBYTE)((pFileOptionHeader->SizeOfHeaders) + (DWORD)ImageBuffer + pFileSectionHeader->Misc.VirtualSize); memcpy(codeBegin, shellCode, SHELLCODELENGTH); //修正E8 DWORD callAddr = ((DWORD)AddressOfMessage - (pFileOptionHeader->ImageBase + (DWORD)codeBegin + 0xD) + (DWORD)ImageBuffer); *(PDWORD)((DWORD)codeBegin + 9) = callAddr; //修正E9 DWORD jmpAddr = (pFileOptionHeader->AddressOfEntryPoint+pFileOptionHeader->ImageBase-(pFileOptionHeader->ImageBase + SHELLCODELENGTH) + (DWORD)ImageBuffer); *(PDWORD)((DWORD)codeBegin + 0xE) = jmpAddr; //修改OEP pFileOptionHeader->AddressOfEntryPoint = (DWORD)codeBegin - (DWORD)ImageBuffer; MemBufferToFile(ImageBuffer); } VOID TestAddSection() { } int main() { LPSTR lpszFile = (LPSTR)"pe.exe"; PVOID FileBuffer = FileToFileBuffer(lpszFile); PVOID MemBuffer=FileBufferToMemBuffer(FileBuffer); TestAddCodeInCodeSec(MemBuffer); }
上面条件不成立的话,可以通过扩展节来进行注入和跳转,请看下面
通过扩展节来向程序注入shellcode
使用代码,在文件中先增加一个节在,将shellcode注入进我们自己创建的节中
条件:当代码节不够空闲块时,就用此方法(还有一种情况,当不够空闲块的时候,由于DOS头下面有一部分没有用的垃圾数据,所以可以把PE整个头上移,并修改DOS头的flnew成员,其他的修改一致)
思路:在程序最后一个节后面添加字节,因为如果添加到前面,需要改变节表里的多个值,然后在修改节表里的值,也就是在节表后面新增一个SectionHeader,Name8个字节随便设,并用character与text节处的character进行或运算,在修改文件大小和内存大小为相等(这样可以省去一些写入步骤)和偏移地址,在设置标准头里的SizeOfSections,在设置SizeOfImage, 获取shellcode的注入位置,然后再通过计算把硬编码应该跳转的地址计算出来 其公式为:要跳转的地址=当前指令的下一条指令地址+5+X——>就可以推出X=要跳转的地址-(当前指令的下一条指令地址+5)
在通过指针将其值修改
在最后修改OEP,并使shellcode最后跳回原来的程序入口
#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<Windows.h> #define SHELLCODELENGTH 0x12 BYTE shellCode[] = { 0x6a,00,0x6a,00,0x6a,00,0x6a,00, 0xe8,00,00,00,00, 0xe9,00,00,00,00 }; PVOID FileToFileBuffer(LPSTR lpszFile) { FILE* file=NULL; PVOID FileBuffer=NULL; size_t FileOfSize=0; file = fopen(lpszFile, "rb+"); if (!file) { printf("文件打开错误"); return NULL; } fseek(file, NULL,SEEK_END); FileOfSize=ftell(file); fseek(file, NULL, SEEK_SET); FileBuffer = malloc(FileOfSize); if (!FileBuffer) { printf("内存分配错误"); fclose(file); return NULL; } if (!fread(FileBuffer, FileOfSize, 1, file)) { printf("文件读取错误"); fclose(file); return NULL; } fclose(file); return FileBuffer; } PVOID FileBufferToMemBuffer(LPVOID FileBuffer) { PVOID MemBuffer = NULL; PIMAGE_DOS_HEADER pFileDosHeader = NULL; PIMAGE_NT_HEADERS pFileNTHeader = NULL; PIMAGE_FILE_HEADER pFilePEHeader = NULL; PIMAGE_OPTIONAL_HEADER pFileOptionHeader = NULL; PIMAGE_SECTION_HEADER pFileSectionHeader = NULL; pFileDosHeader = (PIMAGE_DOS_HEADER)FileBuffer; pFilePEHeader = (PIMAGE_FILE_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4); pFileOptionHeader = (PIMAGE_OPTIONAL_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4 + IMAGE_SIZEOF_FILE_HEADER); pFileSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pFileOptionHeader+ pFilePEHeader->SizeOfOptionalHeader); size_t size = pFileOptionHeader->SizeOfImage; MemBuffer = malloc(size); memset(MemBuffer, 0, size); memcpy(MemBuffer, pFileDosHeader, pFileOptionHeader->SizeOfHeaders); for (int i = 0; i < pFilePEHeader->NumberOfSections; i++) { memcpy((PVOID)((DWORD)MemBuffer + pFileSectionHeader->VirtualAddress), (PVOID)((DWORD)FileBuffer + pFileSectionHeader->PointerToRawData), pFileSectionHeader->Misc.VirtualSize); pFileSectionHeader++; } return MemBuffer; } PVOID MemBufferToFile(LPVOID MemBuffer) { FILE* file=NULL; PVOID FileBuffer = NULL; PIMAGE_DOS_HEADER pFileDosHeader = NULL; PIMAGE_NT_HEADERS pFileNTHeader = NULL; PIMAGE_FILE_HEADER pFilePEHeader = NULL; PIMAGE_OPTIONAL_HEADER pFileOptionHeader = NULL; PIMAGE_SECTION_HEADER pFileSectionHeader = NULL; file = fopen("cpyj.exe", "wb+"); pFileDosHeader = (PIMAGE_DOS_HEADER)MemBuffer; pFilePEHeader = (PIMAGE_FILE_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4); pFileOptionHeader = (PIMAGE_OPTIONAL_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4 + IMAGE_SIZEOF_FILE_HEADER); pFileSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pFileOptionHeader + pFilePEHeader->SizeOfOptionalHeader); size_t size = pFileOptionHeader->SizeOfHeaders; for (int i = 0; i < pFilePEHeader->NumberOfSections; i++) { size += pFileSectionHeader->SizeOfRawData; pFileSectionHeader++; } pFileSectionHeader= (PIMAGE_SECTION_HEADER)((DWORD)pFileOptionHeader + pFilePEHeader->SizeOfOptionalHeader); FileBuffer = malloc(size); memset(FileBuffer, 0, size); memcpy(FileBuffer, MemBuffer, pFileOptionHeader->SizeOfHeaders); for (int i = 0; i < pFilePEHeader->NumberOfSections; i++) { memcpy((PVOID)((DWORD)FileBuffer+pFileSectionHeader->PointerToRawData), (PVOID)((DWORD)MemBuffer + pFileSectionHeader->VirtualAddress), pFileSectionHeader->SizeOfRawData); pFileSectionHeader++; } fwrite(FileBuffer, size, 1, file); return FileBuffer; } PVOID TestAddCodeInCodeSec(LPVOID ImageBuffer) { HMODULE AddressOfDll = GetModuleHandle((LPCWSTR)"user32.dll"); FARPROC AddressOfMessage = GetProcAddress(AddressOfDll, (LPCSTR)"MessageBox"); PIMAGE_DOS_HEADER pFileDosHeader = NULL; PIMAGE_NT_HEADERS pFileNTHeader = NULL; PIMAGE_FILE_HEADER pFilePEHeader = NULL; PIMAGE_OPTIONAL_HEADER pFileOptionHeader = NULL; PIMAGE_SECTION_HEADER pFileSectionHeader = NULL; pFileDosHeader = (PIMAGE_DOS_HEADER)ImageBuffer; pFilePEHeader = (PIMAGE_FILE_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4); pFileOptionHeader = (PIMAGE_OPTIONAL_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4 + IMAGE_SIZEOF_FILE_HEADER); pFileSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pFileOptionHeader + pFilePEHeader->SizeOfOptionalHeader); if (((pFileSectionHeader->SizeOfRawData) - (pFileSectionHeader->Misc.VirtualSize)) < SHELLCODELENGTH) { printf("代码区空间不够"); return NULL; } PVOID codeBegin = (PBYTE)((pFileOptionHeader->SizeOfHeaders) + (DWORD)ImageBuffer + pFileSectionHeader->Misc.VirtualSize); memcpy(codeBegin, shellCode, SHELLCODELENGTH); //修正E8 DWORD callAddr = ((DWORD)AddressOfMessage - (pFileOptionHeader->ImageBase + ((DWORD)((DWORD)codeBegin + 0xD) - (DWORD)ImageBuffer))); *(PDWORD)((DWORD)codeBegin + 9) = callAddr; //修正E9 DWORD jmpAddr = (pFileOptionHeader->AddressOfEntryPoint+pFileOptionHeader->ImageBase-(pFileOptionHeader->ImageBase + SHELLCODELENGTH) + (DWORD)ImageBuffer); *(PDWORD)((DWORD)codeBegin + 0xE) = jmpAddr; //修改OEP pFileOptionHeader->AddressOfEntryPoint = (DWORD)codeBegin - (DWORD)ImageBuffer; MemBufferToFile(ImageBuffer); } VOID TestAddSection(LPSTR path) { PVOID FileBuffer = FileToFileBuffer(path); PVOID MemBuffer = NULL; PIMAGE_DOS_HEADER pFileDosHeader = NULL; PIMAGE_NT_HEADERS pFileNTHeader = NULL; PIMAGE_FILE_HEADER pFilePEHeader = NULL; PIMAGE_OPTIONAL_HEADER pFileOptionHeader = NULL; PIMAGE_SECTION_HEADER pFileSectionHeader = NULL; pFileDosHeader = (PIMAGE_DOS_HEADER)FileBuffer; pFilePEHeader = (PIMAGE_FILE_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4); pFileOptionHeader = (PIMAGE_OPTIONAL_HEADER)(pFileDosHeader->e_lfanew + (DWORD)pFileDosHeader + 4 + IMAGE_SIZEOF_FILE_HEADER); pFileSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pFileOptionHeader + pFilePEHeader->SizeOfOptionalHeader); size_t Addsize=pFileOptionHeader->SectionAlignment; pFileOptionHeader->SizeOfImage += Addsize; PIMAGE_SECTION_HEADER AddSectionHeader= pFileSectionHeader + pFilePEHeader->NumberOfSections; AddSectionHeader->SizeOfRawData=AddSectionHeader->Misc.VirtualSize = Addsize; AddSectionHeader->PointerToRawData = ((PIMAGE_SECTION_HEADER)((DWORD)AddSectionHeader - 40))->PointerToRawData + ((PIMAGE_SECTION_HEADER)((DWORD)AddSectionHeader - 40))->SizeOfRawData; AddSectionHeader->VirtualAddress = ((PIMAGE_SECTION_HEADER)((DWORD)AddSectionHeader - 40))->VirtualAddress + (((PIMAGE_SECTION_HEADER)((DWORD)AddSectionHeader - 40))->Misc.VirtualSize/pFileOptionHeader->SectionAlignment+1)* pFileOptionHeader->SectionAlignment; AddSectionHeader->Characteristics |= pFileSectionHeader->Characteristics; AddSectionHeader->Name[0] = '.'; AddSectionHeader->Name[1] = 't'; AddSectionHeader->Name[2] = 't'; AddSectionHeader->Name[3] = 't'; AddSectionHeader->Name[4] = 't'; pFilePEHeader->NumberOfSections++; MemBuffer = malloc(pFileOptionHeader->SizeOfImage); memset(MemBuffer, 0, pFileOptionHeader->SizeOfImage); memcpy(MemBuffer, FileBuffer, pFileOptionHeader->SizeOfHeaders); for (int i = 0; i < pFilePEHeader->NumberOfSections; i++) { memcpy((PVOID)((DWORD)MemBuffer + pFileSectionHeader->VirtualAddress), (PVOID)((DWORD)FileBuffer + pFileSectionHeader->PointerToRawData), pFileSectionHeader->Misc.VirtualSize); pFileSectionHeader++; } MemBufferToFile(MemBuffer); return; } int main() { LPSTR lpszFile = (LPSTR)"pe.exe"; PVOID FileBuffer = FileToFileBuffer(lpszFile); PVOID MemBuffer=FileBufferToMemBuffer(FileBuffer); TestAddSection(lpszFile); }
如果上面两种情况都不适用,那么可以扩大节
通过扩大节来注入shellcode
使用代码扩大最后一个节
条件:暂时不清楚
思路:在最后一个节里加上一段内存,并且修改sizeofimage和sectionheader里的文件大小和内存大小全部修改,建议修改为一样的。即可
代码跟上面这种方法差不多
还有一种方法合并节
顾名思义就是将所有的节合并为一个节
思路:把多个节合并为一个,需要修改的值为:sectionheader,内存大小,和文件大小,NumberOfSections需要修改
需要注意的是文件对齐
代码先咕一下等基本的PE干了,在过来一次添加上