// 仿PE文件.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <windows.h>
#include <malloc.h>

/*将文件从硬盘读取到缓冲区中
参数1 :文件路径 参数2:接受读取数据的缓冲区的地址的指针【指针的指针】
读取成功返回文件的长度 读取失败则返回0
*/
//int ReadFileToBuffer(IN LPSTR FilePath,OUT LPVOID* PFileBuffer);

//接下来将EXE从文件缓冲区拷贝到内存镜像缓冲区中
//DWORD CopyFileBufferToImageBuffer(IN LPSTR FileBuffer,OUT LPVOID* PImageBuffer);

int main(int argc, char* argv[])

{
char* FilePath1="E:/notepad++.exe"; //读入的文件路劲

DWORD FileLength=0;

FILE* InputStream=NULL;

void* pFileBuffer=NULL;

InputStream=fopen(FilePath1,"rb");//打开文件流

if(FilePath1=NULL){
printf("文件为空\n");
return 0;
}

int nseek=fseek(InputStream,0,SEEK_END);//将文件流指针指向文件末尾
if(nseek!=0){
printf("设置文件位置指针失败\n");
fclose(InputStream);
return 0;
}

FileLength=ftell(InputStream);
printf("the lentgth of the exe is %d Byte\n",FileLength);

//重新设置文件位置指针指向文件首
fseek(InputStream,0,SEEK_SET);
pFileBuffer=(void*)malloc(FileLength);
if(pFileBuffer==NULL){
printf("文件缓冲区申请失败\n");
fclose(InputStream);
return 0;
}

memset(pFileBuffer,0,FileLength);

int n=fread(pFileBuffer,FileLength,1,InputStream);

if(n==0){
printf("文件读取失败\n");
free(pFileBuffer);
fclose(InputStream);
return 0;
}

//接下来将EXE从文件缓冲区拷贝到内存镜像缓冲区中

PIMAGE_DOS_HEADER pDosHeader=NULL;
PIMAGE_NT_HEADERS pNTHeaders=NULL;
PIMAGE_FILE_HEADER pPEHeader=NULL;
PIMAGE_OPTIONAL_HEADER pOptionalHeader=NULL;
PIMAGE_SECTION_HEADER pSectionHeader=NULL;

//判断文件缓冲区是否有效
if(pFileBuffer==NULL){
printf("文件缓冲区指针无效\n");
return 0;
}

//判断该文件是否是PE文件
if(*((PWORD)pFileBuffer)!=IMAGE_DOS_SIGNATURE){
printf("不是有效的DOS文件\n");
return 0;
}
pDosHeader=(PIMAGE_DOS_HEADER)(pFileBuffer);
if(*((PDWORD)((DWORD)pFileBuffer+pDosHeader->e_lfanew))!=IMAGE_NT_SIGNATURE){ //这里注意:FileBuffer是一个指针,也就是一个地址,所以转型为DWROD与pDosHeader->e_lfanew相加
printf("该文件不是有效的PE文件");
return 0;
}

printf("DOS的开始地址是:%x\n",pDosHeader);
//NT头指针
pNTHeaders=(PIMAGE_NT_HEADERS)((DWORD)pDosHeader+pDosHeader->e_lfanew);
printf("NT的开始地址是:%x\n",pNTHeaders);
//PE头指针等于NT头指针加四
pPEHeader=(PIMAGE_FILE_HEADER)(((DWORD)pFileBuffer+pDosHeader->e_lfanew)+4);
printf("PE的开始地址是:%x\n",pPEHeader);

//血的教训,一个指针加上一个整数,加上的实际的大小是该指针表示的数据类型【去掉一个*】乘以整数
pOptionalHeader=(PIMAGE_OPTIONAL_HEADER)((DWORD)pPEHeader+IMAGE_SIZEOF_FILE_HEADER);//指针在加数时务必将其转化为整形
printf("optional的开始地址是:%x\n",pOptionalHeader);

pSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pOptionalHeader+pPEHeader->SizeOfOptionalHeader);
printf("section表的开始地址是:%x\n",pSectionHeader);

