PE文件入门,一篇就够了

news2024/10/7 8:19:49

title: PE文件学习篇
tags:
- Windows
- PE

最近在准备面试相的内容,对pe相关的问题有些生疏了,于是就边看博客复习边整理到论坛上希望对大家有帮助。

在《逆向工程核心原理》这本书接触到了PE文件,但是当时学不进去,感觉很晦涩,虽然是一个结构体一个结构体的进行分析,但还是掌握不了。今天在YouTube上找到了一个视频,看了一下有种恍然大明白的感觉。正巧今天看了一期关于国产大飞机C919的视频很有感想,我们的策略是先整体后局部,即不过分死抠细节,不把国产化率排在首位,先造出来一个大飞机,于是我们就有了一张蓝图,知道方向在哪里。学习PE文件这里也是,先整体的过一遍,知道个轮廓,在学起来会容易和有趣不少。

PE基础

PE文件概念

PE文件(Portable Executable file),是一种可执行文件格式,满足此格式的文件都可以在Windows操作系统运行。在Linux系统运行的文件是ELF。

识别PE文件

通过后缀名判断文件格式是不靠谱的,因为后缀名是可以随意更改的,我们用一个十六进制编辑器打开一个文件,如果他的开头是MZ,且0x3c--0x3f所指示的偏移地址处的值是PE那么我们几乎可以肯定这是个PE文件。

 PE文件格式

从DOS头到节区头是PE头部分,其下的节区合成PE体。

 

 我们学习PE文件就是学习这些结构体,先对结构体来个介绍。我们可以通过PEView查看pe文件,将notepad.exe拖入。我们先来分析一下存储时的PE文件,没错PE文件运行时和在硬盘中存储时是不同的。

 

概括

DOS部分(早期为了兼容DOS所设计)

  • IMAGE_DOS_HEADER(64字节)

MS_DOS Stu,DOS存根,大小是不固定的,链接器会在这里插入数据,不影响程序运行,病毒程序可以插入在这里。虽然倒下不固定,但我们可以通过IMAGE_DOS_HEADER结构体的最后一个成员PE头开始的位置,用这个值减去64即DOS存根的大小。 

PE文件头

  • IMAGE_NT_HEADERS即PE头结构体,包括三个部分PE标识标准PE头扩展PE头 

 

IMAGE_OPTIONAL_HEADER(32位)(224字节)(可扩展),IMAGE_FILE_HEADER结构体的一个成员记录该结构体的大小。  

节表 (记录节的信息)

  • IMAGE_SECTION_HEADER (40字节)

    有几个节区就有几个这样的结构体

​ IMAGE_SECTION_HEADER .text

 

节表后面是一些意义不大的数据,我们可以有效利用这些空间,所以节表和节表数据是不相邻的。 在可选头结构体中有一个成员记录PE头(DOS头+PE文件头+节表)的大小

 

PE文件有两种状态:

磁盘状态(存储)

内存状态(运行)

Q & A

Q:为什么文件对齐参数与内存对齐参数不相同?

A:因为它们分别用于优化文件I/O和虚拟内存管理。

DOS头属性说明

IMAGE_DOS_HEADER结构体是为了早期16位程序而准备的,现在已经弃用除了头尾两个成员,其余的都是可以更改的

 

 

更改之后不影响程序运行。

PE头属性说明

Signature

4个字节的签名。更改之后不可运行。

 

 

Machine

两个字节,标记可以程序可以运行在什么样的CPU上。 任意:0 ;Intel 386以及后续:14C;x64:8664

 

Number of Section

两个字节记录节的数目。 

 

程序的时间戳是指在Windows操作系统上编译或链接可执行文件时,由编译器或链接器自动插入的一个时间戳。它通常存储为32位无符号整数,表示从1970年1月1日00:00:00(格林威治时间)开始的秒数。可以更改。

Pointer to Symbol Table &Number of Symbol

调试相关,不关注,共8个字节

 

Size of Optional Header

两个字节,因为可选头长度是不固定的,该成员记录MAGE_OPTIONAL_HEADER的大小,32位默认是0xE0,64位默认是0xF0。如果可选头长度更改,也要对应修改这里。

 

010F -->0000 0001 0000 1111,每一个位都有意义,比如下标为1的地方是1,那么代表该文件是可执行文件。

IMAGE_OPTIONAL_HEADER (扩展PE头)
Magic

两个字节,标志程序是32位还是64位(最准确)。PE32:10B ;PE32+:20B

 

 

 

