64位c语言调用32位glibc,glibc fclose源代码阅读及伪造_IO_FILE利用fclose实现任意地址执行...

简介

最近学习了一下_IO_FILE的利用,刚好在pwnable.tw上碰到一道相关的题目。拿来做了一下,遇到了一些困难,不过顺利解决了,顺便读了一波相关源码,对_IO_FILE有了更深的理解。

文章分为三部分,分别是利用原理、实例和源码阅读。源码部分比较无聊所以我把它放在了最后。

原理

原理

我们使用fopen打开一个文件会在堆上分配一块内存区域用来存储FILE结构体,存储的结构体包含两个部分,前一部分为_IO_FILE结构体file,后一部分是一个指向struct IO_jump_t的指针vtable, 这个结构体种存储着一系列与文件IO相关的函数指针。

在我们调用fclose关闭一个文件时,我们最终会调用到vtable中存储的函数指针。如果我们能够将vtable中的指针替换为我们自己想要跳转到的地址就可以劫持程序流程。

利用前提

本文仅考虑libc版本 <= 2.23的情况。因为大于等于2.24的libc会对vtable的位置做判断,无法令其指向自己构造的区域

可以控制vtable指针或者fp指针指向的位置

有一块已知地址的可控内存区域,大小需要视情况而定

利用方式1:直接覆盖vtable指针

这个没什么好说的,将vtable指针指向可控内存,将__finish(off=2*SIZE_T)构造为要执行的地址即可

利用方式2:覆盖fp指针

有的时候我们无法直接控制FILE结构体的vtable指针,但是我们可以控制文件指针。因此我们需要伪造整个FILE结构体,然后控制vtable指针指向我们自己构造的函数列表,在__finish(off=2*SIZE_T)位置布置好我们想要调用的地址,最后调用fclose。

这种方式的 关键 在于要伪造一个合适的FILE结构体使得在fclose的过程中不会触发异常造成程序异常终止。为了避免这种情况,一种最简单的方式就是将FILE结构体的_flags变量的_IO_IS_FILEBUF标志位置0。例如置为0xffffdfff。这样做的主要原因是为了绕过一些操作。

if (fp->_IO_file_flags & _IO_IS_FILEBUF)

_IO_un_link ((struct _IO_FILE_plus *) fp);

_IO_acquire_lock (fp);

if (fp->_IO_file_flags & _IO_IS_FILEBUF)

status = _IO_file_close_it (fp);

else

status = fp->_flags & _IO_ERR_SEEN ? -1 : 0;

_IO_release_lock (fp);

_IO_FINISH (fp);

相关代码如上。

可以看到当_IO_IS_FILEBUF位为0时,函数不会执行_IO_un_link和_IO_file_close_it函数,而直接执行_IO_FINISH函数。在_IO_FINISH函数中会直接调用vtable中的__finish函数。其中_IO_IS_FILEBUF被定义为0x2000。

#define _IO_IS_FILEBUF 0x2000

利用实例

题目简介

测试用的题目来源于pwnable.tw,题目名为seethefile。为FILE结构体利用的一道比较经典的题目。在这里只谈一下解题思路,不给出exp。

逆向分析概要

openfile打开一个文件,文件名由用户输入,但是当文件名含flag时会退出程序

readfile将文件中的内容读入一个全局字符数组中

writefile将全局字符数组中的内容输出到屏幕上

closefile关闭文件

当输入为5时程序要求输入一个名字,然后关闭存储文件指针fp,退出程序

2e00afb01606

main.png

以上步骤的文件指针都存放在一个全局变量中,bss对应的结构如下

2e00afb01606

bss.png

漏洞分析

由逆向结果可知。在读取数字时存在栈溢出,但是程序开启了栈保护,所以不可利用;

当输入命令5,读取用户指令时存在一个bss段的溢出,利用这个溢出我们可以覆盖fp的指针指向我们想要的位置,同时可以伪造FILE结构体。利用fclose来实现攻击。

