0
点赞
收藏
分享

微信扫一扫

滴水逆向-文件读写&内存分配-PE准备阶段

滴水逆向-文件读写&内存分配-PE准备阶段_html

 

滴水逆向-文件读写&内存分配-PE准备阶段_html_02

 

滴水逆向-文件读写&内存分配-PE准备阶段_#define_03

 

滴水逆向-文件读写&内存分配-PE准备阶段_逆向_04

 

滴水逆向-文件读写&内存分配-PE准备阶段_#include_05

 

滴水逆向-文件读写&内存分配-PE准备阶段_逆向_06

 

相关练习验证测试代码及课后练习

1.宏定义说明:                            

一、无参数的宏定义的一般形式为:# define 标识符 字符序列

如:

#define TRUE 1
#define FALSE 0

int fun()
{
return TRUE;
}

#define PI 3.1415926

double Function(int r)
{
return 2*PI*r;
}

#define DEBUG 1

void Function()
{
//....
if(DEBUG)
printf("测试信息");
}

注意事项:

1.只作字符序列的替换工作,不作任何语法的检查
2.如果宏定义不当,错误要到预处理之后的编译阶段才能发现

测试验证代码

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>

#define TRUE 998
#define FALSE 668
#define PI 3.1415926
#define DEBUG 1

int fun1()
{
return TRUE;
}

double fun2(int r)
{
return 2*PI*r;
}

void fun3()
{
//....
if(DEBUG)
printf("Testing information\n");
}

int main(int argc, char* argv[])
{
int x = fun1();
printf("%d \n",x);
float y = fun2(2);
printf("%f \n",y);
fun3();
return 0;
}


二、带参数宏定义:#define 标识符(参数表)字符序列

#define MAX(A,B) ((A) > (B)?(A):(B))

代码 x= MAX(p,q)将被替换成 y=((p) >(q)?(p):(q)

注意事项:

1.宏名标识符与左圆括号之间不允许有空白符,应紧接在一起.
2.宏与函数的区别:函数分配额外的堆栈空间,而宏只是替换.
3.为了避免出错,宏定义中给形参加上括号.
4.末尾不需要分号.
5.define可以替代多行的代码,记得后面加 \

#define MALLOC(n,type)\
((type*)malloc((n)*sizeof(type)))

验证测试代码

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>

#define MAX(A,B) ((A) > (B)?(A):(B)) // 这个的功能就是比较大小,谁大输出谁

int fun()
{
return MAX(9,18);
}

int main(int argc, char* argv[])
{
int x = fun();
printf("%d \n",x);
return 0;
}


2.头文件的使用

测试验证

步骤一:

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>

void fun( )
{
printf("Hello World!\n");
}


int main(int argc, char* argv[])
{
fun();
return 0;
}

可以正常执行

如果换成:

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>

int main(int argc, char* argv[])
{
fun();
return 0;
}

void fun( )
{
printf("Hello World!\n");
}

不能正常执行!

error C2065: 'fun' : undeclared identifier
error C2373: 'fun' : redefinition; different type modifiers

显示无法识别定义的函数,所以为了解决这类问题,就有了下面的办法

解决办法:新增头文件(.h),在.h文件中对函数进行说明

具体在VC6++上操作:在classes上右键新建,写一个名字x和y的两个文件,此时会在File栏目生成.cpp和.h的文件
(如果是C语言就是生成.c 如果C++那么就是生成.cpp)
.cpp文件在Source Files .h文件在Header Files

例如:

x.cpp文件的文件内容如下:

// x.cpp: implementation of the x class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "x.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

void funx()
{
printf("Hello x\n");
}

y.cpp文件的文件内容如下:

// y.cpp: implementation of the y class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "y.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

void funy()
{
printf("Hello y\n");
}

x.h文件的文件内容如下

// x.h: interface for the x class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_X_H__E1420025_F5C1_4883_8C12_957B2D2EEFD3__INCLUDED_)
#define AFX_X_H__E1420025_F5C1_4883_8C12_957B2D2EEFD3__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

void funx();


#endif // !defined(AFX_X_H__E1420025_F5C1_4883_8C12_957B2D2EEFD3__INCLUDED_)

y.h文件的文件内容如下

// y.h: interface for the y class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_Y_H__0CCFD82D_D027_419E_810C_22E1F91EA018__INCLUDED_)
#define AFX_Y_H__0CCFD82D_D027_419E_810C_22E1F91EA018__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

void funy();


#endif // !defined(AFX_Y_H__0CCFD82D_D027_419E_810C_22E1F91EA018__INCLUDED_)

下面是在上面的基础上,在主main函数下加载函数名称并执行,下面是主文件的源代码

// sjlx.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "x.h"
#include "y.h"


int main(int argc, char* argv[])
{
funx();
funy();
return 0;
}

上述可以编译成功并执行,打印结果如下:
Hello x
Hello y
Press any key to continue


3.重复包含的问题

什么是重复包含问题:

x.h
#include z.h

y.h
#include z.h

z.h
struct Student
{
int level;
};

上面是课堂给的例子,我这里测试就更改下,例子依然是2.中头文件使用的那个例子

如果此时有个文件同时包含了x.h和y.h会出问题。

例如:

#include "stdafx.h"
#include "x.h"
#include "y.h"

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

return 0;
}

