1、请采用暴力破解的方式去尝试破解crack.exe文件(在实验报告中说明破解原理即可,无需提交破解后的文件)
2、请依据参考文档中的内容编写一个小程序,使其可以实现如下功能:
①判断一个文件是否为PE文件,如果是PE文件,判断它是exe文件还是dll文件,或者是其它类型的PE文件
②请提交实验报告和你的源代码文件

实验文件.rar


https://download.csdn.net/download/guanshanyue96/11295286 - 此文件是网络安全实验6的实验报告,因为篇幅过长,不能把所有内容都博客显示(很多图片没有显示),所以就上传上来供大家参考。或者在下面留下邮箱(因为上传资源到csdn别人下载需要积分,我也不能把积分调到0),我会把文件发到你的邮箱。

  1. 要对一个程序实现爆破,首先要运行下这个程序,看下它的输出,提取它的特征,再根据该特征找到这个特征的地址(定位),再看情况有什么条件提供给我们进行爆破。

运行该程序,发现它的输出是:Please input password: 这句话是提示用户输入,是非常鲜明的特征,而且居于唯一性。我们可以通过这个特征,使用total command搜索这个特征,找到它的地址。然后再使用ida定位到这个地址,分析它的逻辑图,找到爆破的突破点。

(2)搜索Please(使用F7(search)),我们这里使用取巧的方法,搜索Please,如果发现Please input password这句话,就说定位成功了。

成功找到地址!

(3)用ida打开程序,使用搜索功能找到该地址,对该流程图进行分析。

跳转成功!

调出流程图

https://blog.csdn.net/u013736724/article/details/53364363 - IDA功能简介(2)----流程图功能

可是调出流程图失败!我们只可以看汇编代码,我们浏览 0x00422080 这个地址附近的会汇编语言,突然发现了这个字符串

我们尝试使用1234567作为密码,成功登入!

但是我们的目是随便输入密码都可以登入,强行爆破。我再仔细观察这段代码。可以发现0x401020这个地址,就是输入密码之后,会跳转0x401020这个地址。

搜索0x401020

跳转成功!

空格键,查看流程图

注:db定义字节类型变量,一个字节数据占1个字节单元,读完一个,偏移量加1

注:代码以4字节对齐
如上一段代码的地址为0x0c001232
那么下一段的二地址为 0x0c001234

--------------------------------------------------------------------------------------------------------

https://blog.csdn.net/bxd1314/article/details/38433837 - 汇编中bss,data,text,rodata,heap,stack段的作用

解释:

bss段:

BSS段(bsssegment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文BlockStartedby Symbol的简称。BSS段属于静态内存分配。

data段:

数据段(datasegment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

text段:

代码段(codesegment/textsegment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读,某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

rodata段:

存放C中的字符串和#define定义的常量

heap堆:

堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)

stack栈:

是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区

--------------------------------------------------------------------------------------------------------

*** 做了上面那么多,还是进入找不到程序的流程图,发现没什么用,,,我找到的是.data段的汇编,而且通过汇编找到的是.text表,导不出全部逻辑图,这时要重新分析要怎么解决了,又重新浏览一下了一下ida中的函数列表,忽然发现还有_main函数,这是函数的主入口,决定便进入_main函数看一下。

下面进入正式爆破阶段!!!

双击,可以看到程序主入口:

按空格键,想看到程序的逻辑图,但发现没什么用。

再按空格键返回,再仔细观察,看到jmp _mian_0 ,jmp 是跳转的意思,_main_0 是函数名,主函数一进来就是跳转 _main_0 函数

所以我尝试点击了 _mian_0 ,进入下面这个地方:

重要找到程序逻辑图了,仔细观察流程图,此时就要回归到最开始,通过刚打开程序的输出语句,以它作为特征,找到判断语句,也是流程图的一个分叉点:

发现这两个特征点,查看它们进入的判断语句

.text:0040DB85 cmp     [ebp+var_4], 0

.text:0040DB89 jz      short loc_40DB9A

https://blog.csdn.net/zang141588761/article/details/52506226 - 012-cmp指令与JZ指令

二、CMP 和JZ 指令

比较指令CMP  

格式: CMP A,B //  A-B;

功能: 两个操作数的相减,即从A中减去B,其结果会影响标志位,对标志位的影响与SUB指令相同。本条指令主要是用于配合条件转移指令使用。如JZ ZF=0时,跳转

--------------------------------------------------------------------------------------------------------

所以我们把  [ebp+var_4] - 0 = 0 ,就可以跳转 loc_40DB9A (成功登入程序)

所以我们有两个方法 :

(1)尝试把 [ebp+var_4] -> (转为) 0

(2)尝试把 0 -> (转为) [ebp+var_4]

归根到底就是把 这两个地址的值改为相同的了,我们使用 total command 找到 0040DB85 这个地址

进入total command 按F5(Goto)查找地址,记住不是F7(Search),F5是根据输入的地址跳转地址,F7搜索特征码跳转

记住不是输入40DB89(DB4089是40DB85的下一条语句,也可以是40DB85,这个是cmp的语句的地址),应该输入它的偏移量,这个在我上一个实验有说

偏移量 = 40DB89 - 基地址

搜索0,回到最开始

可以看到基地址是0x400000,所以偏移量

40DB89 - 400000 = DB89

74是0x40DB89的地址,而前面的FC-00就是cmp     [ebp+var_4], 0 对应地址的值

FC 对应 [ebp+var_4] ,00 对应 0 (此处有错,0的ascii码不是00。可以查表),我们可以把FC 改为 00 ,或把 00 改为 FC,就可以实现他们相减的0的值为0了

选中00(这里我选的是这个值),按F3(Edit)修改文件,输入FC

  1. 要对一个程序实现爆破,首先要运行下这个程序,看下它的输出,提取它的特征,再根据该特征找到这个特征的地址(定位),再看情况有什么条件提供给我们进行爆破。

运行该程序,发现它的输出是:Please input password: 这句话是提示用户输入,是非常鲜明的特征,而且居于唯一性。我们可以通过这个特征,使用total command搜索这个特征,找到它的地址。然后再使用ida定位到这个地址,分析它的逻辑图,找到爆破的突破点。

(2)搜索Please(使用F7(search)),我们这里使用取巧的方法,搜索Please,如果发现Please input password这句话,就说定位成功了。

成功找到地址!

(3)用ida打开程序,使用搜索功能找到该地址,对该流程图进行分析。

跳转成功!

调出流程图

https://blog.csdn.net/u013736724/article/details/53364363 - IDA功能简介(2)----流程图功能

可是调出流程图失败!我们只可以看汇编代码,我们浏览 0x00422080 这个地址附近的会汇编语言,突然发现了这个字符串

我们尝试使用1234567作为密码,成功登入!

但是我们的目是随便输入密码都可以登入,强行爆破。我再仔细观察这段代码。可以发现0x401020这个地址,就是输入密码之后,会跳转0x401020这个地址。

搜索0x401020

跳转成功!

空格键,查看流程图

注:db定义字节类型变量,一个字节数据占1个字节单元,读完一个,偏移量加1

注:代码以4字节对齐
如上一段代码的地址为0x0c001232
那么下一段的二地址为 0x0c001234

--------------------------------------------------------------------------------------------------------

https://blog.csdn.net/bxd1314/article/details/38433837 - 汇编中bss,data,text,rodata,heap,stack段的作用

解释:

bss段:

BSS段(bsssegment)通常是指用来存放程序中未初始化的全局变量的一块内存区域BSS是英文BlockStartedby Symbol的简称。BSS段属于静态内存分配。

data段:

数据段(datasegment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

text段:

代码段(codesegment/textsegment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读,某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

rodata段:

存放C中的字符串和#define定义的常量

heap堆:

堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)

stack栈:

是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区

--------------------------------------------------------------------------------------------------------

*** 做了上面那么多,还是进入找不到程序的流程图,发现没什么用,,,我找到的是.data段的汇编,而且通过汇编找到的是.text表,导不出全部逻辑图,这时要重新分析要怎么解决了,又重新浏览一下了一下ida中的函数列表,忽然发现还有_main函数,这是函数的主入口,决定便进入_main函数看一下。

下面进入正式爆破阶段!!!

双击,可以看到程序主入口:

按空格键,想看到程序的逻辑图,但发现没什么用。

再按空格键返回,再仔细观察,看到jmp _mian_0 ,jmp 是跳转的意思,_main_0 是函数名,主函数一进来就是跳转 _main_0 函数

所以我尝试点击了 _mian_0 ,进入下面这个地方:

重要找到程序逻辑图了,仔细观察流程图,此时就要回归到最开始,通过刚打开程序的输出语句,以它作为特征,找到判断语句,也是流程图的一个分叉点:

发现这两个特征点,查看它们进入的判断语句

.text:0040DB85 cmp     [ebp+var_4], 0

.text:0040DB89 jz      short loc_40DB9A

https://blog.csdn.net/zang141588761/article/details/52506226 - 012-cmp指令与JZ指令

二、CMP 和JZ 指令

比较指令CMP  

格式: CMP A,B //  A-B;

功能: 两个操作数的相减,即从A中减去B,其结果会影响标志位,对标志位的影响与SUB指令相同。本条指令主要是用于配合条件转移指令使用。如JZ ZF=0时,跳转

--------------------------------------------------------------------------------------------------------

所以我们把  [ebp+var_4] - 0 = 0 ,就可以跳转 loc_40DB9A (成功登入程序)

所以我们有两个方法 :

(1)尝试把 [ebp+var_4] -> (转为) 0

(2)尝试把 0 -> (转为) [ebp+var_4]

归根到底就是把 这两个地址的值改为相同的了,我们使用 total command 找到 0040DB85 这个地址

进入total command 按F5(Goto)查找地址,记住不是F7(Search),F5是根据输入的地址跳转地址,F7搜索特征码跳转

记住不是输入40DB89(DB4089是40DB85的下一条语句,也可以是40DB85,这个是cmp的语句的地址),应该输入它的偏移量,这个在我上一个实验有说

偏移量 = 40DB89 - 基地址

搜索0,回到最开始

可以看到基地址是0x400000,所以偏移量

40DB89 - 400000 = DB89

74是0x40DB89的地址,而前面的FC-00就是cmp     [ebp+var_4], 0 对应地址的值

FC 对应 [ebp+var_4] ,00 对应 0 ,我们可以把FC 改为 00 ,或把 00 改为 FC,就可以实现他们相减的0的值为0了

选中00(这里我选的是这个值),按F3(Edit)修改文件,输入FC

F9(update)更新

可是依旧是破解失败,这次连输入密码都错误了,所以我们再次尝试把FC都改为00

F9(update)更新

依旧是破解不了!

为什么呢?一是我们的思路错了,二是我们忽略了什么,cmp jz 对应的是while(A) A - 条件,我们把A的值改为00,可能变成 while()不符合语法,我们把 00 改为 AC,至于里面的内部机制我就不是很懂了,while(A)可能A减去的必定是0,把0改为FC,这根本不是成立的。可能所以我们尝试再分析程序

cmp的上一句是 mov     [ebp+var_4], eax 用eax 给 [ebp+var_4] 赋值,我们把eax改为 0 ,那么 [ebp+var_4]就等于 0 了cmp  [ebp+var_4] ,0 就等于 0 - 0 = 0了。我把程序修改为原来样子,我们可以通过cmp指令的地址0x40DB85 定位前一个 eax的值,可以知道是FC(看下图)

把FC修改为 00 ,update

重新运行程序,输入1

破解成功,为了验证不是偶然的。再运行程序,输入123

破解成功!!!~~~

爆破程序的源码:

#include <stdio.h>

#define PASSWORD "1234567"

int verify_password(char *password)

{

int authenticated;

authenticated = strcmp(password, PASSWORD);

return authenticated;

}

int main()

{

int valid_flag = 0;

char password[1024];

while(1)

{

printf("Please input password:       ");

scanf("%s", password);

valid_flag = verify_password(password);

if(valid_flag)

{

printf("Incorrect password!\n");

}

else

{

printf("Congratulations!You have passed the verification!\n");

getchar();

break;

}

}

return 0;

}

编写一个小程序,使其可以实现如下功能:
判断一个文件是否为PE文件,如果是PE文件,判断它是exe文件还是dll文件,或者是其它类型的PE文件
请提交实验报告和你的源代码文件

这个我们就可以参考老师发的资料了。

上网百度了一下这个题目,有以下这个参考资料:

https://blog.csdn.net/Krumitz/article/details/89197043 - 网络安全入门实验06:PE文件的解析

老师发的资料很详细,下面就是一个师姐写的资料,写得非常好,而且详细,所以我就贴上来参考一下:

------------------------------------------------------------------------------------------------------------------------

参考师姐:

相关知识

PE(Portable Executable)文件,意为可移植的可执行的文件,是Windows下使用的可执行文件格式,它是微软在UNIX平台的COFF(Common Object File Format,通用对象文件格式)基础上制作而成。最初设计是用来提高程序在不同操作系统上的移植性,但是实际上这种文件格式仅用在Windows系列的操作系统下。

需要完成对PE文件的判断及分类,主要需要了解以下内容:

要点1:PE文件种类

根据《逆向工程 核心原理》,它将PE文件分为4类:

种类

主拓展名

可执行系列

EXE、SCR

库系列

DLL、OCX、CPL、DRV

驱动程序系列

SYS、VXD

对象文件系列

OBJ

:①只有可执行系列(EXE)是可以直接被执行的,库系列(DLL)、驱动程序系列(SYS)都是不可以直接在Shell(Explorer.exe)中运行。

②对于OBJ文件,它是Microsoft的Win32编译器生成COFF格式文件,这种文件格式与普通的PE文件格式是不太相同,并且使用StudyPE+查看,如图所示。这种文件格式连PE文件最基本的MZ与PE都没有(不太清楚为什么PE正式规范将其归为PE文件种类),并且OBJ文件本身不能以任何形式执行,因此本实验程序不考虑OBJ文件的情况(直接判定为非FE文件)

要点2:PE文件的框架结构

PE文件的框架结构如下图所示,本实验需要关注DOS头与NT头这两部分的部分相关参数。

要点3:DOS头部

在DOS头部中有两个重要的成员,分别是:

e_magic:DOS签名(signature,所有的PE文件均为4D5A,对应ASCII的“MZ”)

对应宏定义为#define  IMAGE_DOS_SIGNATURE               0x4D5A      // MZ

e_lfanew:指示NT头的偏移(不同的文件该值不同,是找到NT头的关键)

要点4:NT

在NT头中这三个成员都非常重要,其中:

DWORD Signature:签名结构体(所有的PE文件该值均为0x00005045,对应”PE” 00)

对应宏定义为#define IMAGE_NT_SIGNATURE               0x00004550  // PE00

即:当DOS头中e_magic为“MZ”, NT头中Signature的值为PE00则可判定为PE文件。

IMAGE_FILE_HEADER FileHeader:文件头

在IMAGE_FILE_HEADER中Characteristics用于区分不同类型的PE文件,其中在winnt.h中定义的值如图所示:

需要注意的是:

★Characteristics的值是一个复合值,一般来说,它不会直接等于上面任意一个值,并且,就算都为exe文件其Characteristics值也不一定是相同的,实际上该定义与一个16位的二进制有相应的对应关系,如图所示:


以Unity 2017.3.1f1 (64-bit).exe为例,通过StudyPE+查看如下图所示,可以发现其Characteristics的值为0023.

将十六进制的0023转换为二进制为0000 0000 0010 0011,如图2所示

即:①第0位——置1:此文件不包含基址重定位信息

②第1位——置1:此镜像文件是合法,可执行的

③第5位——置1:应用程序可以处理大于2GB的地址

④第8位——置0:机器类型不是基于32位体系结构(即为64位)

⑤第13位——置0:此镜像文件不是动态链接库(DLL)

也就是说,直接将取到的Characteristics值与宏定义去比对是不可行的,必须判断相应位,例如:

若pNtHeader->FileHeader.Characteristics & 0b0000000000000010

=0x0002=IMAGE_FILE_EXECUTABLE_IMAGE则可说明此镜像文件是合法的。

★根据PE文件的定义,实际上PE文件都是可执行的(只是执行方式不同),因为其第1位一般来说都是置为1的。

用studyPE+观察.dll与.sys文件如图1,2所示,将其Characteristics值转换为2进制可以发现,其第1位均置为1。

也就是说,Characteristics值只能区分该文件是否是DLL(库文件系列),对于.sys与.exe文件是无法区分的。

③IMAGE_OPTIONAL_HEADER OptionalHeader:可选头

在IMAGE_OPTIONAL_HEADER中Subsystem的值用于区分系统驱动文件(.sys)与普通可执行文件(.exe),其中Subsystem成员可拥有的值如下表:

含义

备注

1

Driver文件

系统驱动(如:ntfs.sys)

2

GUI文件

窗口应用程序(如:notepad.sys)

3

GUI文件

控制台应用程序(如:cmd.sys)

即通过该值,可以在使用Characteristics值排除.dll后区分.sys文件与.exe文件。

附:用studyPE+观察.exe与.sys文件如图1,2所示,exe文件Subsystem的值不为1,而.sys文件的值为1。

实验步骤与分析

根据上述的PE文件结构特点,根据e_magic、e_lfnew、Signature、Characteristics、SubSystem这五个重要的特征值,即可判断出该文件是否为PE文件,并且定位到NT头,从而确定文件的类型,具体判断逻辑如下:

--------------------------------------------------------------------------------------------------------------------------------------

上面师姐的资料非常详细,可以说是很好的了,但下面参考的这个资料与上面这个资料对比也可以说是评分秋色。而且在我看来,这个资料的参考价值比师姐的更高(相对于此题的需求来说)

链接: https://blog.csdn.net/Krumitz/article/details/89197043 - 网络安全入门实验06:PE文件的解析

--------------------------------------------------------------------------------------------------------------------------------------

参考资料:

1.实验思路

PE文件的全称是Portable Executable,意为可移植的可执行的文件,常见的EXE、DLL、OCX、SYS、COM都是PE文件,PE文件是微软Windows操作系统上的程序文件(可能是间接被执行,如DLL)

以下图例来自老师给的资料

从这张图中可以直观的看出,PE文件首先具有一个DOS的结构头

其定义如下(来自winnt.h头文件中的定义):

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header

WORD   e_magic;                     // Magic number

WORD   e_cblp;                      // Bytes on last page of file

WORD   e_cp;                        // Pages in file

WORD   e_crlc;                      // Relocations

WORD   e_cparhdr;                   // Size of header in paragraphs

WORD   e_minalloc;                  // Minimum extra paragraphs needed

WORD   e_maxalloc;                  // Maximum extra paragraphs needed

WORD   e_ss;                        // Initial (relative) SS value

WORD   e_sp;                        // Initial SP value

WORD   e_csum;                      // Checksum

WORD   e_ip;                        // Initial IP value

WORD   e_cs;                        // Initial (relative) CS value

WORD   e_lfarlc;                    // File address of relocation table

WORD   e_ovno;                      // Overlay number

WORD   e_res[4];                    // Reserved words

WORD   e_oemid;                     // OEM identifier (for e_oeminfo)

WORD   e_oeminfo;                   // OEM information; e_oemid specific

WORD   e_res2[10];                  // Reserved words

LONG   e_lfanew;                    // File address of new exe header

} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

其中比较重要的是第一个值e_magic和最后一个值e_lfanew

以下定义也来自winnt.h头文件

#define IMAGE_DOS_SIGNATURE                 0x5A4D      // MZ

#define IMAGE_OS2_SIGNATURE                 0x454E      // NE

#define IMAGE_OS2_SIGNATURE_LE              0x454C      // LE

#define IMAGE_VXD_SIGNATURE                 0x454C      // LE

#define IMAGE_NT_SIGNATURE                  0x00004550  // PE00

如果文件是一个PE文件,其e_magic值为0x5A4D,即MZ

即我们可以读取一个文件,如果文件头的值为0x5A4D,则可以判断这是一个PE文件

如果是PE文件,再进行接下来的操作

下面说第二个值e_lfanew,从它的英文注释中可以看出,这个值是表明了一个新的exe头部的地址

从实际来解释,即这个LONG值是一个偏移量,偏移后的位置是一个exe header

在查阅资料的过程中,也看到了有这样的解释

//Offset to start of PE header             指向PE文件头

其意思大致是相同的(其实就是一样的)

第二步:将文件指针移到这个位置,读取这个头部的信息

那么这个头部是什么呢

根据资料,这个Header实际为

typedef struct _IMAGE_NT_HEADERS {

DWORD                   Signature;

IMAGE_FILE_HEADER       FileHeader;

IMAGE_OPTIONAL_HEADER32 OptionalHeader;

} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

解释如下:

Signature 表明了文件是一个PE文件,值为PE\0\0

FileHeader 为 IMAGE_FILE_HEADER 结构体,存储了头部信息

OptionalHeader 则存储了可选头信息

查看一下 IMAGE_FILE_HEADER的定义

typedef struct _IMAGE_FILE_HEADER {

WORD  Machine;

WORD  NumberOfSections;

DWORD TimeDateStamp;

DWORD PointerToSymbolTable;

DWORD NumberOfSymbols;

WORD  SizeOfOptionalHeader;

WORD  Characteristics;

} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

IMAGE_OPTIONAL_HEADER

typedef struct _IMAGE_OPTIONAL_HEADER {

WORD                 Magic;

BYTE                 MajorLinkerVersion;

BYTE                 MinorLinkerVersion;

DWORD                SizeOfCode;

DWORD                SizeOfInitializedData;

DWORD                SizeOfUninitializedData;

DWORD                AddressOfEntryPoint;

DWORD                BaseOfCode;

DWORD                BaseOfData;

DWORD                ImageBase;

DWORD                SectionAlignment;

DWORD                FileAlignment;

WORD                 MajorOperatingSystemVersion;

WORD                 MinorOperatingSystemVersion;

WORD                 MajorImageVersion;

WORD                 MinorImageVersion;

WORD                 MajorSubsystemVersion;

WORD                 MinorSubsystemVersion;

DWORD                Win32VersionValue;

DWORD                SizeOfImage;

DWORD                SizeOfHeaders;

DWORD                CheckSum;

WORD                 Subsystem;

WORD                 DllCharacteristics;

DWORD                SizeOfStackReserve;

DWORD                SizeOfStackCommit;

DWORD                SizeOfHeapReserve;

DWORD                SizeOfHeapCommit;

DWORD                LoaderFlags;

DWORD                NumberOfRvaAndSizes;

IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];

} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

这里就不一一翻译了,毕竟这次的实验主要是判断一个文件是否为PE文件,如果是PE文件,判断它是exe文件还是dll文件,或者是其它类型的PE文件

直接说一下吧

判断是否为PE文件的部分前面说了

这里用于判断为dll还是exe还是其他类型的文件的参数主要是以下两个

一个是

FileHeader里面的Characteristics

FileHeader.Characteristics与IMAGE_FILE_DLL做'&'运算后,若文件是OCX和DLL,此结果为0x2000,与其他格式的PE文件都不同(可以先将OCX和DLL筛选出来)

为什么不与IMAGE_FILE_EXECUTABLE_IMAGE做运算?因为上图红框内也标注了,DLL也是一个executable的文件,所以这里做了运算之后,EXE和DLL两个的结果是相等的,无法正确判断

然后我们就要借助于

刚刚说到的另一个重要的参数

OptionalHeader里面的ImageBase

从定义上可以看出,这个值是文件首选的在内存中加载的地址

DLL的这个值默认为0x10000000

而对于应用EXE来说,它则是0x00400000

所以我们可以通过判断ImageBase的值是否为的值是0x10000000,区分OCX和DLL文件

如果不是DLL或者OCX

直接判断ImageBase的值是否为0x00400000,判断文件是否为EXE

如果都不是,列为其他文件

总结一下:

读取一个文件,如果文件头的值为0x5A4D,则可以判断这是一个PE文件

将文件指针移到PE头的位置,读取这个头部的信息

读取PE头里面的IMAGE_FILE_HEADER 结构体的Characteristics

判断Characteristics与IMAGE_FILE_DLL做'&'运算的结果是否为IMAGE_FILE_DLL

再判断ImageBase的值是否为0x10000000,区分OCX和DLL文件

判断ImageBase的值是否为0x00400000,判断文件是否为EXE

P.S

这里要说一下,实际上,即使同为DLL或者同为EXE程序,每个程序的实际参数都是不一定的,都是可以改变的

比如来自小甲鱼PE详解的这段话:

即使同为EXE文件,是运行在64位还是32位操作系统上,也会使其中参数不一(这里一下想不起来是哪几个参数了)

即使同为DLL文件,他的ImageBase字段也有可能不一致,刚刚也说了,以上实验用作判断的ImageBase的值是“默认”的时候的值

因此,以上的判断方法,仅仅是针对普遍的EXE、DLL和其他PE文件而言

并不能保证正确判断、区分所有的PE文件

但是没有找到一个更好的方法,如果有错误或者可以改进的地方,还希望指出

---------------------

作者:Krumitz

来源:CSDN

原文:https://blog.csdn.net/Krumitz/article/details/89197043

版权声明:本文为博主原创文章,转载请附上博文链接!

我的想法:

以上已经说的让我说无可说了,思路非常清晰,下面的”运行在64位还是32位操作系统上,也会使其中参数不一,针对普遍的EXE、DLL和其他PE文件而言)”,其实在我看来,你想程序跨平台64位,32位系统运行,一般可以用一个笨方法:

