c++檔案複製 (部分)
阿新 • • 發佈:2018-12-13
// FileToImage.cpp: implementation of the FileToImage class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "FileToImage.h" ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// #include <windows.h> #include <winnt.h> #include <malloc.h> #define FILEPATH_IN "E:\\達人\\Jmp\\Debug\\Jmp.exe" #define FILEPATH_OUT "E:\\達人\\Jmp\\Debug\\NewJmp.exe" #define SHELLCODELENGTH 0x12 #define MESSAGEBOXADDR 0x00401066 //宣告全域性變數 extern BYTE shellCode[] = { 0x6A,00,0x6A,00,0x6A,00,0x6A,00, 0xE8,00,00,00,00, 0xE9,00,00,00,00 }; //檔案寫入記憶體開始 int FileLength(FILE* fp) { int fileSize = 0; fseek(fp,0,SEEK_END); fileSize = ftell(fp); fseek(fp,0,SEEK_SET); //指標歸位 return fileSize; } //建立一個函式 //兩個引數 檔案路徑,返回的檔案地址 DWORD ReadPEFile(IN LPSTR lpszFile,OUT LPVOID* PFileBuffer) { FILE* pFile = NULL; //檔案指標 DWORD fileSize = 0; //檔案大小 LPVOID pTempFileBuffer = NULL; //malloc 返回指標(緩衝區指標) //開啟檔案 pFile = fopen(lpszFile,"rb+"); //開啟失敗返回 if(!pFile) { printf("無法開啟 EXE 檔案"); return 0; } //讀取檔案大小 FileLength(pFile); //分配緩衝空間 pTempFileBuffer = malloc(fileSize); //失敗返回方法 if(!pTempFileBuffer) { printf("緩衝區分配失敗"); fclose(pFile); //關閉檔案指標 return 0; } //將緩衝器分配好之後,將檔案資料讀取到緩衝區 size_t n = fread(pTempFileBuffer,fileSize,1,pFile); //size_t = unsigned int fread(分配好的地址*,讀取次數,每次讀取大小,檔案地址*) //失敗返回 if(!n) { printf("讀取資料失敗\n"); free(pTempFileBuffer); //釋放分配好的記憶體 fclose(pFile); //關閉檔案指標 return 0; } //關閉檔案 *PFileBuffer = pTempFileBuffer; //將檔案記憶體地址 賦值 給OUT引數 pTempFileBuffer = NULL; //指標清空 free(pFile); //釋放檔案指標 return fileSize; //返回檔案大小 //檔案讀入記憶體結束 } /** FileBuffer 複製到 ImageBuffer 兩個引數 IN LPVOIE FileBuffer指標, OUT LPVOID* ImageBuffer */ DWORD CopyfFileBufferToImageBuffer(IN LPVOID pFileBuffer,OUT LPVOID* pImageBuffer) { //PE PIMAGE_DOS_HEADER pDosHeader = NULL; //DOS頭 PIMAGE_NT_HEADERS pNTHeader = NULL; //NT頭 PIMAGE_FILE_HEADER pPEHeader = NULL; //標準PE頭 PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL; //可選PE頭 PIMAGE_SECTION_HEADER pSectionHeader = NULL; //節表 LPVOID pTempImageBuffer = NULL; //ImageBudder 臨時指標 //判斷傳入的緩衝區指標是否有效 if(!pFileBuffer) { printf("緩衝區指標無效"); return 0; } //判斷指標內容是否合法 if(*((PWORD)pFileBuffer) != IMAGE_DOS_SIGNATURE) { printf("不是有效的MZ標記指標"); return 0; } //將傳入的 FileBuffer 賦值給 pDosHeader pDosHeader = (PIMAGE_DOS_HEADER)pFileBuffer; //判斷是否是有效的PE頭 if(*((PDWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew)) != IMAGE_NT_SIGNATURE) { printf("不是有效的PE標誌\n"); return 0; } //眾頭歸位 pNTHeader = (PIMAGE_NT_HEADERS)((DWORD)pFileBuffer+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); //申請空間 pTempImageBuffer = malloc(pOptionHeader->SizeOfImage+0x1000); //判斷是否申請成功 if(!pTempImageBuffer) { printf("空間申請失敗\n"); return 0; } //初始化新的緩衝區 memset(pTempImageBuffer,0,pOptionHeader->SizeOfImage); //根據SizeOfHeaders 先複製頭 memcpy(pTempImageBuffer,pDosHeader,pOptionHeader->SizeOfHeaders); //再for迴圈 複製節 PIMAGE_SECTION_HEADER ptempSectionHeader = pSectionHeader; //節表臨時地址 for(int i=0;i<pPEHeader->NumberOfSections;i++,ptempSectionHeader++) { memcpy((void*)((DWORD)pTempImageBuffer+ptempSectionHeader->VirtualAddress),(void*)((DWORD)pDosHeader+ptempSectionHeader->PointerToRawData),ptempSectionHeader->SizeOfRawData); } //返回引數 ImageBuffer 地址指標 *pImageBuffer = pTempImageBuffer; pTempImageBuffer = NULL; //返回檔案拉伸後大小 return pOptionHeader->SizeOfImage; } /** ImageBuffer 複製到 FileBuffer 兩個傳入引數 IN LPSTR FileBuffer指標, OUT LPVOID* ImageBuffer 一個傳出引數 PFileBuffer 檔案路徑 */ DWORD CopyImageBufferToFileBuffer(IN LPVOID pImageBuffer,OUT LPVOID* pFileBuffer) { PIMAGE_DOS_HEADER pDosHeader = NULL; //DOS頭 PIMAGE_NT_HEADERS pNTHeader = NULL; //NT頭 PIMAGE_FILE_HEADER pPEHeader = NULL; //PE頭 PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL; //可選PE頭 PIMAGE_SECTION_HEADER pSectionHeader = NULL; //節表部分 LPVOID pTempFileBuffer = NULL; //TempFileBuffer //檔案記憶體地址的合法性 if(!pImageBuffer) { printf("檔案的記憶體地址不正確\n"); return 0; } //判斷是否為可執行檔案 if(*((PWORD)pImageBuffer)!=IMAGE_DOS_SIGNATURE) { printf("不是標準的MZ檔案\n"); return 0; } //是否為標準PE頭 pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer; if(*(((PDWORD)pImageBuffer+pDosHeader->e_lfanew))!=IMAGE_NT_SIGNATURE) { printf("不是標準的PE檔案\n"); return 0; } //眾頭歸位 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); //分配空間 FILE* fp = fopen(FILEPATH_IN,"rb+"); pTempFileBuffer = malloc(FileLength(fp)); //檔案臨時地址使用 if(!pTempFileBuffer) { printf("TempFileBuffer 空間分配失敗\n"); return 0; } //初始化空間 memset(pTempFileBuffer,0,pOptionHeader->SizeOfImage); //頭部轉移 memcpy(pTempFileBuffer,pDosHeader,pOptionHeader->SizeOfHeaders); //節內容轉移 PIMAGE_SECTION_HEADER pTempSectionHeader = pSectionHeader; for(int z=0;z<pPEHeader->NumberOfSections;z++,pTempSectionHeader++) { memcpy((void*)((DWORD)pTempFileBuffer+pTempSectionHeader->PointerToRawData),(void*)((DWORD)pImageBuffer+pTempSectionHeader->VirtualAddress),pTempSectionHeader->SizeOfRawData); } //返回FileBuffer地址 *pFileBuffer = pTempFileBuffer; pTempFileBuffer = NULL; free(fp); //返回檔案大小 return pOptionHeader->SizeOfImage; } //存檔 將資料寫入檔案 /* 檔案FileBuffer,檔案路徑 */ BOOL WriteToFile(IN LPVOID pFileBuffer,IN LPSTR FilePath) { FILE* fp = NULL; //引數合理化 if(!pFileBuffer) { printf("緩衝區檔案有誤\n"); return 0; } if(!FilePath) { printf("檔案路徑有問題\n"); return 0; } //建立一個二進位制檔案 fp = fopen(FilePath,"Wb"); //判斷二進位制檔案是否建立 if(!fp) { printf("檔案建立失敗\n"); return 0; } //存入檔案 int Size_File = FileLength(fp); size_t x = fwrite(pFileBuffer,Size_File,1,fp); //判斷檔案是否寫入 if(!x) { printf("檔案寫入失敗\n"); return 0; } //初始化 free(fp); return 1; } //空白區新增程式碼 VOID TestAddCodeInCodeSec() { LPVOID NewFileBuffer = NULL; LPVOID pFileBuffer = NULL; //檔案地址 LPVOID pImageBuffer = NULL; //記憶體地址 LPVOID pNewBuffer = NULL; //新地址 PIMAGE_DOS_HEADER pDosHeader = NULL; //Dos頭地址 PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL; //可選PE頭地址 PIMAGE_SECTION_HEADER pSectionHeader = NULL; //節表位置 PBYTE codeBegin = NULL; //新增程式碼開始位置 BOOL isOK = FALSE; //判斷 DWORD size = 0; //大小 //file --> FileBuffer ReadPEFile(FILEPATH_IN,&pFileBuffer); if(!pFileBuffer) { printf("檔案-->緩衝區失敗"); return ; } //FileBuffer --> ImageBuffer CopyfFileBufferToImageBuffer(pFileBuffer,&pImageBuffer); if(!pImageBuffer) { printf("FileBuffer-->ImageBuffer 失敗"); free(pFileBuffer); return ; } //判斷是否有在足夠的緩衝區 pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer; //可選PE頭 pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pImageBuffer + pDosHeader->e_lfanew)+4+IMAGE_SIZEOF_FILE_HEADER); //節表 pSectionHeader = (PIMAGE_SECTION_HEADER)(((DWORD)pImageBuffer+pDosHeader->e_lfanew)+4+IMAGE_SIZEOF_FILE_HEADER+IMAGE_SIZEOF_NT_OPTIONAL32_HEADER); //判斷 //檔案拉伸後大小 - Misc大小 < 新增的程式碼大小 if(((pSectionHeader->SizeOfRawData)-(pSectionHeader->Misc.VirtualSize)) < SHELLCODELENGTH){ printf("檔案位置不夠\n"); free(pFileBuffer); free(pImageBuffer); } //程式碼複製 codeBegin = (PBYTE)(DWORD)pImageBuffer + pSectionHeader->VirtualAddress+pSectionHeader->SizeOfRawData; memcpy(codeBegin,shellCode,SHELLCODELENGTH); //修正E8 //有三張圖 file image runImage DWORD callAddr = (MESSAGEBOXADDR - (pOptionHeader->ImageBase+((DWORD)codeBegin+0xD - (DWORD)pImageBuffer))); *(PDWORD)(codeBegin+0x9) = callAddr; //把這個值賦給 codeBegin+0x9位置 //修正E9 DWORD JmpAddr = ((pOptionHeader->ImageBase + pOptionHeader->AddressOfEntryPoint) - (pOptionHeader->ImageBase + ((DWORD)codeBegin+0x12 - (DWORD)pImageBuffer))); *(PDWORD)(codeBegin+0xE) = JmpAddr; //修改OEP pOptionHeader->AddressOfEntryPoint = (DWORD)codeBegin - (DWORD)pImageBuffer; //ImageBuffer --> NewBuffer CopyImageBufferToFileBuffer(pImageBuffer,&NewFileBuffer); if(size==0 || !NewFileBuffer) { printf("ToNewFileBuffer失敗"); free(pFileBuffer); free(pImageBuffer); return ; } //存檔 isOK = WriteToFile(NewFileBuffer,FILEPATH_OUT); if(isOK) { printf("存檔成功"); return ; } //釋放記憶體 free(pFileBuffer); free(pImageBuffer); return ; } //新增一個 /* * 需修改:節表個數;總程式碼數;節表新增節;修改新增節的屬性(名字,程式碼大小,記憶體中開始地址,檔案中大小,檔案開始地址);增加資料 */ VOID TestAddSectionCode() { LPVOID pFileBuffer = NULL; //檔案Buffer LPVOID pImageBuffer = NULL; //記憶體Buffer PIMAGE_DOS_HEADER pDosHeader = NULL; //DOSHeader PIMAGE_FILE_HEADER pPEHeader = NULL; PIMAGE_OPTIONAL_HEADER32 pOptionHeader = NULL; PIMAGE_SECTION_HEADER pSectionHeader = NULL; //file --> FileBuffer ReadPEFile(FILEPATH_IN,&pFileBuffer); if(!pFileBuffer) { printf("檔案-->緩衝區失敗"); return ; } //FileBuffer --> ImageBuffer CopyfFileBufferToImageBuffer(pFileBuffer,&pImageBuffer); if(!pImageBuffer) { printf("FileBuffer-->ImageBuffer 失敗"); free(pFileBuffer); return ; } //眾頭歸位 pDosHeader = (PIMAGE_DOS_HEADER)pImageBuffer; pPEHeader = (PIMAGE_FILE_HEADER)(((DWORD)pDosHeader+pDosHeader->e_lfanew) + 4); pOptionHeader = (PIMAGE_OPTIONAL_HEADER32)(((DWORD)pPEHeader)+IMAGE_SIZEOF_FILE_HEADER); pSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD)pOptionHeader + (DWORD)pPEHeader->SizeOfOptionalHeader); //判斷空間是否充足 //節末 PIMAGE_SECTION_HEADER AddSection = NULL; PIMAGE_SECTION_HEADER MySection = NULL; //最後一個節表的最末端 MySection = AddSection = (PIMAGE_SECTION_HEADER)((DWORD)pSectionHeader + (pPEHeader->NumberOfSections*IMAGE_SIZEOF_SECTION_HEADER)); //新增節 memcpy((LPDWORD)MySection,(LPDWORD)pSectionHeader,IMAGE_SIZEOF_SECTION_HEADER); MySection--; AddSection->Name[0]='.'; AddSection->Name[1]='a'; AddSection->Name[2]='d'; AddSection->Name[3]='d'; //節大小 AddSection->Misc.VirtualSize = 0x1000; //記憶體地址 AddSection->VirtualAddress = MySection->SizeOfRawData + MySection->VirtualAddress; //檔案拉伸大小 AddSection->SizeOfRawData = 0x1000; //檔案中的位置 AddSection->PointerToRawData = MySection->SizeOfRawData + MySection->PointerToRawData; //節的個數 pPEHeader->NumberOfSections += 1; //程式碼總數 pOptionHeader->SizeOfImage += 0x1000; //釋放記憶體 free(pFileBuffer); free(pImageBuffer); return ; }