解决方案

#if !defined(ZZZ) //这句话的意思可以这样去理解,如果ZZZ已经存在了,就不在声明
#define ZZZ //ZZZ相当于一个编号,越复杂越好,唯一的.

struct Student
{
int level;
};

#endif


4.内存分配与释放

malloc函数使用的例子

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>

void fun( )
{
char* string;

/* Allocate space for a path name */
string = (char*) malloc( _MAX_PATH );
if( string == NULL )
printf( "Insufficient memory available\n" );
else
{
printf( "Memory space allocated for path name\n" );
free( string );
printf( "Memory freed\n" );
}
}


int main(int argc, char* argv[])
{
fun();
return 0;
}

malloc函数的使用和解释可参考下面链接


malloc函数使用流程

//声明指针
int* ptr;

//在堆中申请内存,分配128个int
ptr = (int *)malloc(sizeof(int)*128);

//无论申请的空间大小,一定要进行校验判断是否申请成功
if(ptr == NULL)
{
return 0;
}

//初始化分配的内存空间
memset(ptr,0,sizeof(int)*128);

//开始使用
*(ptr) = 1;

//使用完毕 释放申请的堆空间
free(ptr);

//将指针设置为NULL
ptr = NULL;

下面是测试验证代码,可以正常运行

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

int fun()
{
//什么指针
int* ptr;
//在堆中申请内存,分配128个int
ptr = (int*)malloc(sizeof(int)*128);
//无论申请空间的大小,一定要先进行判断内存申请是否成功
if (ptr == NULL)
{
return 0;
}
//初始化分配的内存空间
memset(ptr,0,sizeof(int*)128);
//开始使用内存
*(ptr) = 1;
//使用完内存,要释放申请的堆空间
free(ptr);
//将指针设置为NULL
ptr = NULL;

printf("%x \n",ptr);
}

int main(int argc, char* argv[])
{
fun();
printf("Hello World!\n");
return 0;
}

5.文件读写相关函数

可以参考下面网站:
http://c.biancheng.net/cpp/u/stdio_h/

(1)fopen函数 打开文件函数 (打开一个文件并返回文件指针)
(2)fseek函数 查找文件头或者尾函数(移动文件的读写指针到指定的位置)
(3)ftell函数 定位指针函数 (获取文件读写指针的当前位置)
(4)fclose函数 关闭文件函数 (关闭文件流)
(5)fread函数 读取文件内容函数 (从文件流中读取数据)

fopen函数相关参考:
https://www.runoob.com/cprogramming/c-function-fopen.html
http://c.biancheng.net/cpp/html/250.html


测试的例子

#include "stdafx.h"
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <memory.h>

#define F_PATH "C:\\cntflx\\notepad.exe"

void pe_openfiles()
{
FILE* fstream;
fstream = fopen(F_PATH,"ab+");

if (fstream == NULL)
{
printf("Open the notepad failed\n");
exit(1);
}
else
{
printf("Open the notepad success!\n");
printf("%x \n",fstream);
}

fclose(fstream);

//return 0;
}

fseek函数相关参考:


ftell函数相关参考:
http://c.biancheng.net/cpp/html/2519.html

int pe_getfile_size()
{
FILE* fp=fopen(F_PATH,"r");
if (!fp)
{
return -1;
}
fseek(fp,0L,SEEK_END);
int size = ftell(fp);
fseek(fp,0,SEEK_SET);
fclose(fp);

return size;
}