首先让程序识别当前系统是64位还是32位机,然后根据64位机或32位机使用不同的参数~~~

方法很笨,但是还是非常有用的。

还有个地方漏了过去,就是

(1)读取一个文件,如果文件头的值为0x5A4D,则可以判断这是一个PE文件

(2)将文件指针移到PE头的位置,读取这个头部的信息

(3)读取PE头里面的IMAGE_FILE_HEADER 结构体的Characteristics

(4)判断Characteristics与做0b0010000000000000运算的结果是否为IMAGE_FILE_DLL

(5)判断ImageBase的值是否为0x00400000,判断文件是否为EXE

它的判断dll文件有错。还是师姐的仔细。

--------------------------------------------------------------------------------------------------------------------------------------

代码:

#include<iostream>

#include<Windows.h>

#include<fileapi.h>

#include<tchar.h>

#define OtherPE 3

#define isDLL 2

#define isEXE 1

#define NotPE 0

using namespace std;

int myCheck(char *FilePath)

{

//用于读取IMAGE_DOS_HEADER信息

IMAGE_DOS_HEADER myDosHeader;

HANDLE hFile = CreateFile(

FilePath,

GENERIC_READ,

FILE_SHARE_READ,

NULL,

OPEN_EXISTING,

FILE_ATTRIBUTE_NORMAL,

NULL

);

DWORD readSize = 0;

//将信息读入IMAGE_DOS_HEADER

ReadFile(hFile, &myDosHeader, sizeof(myDosHeader), &readSize, NULL);

//判断头部是否为0x5A4D,即MZ

if (myDosHeader.e_magic == 0x5A4D)

{

IMAGE_NT_HEADERS myNtHeaders;

readSize = 0;

//如果是,将指针设置到PE文件头的位置

SetFilePointer(hFile, myDosHeader.e_lfanew, NULL, FILE_BEGIN);

//读取PE文件头

ReadFile(hFile, &myNtHeaders, sizeof(myNtHeaders), &readSize, NULL);

CloseHandle(hFile);

//判断是否为DLL

if ((myNtHeaders.FileHeader.Characteristics & 0b0010000000000000) == IMAGE_FILE_DLL)

{

return isDLL;

}

//判断是否为EXE

else if (myNtHeaders.OptionalHeader.ImageBase == 0x00400000)

{

return isEXE;

}

//其他PE

else

{

return OtherPE;

}

}

CloseHandle(hFile);

return NotPE;

}