//根据SIZE_OF_IMAGE来分配内存缓冲区的大小,虽然每一个应用程序在理论上都拥有独立的4GB虚拟内存,但是还是根据SIZE FOF IMAGE来分配内存大小
LPVOID pImageBuffer=NULL;
pImageBuffer=malloc(pOptionalHeader->SizeOfImage);
printf("%x\n",pOptionalHeader->SizeOfImage);
if(pImageBuffer==NULL){
printf("分配内存镜像文件失败\n");
}

memset(pImageBuffer,0,pOptionalHeader->SizeOfImage);

//开始从文件缓冲区拷贝到镜像缓冲区中 1:第一步:将所有的头拷贝到镜像缓冲区中 DosHeader+NTHeader+SectionHeader
memcpy(pImageBuffer,pFileBuffer,pOptionalHeader->SizeOfHeaders);

//第二步:循环将区块拷贝到IMAGBUFFER中
PIMAGE_SECTION_HEADER pTempSectionHeader=pSectionHeader;

for(int i=0;i<pPEHeader->NumberOfSections;i++,pTempSectionHeader++){
memcpy((void*)((DWORD)pImageBuffer+pTempSectionHeader->VirtualAddress),(void*)((DWORD)pDosHeader+pTempSectionHeader->PointerToRawData),pTempSectionHeader->SizeOfRawData);
}

PIMAGE_DOS_HEADER pImageDosHeader=NULL;
PIMAGE_NT_HEADERS pImageNTHeaders=NULL;
PIMAGE_FILE_HEADER pImagePEHeader=NULL;
PIMAGE_OPTIONAL_HEADER pImageOptionalHeader=NULL;
PIMAGE_SECTION_HEADER pImageSectionHeader=NULL;

pImageDosHeader=(PIMAGE_DOS_HEADER)pImageBuffer;
printf("IMAGE中DOS头的首地址是:%x\n",pImageDosHeader);

pImageNTHeaders=(PIMAGE_NT_HEADERS)((DWORD)pImageDosHeader+pImageDosHeader->e_lfanew);
printf("IMAGE中NT头的首地址是:%x\n",pImageNTHeaders);

pImagePEHeader=(PIMAGE_FILE_HEADER)((DWORD)pImageNTHeaders+4);
printf("IMAGE中PE头的首地址是:%x\n",pImagePEHeader);

pImageOptionalHeader=(PIMAGE_OPTIONAL_HEADER)((DWORD)pImagePEHeader+IMAGE_SIZEOF_FILE_HEADER);
printf("IMAGE中OPTIONAL头的首地址是:%x\n",pImageOptionalHeader);

pImageSectionHeader=(PIMAGE_SECTION_HEADER)((DWORD)pImageOptionalHeader+pImagePEHeader->SizeOfOptionalHeader);

//重新申请一块文件缓冲区,将镜像中的可执行程序还原到文件缓冲区中
LPVOID pNewFileBuffer=NULL;
pNewFileBuffer=malloc(FileLength);
if(pNewFileBuffer==NULL){
printf("重新申请文件缓冲区失败\n");
return 0;
}

memset(pNewFileBuffer,0,FileLength);
//第一步:将第一部分拷贝到新的文件缓冲区中DOSHEADER+NTHEADER+SECTIONHEADER
memcpy(pNewFileBuffer,pImageDosHeader,pImageOptionalHeader->SizeOfHeaders);

//第二步:循环将各个区块拷贝到新的文件缓冲区中
//用一个临时指针来完成pImageSectionHeader指针的自增变化

PIMAGE_SECTION_HEADER pTempImageSectionHeader=NULL;
pTempImageSectionHeader=pImageSectionHeader;

for(i=0;i<pImagePEHeader->NumberOfSections;i++,pTempImageSectionHeader++){
memcpy((void*)((DWORD)pNewFileBuffer+pTempImageSectionHeader->PointerToRawData),(void*)((DWORD)pImageDosHeader+pTempImageSectionHeader->VirtualAddress),pTempImageSectionHeader->SizeOfRawData);
}

//将还原后的文件缓冲区写到一个文件中,并测试是有可以运行

char* FilePath2="E:/zhuhao3.exe"; //文件输出路径
FILE* OutputStream=NULL;
OutputStream=fopen(FilePath2,"w+");

fwrite(pFileBuffer,FileLength,1,OutputStream);

char* pchar;
char arry[]="zhuhao";
pchar=arry;
int a=3;

return 0;
}

