返回:安全开发篇(一)目录 · 上一篇:006、include 预处理指令 · 下一篇:008、函数调用过程

对应视频:1.6 基础-程序入口点.mp4

1、学习目标

这一节理解 C 程序从哪里开始执行。对普通控制台程序来说,最重要的入口就是 main 函数。

需要掌握:

  1. main 函数的作用;
  2. int main(void) 的含义;
  3. 返回值的作用;
  4. 命令行参数入口形式;
  5. 入口点和后续逆向分析的关系。

2、最常见入口

1
2
3
4
5
6
7
#include <stdio.h>

int main(void)
{
printf("program start\n");
return 0;
}

这里 main 是程序入口函数。程序运行时,执行流程从入口开始,再按照语句顺序继续向下执行。

部分 含义
int main 返回一个整数状态码
main 入口函数名
void 不接收参数
return 0 正常结束

3、带参数的入口

命令行程序常用下面这种形式:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>

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

for (int i = 0; i < argc; i++)
{
printf("argv[%d] = %s\n", i, argv[i]);
}

return 0;
}
参数 含义
argc 命令行参数数量
argv 命令行参数字符串数组
argv[0] 通常是程序路径或程序名

后续写扫描器、文件处理工具、批量检测工具时,命令行参数会非常常见。

4、返回值

main 的返回值会交给操作系统或调用它的脚本。

返回值 常见含义
0 正常结束
非 0 出错或异常结束

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>

int main(void)
{
int ok = 1;

if (!ok)
{
return 1;
}

return 0;
}

5、入口点和调试

在 Visual Studio 中,可以从 main 设置断点,然后逐行调试。这样能观察:

  1. 程序是否真的从 main 开始进入;
  2. 变量什么时候创建;
  3. 函数什么时候被调用;
  4. 返回语句执行后程序如何结束。

调试时先从入口点建立全局顺序感,再逐步进入函数内部。不要一开始就陷在某一行代码里。

6、安全开发观察

入口点在逆向分析里是重要概念。源码里的 main 和可执行文件真正的入口点不是完全等价的,中间还会有运行库初始化过程。

入门阶段先记住:

  1. C 代码层面从 main 开始理解;
  2. 可执行文件层面还有更底层的程序入口;
  3. 逆向分析会从入口附近追踪程序行为;
  4. 工具类程序常通过 argc、argv 接收外部输入,输入检查会影响安全性。

7、复盘题

7.1 int main(void) 中的 void 表示什么?

表示 main 函数不接收参数。也就是说,当前程序不通过 argc 和 argv 处理命令行输入。

7.2 return 0 的含义是什么?

表示程序正常结束,并把状态码 0 返回给操作系统或调用者。

7.3 为什么安全工具常用带参数的 main?

因为安全工具经常需要从命令行接收目标地址、文件路径、端口、配置项等输入。argc 和 argv 是控制台工具处理外部参数的基础。

这一节要形成一个直觉:写代码时从 main 看执行顺序,做逆向时从入口点追踪程序行为。