int main()

{

WIN32_FIND_DATA stFindFile;

HANDLE hFindFile;

char *szFilter = (char *)"*.*";   // 所有类型的文件

char szCheckFile[MAX_PATH];  // 保存检测的文件的路径

char szSearch[MAX_PATH];    // 保存完整筛选路径

int ret = 0;                // 搜索的返回值

char directory[256];//保存目录值

cout << "请输入你要搜索的目录的路径:" << endl;

cin >> directory;

//获取当前目录

//GetCurrentDirectory(256, directory);

lstrcpy(szCheckFile, directory);//存入路径中

lstrcat(szCheckFile, "\\");// 添加'\'

lstrcpy(szSearch, directory);//存入路径中

lstrcat(szSearch, "\\");//添加'\'

lstrcat(szSearch, szFilter);//添加过滤条件

hFindFile = FindFirstFile(szSearch, &stFindFile);

if (hFindFile != INVALID_HANDLE_VALUE)

{

do

{

// 组成完整的程序的路径

lstrcat(szCheckFile, stFindFile.cFileName);

//

switch (myCheck(szCheckFile))

{

case isEXE:

cout << stFindFile.cFileName << " is a EXE File" << endl;

break;

case isDLL:

cout << stFindFile.cFileName << " is a DLL File" << endl;

break;

case OtherPE:

cout << stFindFile.cFileName << " is not EXE or DLL but a PE File" << endl;

break;

default:

cout << stFindFile.cFileName << " is not a PE File" << endl;

break;

}

// 重置文件路径

// 这里不重置szCheckFile里的值,接下来会出错

lstrcpy(szCheckFile, directory);

lstrcat(szCheckFile, "\\");

ret = FindNextFile(hFindFile, &stFindFile);

} while (ret != 0);

}

FindClose(hFindFile);

system("pause");

return 0;

}

