MetInfo6.0.0目录遍历漏洞原理分析

news2025/4/1 19:07:18

所需进行代码审计的文件路径:

C:\phpStudy\WWW\MetInfo6.0.0\include\thumb.php

C:\phpStudy\WWW\MetInfo6.0.0\app\system\entrance.php

C:\phpStudy\WWW\MetInfo6.0.0\app\system\include\class\load.class.php 

C:\phpStudy\WWW\MetInfo6.0.0\app\system\include\moduleold_thumb.class.php

文件间的关联与作用

thumb.php:

<?php
# MetInfo Enterprise Content Management System
# Copyright (C) MetInfo Co.,Ltd (http://www.metinfo.cn). All rights reserved.
define('M_NAME', 'include');
define('M_MODULE', 'include');
define('M_CLASS', 'old_thumb');
define('M_ACTION', 'doshow');
require_once '../app/system/entrance.php';
# This program is an open source system, commercial use, please consciously to purchase commercial license.
# Copyright (C) MetInfo Co., Ltd. (http://www.metinfo.cn). All rights reserved.
?>

 此文件定义了 4 个常量。M_NAMEM_MODULE被设为include,虽在此漏洞利用过程中未直接起关键作用,但它们是系统模块标识的一部分。重点是M_CLASS被定义为old_thumbM_ACTION被定义为doshow ,这两个常量为系统后续确定执行的类和方法提供了核心标识。同时,通过require_once '../app/system/entrance.php';引入系统入口文件 entrance.php,启动整个系统执行流程。

重点代码:
<?php
define('M_CLASS', 'old_thumb');
define('M_ACTION', 'doshow');
require_once '../app/system/entrance.php';
?>
  1. define 函数
    • define('M_CLASS', 'old_thumb');:这行代码使用 define 函数定义了一个名为 M_CLASS 的常量,并将其值设置为 old_thumb。常量在整个脚本执行过程中值是固定不变的,不能被重新赋值。
    • define('M_ACTION', 'doshow');:同样使用 define 函数定义了名为 M_ACTION 的常量,值为 doshow。这些常量后续会被用来确定系统要执行的类和类中的方法。
  2. require_once 语句
    • require_once '../app/system/entrance.php';require_once 是 PHP 中用于引入外部文件的语句。它会尝试引入 ../app/system/entrance.php 文件。如果该文件已经被引入过,require_once 不会再次引入,以避免重复引入导致的问题。在这里,它的作用是启动系统的执行流程,进入 entrance.php 文件继续执行。

entrance.php