记录代码开始的位置,记录的是相对Image Base的距离。PE文件在内存中展开后最前面都是数据,需要一个值告诉操作系统从哪里开始运行。 那么么该程序就从01000000+0000739D=0100739D, OD会在程序开始设置一个断点,地址就是这里。对这里进行修饰会增加逆向分析的难度,因为调试机器找不到程序入口。

Image Base

4字节,内存镜像基址。对于32位机器,操作系统会位每个进程分配一个4GB的虚拟地址空间,之所以是4GB,是因为32位操作系统指针长度为4字节32为,所以寻址能力是2的32次方。该成员指明程序在虚拟地址空间的何处展开,即基地址。 

 

File Alignment

文件对齐大小。

Size of Image

文件在内存中展开时的大小。

Size of Header

四字节,所有头+节表按照文件对齐后的大小。

Checksum

校验和,以两字节为单位,将所有的数据相加。用来判断程序是否受到修改,但是我们可以通过修改其他数值来平衡,所以意义不大。

PE节表

学习节表之前首先要知道PE文件的两种状态

文件状态和内存状态

 

Name

8字节,当前节的名字,可以随意更改。

Vitual Size

当前这个节未对齐时的大小,即实际大小。实际大小有可能会比Size of Raw Data大,因为未初始化的全局变量在文件中是不占空间的。在内存中展开时以什么为基准呢?答案是谁大按谁,如果Vitual Size>Size of Raw Data,则按照Vitual Size展开,反之则按照Size of Raw Data。

VirtualAddress

在内存中的偏移地址,加上ImageBase则是内存中的真实地址。

Size of Raw Data

文件对齐后的大小,Vitual Size的值是7748,文件对其大小是100,Size of Raw Data的值为7800。

Pointer to Raw Data

当前节在文件中从何处开始

 

可以看到下标为5的位是1,代表该节中含有代码。

RVA与FOA的转换

用一个简单的程序开始RVA.c

1

2

3

4

5

6

7

8

9

10

11

#include<stdio.h>

#include<Windows.h>

int main()

{

    static int c = 123456;

    int a, b;

    printf("全局变量的地址是:%p\n", &c);

    printf("全局变量的值是:%d\n", c);

    getchar();

    return 0;

}

我们的任务是通过地址找到该全局变量,然后改变它的值。

 

我们运行程序,看到其地址是00bca000,这是在内存中的地址,我们知道PE文件在内存中和在文件中展开是不一样的,我们就是要通过内存中的这个地址找到文件中对应的位置。

RVA

相对虚拟地址(Relative virtual address) RVA=内存地址-ImageBase

 

查看其Image Base得到 RVA=D0A000-400000=90 A000

FOA

文件偏移地址(File offset address) FOA

转换过程
  1. 判断RVA是否在PE头部,如果在则RVA=FOA,因为头部没有被拉伸
  2. 如果不在头部,判断RVA位于哪个节中 ,求出 差值=RVA-节.VA,也就是该地址相对节头的距离。为什么要求差值?因为在文件和在内存中差值是相同的。 FOA=节.PointerToData+差值

他的位置是在00CAA000处,这里的位置即内存中的位置,不用想,他肯定不在头中。我们必须将运行中的程序进行分析,因为基地址也是随机化的。

 

 

 

我大为震惊。其实这个过程遇到了很多麻烦,基地址随机是在这个过程中认识到的。这个过程挺美妙的,虽然是个很简单的东西,却体现出了逆向的的思想与魅力。

修改PE文件

在空白区域添加代码

我们要插入这样一个代码

1

2

3

4

5

6

#include<windows.h>

int main(int argc, char* argv[])

{

    MessageBox(0, 0, 0, 0);

    return 0;

}

功能呢就是弹出一个这样的错误窗口。这个程序的核心就是调用了一个messagebox函数弹出了一个窗口。由于我们是要对pe文件进行操作,所以肯定不是将代码写入,而是要将机器码插入。就是利于栈传第四个参数0,然后call。

 

将图一标记位置改为call 1c1023 得到图二,后面的0A=1c1023-1c1019.我们的目标指示让他弹出窗口,不能破坏程序运行,所以弹出之后我们还要跳回到初始位置,让程序正常运行,我们使用JMP(E9)指令来实现该操作,E9后面也是跟偏移量,用法与E8相同。找到messagebox的地址75858A70。根据call指令的位置来计算。 

