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驱动开发技术详解》之读写操作
缓冲区方式读写操作 设置缓冲区读写方式:
随机推荐
- cocos2dx3.0的CCCallFunc、CCCallFuncN
来源: http://blog.csdn.net/crayondeng/article/details/18767407 二.在cocos2d-x中,还有一个地方是需要大量使用到回调函数的,这就是回调 ...
- ContextFlyout 在10586或10240的使用
虽然ContextFlyout只能在红石以上版本使用,但可以采用附加属性的方法手动写一个 public static class ContextFlyoutSetter { public static ...
- iOS10权限设置问题以及xcdoe8更新细节问题
<key>NSVideoSubscriberAccountUsageDescription</key> <string></string> <ke ...
- Winform 后台将指定的控件集合添加到制定容器中
/// <summary> /// 把按钮按照行数分割排列 /// </summary> /// <param name="ControlArry"& ...
- 正则匹配闭合HTML标签(支持嵌套)
任何复杂的正则表达式都是由简单的子表达式组成的,要想写出复杂的正则来,一方面需要有化繁为简的功底,另外一方面,我们需要从正则引擎的角度去思考问题.关于正则引擎的原理,推荐<Mastering R ...
- Oracle以15分钟为界,统计一天内各时间段的数据笔数
db.table替换为自己的表名,StartTime为date字段 select count(*), (case floor((to_char(StartTime,'mi'))/15) when 0 ...
- thinkphp 3.2 linux二级目录安装
详解:http://document.thinkphp.cn/manual_3_2.html#url_rewrite 注意:linux系统对大小写敏感 服务器系统:linux (阿里云服务器) thi ...
- js学习篇1--数组
javascript的数组可以包含各种类型的数据. 1. 数组的长度 ,直接用 length 属性; var arr=[1,2,3]; arr.length; js中,直接给数组的length赋值是会 ...
- Linux系统资源查看
以下Linux系统资源查看命令中,较常用的为vmstat 与 lsof vmstat [刷新延时 刷新次数] ucm@ucm-Aspire-TC-:~$ vmstat procs ---------- ...
- Python *与** 参数问题
问题: Python的函数定义中有两种特殊的情况,即出现*,**的形式. 如:def myfun1(username, *keys)或def myfun2(username, **ke ...