测试:

输入系统文件目录:

实验完成!!!


通过此次实验,认识了爆破软件和PE文件解释程序的编写。

首先说爆破软件的收获吧,可以说把之前逆向分析等知识综合利用了一下。我也非常庆幸之前仔细分析过逆向的汇编语言,对汇编不再陌生。后来在分析MFC等程序和从老师的思路上学会了逆向分析程序可以只关注重点分析。这里我爆破这个软件,就要找到判断跳转的节点(分叉点),修改相应的值就可以爆破了。

而找到这个节点,就是我们的首要任务。在这里我总结了一下规律。

  1. 首先要找到程序的入口(一般是main函数)
  2. 然后通过程序的入口得到程序的流程图
  3. 通过流程图结合程序运行的输出语句(特征值)找到判断语句位置
  4. 研究判断语句,在判断语句的附近(一般是判断语句的上面,可能修改判断语句也可以,但暂未尝试过)找到可以修改跳转的条件,修改。

我建议使用ida 和 total commmand 配合使用。ida这个工具用来分析程序流程图,找到跳转的节点的地址。total command可以查看程序的16进制值和地址,通过地址找到相关值(修改这个相关值可以改变节点接下来的跳转路线),并修改。

total使用到的键有:

F3(edit)- 修改值

F5(goto)- 通过地址值跳转到相应的地址