漏洞利用

leak libc

题目给出了libc的文件,为了执行libc中的system命令,还需要获取libc加载的基址。我们可以通过打开/proc/self/mmap这个虚拟文件来获取当前进程的地址空间情况。获得到libc的加载基址后就可以计算出libc中system的偏移。接下来我们就可以利用_IO_FILE结构体进行攻击。

构造FILE

构造FILE结构体只需要关注两个变量,第一个为FILE结构体的_flags字段,只需要_flags & 0x2000为0就会直接调用_IO_FINSH(fp),_IO_FINISH(fp)相当于调用fp->vtabl->__finish(fp)。

将fp指向一块内存P,P偏移0的前4字节设置为0xffffdfff,P偏移4位置放上要执行的字符串指令(字符串以';'开头即可),P偏移sizeof(_IO_FILE)大小位置(vtable)覆盖为内存区域Q,Q偏移2*4字节处(vtable->__finish)覆盖为system函数地址即可。

glibc fclose源码学习

glibc的版本为2.23.90,复制粘贴比较多,主要是为了方便查阅。以下内容对大部分的fclose函数进行了层层解剖,很多部分与漏洞利用无太大关系,按需取用。

_IO_FILE与_IO_FILE_plus结构体

在阅读fclose前先来了解一些有关于FILE结构体的知识。

在C语言中,成功调用fopen函数后会在堆上分配一块空间用于存放_IO_FILE_plus结构体,并且返回结构体的首地址。阅读源码可以发现_IO_FILE_plus结构体只是在_IO_FILE结构体后添加了一个虚表指针 vtable。

/* _IO_FILE_plus结构体 */

/* in libio/libioP.h */

struct _IO_FILE_plus

{

_IO_FILE file;

const struct _IO_jump_t *vtable;

};

虚表指针指向了如下的一个结构体。JUMP_FIELD是一个接收两个参数的宏,前一个参数为类型名,后一个为变量名。结构体的前两个变量实际上不会被使用到,所以默认为0,其余的变量存储着不同的函数指针,在使用FILE结构体进行IO操作的过程中会通过这些函数指针调用到对应的函数。

/*_IO_jump_t虚表结构体*/

/* in libio/libioP.h */

struct _IO_jump_t

{

JUMP_FIELD(size_t, __dummy);

JUMP_FIELD(size_t, __dummy2);

JUMP_FIELD(_IO_finish_t, __finish);

JUMP_FIELD(_IO_overflow_t, __overflow);

JUMP_FIELD(_IO_underflow_t, __underflow);

JUMP_FIELD(_IO_underflow_t, __uflow);

JUMP_FIELD(_IO_pbackfail_t, __pbackfail);

/* showmany */

JUMP_FIELD(_IO_xsputn_t, __xsputn);

JUMP_FIELD(_IO_xsgetn_t, __xsgetn);

JUMP_FIELD(_IO_seekoff_t, __seekoff);

JUMP_FIELD(_IO_seekpos_t, __seekpos);

JUMP_FIELD(_IO_setbuf_t, __setbuf);

JUMP_FIELD(_IO_sync_t, __sync);

JUMP_FIELD(_IO_doallocate_t, __doallocate);

JUMP_FIELD(_IO_read_t, __read);

JUMP_FIELD(_IO_write_t, __write);

JUMP_FIELD(_IO_seek_t, __seek);

JUMP_FIELD(_IO_close_t, __close);

JUMP_FIELD(_IO_stat_t, __stat);

JUMP_FIELD(_IO_showmanyc_t, __showmanyc);

JUMP_FIELD(_IO_imbue_t, __imbue);

#if 0

get_column;

set_column;

#endif

};

_IO_FILE结构体的定义如下。__flags FILE结构体的一些状态;_markers为指向markers结构体的指针变量,为一个单向链表结构,存放流的位置;_chain变量为一个链表的指针,进程中创建的FILE结构体会通过这个变量连成一个单向链表;

