PE读写
// 仿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读写的更多相关文章
- 一文说清OpenCL框架
背景 Read the fucking official documents! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: 对不 ...
- PE文件头
pe文件头查看器下载与原文地址: http://www.pc6.com/softview/SoftView_109840.html PE文件入门: PE文件总的来说是由DOS文件头.DOS加载模块.P ...
- EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~再续~添加对各只读服务器的心跳检测
回到目录 上一讲中基本实现了对数据库的读写分离,而在选择只读数据库上只是随机选择,并没有去检测数据库服务器是否有效,如服务器挂了,SQL服务停了,端口被封了等等,而本讲主要对以上功能进行一个实现,并对 ...
- PE文件的执行顺序
当一个PE文件被执行时,PE装载器首先检查DOS MZ header里的PE header的偏移量.如果找到,则直接跳转到PE header的位置. 当PE装载器跳转到PE header后,第二步要做 ...
- 手写PE文件(一)
DOS Header(IMAGE_DOS_HEADER)->64 Byte DOS头部 DOS Stub 112字节 "PE"00(Signature) 4个字节 IMAGE ...
- 通用PE u盘启动盘制作
导读 通用pe工具箱是现在最老牌的的U盘装系统和维护电脑的专用工具之一,一键式制作.操作简单便捷,几乎100%支持所有U盘,不再为装机烦恼们,抓紧时间下载通用pe工具箱体验下吧. 准备工作 ①从通用p ...
- 怎样用通用pe工具箱制作U盘启动盘
U盘启动盘制作过程,随着网络的普及,电脑已经成为我们日常生活中的重要一环,最近自己重装了下电脑系统,无意中发现一个傻瓜式的U盘装系统方法,就把怎么制作通用pe工具箱u盘启动盘的经验拿出来跟大家分享下. ...
- 如何用Java语言向串口读写数据
原作者:赛迪网作者 shihuchen ,我在他的基础上进行了部分修改 [赛迪网讯]串口, RS-232-C(又称EIA RS-232-C,以下简称RS232)是在1970年由美国电子工业协会(EIA ...
- 《Windows驱动开发技术详解》之读写操作
缓冲区方式读写操作 设置缓冲区读写方式:
随机推荐
- JAVA之IO流(字符流)
字符流InputStreamReader和OutputStreamWriter是Writer和Read的子类:是字节流通向字符流的桥梁,也就是可以把字节流转化为字符流. InputStreamRead ...
- BZOJ 3489: A simple rmq problem
3489: A simple rmq problem Time Limit: 40 Sec Memory Limit: 600 MBSubmit: 1594 Solved: 520[Submit] ...
- 统一的Json组件和csv下载组件
java-web-common java-web-common Json组件 目标和用途 规范Json接口格式 Controller中一律返回Java object,组件将自动转换数据格式,满足Jso ...
- thinkphp 命名空间
什么是命名空间?从广义上来说,命名空间是一种封装事物的方法.在很多地方都可以见到这种抽象概念.例如,在操作系统中目录用来将相关文件分组,对于目录中的文件来说,它就扮演了命名空间的角色.具体举个例子,文 ...
- History lives on in this distinguished Polish city 2017/1/4
原文 History lives on in this distinguished Polish city Though it may be ancient. KraKow, Poland, is a ...
- git文件迁移到新架构
环境: ubuntu16.04 代码托管地址:git.oschina.net 迁移原因: git上某工程是一堆静态页面html,因为在ubuntu下缺乏git图形客户端,想使用eclipse集成的gi ...
- 记一次ss故障
本文主要参考: https://github.com/shadowsocks/shadowsocks shadowssocks 分为客户端和服务器端. 我们平时买的服务,使用是要用的是客户端. 如果你 ...
- Android SDK升级后报错error when loading the sdk 发现了元素 d:skin 开头无效内容
把错误位置的devices.xml这个文件删除,再把sdk里面tools\lib下的这个文件拷贝到你删除的那个文件夹里,重启eclipse
- 很方便的后台ajax上传文件
<a href="javascript:void(0);" url="{:U('teacherd?id='.$vo['id'])}" class=&quo ...
- JavaScript - 正则表达之二
正则表达式的大致匹配过程是:依次拿出表达式和文本中的字符比较,如果每一个字符都能匹配,则匹配成功:一旦有匹配不成功的字符则匹配失败. 正则表达式通常用于在文本中查找匹配的字符串.Python里数量词默 ...