F7(Search)- 通过搜索特征值跳转到相应的地址

F9(update)- 更新,修改完文件后需要更要更新保存

对于PE文件的解析程序的编写。我认为首先要了解PE文件解析的原理,可以通过百度,谷歌找到相应的资料(小甲鱼的教程也不错),查找相应的参数,然后编写PE文件解析程序。

它的程序编写流程是:

(1)读取一个文件,如果文件头的值为0x5A4D,则可以判断这是一个PE文件

(2)将文件指针移到PE头的位置,读取这个头部的信息

(3)读取PE头里面的IMAGE_FILE_HEADER 结构体的Characteristics

(4)判断Characteristics与做0b0010000000000000运算的结果是否为IMAGE_FILE_DLL

(5)判断ImageBase的值是否为0x00400000,判断文件是否为EXE

注:运行上面以上代码时要把unicode编码修改为多字节编码。不然会报错。

不足之处:对于爆破时分析程序,我还是查看了一下程序的源码,使用ida、total command、源码相结合才爆破成功。说明我们对于爆破真正有难度的程序(商业)路还很长,我们想真正成为爆破高手还需要不断学习程序逆向分析和汇编语言。还有此次的PE文件解析程序是参考网上的,实在写得太好了,太详细,详细了解了编写流程,运行,debug,修改一下程序的不足,瑕疵之处就上交了,可谓是偷懒了一下,但也学习了不少。