E8所在的位置是3A8,这是文件中的位置,我们要考虑的是运行时的位置,所以要把这个地址加上Image Base =01000000,所以最后得到的 offset=75858A70-010003A8-5=7485 86C3.最后跳转到程序的入口处,查看可选头的成员入口值为739D加上Image Base得到0100739D. offset=0100739D-010003AD-5=6FEB 

 

在108处占4个字节,我们插入的程序起始位置是000003A0.然后,然后就没然后了,程序运行不起,ida和od看到的东西都很奇怪,延误了两天,这里我直接说一下踩的坑,我随意找了一个空白处填充机器码,但后来发现不是所有的位置都能发生跳转,然后就将指令插入在了text段的末尾,然后发现跳转的有些差异,不会跳转在我设置的地方,后知后觉的发现,视频里的老哥演示的的时候拿的是一个文件对齐和内存对齐相同大小的程序,我用的程序是一个不同的,所以就要计算一下 用我们前面学习到的知识。下面理一下步骤

  1. 首先在文件中确定一段空间,然后运行程序的时候查看 是否为空
  2. 插入,根据内存中的位置计算
  3. 改入口,内存中代码的起始位置 

第一次尝试的时候成功弹出了窗口,但是关闭之后没有出现记事本,由此我们可以判断执行完我们的代码后,没有成功的返回原入口。此时才想起来补码写错了,插入的位置是87b0,入口点是739d,739d-83b0-5=

然后我就在e9后面填充了E8 EF 00 00,意识到返回出现问题后,想到了有符号数的符号扩展,应该扩展其符号位即1,所以正确的补码形式是FF FF EF E8,填充进去就是E8 EF FF FF.

删除节

删除一个节比较简单,尤其是删除最后一个节,.reloc节区是基址重定位表,删除这个节区对程序的正常运行没有影响,而且删除这个节区可以将文件的大小缩减。下面说一下步骤:

  1. 将.reloc节区头用0覆盖
  2. 删除reloc节区
  3. 修改Image_FILE_HEADER中的numberofsection成员
  4. 修改IMAGE_OPTIONAL_HEADER中的SizeofImage
覆盖.reloc节区头

28个字节

 

因为是最后一个节区,所以我们只要将C000即后面的东西删除即可

修改Image_FILE_HEADER

 

 

扩大节

为什么要扩大节?

前面演示插入的代码很短,如果要插入一段比较长的代码,可能找不到合适的空间。常见的解决方案就是扩大节,那么扩大哪一个节呢?

 

根据这个图不难看出,最好是扩大最后一个节,因为扩大前面的节如果想不影响程序的正常运行,还要去修改节表里的属性。

扩大节的步骤

  1. 分配空间
  2. 修改SizeofRawData和VirtualSize
  3. 修改SizeofImage(内存对齐大小)
  4. 如果扩展的节没有可执行属性,我们可以在节表结构体更改其属性。

1.分配一块新的空间,大小为S,这里我们选择在最后一个节后面分配0x1000byte的空间

2.修改该节节表信息。要修改Size of Raw Data(实际大小)和Virtual Size(文件对齐后的大小),将这两个值修改为N。从前面的学习,我们了解到文件对其后的大小不一定大于实际大小,我们只需选择其中那个大的值max,N=max+S。 

将该值按照内存对齐之后,再加上新增的0x1000即可,修改完保存,程序正常运行。

新增节

合并节

详解导入导出表

导出表

前置知识,一个可执行程序是有多个pe文件组成的。

导入表:描述pe文件引用了哪些文件,相当于进货清单。

导出表:当前pe文件提供哪些函数供其他文件使用,相当于饭店的菜单。

导出表在哪里?

在扩展pe头,最后一个成员,是个结构体数组,这个结构体的第一个成员就存放着导出表的相关信息。

 

 

 

导出表的第一个成员VirtualAddress记录着内存偏移地址(RVA),Size记录着导出表的大小。

我们动一下手,拿keyHook.dll试试手

 RVA是80B0,查了一下在rdata段,rdata段的起始RVA为6000,所以相对地址就是20B0,rdata段的pointer to raw data及文件偏移地址为5000,所以他的FOA为70B0,大小是5B字节。​​​​​​​

 

 

它还含有三张子表格,我们可以看到这是40字节的内容,而我们刚才查看的是5B字节,其实这个5B是算上子表之后的大小。

Name

name指针,对应的值是000080EC,对应的FOA是70EC

