zoukankan      html  css  js  c++  java
  • 滴水逆向-文件读写&内存分配-PE准备阶段

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

    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
    ");
    }
    
    int main(int argc, char* argv[])
    {
        int x = fun1();
        printf("%d 
    ",x);
        float y = fun2(2);
        printf("%f 
    ",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 
    ",x);
        return 0;
    }
    
    
    2.头文件的使用        
    
    测试验证
                    
    步骤一:                
                        
    #include "stdafx.h"
    #include <stdlib.h>
    #include <stdio.h>
    #include <malloc.h>
    
    void fun( )
    {
        printf("Hello World!
    ");
    }
    
    
    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!
    ");
    }                
                    
    不能正常执行!                
    
    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
    ");
    }
    
    y.cpp文件的文件内容如下:
    
    // y.cpp: implementation of the y class.
    //
    //////////////////////////////////////////////////////////////////////
    
    #include "stdafx.h"
    #include "y.h"
    
    //////////////////////////////////////////////////////////////////////
    // Construction/Destruction
    //////////////////////////////////////////////////////////////////////
    
    void funy()
    {
        printf("Hello y
    ");
    }
    
    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
    " );
       else
       {
           printf( "Memory space allocated for path name
    " );
           free( string );
           printf( "Memory freed
    " );
       }
    }
    
    
    int main(int argc, char* argv[])
    {
        fun();
        return 0;
    }
    
    malloc函数的使用和解释可参考下面链接
    https://blog.csdn.net/wang13342322203/article/details/80862382
    
    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 
    ",ptr);
    }
    
    int main(int argc, char* argv[])
    {
        fun();
        printf("Hello World!
    ");
        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
    https://www.cnblogs.com/sky-of-chuanqingchen/p/4123163.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
    ");
            exit(1);
        }
        else
        {
            printf("Open the notepad success!
    ");
            printf("%x 
    ",fstream);
        }
    
        fclose(fstream);
    
        //return 0;
    }
    
    fseek函数相关参考:
    https://blog.csdn.net/yutianzuijin/article/details/27205121
    
    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语言获取文件大小
    https://blog.csdn.net/yutianzuijin/article/details/27205121
    
    课后练习
    
    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 
    ",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 
    ",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 
    ",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 
    ",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;
    }
    迷茫的人生,需要不断努力,才能看清远方模糊的志向!
  • 相关阅读:
    AtCoder ABC 129F Takahashi's Basics in Education and Learning
    AtCoder ABC 129E Sum Equals Xor
    UVA 511 Do You Know the Way to San Jose?
    UVA 12504 Updating a Dictionary
    [Poi2000] 病毒
    [loj10061] 最短母串
    [Poi2010] Antisymmetry
    校内集训20181003
    校内集训20181001
    校内集训20180925
  • 原文地址:https://www.cnblogs.com/autopwn/p/15189169.html
Copyright © 2011-2022 走看看