PE逆向定位main函数
- 一般而言,逆向一般分为静态分析和动态调试,现在先来说说静态分析。
- 参考:逆向工程核心原理第二章
- [[原创]逆向技术之寻找Main入口点-软件逆向-看雪-安全社区|安全招聘|kanxue.com](https://bbs.kanxue.com/thread-224500.htm)
- 逆向分析-快速定位main函数
查看程序信息
- 对于静态分析而言,拿到一个程序,并不要着急去使用
IDA pro
将这个可执行文件或者dll
文件逆向出来。而是先要收集程序的一些相关的信息,一般而言要收集的程序信息有如下:- 查看程序的架构,这个程序是在什么架构下的,不同架构下的程序其二进制指令是不同的即对于的汇编指令是不同的。例如:
x86
架构、x86_64
架构、mips
架构、arm
架构等 - 查看程序的文件结构,对于
Windows
系统、Linux
系统、MAC
系统,其对应的可执行文件的格式都不一样的,如果是windows
系统的可执行文件那就不能在其他系统上直接运行。如果在动态调试的时候就需要选择对应的系统了。 - 查看程序的编译环境,对于相同的代码来说,不同编译器或者编译环境编译成的可执行文件,在
main
函数执行前以及在main
函数结束后所执行的东西是不同的。(这个文章后面会详细说明) - 查看程序的壳,有些程序并不想那么轻易的被反汇编,反编译,这个时候程序就会被加一个壳,这样在对程序进行逆向分析的时候就只能逆向出来程序的壳。而不能逆向出程序的正确代码。而壳这个称呼其实就是有保护程序的意思和自然界一些壳的功能非常相似。
- 查看程序的动态链接库,一般而言如果不是静态编译的程序都会有一个动态链接库,而在逆向的目标程序中会保存着动态链接库的信息,已经一些用到的
函数接口
。从而使得我们在逆向的时候能查找资料或者能很快的反应过来这个函数的作用和功能。 - 查看程序编写的语言,在逆向的时候目标程序不都是
C
语言编写的,可能还有rust
、C++
、golang
以及一些比较古老和小众的语言。获取程序是使用哪种语言编写的这有助于我们了解到该程序会使用哪些标准库,以及一些语言特性。
- 查看程序的架构,这个程序是在什么架构下的,不同架构下的程序其二进制指令是不同的即对于的汇编指令是不同的。例如:
- 上面简单解释了一下收集程序信息的一些作用,接下来介绍一下怎么收集、使用什么工具收集。这里选用的工具是
die
,die
的全称为Detect It Easy
,它是一个开源的可执行文件分析工具,用来检测上面所说的程序信息。它的下载方式在这里:horsicq/Detect-It-Easy:用于确定 Windows、Linux 和 MacOS 文件类型的程序。 - 这里做一个示范,随便找一个
.exe
的可执行文件,在拿到一个.exe
可执行文件时,不要先急着使用IDA
反汇编它,而是先打开DIE
。
- 这样在没有开启高级选项其信息是这样的
- 在开启高级选项后会出现一大串东西,但是其实这一大串东西目前不知道有没有用。但是下图画红框的地方是需要注意的:它标识了
程序基地址
以及程序入口点
,对于程序入口点(EnteryPoint)并不是main
函数,这里放后面会详细说明,这里先知道有EnteryPoint
这个东西 - 在下图中其实我们就能收集到上面所说的层序相关信息,有助于我们逆向分析程序。
程序入口点(EntryPoint)
- 在学
PE
文件结构的时候在NT选项头
的这个结构体即_IMAGE_OPTIONAL_HEADER
这个结构体中,会发现有这么一个成员,这个成员其实就是EntryPoint
1 | typedef struct _IMAGE_OPTIONAL_HEADER{ |
- 如果没学过
PE
文件格式其实也不大,这里具体介绍一下EntryPoint
这个概念:
EP(EntryPoint)入口点:
EP是Windows可执行文件的代码入口点,是执行应用程序时最先执行的代码的起始位置,它依赖于CPU。
注解:从EP的概念中其实就可以知道,我们点击一个
exe
文件,它就是从这个入口点保存的地址开始运行的,即EIP、RIP
一开始的值为EP
- 在学习
C
语言的时候,我们写的代码都是从main
函数开始执行的,但是程序并不是一开始就执行main
函数,而是从EP
开始执行。
定位main函数
- 在收集完信息后,如果有壳就脱壳,没壳就可以直接使用
IDA
进行逆向分析了。如果有做过几题逆向题就会发现,逆向题一开始都是先去寻找main
函数,找到main
函数后才开始对程序进行逆向分析。其实我们编写一个程序也是从main
函数开始。 - 但是在逆向分析中有的时候
main
函数可并不是那么好找的。接下来就使用一个例子来说明为什么有的时候main
函数不好找
例子
- 使用
vs2022
编写如下程序,编译后找到对应的可执行文件
- 下面是对应的可执行文件,在这里除了有
Realme.exe
文件外,其实还有Realme.pdb
文件,这个.pdb
文件是什么呢?pdb
的全称其实是Program Database
(程序数据库),它包含了调试信息,包括变量名、函数名、行号等信息。
- 这时我们使用
Ida
对Realme.exe
文件进行逆向,在逆向的时候我们会出现一个这样的提示,其实就是Realme.exe
文件连接了一个调试信息和符号表在Realme.pdb
中,我们是否要加载这个符号表,这里我们先选择Yes
- 等
Ida
反编译完后直接在Functions
那一栏搜索main
,操作下来会很快的确定到main
函数,这相当的轻松。
- 此时我们关掉这个
ida
界面,对该程序重新逆向,遇到这个选项的时候选择No
Ida
反编译好该文件后继续搜索main
函数,发现并没有搜索到main
函数
- 这时因为程序没有加载
.pdb
文件,所以IDA
在逆向的时候没有对应的符号表,而在真实的环境中,程序都是又多、又没有符号表。在这种情况下就需要先定位到main
函数才能开始逆向分析。对于找到main
函数,其实我们就需要从EP程序入口点
入手。 - 程序入口点在收集程序信息的时候就已经知道了,并且
IDA
中对程序入口点的函数都会使用start
名称,搜索一下函数名称就可以看到(可以多试几个程序,看看这些程序的start
函数)
- 接下来就以
vs2022
编译的x64 debug
的这个realme.exe
文件在有符号表的情况下进行分析,看看这个程序从start
到main
会执行哪些步骤。 - 首先可以查壳看看该程序的的
EP
- 接下来在
IDA
中找到EP
也就是对应的start
函数,此时发现这个start
函数会jmp
到mainCRTStartup
这个函数中去,这个函数的全称为main CRT Startup
,CRT C Runtime Library
- 这时跟进这个函数看看,发现这个函数中会
call
一个函数,一个名为__scrt_common_main
这个函数,接下来继续跟进
- 发现
__scrt_common_main
会call
俩个函数,这时会注意到第二个函数与main
函数有关系,所以跟进到__scrt_common_main_seh
这个函数中,进行分析。
- 进入到
__scrt_common_main_seh
会发现这是一个比较复杂的函数
- 这个时候定位到函数块结束前面一点的位置,会看到这个函数会调用
invoke_main
跟进到这个函数中去
- 进入到这个函数中去就会发现有一个
j_main
,跟进j_main
- 发现
j_main
这个函数会执行jmp main
,而jmp main
中jmp
到的位置其实就是main
函数的位置
- 所以在
start
到main
之间vs2022
编译的x64
程序执行的流程是这样的:
1 | start |
定位main函数的方法
-
通过上面的分享,这时如果遇到一个
vs2022
编译的x64
版本的exe
程序尽管它没有符号表,我们也能比较快速的找到main
函数。但是其他开发环境编译的程序start->main
是否也是这样的流程呢?答案是其他开发环境编译的程序可能并不是这样的流程,主要有以下几点:- 不同编译器,编译后的
exe
程序start->main
函数之间执行的程序是不同的。 - 相同编译器但是版本不同,编译后的
exe
程序start->main
函数之间执行的程序也是不同的。
- 不同编译器,编译后的
-
因为编译器的原因
start->main
之间执行的程序逻辑并不相同,这样我们并不能学习一个vs2022 x64
编译的程序start->main
之间的过程就一劳永逸,还需要一些其他的方法来确定main函数的地址,这里介绍几个方法。- 方法一:收集到逆向的目标程序编译环境(包括开发环境、编译器版本等)信息后,在本地配置一个相同或者差不多的环境(比如都使用
vs2022
)使用该开发环境编写一个简单的程序并带有符号表编译,通过调试这个简单的程序熟悉start->main
之间的程序流程,这样逆向目标程序就很容易找到main
函数了。 - 方法二:字符串搜索法
- 方法三:动态调试,调试call到相应函数时程序会触发一些行为,或者在调试器中看到一些字符串即可确定函数。
- 方法四:API检索法在调用代码中设置断点、在API代码中设置断点。
- 方法五:寻找
exit
函数,寻找exit函数的参数从哪里来,一般来说exit函数的参数是main的返回值。
- 方法一:收集到逆向的目标程序编译环境(包括开发环境、编译器版本等)信息后,在本地配置一个相同或者差不多的环境(比如都使用
-
对于方法一,一种就是现学,另一种就是平时的积累,没什么好说的,在文章后面会对各个编译器和开发环境下编译的
exe
文件从start->main
的这一过程进行分析并积累起来。接下来重点介绍一下方法二、三、四
注意:对于方法二、三、四
其实也适用于定位其他关键函数。
方法二
方法三
方法四
Visual_studio2022_start分析
x64
x32
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 iyheart的博客!