指向一个ascii字符串(当前dll的名称),0表示结尾。

NumberOfFunctions

所有导出函数的个数

NumberOfNames

根据函数名到处函数的个数,除了根据函数名导出函数,还能根据序号,也就是启用函数名定义一套序号规则,在一定程度上,通过序号导出函数能够增加程序的分析难度。

AddressOfFunctions

导出函数地址表RVA,又是一张表,表的成员每一个都是四字节大小,代表的是函数所在的地址。

 

AddressOfNames

导出函数名称表。存储的函数名称所在的地址。每个成员四字节大小。

 

首先查到AddressOfNames的RVA为80D0,那么FOA是70D0,第一个成员80F8注意这是RVA,换算成FOA是70F8,对应可以看到“HookStart”,后面一个是8102,换算成FOA是7102,对应“Hookstop”

AddressOfNamesOrdinals

导出函数序列号表。有几个根据函数名称导出的函数,该表就有几个成员。每个成员二字节大小。

这是一个API,它有两个参数,DLL的句柄就是该DLL在内存展开时的地址,函数名

 

 

当API通过函数名调用函数,比如说它调用了hookstart,那么它会前往函数名称列表获得hookstart的索引值0,之后会去序号列表,序号列表下标为零的值是0,拿到这个0再去函数地址列表充当索引最终找到函数的地址。有时候不是通过函数名而是通过函数序号查找函数,这就要用到刚才没介绍的一个成员Base,它的值是函数地址列表的起始序号,如果其实序号为10,所调用的函数的序号是11,那么第二个成员hookstop的序号对应为11,完成调用。

导入表

导入几个模块就有几张导入表,每个表记录该模块的信息。

两个成员分别是导入表的地址和导入表的大小。有没有指明导入表数量的成员?答案是没有,我们可以通过查看16进制数据判断,每个导入表的大小是20个字节,从起始位置划分每20字节一组,直到出现一组20字节全部为0即代表结束,从而可以判断数量。

这个联合指向的是IMAGE_THUNK_DATA结构体,这些结构体组成INT(import name table),要用到该模块的几个函数,就有几个IMAGE_THUNK_DATA结构体,每个结构体大小是4字节,当出现连续的4字节为0,则说明INT截止。

导入表的地址是6B24,6B24处的第一个成员的值是7b60,转换成foa是6b60,IMAGE_THUNK_DATA结构体就在6B60处

 

 

完整的理一遍,首先通过扩展pe头的左后一个成员import table找到了导入表,导入表的第四个成员是个RVA指向了kernel32.dll字符串,这是导入的模块的名称,通过导入表的第一个成员(一个RVA指向)IMAGE_THUNK_DATA,该成员的最高位不为1,说明是个RVA,通过这个RVA找到了importbyname,通过该成员的第三个字节找到了导入的这个模块所使用的一个函数GetModuleFileNameA 

PE文件加载前后,IAT(import address table)导入地址表发生变化,IAT不在指向函数名称,而是已经根据函数名称更换了表格。INT那里相当于一层保险,当程序IAT被修改(脱壳时就要修复导入表),无法找到函数时,可以根据INT和相关函数得到函数地址,从而修复IAT。

重定位表

重定位表的作用:如果可执行文件中的全部的地址相关的数值都是RVA即相对imagebase来的,那么重定位表可有可无。但是有的全局变量他的地址是硬编码,只有文件被加载到了内存中特定的位置在能正常使用,但是可执行文件往往要加载多个dll,原来那个位置可能已经被占了,这时候只能再选一个空闲的地址,此时imagebase就不是预期的值了,这种情况就要根据重定位表进行修改。

1

2

3

4

5

int x=0;

int main()

{

    x=11;

}

上面的代码的汇编码如下,mov 【00427e34】,11h 由于全局变量使用了硬编码,显然只有加载的特定的位置该代码才能生效。

 

上图代表的就是这个结构体,x表示第一个成员,y表示大小,第一个结构体的y为16,所以该结构体16字节大小,再往下就是下一个,下一个是20字节大小,再往下是12字节大小,当遇到连续的八个字节为0,也就是x和y都为0时,代表该表格结束。解释一下为什么要这样设计,其实这个表存放的是要进行重定位的成员的地址,X代表的相当于一个基地址,Y后的每一个成员即从第九个字节开始,每两个字节为一个成员,比如X的值为80 00 00 00,后面的字节为12,16,18,则代表 80 00 00 12、80 00 00 16、80 00 00 16需要进行重定位,可以看到存放一个实际的地址需要4个字节,存放10个是40字节,而我们采用基地址加偏移的方法只使用了24个字节,需要重定位的值越多,节省的空间就越多。(这个区块是根据内存页进行划分的,每个页4KB,每个页有一个重定位表,而两个字节的偏移地址能表示0~ffff,足够对一个页进行寻址,若要寻址至少需要12个位,一字节不够,所以选择二字节作为偏移地址的单位)。