PE读写的更多相关文章

  1. 一文说清OpenCL框架

    背景 Read the fucking official documents! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: 对不 ...

  2. PE文件头

    pe文件头查看器下载与原文地址: http://www.pc6.com/softview/SoftView_109840.html PE文件入门: PE文件总的来说是由DOS文件头.DOS加载模块.P ...

  3. EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~再续~添加对各只读服务器的心跳检测

    回到目录 上一讲中基本实现了对数据库的读写分离,而在选择只读数据库上只是随机选择,并没有去检测数据库服务器是否有效,如服务器挂了,SQL服务停了,端口被封了等等,而本讲主要对以上功能进行一个实现,并对 ...

  4. PE文件的执行顺序

    当一个PE文件被执行时,PE装载器首先检查DOS MZ header里的PE header的偏移量.如果找到,则直接跳转到PE header的位置. 当PE装载器跳转到PE header后,第二步要做 ...

  5. 手写PE文件(一)

    DOS Header(IMAGE_DOS_HEADER)->64 Byte DOS头部 DOS Stub 112字节 "PE"00(Signature) 4个字节 IMAGE ...

  6. 通用PE u盘启动盘制作

    导读 通用pe工具箱是现在最老牌的的U盘装系统和维护电脑的专用工具之一,一键式制作.操作简单便捷,几乎100%支持所有U盘,不再为装机烦恼们,抓紧时间下载通用pe工具箱体验下吧. 准备工作 ①从通用p ...

  7. 怎样用通用pe工具箱制作U盘启动盘

    U盘启动盘制作过程,随着网络的普及,电脑已经成为我们日常生活中的重要一环,最近自己重装了下电脑系统,无意中发现一个傻瓜式的U盘装系统方法,就把怎么制作通用pe工具箱u盘启动盘的经验拿出来跟大家分享下. ...

  8. 如何用Java语言向串口读写数据

    原作者:赛迪网作者 shihuchen ,我在他的基础上进行了部分修改 [赛迪网讯]串口, RS-232-C(又称EIA RS-232-C,以下简称RS232)是在1970年由美国电子工业协会(EIA ...

  9. 《Windows驱动开发技术详解》之读写操作

    缓冲区方式读写操作 设置缓冲区读写方式:

随机推荐

  1. 解决UINavigationController在pushViewController时出现的"卡顿"问题

    进行开发中,遇到了个小问题: 在使用UINavigationController的-pushViewController:animated:执行入栈一个子控制器操作时(即最新栈顶子控制器),会出现推出 ...

  2. POJ2175 Evacuation Plan

    Evacuation Plan Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4617   Accepted: 1218   ...

  3. SAM初探

    SAM,即Suffix Automaton,后缀自动机. 关于字符串有很多玩法,有很多算法都是围绕字符串展开的.为什么?我的理解是:相较于数字组成的序列,字母组成的序列中每个单位上元素的个数是有限的. ...

  4. sublime的插件安装

    如何将Emmet安装到到 Sublime text 3?   看清楚哦~~这是Sublime text 3不是2的版本,两者的安装还是有区别的,下面的方法是我感觉比较简单的,其他的要命令什么的感觉太复 ...

  5. Jquery实现特效滑动菜单栏

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. 查看IO负载

    负载(load)是linux机器的一个重要指标,直观了反应了机器当前的状态.如果机器负载过高,那么对机器的操作将难以进行. Linux的负载高,主要是由于CPU使用.内存使用.IO消耗三部分构成.任意 ...

  7. 原生JS会跳动的电子表

     一个会跳动的电子表,源码--time.html  图片--img github地址:https://github.com/1056237661/practiceCode <!DOCTYPE h ...

  8. redis 常用命令

    临时启动:redis-server.exe redis.conf/redis-server redis.windows.conf安装Windows服务:redis-server.exe --servi ...

  9. Java集合之LinkedList

    一.LinkedList概述 1.初识LinkedList 上一篇中讲解了ArrayList,本篇文章讲解一下LinkedList的实现. LinkedList是基于链表实现的,所以先讲解一下什么是链 ...

  10. MFC去掉标题栏

    在初始化的时候加入以下函数 //去掉标题栏 ModifyStyle(WS_CAPTION, NULL, SWP_DRAWFRAME );