fclose函数相关参考:
http://c.biancheng.net/cpp/html/2505.html

fread函数相关参考:
http://c.biancheng.net/cpp/html/2516.html

C语言获取文件大小


课后练习

1.用十六进制文本编辑器,打开一个记事本的.exe文件,再打开在内存中的记事本进程,记录下这两个文件的不同.
有两处不同

操作方式:
(1)使用winhex打开在硬盘上没有执行的notepad.exe文件,此时是没被执行的普通文件内容
(2)正常执行notepad.exe文件,然后最小化,再使用winhex的工具选项-打开RAM内存--选择名称为notepad.exe的内容

编号不同,没有运行前的编号为00000000开头,运行后变成了0100000开头
数据不同:运行前的部分内容和运行后的部分内容有一点相同的,到后面就不同了

2.将记事本的.exe文件读取到内存,并返回读取后在内存中的地址.

大概思路:
(1)打开文件
(2)得到文件的大小 --> 读取文件到内存,然后跳转到文件末尾,查看跳转的长度
(3)根据大小申请内存
(4)把文件中内容读取到内存里
(5)返回内存编号

记事本路径:C:\cntflx

#define F_PATH "C:\\cntflx\\notepad.exe"

第一种写法:

#include "stdafx.h"
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <memory.h>

#define F_PATH "C:\\cntflx\\notepad.exe"

int Pe_Getfile_Size()
{
FILE* fp=fopen(F_PATH,"r");
if (!fp)
{
return -1;
}
fseek(fp,0L,SEEK_END);
int size = ftell(fp);
fseek(fp,0,SEEK_SET);
fclose(fp);

return size;
}

int FileSizes = Pe_Getfile_Size();

int Pe_ReadMemtory_addrs1()
{
//定义一个文件的指针,并初始化其为NULL
FILE* fstream = NULL;

//初始化exe文件长度
int FstreamSizes = 0;

//准备打开文件notepad.exe ,读写,且是读二进制文件
fstream = fopen(F_PATH,"ab+");

//获取打开文件的exe大小
FstreamSizes = FileSizes;
// printf("%d \n",FstreamSizes);

//申请动态内存指向FileBuffer
int* FileBuffer = (int*)malloc(FstreamSizes);

//判断申请的内存是否成功,不成功就返回0,成功就开始读exe内容写入申请的内存中
if (FileBuffer == NULL)
{
return 0;
}
else
{
fread(FileBuffer,FstreamSizes,1,fstream);
}
memset(FileBuffer,0,Pe_Getfile_Size());

//返回内存编号
int addr = (int)FileBuffer;
printf("%x \n",addr);
//释放申请的内存空间
free(FileBuffer);
FileBuffer = NULL;
fclose(fstream);

return 0;
}

int main(int argc, char* argv[])
{
Pe_ReadMemtory_addrs1();
return 0;
}

第二种写法:

#include "stdafx.h"
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <memory.h>

#define F_PATH "C:\\cntflx\\notepad.exe"

int Pe_Getfile_Size()
{
FILE* fp=fopen(F_PATH,"r");
if (!fp)
{
return -1;
}
fseek(fp,0L,SEEK_END);
int size = ftell(fp);
fseek(fp,0,SEEK_SET);
fclose(fp);

return size;
}

int FileSizes = Pe_Getfile_Size();

int Pe_ReadMemtory_addrs2()
{
FILE* fd = fopen(F_PATH,"ab+");

int* ptr;
ptr = (int*)malloc(FileSizes);

if (ptr == NULL)
{
return 0;
}
memset(ptr,0,Pe_Getfile_Size());

fread(ptr, FileSizes, 1,fd);
int addrs = (int)ptr;
printf("%x \n",addrs);

free(ptr);
ptr = NULL;
fclose(fd);

return 0;
}

int main(int argc, char* argv[])
{
Pe_ReadMemtory_addrs2();
return 0;
}

第三种写法:

下面这个是摘自互联网上的,对应地址:https://www.it610.com/article/1304362410466906112.htm

#include "stdafx.h"
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <memory.h>

int file_length(FILE *fp);