重点: Y后的成员,两字节即16位一组,其实表示有效地址的是低12位,高四位并非没有作用,当高四位位0011的时候,才代表该处的值需要进行修复,比如说第一个成员为0011 0011 1111 1111,前四位为0011,代表该成员需要被修复,取低12位加上X基地址即是真正需要修改的。若高4位不是0011,则该处数据无作用,可以理解为用来内存对齐的垃圾数据。

完结撒花了!!!!!!!!!!!!!!!!!!!!!! hhh

 

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

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

相关文章

pytorch在docker里面使用GPU

本博客主要介绍如何在容器里面使用pytorch进行推理&#xff0c;训练&#xff0c;同时用上GPU。 1. 前置条件&#xff0c;安装好docker。 2. 安装nvidia-container-toolkit 参考官方文档&#xff1a; Installing the NVIDIA Container Toolkit — NVIDIA Container Toolkit 1.…

【汽车操作系统】Autosar和商用OS

目录 什么是AUTOSAR? CP AUTOSAR架构 CAN通信 AP AUTOSAR 背景 CP&AP 开发方面的不同&#xff1a; WRLinux介绍 QNX介绍 什么是AUTOSAR? 随着汽车功能越来越多&#xff0c;导致ECU的数量越来越多。1993年的时候&#xff0c;奥迪A8才只有5个ECU现在典型的现代汽车…

SSRF服务端请求伪造漏洞原理与修复及靶场实践

SSRF服务端请求伪造漏洞原理与修复及靶场实践 SSRF漏洞原理与检测 SSRF&#xff08;Server-Side Request Forgery&#xff0c;服务器端请求伪造&#xff09;漏洞是一种因为服务端提供了远程访问服务&#xff0c;而并未对请求目标进行限制或限制不严格而引起的安全漏洞&#x…

C语言/数据结构——每日一题(有效的括号)

一.前言 如果想要使用C语言来解决这道题——有效的括号&#xff1a;https://leetcode.cn/problems/valid-parentheses/description/我们必须要借用上一篇我们所讲的内容——栈的实现&#xff1a;https://blog.csdn.net/yiqingaa/article/details/138923750?spm1001.2014.3001.…

leetcode124 二叉树中的最大路径和-dp

题目 二叉树中的 路径 被定义为一条节点序列&#xff0c;序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点&#xff0c;且不一定经过根节点。 路径和 是路径中各节点值的总和。 给你一个二叉树的根节点 root &…

SpringCloud微服务04-Elasticsearch-DSL查询-聚合

一、Elasticsearch 搜索引擎&#xff0c;响应速度非常快&#xff0c;特别是对大数据量的情况 1.初始elasticsearch 如果只需要商品搜索&#xff0c;百度这种搜索网站&#xff0c;只需要第二个就够了 docker部署&#xff1a;day08-Elasticsearch - 飞书云文档 (feishu.cn) e…

我爱我家:租赁下位替代买房,能行吗?

我爱我家&#xff0c;凭什么五天四板&#xff1f; 上周五的楼市组合拳出台后&#xff0c;地产板块迎来高潮。 这其中最火的不是我们常说的“招宝万金”&#xff0c;而是——我爱我家。 五天四板&#xff0c;一个月不到&#xff0c;股价轻松翻翻。 公司有什么变化吗&#xff1…

蓝桥杯嵌入式国赛笔记(2):拓展板按键程序设计

目录 1、前言 2、电路原理 3、代码编写 3.1 读取Btn电压 3.2 检索按键 3.3 main文件编写 3.3.1 进行变量定义 3.3.2 AD_Key函数 3.3.3 LCD函数 3.3.4 main函数 3.3.5 完整代码 4、测试 5、总结 1、前言 本文进行拓展板按键程序设计&#xff0c;拓展板的按键是通…

分布式事务解决方案(强一致性)