//当前访问的主机名
define ('HTTP_HOST', isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME']);
//来源页面
define('HTTP_REFERER', $_SERVER['HTTP_REFERER']);
//来源页面
define('REQUEST_URI', $_SERVER['REQUEST_URI']);

//脚本路径
$phpfile = basename(__FILE__);
$_SERVER['PHP_SELF']=htmlentities($_SERVER['PHP_SELF']);
define ('PHP_SELF', $_SERVER['PHP_SELF']=="" ? $_SERVER['SCRIPT_NAME'] : $_SERVER['PHP_SELF']);

if (!preg_match('/^[A-Za-z0-9_]+$/', M_TYPE.M_NAME.M_MODULE.M_CLASS.M_ACTION)) {
    echo 'Constants must be numbers or letters or underlined';
    die();
}

require_once PATH_SYS_CLASS.'load.class.php';

load::module();

# This program is an open source system, commercial use, please consciously to purchase commercial license.
# Copyright (C) MetInfo Co., Ltd. (http://www.metinfo.cn). All rights reserved.

        该文件首先定义了与 HTTP 请求和服务器相关的常量,如HTTP_HOST用于获取当前访问的主机名,HTTP_REFERER记录来源页面,REQUEST_URI表示当前请求的 URI 等。这些常量主要用于系统对请求环境的识别和记录,但与本次路径穿越漏洞利用无直接关联。接着,它对M_TYPE.M_NAME.M_MODULE.M_CLASS.M_ACTION进行正则匹配检查,确保其由数字、字母或下划线组成,目的是保证系统常量的规范性。关键在于require_once PATH_SYS_CLASS.'load.class.php';引入了load.class.php文件,并调用load::module();方法。在调用load::module()方法时,默认会依据 thumb.php 中定义的M_CLASSM_ACTION常量来确定要加载的类和执行的动作,由此建立起与 thumb.php 和load.class.php的紧密联系。

重点代码:
require_once PATH_SYS_CLASS.'load.class.php';
load::module();
  1. require_once 语句
    • require_once PATH_SYS_CLASS.'load.class.php';:这行代码引入了 load.class.php 文件,PATH_SYS_CLASS 是一个预定义的路径常量(在提供的代码中虽然没有看到它的定义,但从代码逻辑推测应该是存在的),它和 'load.class.php' 拼接成完整的文件路径。引入这个文件是为了使用其中定义的 load 类及其相关方法。
  2. load::module() 方法调用
    • load::module();:这里调用了 load 类的静态方法 moduleload 类定义在 load.class.php 文件中,module 方法的作用是根据传入的参数(如果没有传入参数则使用默认值)来加载相应的类并执行类中的方法。在这个调用中,由于没有传入参数,它会使用默认的参数值,而默认值就与 thumb.php 中定义的 M_CLASS 和 M_ACTION 常量相关。

load.class.php:

class load {
    // ...
    public static function module($path = '', $modulename = '', $action = '') {
        if (!$path) {
            if (!$path) $path = PATH_OWN_FILE;
            if (!$modulename) $modulename = M_CLASS;
            if (!$action) $action = M_ACTION;
            if (!$action) $action = 'doindex';
        }
        return self::_load_class($path, $modulename, $action);
    }
    // ...
    private static function _load_class($path, $classname, $action = '') {
        $classname=str_replace('.class.php', '', $classname);
        $is_myclass = 0;
        if(!self::$mclass[$classname]){
            if(file_exists($path.$classname.'.class.php')){
                require_once $path.$classname.'.class.php';
            } else {
                echo str_replace(PATH_WEB, '', $path).$classname.'.class.php is not exists';
                exit;
            }
            $myclass = "my_{$classname}";
            if (file_exists($path.'myclass/'.$myclass.'.class.php')) {
                $is_myclass = 1;
                require_once $path.'myclass/'.$myclass.'.class.php';
            }
        }
        if ($action) {
            if (!class_exists($classname)) {
                die($classname . ' ' . $action . ' class\'s file is not exists!!!');
            }
            if(self::$mclass[$classname]){
                $newclass = self::$mclass[$classname];
            }else{
                if($is_myclass){
                    $newclass = new $myclass;
                }else{
                    $newclass = new $classname;
                }
                self::$mclass[$classname] = $newclass;
            }
            if ($action!='new') {
                if(substr($action, 0, 2) != 'do'){
                    die($action.' function no permission load!!!');
                }
                if(method_exists($newclass, $action)){
                    call_user_func(array($newclass, $action));
                }else{
                    die($action.' function is not exists!!!');
                }
            }
            return $newclass;
        }
        return  true;
    }
    // ...
}

该文件提供了一系列加载类、函数库、模块等的方法。其中load::module方法至关重要,在没有传入特定参数时,它会使用默认值。这里if (!$modulename) $modulename = M_CLASS;if (!$action) $action = M_ACTION;,意味着会使用 thumb.php 中定义的M_CLASS(即old_thumb)和M_ACTION(即doshow)。然后调用self::_load_class方法。_load_class方法会先检查要加载的类文件是否存在,若存在则引入。当$action存在且符合条件(以do开头)时,会实例化类并调用类中的对应方法。由于load::module方法在 entrance.php 中被调用,且根据 thumb.php 的常量设置,最终会调用old_thumb类的doshow方法。

重点代码:
class load {
    public static function module($path = '', $modulename = '', $action = '') {
        if (!$modulename) $modulename = M_CLASS;
        if (!$action) $action = M_ACTION;
        return self::_load_class($path, $modulename, $action);
    }

    private static function _load_class($path, $classname, $action = '') {
        if ($action) {
            if (!class_exists($classname)) {
                die($classname . ' ' . $action . ' class\'s file is not exists!!!');
            }
            $newclass = new $classname;
            if ($action!='new') {
                if(substr($action, 0, 2) == 'do' && method_exists($newclass, $action)) {
                    call_user_func(array($newclass, $action));
                }
            }
            return $newclass;
        }
        return  true;
    }
}
  1. module 方法
    • public static function module($path = '', $modulename = '', $action = ''):这是 load 类的一个公共静态方法,接受三个参数 $path(文件路径)、$modulename(类名)和 $action(要执行的方法名)。
    • if (!$modulename) $modulename = M_CLASS;:如果没有传入 $modulename 参数,就使用 M_CLASS 常量的值作为类名。
    • if (!$action) $action = M_ACTION;:同理,如果没有传入 $action 参数,就使用 M_ACTION 常量的值作为要执行的方法名。
    • return self::_load_class($path, $modulename, $action);:调用 _load_class 方法,并将当前的参数传递过去,_load_class 方法会负责加载类并执行相应的方法。
  2. _load_class 方法
    • private static function _load_class($path, $classname, $action = ''):这是一个私有静态方法,用于实际加载类和执行方法。
    • if ($action):检查是否传入了 $action 参数,如果有传入才会继续执行后续逻辑。
    • if (!class_exists($classname)):检查指定的类名 $classname 是否存在,如果不存在就输出错误信息并终止脚本执行。
    • $newclass = new $classname;:如果类存在,就实例化这个类。
    • if ($action!='new'):如果 $action 不是 new,则继续检查。
    • if(substr($action, 0, 2) == 'do' && method_exists($newclass, $action)):检查 $action 是否以 do 开头,并且类中是否存在这个方法,如果满足条件,就使用 call_user_func 函数调用类中的方法。

old_thumb.class.php:

<?php
# MetInfo Enterprise Content Management System
# Copyright (C) MetInfo Co.,Ltd (http://www.metinfo.cn). All rights reserved.

defined('IN_MET') or exit('No permission');

load::sys_class('web');

class old_thumb extends web{
    public function doshow(){
        global $_M;
        $dir = str_replace(array('../','./'), '', $_GET['dir']);
        if(substr(str_replace($_M['url']['site'], '', $dir),0,4) == 'http' && strpos($dir, './') === false){
            header("Content-type: image/jpeg");
            ob_start();
            readfile($dir);
            ob_flush();
            flush();
            die;
        }
        if($_M['form']['pageset']){
            $path = $dir."&met-table={$_M['form']['met-table']}&met-field={$_M['form']['met-field']}";
        }else{
            $path = $dir;
        }
        $image =  thumb($path,$_M['form']['x'],$_M['form']['y']);
        if($_M['form']['pageset']){
            $img = explode('?', $image);
            $img = $img[0];
        }else{
            $img = $image;
        }
        if($img){
            header("Content-type: image/jpeg");
            ob_start();
            readfile(PATH_WEB.str_replace($_M['url']['site'], '', $img));
            ob_flush();
            flush();
        }
    }
}
# This program is an open source system, commercial use, please consciously to purchase commercial license.
# Copyright (C) MetInfo Co., Ltd. (http://www.metinfo.cn). All rights reserved.

此文件定义了old_thumb类,其中doshow方法存在路径穿越漏洞。在doshow方法中,$dir = str_replace(array('../','./'), '', $_GET['dir']);$_GET中获取dir参数,并尝试通过str_replace函数移除.././来进行简单过滤。但这种过滤方式存在严重缺陷,攻击者可构造特殊输入如....//绕过过滤。随后,若满足一定条件,会使用readfile($dir);函数读取文件。若攻击者成功绕过过滤,就能利用该函数读取服务器上的任意文件,例如敏感文件/etc/passwd,从而导致敏感信息泄露。

重点代码:
class old_thumb {
    public function doshow() {
        $dir = str_replace(array('../','./'), '', $_GET['dir']);
        if(substr(str_replace($_M['url']['site'], '', $dir),0,4) == 'http' && strpos($dir, './') === false){
            readfile($dir);
        }
        // ... 其他逻辑
        if ($img) {
            readfile(PATH_WEB.str_replace($_M['url']['site'], '', $img));
        }
    }
}
  1. old_thumb 类
    • class old_thumb:定义了一个名为 old_thumb 的类。
  2. doshow 方法
    • public function doshow():这是 old_thumb 类的一个公共方法。
    • $dir = str_replace(array('../','./'), '', $_GET['dir']);:从 $_GET 超全局变量中获取名为 dir 的参数值,然后使用 str_replace 函数尝试移除字符串中的 ../ 和 ./。这里的意图是对用户输入的路径进行简单过滤,防止目录穿越。
    • if(substr(str_replace($_M['url']['site'], '', $dir),0,4) == 'http' && strpos($dir, './') === false):进一步检查处理后的 $dir 参数,如果它以 http 开头并且不包含 ./,则执行 readfile($dir);readfile 函数会读取指定路径的文件内容并输出。
    • if ($img):在后续逻辑中,如果 $img 存在,也会使用 readfile 函数读取经过处理的路径对应的文件内容。这里的问题在于,str_replace 函数的过滤方式不够严格,攻击者可以通过构造特殊的输入(比如 ....//)绕过过滤,从而实现路径穿越,读取服务器上的任意文件。

利用过程及方式

  • 攻击者构造请求:攻击者精心构造一个包含恶意dir参数的 HTTP 请求,假设系统访问入口为http://example.com/thumb.php,攻击者构造的请求可能是http://example.com/thumb.php?dir=../../../etc/passwd。这里使用../../../等目录穿越字符,试图突破正常的文件访问限制,访问到服务器上的敏感文件/etc/passwd。这是利用了old_thumb.class.phpdoshow方法对dir参数过滤不严格的漏洞。
  • 系统执行流程:当攻击者的请求发送到服务器并到达 thumb.php 文件后,thumb.php 引入 entrance.php 文件,启动系统流程。entrance.php 文件在执行过程中,引入load.class.php并调用load::module()方法。由于 thumb.php 中定义的M_CLASSold_thumbM_ACTIONdoshowload::module方法在执行时,会根据这些默认常量设置,通过_load_class方法实例化old_thumb类并调用其doshow方法。具体来说,load::module方法中if (!$modulename) $modulename = M_CLASS;if (!$action) $action = M_ACTION;语句使得old_thumb类和doshow方法被选中,然后_load_class方法负责完成类的实例化和方法调用准备工作。
  • 漏洞触发:在old_thumb.class.phpdoshow方法被调用后,获取到攻击者传入的恶意dir参数。尽管进行了简单的str_replace过滤,但攻击者构造的特殊输入可能绕过该过滤。例如,若攻击者输入....//,经过str_replace后可能仍然包含有效的目录穿越字符。随后,readfile函数会尝试读取经过处理后的dir对应的文件路径。如果攻击者成功绕过过滤,readfile函数就会读取服务器上的敏感文件,如/etc/passwd,将文件内容返回给攻击者,导致敏感信息泄露。

代码分析和理解

  • 常量定义的影响:thumb.php 中的常量定义在整个系统执行流程中起着关键的引导作用。M_CLASSM_ACTION常量如同系统执行的 “导航标”,虽然它们本身只是简单的字符串定义,但却决定了系统后续执行的具体类和方法。攻击者正是利用了这一机制,通过控制与这些常量相关的请求参数,间接地影响到存在漏洞的old_thumb.class.php中的doshow方法。这种常量定义方式在实现系统功能模块化和灵活性的同时,也为潜在的安全攻击留下了隐患,因为常量的全局有效性使得攻击者可以在系统的执行流程中找到切入点。
  • 文件加载和方法调用:entrance.php 引入load.class.php并调用相关方法,体现了系统模块化设计的思路,将不同功能的代码分离到不同文件中,便于管理和维护。然而,这种设计也为攻击者利用模块间的关联创造了条件。load.class.php中的方法负责加载各类资源和调用相应的功能,其逻辑较为复杂。例如,load::module_load_class方法之间的协作,通过层层传递参数和执行逻辑,最终实现类的加载和方法的调用。攻击者通过分析系统的这种执行逻辑,利用 thumb.php 中的常量设置,精准地控制load::module方法的参数,从而调用到存在漏洞的doshow方法。这表明在系统设计中,虽然模块化提高了开发效率,但也需要更加严格地把控模块间交互的安全性,避免因复杂的调用关系而引入安全风险。
  • 输入验证和过滤不足old_thumb.class.phpdoshow方法对dir参数的验证和过滤过于简单。仅使用str_replace函数移除.././,这种方式无法有效抵御目录穿越攻击。从安全编程的角度来看,对用户输入的验证应该采用更加严格和全面的方式,例如使用白名单过滤,只允许合法的字符和路径格式。攻击者通过构造特殊输入,如....//,可以轻易绕过这种简单的过滤机制。一旦绕过成功,readfile函数就会被攻击者利用来读取任意文件,这充分暴露了代码在安全防护方面的不足。在开发过程中,对于涉及文件操作的用户输入,必须进行严格的安全检查,以防止类似的路径穿越漏洞导致的安全问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2324220.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux打包前端vue,后端springboot项目

第一步先对整个项目进行通过maven进行clean在进行compile 第二步直接进行打包package和install都可以 第三部把对应的jar放到服务器上 把jar包放到服务器上某个地址下&#xff0c;然后cd到这个目录下&#xff0c;然后执行命令 nohup java -jar ruoyi-admin.jar > springbo…

Elasticsearch:使用 AI SDK 和 Elastic 构建 AI 代理

作者&#xff1a;来自 Elastic Carly Richmond 你是否经常听到 AI 代理&#xff08;AI agents&#xff09;这个词&#xff0c;但不太确定它们是什么&#xff0c;或者如何在 TypeScript&#xff08;或 JavaScript&#xff09;中构建一个&#xff1f;跟我一起深入了解 AI 代理的概…

Docker 快速入门指南

Docker 快速入门指南 1. Docker 常用指令 Docker 是一个轻量级的容器化平台&#xff0c;可以帮助开发者快速构建、测试和部署应用程序。以下是一些常用的 Docker 命令。 1.1 镜像管理 # 搜索镜像 docker search <image_name># 拉取镜像 docker pull <image_name>…

自顶向下学习K8S--部署Agones

本文在本人博客&#xff0c;原文地址&#xff1a;http://viogami.tech/index.php/blog/346/ 我是gopher&#xff0c;离不开云原生&#xff0c;自然也逃不了理解docker和K8S这俩。今天抽空想玩下agones&#xff0c;进而对K8S有实践性的理解。 学一个新事物从底层理论学肯定是最…

unity中Xcharts图表鼠标悬浮表现异常

鼠标悬浮在面板附近&#xff0c;只显示单独的一个项目 而且无论鼠标如何移动&#xff0c;根本没有效果。 解决方案&#xff1a; 需要在对应的Canvas上绑定主相机才可以 鼠标移动到项目上就有信息展示了

【Java SE】包装类 Byte、Short、Integer、Long、Character、Float、Double、Boolean

参考笔记&#xff1a;java 包装类 万字详解&#xff08;通俗易懂)_java包装类-CSDN博客 目录 1.简介 2.包装类的继承关系图 3.装箱和拆箱 3.1 介绍 3.2 手动拆装箱 3.3. 自动拆装箱 ​4.关于String类型的转化问题 4.1 String类型和基本类型的相互转化 4.1.1 String —…

口腔种植全流程AI导航系统及辅助诊疗与耗材智能化编程分析

一、系统架构与编程框架设计 口腔种植全流程人工智能导航系统的开发是一项高度复杂的多学科融合工程,其核心架构需在医学精准性、工程实时性与临床实用性之间实现平衡。系统设计以模块化分层架构为基础,结合高实时性数据流与多模态协同控制理念,覆盖从数据采集、智能决策到…

Java 集合中ArrayList与LinkedList的性能比较

一、需求&#xff1a; 头部插入‌&#xff1a;向列表头部插入10万个整数。‌随机访问‌&#xff1a;从列表中间位置连续获取1万个元素。‌头部删除‌&#xff1a;从列表头部连续删除10万个元素。 二、 使用ArrayList与LinkedList测试 //常量定义&#xff0c;用于测试操作的次数…

漏洞发现:AWVS 联动 XRAY 图形化工具.(主动+被动 双重扫描)

漏洞发现&#xff1a;AWVS 联动 XRAY 图形化工具. 漏洞发现是网络安全领域的关键环节&#xff0c;指通过技术手段识别计算机系统、网络设备或软件中存在的设计缺陷、配置错误或代码漏洞的过程。这些漏洞可能被攻击者利用&#xff0c;导致数据泄露、服务中断或权限提升等风险。…

Linux ping/telnet/nc命令

在Linux操作系统中&#xff0c;ping命令用于测试网络连接和发送数据包到目的主机。 然而&#xff0c;ping命令默认情况下只能测试IP地址和域名&#xff0c;而无法直接测试端口号。 ping www.baidu.comping 192.168.0.1 测试端口 如果你想测试特定端口是否开放并响应&#xff…

Netty - 从Nginx 四层(TCP/UDP)流量中获取客户端真实/网络出口IP

文章目录 一、背景与原理1.1 问题场景网络架构影响分析1.1 客户端与Nginx之间存在的NAT/VPN1.2 Nginx与RPC服务之间的NAT 1.2 技术原理 二、环境配置验证2.1 Nginx配置2.2 版本要求 三、Netty服务端实现3.1 Pipeline配置&#xff08;核心代码&#xff09;3.2 协议处理器实现3.3…

Ubuntu下载docker、xshell

配置&#xff1a;VMware虚拟机、Ubuntu24.04.1 首先打开vm启动虚拟机 下载docker Ubuntu启动之后&#xff0c;按CTRLALTT 打开终端 1.更新软件包索引并安装依赖 sudo apt-get updatesudo apt-get install \ca-certificates \curl \gnupg \lsb-release 2.添加docker官方的GP…

迅为iTOP-RK3576人工智能开发板Android 系统接口功能测试

2.1 开机启动 开发板接通电源&#xff0c;并按下电源开关&#xff0c;系统即启动&#xff0c;在启动过程中&#xff0c;系统会显示下图中的开机画面&#xff0c;它们分别是 Android 系统启动时的 Logo 画面&#xff1a; 最后会显示如下解锁画面&#xff1a; 2.2 命令终端 将…

office_word中使用宏以及DeepSeek

前言 Word中可以利用DeepSeek来生成各种宏&#xff0c;从而生成我们需要各种数据和图表&#xff0c;这样可以大大减少我们手工的操作。 1、Office的版本 采用的是微软的office2016&#xff0c;如下图&#xff1a; 2、新建一个Word文档 3、开启开发工具 这样菜单中的“开发工具…

数据结构day04

一 栈 1栈的基本概念 各位同学大家好&#xff0c;从这个小节开始&#xff0c;我们会正式进入第三章的学习&#xff0c;我们会学习栈和队列&#xff0c;那这个小节中我们会先认识栈的基本概念。我们会从栈的定义和栈的基本操作来认识栈这种数据结构&#xff0c;也就是要探讨栈的…

质量工程:数字化转型时代的质量体系重构

前言&#xff1a;质量理念的范式转移阅读原文 如果把软件开发比作建造摩天大楼&#xff1a; 传统测试 竣工后检查裂缝&#xff08;高成本返工&#xff09; 质量工程 从地基开始的全流程监理体系&#xff08;设计图纸→施工工艺→建材选择→竣工验收&#xff09; IEEE研究…

pyQt学习笔记——Qt资源文件(.qrc)的创建与使用

Qt资源文件&#xff08;.qrc&#xff09;的创建与使用 1. 选择打开资源2. 创建新资源3. 添加资源文件夹4. 选择要加载的图片文件5. 编译resource.qrc文件6. 替换PySlide6为PyQt57. 其他说明 1. 选择打开资源 在Qt项目中&#xff0c;可以通过windowIcon点击选择打开资源。 2. 创…

优雅的开始一个Python项目

优雅的开始一个Python项目 这是我在初始化一个Python项目时&#xff0c;一键生成的项目文件。它自动完成了git初始化、环境管理、日志模块这三件事情&#xff0c;并在最后进入了虚拟环境。 uv安装 uv是一个现代的Python包管理和项目管理工具。uv中文文档 安装uv: # unix: …

[学成在线]07-视频转码

视频转码 视频上传成功后需要对视频进行转码处理。 首先我们要分清文件格式和编码格式&#xff1a; 文件格式&#xff1a;是指.mp4、.avi、.rmvb等这些不同扩展名的视频文件的文件格式 &#xff0c;视频文件的内容主要包括视频和音频&#xff0c;其文件格式是按照一定的编码…

qt+opengl 加载三维obj文件

1前面我们已经熟悉了opengl自定义顶点生成一个立方体&#xff0c;并且我们实现了立方体的旋转&#xff0c;光照等功能。下面我们来用opengl来加载一个obj文件。准备我们首先准备一个简单的obj文件&#xff08;head.obj&#xff09;。资源在本页下载 2 在obj文件里面&#xff0c…