void fun_02()
{

// 定义一个文件指针
FILE *fp1 = NULL;
int FpSize = 0; // 初始化exe文件长度

// 打开文件(读和写)
fp1 = fopen("C:\\Windows\\System32\\notepad.exe","rb");
//获取exe大小
FpSize = file_length(fp1);
// 开辟一段动态内存,用FileBuffer指向
char * FileBuffer = (char *)malloc(FpSize);
// 将.exe写入内存中
if(FileBuffer != NULL)
{

fread(FileBuffer,FpSize,1,fp1);
}
// 返回内存编号
int addr = (int)FileBuffer;
printf("%x",FileBuffer);
// 释放开辟的内存
free(FileBuffer);
fclose(fp1);
}

int file_length(FILE *fp)
{

// 初始化一个计数器
int num;
fseek(fp,0,SEEK_END);
num = ftell(fp);
// 使用完毕后,要将文件指针指向文件开始
fseek(fp,0,SEEK_SET);
return num;
}

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

fun_02();
getchar();
return 0;
}

执行结果是0x00530068

3.将内存中的数据存储到一个文件中,(.exe格式),然后双击打开,看是否能够使用.

源代码如下:

#include "stdafx.h"
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <memory.h>

#define F_PATH "C:\\cntflx\\notepad.exe"
#define W_PATH "C:\\cntflx\\newnotepad.exe"

int Pe_Getfile_Size()
{
FILE* fp=fopen(F_PATH,"r");
if (!fp)
{
return -1;
}
fseek(fp,0L,SEEK_END);
int size = ftell(fp);
fseek(fp,0,SEEK_SET);
fclose(fp);

return size;
}

int FileSizes = Pe_Getfile_Size();

int Pe_ReadMemtory_addrs1()
{
//定义两个文件的指针,并初始化为NULL
FILE* fstream1 = NULL;
FILE* fstream2 = NULL;

//初始化exe文件长度
int FstreamSizes = 0;

//准备打开文件notepad.exe ,读写,且是读二进制文件
fstream1 = fopen(F_PATH,"ab+");

//写入一个新的不存在的exe文件
fstream2 = fopen(W_PATH,"ab+");

//获取打开文件的exe大小
FstreamSizes = FileSizes;
// printf("%d \n",FstreamSizes);

//申请动态内存指向FileBuffer
int* FileBuffer = (int*)malloc(FstreamSizes);

//判断申请的内存是否成功,不成功就返回0
//成功的话就开始读exe文件内容,写入到另一个exe文件中

if (FileBuffer == NULL)
{
return 0;
}
else
{
fread(FileBuffer,FstreamSizes+1,1,fstream1);
fwrite(FileBuffer,FstreamSizes,1,fstream2);
}
memset(FileBuffer,0,Pe_Getfile_Size());
//释放堆中申请的内存,并关闭打开的文件流

free(FileBuffer);
FileBuffer = NULL;
fclose(fstream1);
fclose(fstream2);

return 0;
}

int main(int argc, char* argv[])
{
Pe_ReadMemtory_addrs1();
return 0;
}

下面这个是摘自互联网上的,对应地址:https://www.it610.com/article/1304362410466906112.htm

#include "stdafx.h"
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <memory.h>

int file_length(FILE *fp);

void fun_02()
{

// 定义两个文件指针,一个读一个写
FILE *fp1 = NULL;
FILE *fp2 = NULL;
int FpSize = 0; // 初始化exe文件长度

// 打开文件(读和写)
fp1 = fopen("C:\\Windows\\System32\\notepad.exe","rb");
fp2 = fopen("C:\\cntflx\\hehetest.exe","wb");
//获取exe大小
FpSize = file_length(fp1);
// 开辟一段动态内存,用FileBuffer指向
char * FileBuffer = (char *)malloc(FpSize);
// 将.exe写入内存中
if(FileBuffer != NULL)
{

fread(FileBuffer,FpSize+1,1,fp1);
fwrite(FileBuffer,FpSize,1,fp2);

}
// 释放堆中开辟的内存、关闭流
free(FileBuffer);
fclose(fp1);
fclose(fp2);

}

int file_length(FILE *fp)
{

// 初始化一个计数器
int num;
fseek(fp,0,SEEK_END);
num = ftell(fp);
// 使用完毕后,要将文件指针指向文件开始
fseek(fp,0,SEEK_SET);
return num;

}

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

fun_02();
getchar();
return 0;
}

 

迷茫的人生,需要不断努力,才能看清远方模糊的志向!

举报

相关推荐

0 条评论