另一点需要注意的是在新版本中,_IO_FILE_complete结构体被删除,其中的字段被添加到_IO_FILE结构体中

/*_IO_FILE结构体*/

/* libio/libio.h */

struct _IO_FILE {

int _flags; /* High-order word is _IO_MAGIC; rest is flags. */

#define _IO_file_flags _flags

/* The following pointers correspond to the C++ streambuf protocol. */

/* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */

char* _IO_read_ptr; /* Current read pointer */

char* _IO_read_end; /* End of get area. */

char* _IO_read_base; /* Start of putback+get area. */

char* _IO_write_base; /* Start of put area. */

char* _IO_write_ptr; /* Current put pointer. */

char* _IO_write_end; /* End of put area. */

char* _IO_buf_base; /* Start of reserve area. */

char* _IO_buf_end; /* End of reserve area. */

/* The following fields are used to support backing up and undo. */

char *_IO_save_base; /* Pointer to start of non-current get area. */

char *_IO_backup_base; /* Pointer to first valid character of backup area */

char *_IO_save_end; /* Pointer to end of non-current get area. */

struct _IO_marker *_markers;

struct _IO_FILE *_chain;

int _fileno;

#if 0

int _blksize;

#else

int _flags2;

#endif

_IO_off_t _old_offset; /* This used to be _offset but it's too small. */

#define __HAVE_COLUMN /* temporary */

/* 1+column number of pbase(); 0 is unknown. */

unsigned short _cur_column;

signed char _vtable_offset;

char _shortbuf[1];

/* char* _save_gptr; char* _save_egptr; */

_IO_lock_t *_lock;

#ifdef _IO_USE_OLD_IO_FILE

};

struct _IO_FILE_complete

{

struct _IO_FILE _file;

#endif

#if defined _G_IO_IO_FILE_VERSION && _G_IO_IO_FILE_VERSION == 0x20001

_IO_off64_t _offset;

# if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T

/* Wide character stream stuff. */

struct _IO_codecvt *_codecvt;

struct _IO_wide_data *_wide_data;

struct _IO_FILE *_freeres_list;

void *_freeres_buf;

# else

void *__pad1;

void *__pad2;

void *__pad3;

void *__pad4;

# endif

size_t __pad5;

int _mode;

/* Make sure we don't get into trouble again. */

char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];

#endif

};

fclose代码

为了精简我删掉了一部分关系不大的代码,下面的函数是新版本的fclose代码,IO_old_fclose主要代码与新版本类似

/* libio/iofclose.c */

int

_IO_new_fclose (_IO_FILE *fp)

{

int status;

/*这里本来有个对版本进行检测的代码,根据FILE结构中_vtable_offset变量是否为0来判断,不为0则执行_IO_old_fclose*/

/* First unlink the stream. */

if (fp->_IO_file_flags & _IO_IS_FILEBUF)

_IO_un_link ((struct _IO_FILE_plus *) fp);

_IO_acquire_lock (fp);

if (fp->_IO_file_flags & _IO_IS_FILEBUF)

status = _IO_file_close_it (fp);

else

status = fp->_flags & _IO_ERR_SEEN ? -1 : 0;

_IO_release_lock (fp);

_IO_FINISH (fp);

if (fp->_mode > 0)

{

#if _LIBC

/* This stream has a wide orientation. This means we have to free

the conversion functions. */

struct _IO_codecvt *cc = fp->_codecvt;

__libc_lock_lock (__gconv_lock);

__gconv_release_step (cc->__cd_in.__cd.__steps);

__gconv_release_step (cc->__cd_out.__cd.__steps);

__libc_lock_unlock (__gconv_lock);

#endif

}

else

{

if (_IO_have_backup (fp))

_IO_free_backup_area (fp);

}

if (fp != _IO_stdin && fp != _IO_stdout && fp != _IO_stderr)

{

fp->_IO_file_flags = 0;

free(fp);

}

return status;

}

该函数的流程可以粗略地进行如下表示:

2e00afb01606

fclose flowchart.png

流程图中有几个关键函数,至于加解锁什么的我忽略了:

_IO_un_link

_IO_file_close_it

_IO_FINISH

_IO_free_backup_area

free

在检查vtable_offset==0之后函数对fp->_flags的_IO_IS_FILEBUF位进行检查,_IO_IS_FILEBUF定义如下

#define _IO_IS_FILEBUF 0x2000

若该位不为0则调用_IO_un_link(fp)将fp指向的FILE结构体从_IO_list_all的单向链表中取下,并调用_IO_file_close_it(fp)关闭fp。

然后将调用_IO_FINISH(fp),相当于执行((struct IO_FILE_plus *)fp->vtable)->__finish(fp)。

_IO_un_link

/* in libio/genops.c */

void

_IO_un_link (struct _IO_FILE_plus *fp)

{

if (fp->file._flags & _IO_LINKED)

{

struct _IO_FILE **f;

#ifdef _IO_MTSAFE_IO

_IO_cleanup_region_start_noarg (flush_cleanup);

_IO_lock_lock (list_all_lock);

run_fp = (_IO_FILE *) fp;

_IO_flockfile ((_IO_FILE *) fp);

#endif

if (_IO_list_all == NULL)

;

else if (fp == _IO_list_all)

{

_IO_list_all = (struct _IO_FILE_plus *) _IO_list_all->file._chain;

++_IO_list_all_stamp;

}

else

for (f = &_IO_list_all->file._chain; *f; f = &(*f)->_chain)

if (*f == (_IO_FILE *) fp)

{

*f = fp->file._chain;

++_IO_list_all_stamp;

break;

}

fp->file._flags &= ~_IO_LINKED;

#ifdef _IO_MTSAFE_IO

_IO_funlockfile ((_IO_FILE *) fp);

run_fp = NULL;

_IO_lock_unlock (list_all_lock);

_IO_cleanup_region_end (0);

#endif

}

}

_IO_un_link首先判断fp的标志位中的_IO_LINKED是否置位,若置位进行下一步操作,最后将其清零

#define _IO_LINKED 0x80 /* Set if linked (using _chain) to streambuf::_list_all.*/

若_IO_list_all != fp则_IO_un_link函数将从_IO_list_all开始遍历链表,寻找fp指针,找到后将其前一个节点指针指向后一个节点指针即指向fp->file._chain;若_IO_list_all==fp则将全局变量_IO_list_all的值更改为IO_list_all->file._chain。

_IO_file_close_it

/* in libio/fileops.c */

/* 在新版本中 _IO_file_close_it被定义为_IO_new_file_close_it */

int

_IO_new_file_close_it (_IO_FILE *fp)

{

int write_status;

if (!_IO_file_is_open (fp))

return EOF;

if ((fp->_flags & _IO_NO_WRITES) == 0

&& (fp->_flags & _IO_CURRENTLY_PUTTING) != 0)

write_status = _IO_do_flush (fp);

else

write_status = 0;

_IO_unsave_markers (fp);

int close_status = ((fp->_flags2 & _IO_FLAGS2_NOCLOSE) == 0

? _IO_SYSCLOSE (fp) : 0);

/* Free buffer. */

#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T

if (fp->_mode > 0)

{

if (_IO_have_wbackup (fp))

_IO_free_wbackup_area (fp);

_IO_wsetb (fp, NULL, NULL, 0);

_IO_wsetg (fp, NULL, NULL, NULL);

_IO_wsetp (fp, NULL, NULL);

}

#endif

_IO_setb (fp, NULL, NULL, 0);

_IO_setg (fp, NULL, NULL, NULL);

_IO_setp (fp, NULL, NULL);

_IO_un_link ((struct _IO_FILE_plus *) fp);

fp->_flags = _IO_MAGIC|CLOSED_FILEBUF_FLAGS;

fp->_fileno = -1;

fp->_offset = _IO_pos_BAD;

return close_status ? close_status : write_status;

}