通过此次试验,收益良多

网络安全学习第6篇 - 爆破及PE文件解释相关推荐

  1. [网络安全自学篇] 六十一.PE文件逆向之数字签名详细解析及Signcode、PEView、010Editor、Asn1View等工具用法(二)

    本系列虽然叫"网络安全自学篇",但由于系统安全.软件安全与网络安全息息相关,作者同样会分享一些系统安全案例及基础工具用法,也是记录自己的成长史,希望大家喜欢,一起进步.前文 &qu ...

  2. [网络安全自学篇] 五十七.PE文件逆向之什么是数字签名及Signtool签名工具详解(一)

    本系列虽然叫"网络安全自学篇",但由于系统安全.软件安全与网络安全息息相关,作者同样会分享一些系统安全案例及基础工具用法,也是记录自己的成长史,希望大家喜欢,一起进步.前文讲解了i ...

  3. 网络安全学习第4篇-使用特征码和MD5对勒索病毒进行专杀,并对加密文件进行解密

    请使用IDA或其它分析工具分析本次的样本文件,写一个简要的行为分析报告,并编写一个针对于这次样本的专杀(恢复)程序. 要求: 1.样本分析只要说明主要行为即可.提示:sub_401320主要用于文件加 ...

  4. 网络安全学习第15篇 - 游戏内存修改

    请依据实验文档<游戏辅助的实现>中的内容,自行编写一个游戏内存数据修改程序,使其可以对某款游戏的某一项或某几项数值进行修改.有余力的同学可以任选一款游戏尝试修改. 实验报告的最后请简述,作 ...

  5. 网络安全学习第10篇 - ping程序的实现,抓包分析ping数据包以及ping工具对于网络安全方面的威胁

    请结合附件:Ping的实现原理与ping.cpp的内容,编写一个程序,使其能够实现简单的ping的功能,即判断目标网站是否可以连接,然后通过Wireshark进行抓包分析其ICMP协议,指出哪个数据包 ...

  6. PHP学习笔记 - 进阶篇(7)

    PHP学习笔记 - 进阶篇(7) 文件操作 读取文件内容 PHP具有丰富的文件操作函数,最简单的读取文件的函数为file_get_contents,可以将整个文件全部读取到一个字符串中. $conte ...

  7. [网络安全学习篇10]:扫描技术、暴力破解工具(千峰网络安全视频笔记 10 day)

    引言:我的系列博客[网络安全学习篇]上线了,小编也是初次创作博客,经验不足:对千峰网络信息安全开源的视频公开课程的学习整理的笔记整理的也比较粗糙,其实看到目录有300多集的时候,讲道理,有点怂了,所以 ...

  8. 网络安全学习篇28_阶段一小结篇_木马的原理及木马防范

    上一篇博客:网络安全学习篇27_阶段一小结篇_DNS欺骗与钓鱼网站的防范 写在前面: 刚开始接触了一些关键词如渗透,sql注入,靶场等就发现对此方面挺感兴趣,毕竟有的人大大小小都有一个黑客梦,恰巧在 ...

  9. 网络安全学习篇26_阶段一小结篇_kali中间人渗透

    上一篇博客:防火墙 写在前面: 刚开始接触了一些关键词如渗透,sql注入,靶场等就发现对此方面挺感兴趣,毕竟有的人大大小小都有一个黑客梦,恰巧在 B站碰到了千峰网络培训发布的系列安全培训视频,系列课程 ...