强一致性事务概述 分布式事务领域&#xff0c;最早采用的是符合CAP理论的强一致性事务方案来解决分布式事务问题&#xff0c;强一致性分布式事务要求在任意时刻查询参与全局事务的各个节点的数据都是一致的 典型案例&#xff1a; 包括DTP模型&#xff08;全局事务模型&#x…

【Crypto】MD5

文章目录 MD5解题感悟 MD5 提示的很明显MD5 小小flag&#xff0c;拿下&#xff01; 解题感悟 没啥感悟…

LLM 大模型学习必知必会系列(十一):大模型自动评估理论和实战以及大模型评估框架详解

LLM 大模型学习必知必会系列(十一)&#xff1a;大模型自动评估理论和实战以及大模型评估框架详解 0.前言 大语言模型&#xff08;LLM&#xff09;评测是LLM开发和应用中的关键环节。目前评测方法可以分为人工评测和自动评测&#xff0c;其中&#xff0c;自动评测技术相比人工…

android14上使用frida,

由于之前使用frida已经是2年前了,后来一直没有研究两年以后 首先手机得root才可以, 我使用的是一加9pro, root方法参考一加全能盒子、一加全能工具箱官方网站——大侠阿木 (daxiaamu.com)​编辑https://optool.daxiaamu.com/index.php 由于之前使用的是frida 15.1.1在and…

Amesim示例篇-案例1:空间中的铝块散热

前言 本文将通过一个案例继续对Thermal库的元件进一步讲解。 案例1&#xff1a;一个300mm*300mm*1000mm&#xff08;长*宽*高&#xff09;的铝板初始温度为45℃&#xff0c;竖直在环境为25℃的空间内静置60min。对流换热系数设置为5W/m2K。本文将通过两种建模方法对铝块的温度…

微软刚发布的Copilot+PC为什么让Intel和AMD尴尬?2024 AI PC元年——产业布局及前景展望

美国东部时间5月20日在微软位于华盛顿的新园区举行的发布会上&#xff0c;宣布将旗下AI助手Copilot全面融入Windows系统&#xff0c;能够在不调用云数据中心的情况下处理更多人工智能任务。 “将世界作为一个提示词就从Windows系统开始”。微软的新PC将是“CopilotPC”&#xf…

树洞陪聊系统源码/陪聊/陪玩/树洞/陪陪/公众号开发/源码交付/树洞系统源码

独立版本源码交付&#xff0c;自研UI和前后端代码 平台自带店员&#xff0c;无需自主招募&#xff0c;搭建直接运营 支持三方登录&#xff0c;官方支付、虎皮椒、易支付/码支付 支持首单体验、盲盒订单、指定下单等多个模式 支持钱包预充值、店员收藏、订单评价等功能 支持…

You must call removeView() on the child‘s parent first.异常分析及解决

问题描述 对试图组件快速的左右滑动过程&#xff0c;发现某一张图片没加载出来&#xff0c;偶现crash 问题分析 view在上次已经是某个ParentView的child&#xff0c;然而现在又把它做为另外一个view的child&#xff0c;于是出现一个view有两个parent。所以就产生了这个错误。…

深入了解Python代码中的缩进与逻辑结构

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、认识缩进在代码中的重要性 代码示例&#xff1a;天气与打球决策 二、缩进与逻辑嵌套 …

uniapp使用内置的switch组件的问题

说明 开关选择器 属性说明 属性名类型默认值说明平台差异说明checkedBooleanfalse是否选中disabledBooleanfalse是否禁用不支持&#xff1a;抖音小程序、飞书小程序typeStringswitch 样式 有效值&#xff1a;switch、checkbox colorColorswitch的颜色&#xff0c;通css的co…

Tensorflow入门实战 P01-实现手写数字识别mnist

目录 1、背景&#xff1a;MNIST手写数字识别 2、完整代码&#xff08;Tensorflow&#xff09;&#xff1a; 3、运行过程及结果&#xff1a; 4、小结&#xff08;还是很清晰的&#xff09; 5、 展望 &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客…

摔到脑袋,没有骨折,没有脱位,脊髓怎么会损伤?

在一个周末的午后&#xff0c;小明在公园的足球场上不慎摔倒&#xff0c;头部重重撞到草地。虽然很快恢复了意识&#xff0c;但回家后却感到颈部僵硬&#xff0c;四肢无力。家人急忙带他前往医院就医做了相关检查。 经过医生的仔细检查&#xff0c;结果显示小明的头部没有骨折或…