_IO_new_file_close_it首先根据fp->_fileno是否为0判断文件是否打开

#define _IO_file_is_open(__fp) ((__fp)->_fileno != -1)

若文件未打开,则直接返回EOF。否则函数将继续执行

if ((fp->_flags & _IO_NO_WRITES) == 0

&& (fp->_flags & _IO_CURRENTLY_PUTTING) != 0)

write_status = _IO_do_flush (fp);

以上代码将fp中未输出的部分输出,_IO_do_flush(fp)定义如下

#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T

# define _IO_do_flush(_f) \

((_f)->_mode <= 0 \

? _IO_do_write(_f, (_f)->_IO_write_base, \

(_f)->_IO_write_ptr-(_f)->_IO_write_base) \

: _IO_wdo_write(_f, (_f)->_wide_data->_IO_write_base, \

((_f)->_wide_data->_IO_write_ptr \

- (_f)->_wide_data->_IO_write_base)))

#else

# define _IO_do_flush(_f) \

_IO_do_write(_f, (_f)->_IO_write_base, \

(_f)->_IO_write_ptr-(_f)->_IO_write_base)

#endif

不做过多解释。

然后fclose将调用_IO_unsave_markers(fp)将保存的markers清除,在这个版本的libc代码中,这个函数有一部分功能还没完成,用(#define TODO围着),唯一值得注意的是函数最后

if (_IO_have_backup (fp))

_IO_free_backup_area (fp);

void

_IO_free_backup_area (_IO_FILE *fp)

{

if (_IO_in_backup (fp))

_IO_switch_to_main_get_area (fp); /* Just in case. */

free (fp->_IO_save_base);

fp->_IO_save_base = NULL;

fp->_IO_save_end = NULL;

fp->_IO_backup_base = NULL;

}

如果fp->_IO_save_base不为空,它将被free。

之后在_IO_new_file_close_it中执行了

int close_status = ((fp->_flags2 & _IO_FLAGS2_NOCLOSE) == 0

? _IO_SYSCLOSE (fp) : 0);

当fp->_flags2的_IO_FLAGS2_NOCLOSE没有被置位时,会调用_IO_SYSCLOSE(fp),相当于调用_IO_FILE_plus结构体中的vtable中的__close函数。这一次调用_IO_un_link好像并没有实际作用?

最后又调用了_IO_un_link(fp)并设置了一些flags

_IO_un_link ((struct _IO_FILE_plus *) fp);

fp->_flags = _IO_MAGIC|CLOSED_FILEBUF_FLAGS;

fp->_fileno = -1;

fp->_offset = _IO_pos_BAD;

_IO_have_backup

上面已经提到了,略略略

free(fp)

用户打开的FILE结构体是分配在堆上的,在fclose中最终会被free释放。

至此glibc的fclose源代码分析完毕。

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

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

相关文章

戴尔笔记本电脑开机黑屏怎么办_戴尔笔记本电脑充不进电怎么办

笔记本电脑电池充不进电要怎么办呢&#xff1f;笔记本电脑之所以这么受欢迎&#xff0c;是因为笔记本有配备电池&#xff0c;能够在没有电源的情况下使用五六个小时。而电池的电用光后&#xff0c;就需要进行充电。不过有些用户反映说&#xff0c;自己的电池充不进电&#xff0…

IIS安装2个SSL_顶级域名0元撸-免费注册2个腾讯云域名 免费SSL证书

前言这两天折腾甜糖CDN&#xff0c;为了收益最大化申请了公网IP&#xff0c;于是顺带折腾了一下群晖外网访问。使用的DDNS方案是腾讯dnspod&#xff0c;注册一个便宜的顶级域名访问我的群晖&#xff0c;折腾过程中发现可以免费注册2个顶级域名&#xff0c;不敢独享发出来大家一…

三菱a系列motion软体_工控电缆如何制作?(以三菱PLC、触摸屏为例)

RS232接口的三菱Q系列PLC编程通讯电缆三菱GT11/GT15触摸屏RS232串口编程电缆三菱GT11/GT15触摸屏连接Q系列PLC电缆三菱GT11/GT15触摸屏连接FX2/FX2C/A/QnA系列PLC电缆三菱GT11/GT15 触摸屏连接FX3U/FX2N/FX1N系列PLC电缆FX2、A系列PLC到A970GOT人机介面连接电缆FX0s/FX0n/FX2n/…

电脑入门完全自学手册_「新书推荐」新能源汽车维修完全自学手册

《新能源汽车维修完全自学手册》作者&#xff1a;广州瑞佩尔信息科技有限公司 、胡欢贵售价&#xff1a;85.00上市时间&#xff1a;2020年7月本书内容分为 8 章, 第 1 章为高压安全系统, 主要介绍了新能源汽车中高压安全防护装置构造以及维修所需的安全防护工具、 安全作业规范…

C/C++混淆点-左移右移操作符

对一个数实行左移或者右移操作&#xff0c;即先把操作数转换为二进制&#xff0c;然后左移&#xff08;>>&#xff09;即从左到右开始舍弃&#xff0c;右移&#xff08;<<&#xff09;即从各位之后开始加0。最后再转换为十进制。 #include<iostream> using…

ar路由器 pppoe下发ipv6 dns_IPv6网络设置各种疑难杂症诊疗区

1、Windows电脑系统IPv6无网络访问权限怎么解决&#xff1f;Win7系统下连接IPv6无网络访问权限的解决方法&#xff08;1&#xff09;首先修复网络连接&#xff0c;Win XP操作系统的网络连接有“修复”选项&#xff0c;Win7没有&#xff0c;不过可以使用“诊断”选项&#xff0c…

c语言判断化学方程式,下列是某同学写的六个化学方程式:①Mg+O2点燃.MgO2②C+O2点燃.CO...

化学方程式是最重要的化学语言&#xff0c;正确、熟练地书写化学方程式是学习化学必需具备的重要基本功。怎样书写化学方程式?1.要遵循两个基本原则(1)以客观事实为基础化学方程式既然是化学反应的表达形式&#xff0c;显然&#xff0c;有某一反应存在&#xff0c;才能用化学方…

tensorboard ckpt pb 模型的输出节点_“技术需求”与“技术成果”项目之间关联度计算模型 TOP10 baseline...

竞赛网址&#xff1a;传送门线上分数&#xff1a;0.78490746000&#xff0c;目前可以进入前10参考了苏神的代码&#xff0c;非常感谢&#xff1a;传送门调参技巧&#xff1a;传送门中文bert权重&#xff1a;传送门#! -*- coding:utf-8 -*-

白盒测试六种方法案例分析

1、语句覆盖 2、判定覆盖 3、条件覆盖 4、判定/条件覆盖 5、组合覆盖 6、路径覆盖

android 启动优化方案,Android 项目优化(五):应用启动优化

介绍了前面的优化的方案后&#xff0c;这里我们在针对应用的启动优化做一下讲解和说明。一、App启动概述一个应用App的启动速度能够影响用户的首次体验&#xff0c;启动速度较慢(感官上)的应用可能导致用户再次开启App的意图下降&#xff0c;或者卸载放弃该应用程序。应用程序启…

排序总结

排序总结 快速排序基本思路&#xff1a; 基本思想&#xff1a; 1&#xff09;选择一个基准元素,通常选择第一个元素或者最后一个元素, 2&#xff09;通过一趟排序讲待排序的记录分割成独立的两部分&#xff0c;其中一部分记录的元素值均比基准元素值小。另一部分记录的 元素值…

iphone最新款手机_苹果用户不换安卓手机的8点原因,最后一点最关键

快速的更新换代似乎已经成为了安卓手机的发展规律。与之相比&#xff0c;苹果公司的发展却逐渐从之前的“特立独行”变为了“固步自封”&#xff0c;产品风格也由原先的桀骜不驯&#xff0c;转变为现在向市场的不断妥协。即便如此&#xff0c;仍旧有很大一部分苹果用户没有考虑…

windows和android双系统平板,Windows平板打造双系统爽玩安卓APP

随着微软的surface更新换代&#xff0c; Windows平板是越来越受欢迎&#xff0c;在工作上&#xff0c;win平板处理办公文件和兼容性的优点得到了大家认可。但是在视听娱乐等休闲方面&#xff0c;始终还是没有安卓平板来的好用&#xff0c;而且安卓平台有大量好玩的APP&#xff…

ilitek win10 触摸屏驱动_想做多大尺寸触摸框找融创方圆定制触摸屏工厂

融创方圆定制大尺寸拼接屏多点触摸屏&#xff0c;大屏拼接屏红外多点触摸框&#xff0c;触摸拼接屏&#xff0c;拼接触摸屏&#xff0c;触摸拼接墙&#xff0c;拼接墙触摸屏&#xff0c;我们大尺寸多点触摸框反应灵敏&#xff0c;无盲区&#xff0c;无鬼点&#xff0c;无漂移&a…

most recent call last 报错_视频|救援情景剧、创意快闪……400w+人次为重庆这场消防宣传活动打call...

鼎牛配资app西安笑赢配资大赚配资公司推选简配资乐赢资本 昔日&#xff0c;两江新区2020年“119”消防宣扬月启动典礼正在重庆欢欣谷盛大举办。两江新区消防供图华龙网-新重庆客户端 收华龙网-新重庆客户端11月4日18时40分讯(记者 李华裔)按照实在救济动作改编的情形剧、小伴侣…

html中使用什么标签做的导航栏_自媒体人如何自己建立一个手机网站,超简单,任何人都能做...

随着移动互联网的兴起&#xff0c;越来越多的公司、个人把展示的内容转到了手机网站上&#xff0c;学会制作手机网站就成了大家关注的热点。传统的网页制作工具制作电脑端的网站功能很强大&#xff0c;但手机网站由于手机屏幕大小和CPU处理能力较弱&#xff0c;对网站的要求与传…

哈夫曼编码和带权路径计算

哈夫曼树是一种带权路径长度最短的二叉树&#xff0c;也称为最优二叉树。下面用一幅图来说明。 它们的带权路径长度分别为&#xff1a; 图a&#xff1a; WPL5*27*22*213*254 图b&#xff1a; WPL5*32*37*213*148 可见&#xff0c;图b的带权路径长度较小&#xff0c;我们可以…

codesys raspberry pi_11月7日|Pi第四次减产来袭?4点浅析中文区用户关心的问题

手里有派&#xff0c;心中有爱这两天一些派友私下找我在抱怨&#xff0c;也有用户在我们的微信社群发出所谓的灵魂询问&#xff1a;“主网在哪里&#xff1f;&#xff1f;制宪大会在哪里&#xff1f;停产或者减产在哪里&#xff1f;kyc在哪里&#xff1f;”我简单的回应一下&am…

android 网页取词,有道词典屏幕取词怎么用?,你知道吗?在浏览网页

有道词典屏幕取词怎么用&#xff1f;,你知道吗&#xff1f;在浏览网页你知道吗&#xff1f;在浏览网页时遇到不懂的外文、词语等&#xff0c;我们可以通过有道词典的屏幕取词来进行翻译哦&#xff01;好吧&#xff0c;你肯定会问&#xff1a;我如何使用这一功能呢&#xff1f;下…

你发这些什么目的_微信CRM系统究竟是什么?

作为一个电商运营人&#xff0c;近期行业内经常会听到一个名词&#xff0c;微信CRM系统&#xff0c;私域流量&#xff0c;用微信CRM系统打造属于自己的私域流量。相信很多做电商的也是和我一样&#xff0c;对于这个词很耳熟&#xff0c;但是又不知道是什么意思&#xff0c;因此…