最新文章

  1. ASP.NET页面之间传值的方式之QueryString(个人整理)
  2. 把「我的世界」马赛克变成逼真大片,英伟达又出黑科技
  3. 在线答题系统开发经验mysql,php
  4. 一款机械陀螺仪-四旋翼上的机械陀螺仪
  5. java hdfs 新建目录_如何用java在hdfs中创建一个新目录?
  6. 加快发展设施业 农业大健康-林裕豪:从玉农业践行基础支撑
  7. proteus 8.4安装教程
  8. c语言四字节转浮点数_C语言浮点书于字节互相转换
  9. 108. Convert Sorted Array to Binary Search Tree
  10. ASP.NET 常见参考项目的 UI、BLL 、Model 、 DAL 分析
  11. Hongjin2 软件研发作为一项工程而言
  12. 51单片机之特殊功能寄存器SFR
  13. c语言调用子程序,哪位师傅知道51单片机怎样编写子程序?C语言的。在主程序里调...
  14. current online redo logfile 丢失的处理方法
  15. 计算机仿真类的论文,最新计算机仿真参考文献 计算机仿真专著类参考文献有哪些...
  16. 黑帽SEO研究之js快照劫持代码分析
  17. www读取本地图片做微缩图
  18. 计算机组成原理复习笔记——二、数据的表示和运算
  19. 和谁在一起的确很重要
  20. 【PyCharm实用教程】最详细的Pycharm使用教程,你真不要进来学习一下?

热门文章

  1. 快速上手Django(二) Django 根据模型(models)生成更新数据库表make migrations
  2. MACD指标为什么不灵了?试试QMACD
  3. java中的递归算法_java递归实现
  4. python tushare获取股票数据_python调用tushare获取沪股通、深股通成份股数据
  5. [ecshop 经验 ]transport.js run error 68ecshop 小京东 火狐提示 同源策略和跨域访问 68ecshop
  6. 使用IDEA 进行 安卓开发
  7. 微信小程序-轮播图的实现
  8. Go语言处理Windows系统的图标ICO文件(上)
  9. 美国电子计算机大学排名,美国大学电子计算机专业排名院校有哪些?
  10. 《勒索软件防护发展报告(2022年)》正式发布,助力企业高效应对勒索软件攻击