1. 程式人生 > >c++檔案複製 (部分)

c++檔案複製 (部分)

// 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 ;
}