【第33节】windows原理:初探PE文件

目录

一、PE文件概述

二、DOS头部

三、DOS头部与NT头部之间

四、NT头部

五、文件头区段

六、了解个别概念

七、扩展头

八、区段头表


一、PE文件概述

        PE文件是有特定格式的文件,像后缀名是EXE的可执行文件、后缀名是DLL的动态链接库文件、sys格式的驱动文件,这些都属于PE格式文件。

        PE文件主要分成头和主体两部分,这两部分里面还会再细分。文件头是由几个结构体组成的,包含了文件的一些描述信息;文件主体由多个段构成,里面有文件的可执行代码、执行时要用的数据,还有资源(像Windows程序里的图标、一些界面等)。一般来说,不用于执行的就是数据,用于执行的就是代码,所以主体大概能分成代码和数据两部分,实际上按照不同作用,还能再细分成多个部分。

PE文件是按下面的结构顺序组成的:
1. DOS头部:是为了和DOS程序兼容才设置的。
2. NT头部:存着PE文件的所有属性、初始化信息等内容。
3. 区段头表:对PE文件主体属性进行分段描述,数量不固定。
4. 各个区段:是PE文件的主体,分段存着可执行代码、各种数据和资源等。
5. 一些调试信息:先不详细说。

        接下来会逐个介绍这些部分,总结每个部分的关键内容,把这些要点记住,基本上就能了解PE文件的结构了。同时,会用LoadPE做例子来讲怎么使用,为后面写PE解析工具做准备。

二、DOS头部

typedef struct IMAGE_DOS_HEADER {WORD   e_magic;WORD   e_cblp;WORD   e_cp;WORD   e_crlc;WORD   e_cparhdr;WORD   e_minalloc;WORD   e_maxalloc;WORD   e_ss;WORD   e_sp;WORD   e_csum;WORD   e_ip;WORD   e_cs;WORD   e_lfarlc;WORD   e_ovno;WORD   e_res[4];WORD   e_oemid;WORD   e_oeminfo;WORD   e_res2[10];LONG   e_lfanew;
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

说明
1. 这个结构体从文件的第一个字节开始。
2. 真正有用的数据成员是第一个和最后一个,也就是 `e_magic` 和 `e_lfanew`。
3. `e_magic` 是魔数,它是DOS头的标志位,其值始终为4D5A,在系统里用宏定义成 `IMAGE_DOS_SIGNATURE`,用来代表DOS标志。
4. `e_lfanew` 指的是新EXE文件的偏移量,也就是NT头部在文件中的偏移位置。
5. 其他的数据成员大多没什么用,里面的内容很多都是0。

使用
1. 可以利用 `e_magic` 来判断一个文件是不是PE文件。要是从文件开头用 `PIMAGE_DOS_HEADER` 进行解析,`e_magic` 成员的值不是 `IMAGE_DOS_SIGNATURE`,那就说明这个文件不是PE文件。示例代码如下:

if(((PIMAGE_DOS_HEADER)pFile)->e_magic != IMAGE_DOS_SIGNATURE){//不是DOS头,返回return;
}

2. `e_lfanew` 用来计算偏移量,从而找到NT头在文件中的位置。假设文件已经被读入内存,内存首地址是 `pFile`(`void` 类型的指针),通过 `(long)pFile+((PIMAGE_DOS_HEADER)pFile)->e_lfanew` 就能得到NT头的位置。
3. 在加载器里,这部分内容能让加载器找到NT头,在DOS环境下还能提示程序的运行环境是Windows。

三、DOS头部与NT头部之间

        在DOS头部和NT头部之间有一块区域,这里存储着一些会被DOS头用到的数据,比如提示字符串等。这部分区域的大小不固定,NT头的具体位置由DOS头的最后一个成员 `e_lfanew` 来确定。

使用
        DOS头和这部分空间的作用比较小。可以把PE头放到这个区域,甚至让DOS头和PE头重合,以此来实现一些特殊的用途,比如缩小PE文件的体积。

四、NT头部

typedef struct _IMAGE_NT_HEADERS {DWORD Signature;IMAGE_FILE_HEADER FileHeader;IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

说明
1. NT头由一个简单标记、一个不算复杂的文件头和一个相对复杂的扩展头构成。
2. 如果是PE文件,这个标记的值一直是0x00004550,对应的ASCII码是 `PE00`,在系统里用宏定义成 `IMAGE_NT_SIGNATURE`。
3. 另外两个成员是结构体,里面存的信息很有用,对这两个结构体进行解析才是真正开始解析PE文件。

使用
1. `Signature` 的作用和DOS头里的 `e_magic` 差不多,都是用来判断文件是不是PE文件的。示例代码如下:

DWORD dwNewPos =(DWORD)pFile+((PIMAGE_DOS_HEADER)pFile)->e_lfanew;
PIMAGE_NT_HEADERS32 pNTHeader =(PIMAGE_NT_HEADERS32)(dwNewPos);
if (pNTHeader->Signature != IMAGE_NT_SIGNATURE){//不是NT头,说明不是PE文件,返回return;
}

2. 因为另外两个成员是结构体,而且比较复杂,所以可以用指针指向这些数据成员,比如 `pFileHeader = &(pNTHeader->FileHeader);` 和 `pOptionalHeader = &(pNTHeader->OptionalHeader);`,然后通过指针来读取信息。

五、文件头区段

NT头的第二个成员是文件头结构体,存储着关于PE文件的一些信息。

typedef struct IMAGE_FILE_HEADER {WORD   Machine;WORD   NumberOfSections;DWORD  TimeDateStamp;DWORD  PointerToSymbolTable;DWORD  NumberOfSymbols;WORD   SizeOfOptionalHeader;WORD   Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

说明:
1. Machine:表示文件可运行的CPU平台,如0x014c代表i386(Intel 32位平台),0x0200代表Intel 64位平台,更多信息可查阅相关书籍。
2. NumberOfSections:区段的个数,即PE文件主体被分成的部分,一般有代码、只读数据、数据、重定位等区段。
3. TimeDateStamp:文件创建时间,是32位数值,可使用 `struct tm*gmtime(const time_t*timer);` 函数解析,将 `TimeDateStamp` 地址强制转换后作为参数,用 `tm` 结构体接收得到具体时间。
4. PointerToSymbolTable:一般没用,多为0,后面的符号个数同样用处不大。
5. SizeOfOptionalHeader:扩展头的大小,32位程序中一般是00E0,64位程序中一般是00F0。
6. Characteristics:PE文件属性值很重要,如DLL一般是0x0210,EXE一般是0x010F,不同属性值对应不同含义,可转换为二进制对照相关表查看。

 使用:
1. 文件头7个数据成员中,5个有用。


2. 有用的数据成员在PE解析工具中主要用于显示,如LoadPE软件显示了其中4个信息。

示例代码如下:

PIMAGE_NT_HEADERS32    pNTHeader =(PIMAGE_NT_HEADERS32)((long)pFile + ((PIMAGE_DOS_HEADER)pFile)->e_lfanew);
PIMAGE_FILE_HEADER        pFileHeader =&(pNTHeader->FileHeader);

`pFileHeader` 所指数据都可显示。


3. 时间转换代码:

tm*FileTime = gmtime((time_t*)&pFileHeader->TimeDateStamp);

`FileTime` 包含时间的所有信息,`tm` 结构体定义如下:

struct tm{int tm_sec;  /*seconds after the minute -[0,59]秒*/int tm_min;/*minutes after the hour -[0,59]分*/int tm_hour;/*hours since midnight -[0,23]  小时*/int tm_mday;/*day of the month -[1,31]      日*/int tm_mon;/*months since January -[0,11]   月*/int tm_year;/*years since 1900              年*/int tm_wday;/*days since Sunday -[0,6]      星期几*/int tm_yday;/*days since January 1-[0,365]这一年的第几天*/int tm_isdst;/*daylight savings time flag*/
};

需注意月从0开始,日从1开始,LoadPE中的时间标志功能可用此实现。

六、了解个别概念

(1)虚拟地址与相对虚拟地址:每个程序都配有4GB的虚拟内存地址。当加载PE文件时,不是直接把文件原样复制到内存里,而是要经过扩充或调整。PE文件无法提供各部分在内存中的准确加载位置,也就是虚拟地址(VA),它给出的是相对于自身起始加载位置的偏移量,即相对虚拟地址(RVA)。虚拟地址的计算公式为VA = 加载基址(ImageBase) + RVA。PE文件有默认的加载基址,这个基址由扩展头的ImageBase成员确定。要是默认加载基址被占用,文件就会被加载到其他地址。
(2)文件偏移:文件偏移指的是文件在磁盘这类存储设备里,各部分相对于文件开头的偏移量,它代表加载前PE文件的位置。在扩展头中,描述PE文件结构位置用的是RVA。当把目标文件读入内存后,需要将RVA转换为文件偏移,具体转换方法会在介绍区段表时详细讲解。
(3)对齐的概念:区块无论是在内存还是磁盘中存放,都需要进行对齐操作,不过内存和磁盘的对齐值不一样。
    - 磁盘区块对齐:PE文件头中的`FileAligment`确定了磁盘区块的对齐值。每个区块都从对齐值倍数的偏移位置开始存放,要是区块实际大小不足对齐值的倍数,多余部分会用00h填充,这部分填充区域就形成了区块间隙。举例来说,如果对齐值是200h,第一个区块起始于400h,长度为90h,那么490h到600h就会被00h填充,下一个区块则从600h开始。
    - 内存区块对齐:PE文件头的`SectionAligment`规定了内存中区块的对齐值。当PE文件映射到内存时,区块至少要从一个页边界开始。在X86系列CPU中,一页的大小是4KB(即1000h);在IA - 64架构中,一页大小为8KB(2000h)。在X86系统里,PE文件区块的内存对齐值通常为1000h,每个区块都按1000h的倍数在内存中存放。

七、扩展头

typedef struct _IMAGE_OPTIONAL_HEADER {//Standard fields.WORD   Magic;BYTE   MajorLinkerVersion;BYTE   MinorLinkerVersion;DWORD  SizeOfCode;DWORD  SizeOfInitializedData;DWORD  SizeOfUninitializedData;DWORD  AddressOfEntryPoint;DWORD  BaseOfCode;DWORD  BaseOfData;//NT additional fields.DWORD  ImageBase;DWORD  SectionAlignment;DWORD  FileAlignment;WORD   MajorOperatingSystemVersion;WORD   MinorOperatingSystemVersion;WORD   MajorImageVersion;WORD   MinorImageVersion;WORD   MajorSubsystemVersion;WORD   MinorSubsystemVersion;DWORD  Win32VersionValue;DWORD  SizeOfImage;DWORD  SizeOfHeaders;DWORD  CheckSum;WORD   Subsystem;WORD   DllCharacteristics;DWORD  SizeOfStackReserve;DWORD  SizeOfStackCommit;DWORD  SizeOfHeapReserve;DWORD  SizeOfHeapCommit;DWORD  LoaderFlags;DWORD  NumberOfRvaAndSizes;IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

说明:
1. 共31个成员,重要的有6个,没用的有11个,还有一个极度重要的数据目录。成员多为记忆性内容,在PE解析器中有选择地显示,重点是数据目录。
2. 扩展头是NT头部的第三部分,紧随文件头结构之后,存储加载文件时的初始化信息,扩展头大小一般为E⁰ 。扩展头也叫可选头,但不是真正可选,而是必须有。
3. `IMAGE_NUMBEROF_DIRECTORY_ENTRIES` 是宏定义,值为0x10,表示一般有16个数据目录。数据目录定义如下:

typedef struct _IMAGE_DATA_DIRECTORY {DWORD VirtualAddress;DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

        数据目录表指示数据存储的相对虚拟地址(RVA)和大小,帮助找到数据,数据真身都在PE文件的区段中。具体每个数据目录的解析涉及相对虚拟地址到文件偏移的转换,后续介绍。先列出数据目录名字与介绍:
    - `IMAGE_DIRECTORY_ENTRY_EXPORT`:索引导出表(`IMAGE_EXPORT_DIRECTORY` 结构)。
    - `IMAGE_DIRECTORY_ENTRY_IMPORT`:索引导入表(`IMAGE_IMPORT_DESCRIPTOR` 结构数组)。
    - `IMAGE_DIRECTORY_ENTRY_RESOURCE`:索引资源(`IMAGE_RESOURCE_DIRECTORY` 结构)。
    - `IMAGE_DIRECTORY_ENTRY_EXCEPTION`:索引异常处理程序表(`IMAGE_RUNTIME_FUNCTION_ENTRY` 结构数组)。
    - `IMAGE_DIRECTORY_ENTRY_SECURITY`:索引安全结构,不加载入内存,地址成员是文件偏移,不是相对虚拟地址。
    - `IMAGE_DIRECTORY_ENTRY_BASERELOC`:索引基址重定位信息。
    - `IMAGE_DIRECTORY_ENTRY_DEBUG`:索引调试信息。
    - `IMAGE_DIRECTORY_ENTRY_ARCHITECTURE`:版权。
    - `IMAGE_DIRECTORY_ENTRY_GLOBALPTR`:全局指针目录,用在64位平台。
    - `IMAGE_DIRECTORY_ENTRY_TLS`:指向线程局部存储(`Thread Local Storage`)初始化节。
    - `IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG`:载入配置。
    - `IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT`:绑定输入目录。
    - `IMAGE_DIRECTORY_ENTRY_IAT`:导入地址表。
    - `IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT`:延迟载入描述。
    - `IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR`:COM信息。
    - 还有一个全零的保留目录,一般数组长度为16,文件可拥有更多数据目录,此时扩展头大小不是E0。

使用:
1. 显示扩展头信息可自行决定,LoadPE软件显示了其中12个。示例代码如下:

DWORD dwNewPos =(DWORD)pFile+((PIMAGE_DOS_HEADER)pFile)->e_lfanew;
PIMAGE_NT_HEADERS32    pNTHeader =(PIMAGE_NT_HEADERS32)(dwNewPos);
PIMAGE_OPTIONAL_HEADER32 pOptionalHeader =&(pNTHeader->OptionalHeader);

用 `pOptionalHeader` 指针指向要显示的信息即可。
2. 读取数据目录表信息的伪代码如下:

PIMAGE_FILE_HEADER      pFileHeader =&(pNTHeader->FileHeader);
PIMAGE_OPTIONAL_HEADER32 pOptionalHeader =&(pNTHeader->OptionalHeader);
PIMAGE_DATA_DIRECTORY    pDataDirectory = pOptionalHeader->DataDirectory;
DWORD    i=0;
while(i !=0x10) {//显示pDataDirectory[i].VirtualAddress;//显示pDataDirectory[i].Size;
}

        LoadPE的数据目录信息界面可显示数据目录信息,点击基本界面中的目录即可,显示顺序与上述表格一致。数据目录具体解析后续详细介绍,至此NT头内容结束,接下来是区段头表。

八、区段头表

一般称这部分为区段表,叫区段头表可能更合适。回顾PE文件结构:
1. DOS头
2. DOS头用的数据
3. NT头(包括文件头与扩展头)
4. 区段(节)头表
5. 各个区段(节)

        区段无需直接解析,区段头表是直接探索的最后位置。区段头表存储PE文件主体的一些属性,由若干个结构体依次排列组成(即结构体数组),每个结构体代表PE文件主体中一段数据的属性,每个区段头对应PE文件主体的一段数据(区段或节),区段头规定了区段(节)的属性。

typedef struct _IMAGE_SECTION_HEADER {BYTE Name[IMAGE_SIZEOF_SHORT_NAME];union {DWORD PhysicalAddress;DWORD VirtualSize;} Misc;DWORD VirtualAddress;DWORD SizeOfRawData;DWORD PointerToRawData;DWORD PointerToRelocations;DWORD PointerToLinenumbers;WORD NumberOfRelocations;WORD NumberOfLinenumbers;DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

说明
1. 区段头表是由多个这样的结构体组成的,最后以一个全为 0 的结构体结束。
2. 区段名字的规则:
    - `.text 段`:通常是代码段,很重要。
    - `.data 段`:一般是数据段。
    - `.bss 段`:代表未初始化的数据,像 static 变量,可能在进入函数时才会被初始化。
    - `.rdata 段`:表示只读的数据,例如字符串。
    - `.textbss 段`:和代码有关,但具体作用不太清楚。
    - `.idata 和.edata`:存放导入表和导出表的信息。
    - `.rsrc 段`:存储资源的区段。
    - `.reloc 段`:存储重定位信息的区段。
3.VirtualSize:这个区段在虚拟内存里会用到的总大小,没有经过对齐处理。要注意这是个联合体。
4. VirtualAddress:该区段起始的相对虚拟地址,也就是说这个区段加载时,是以 PE 文件加载基地址加上这个数据成员的值为起始点的。
5. SizeOfRawData:这个区段在磁盘文件里的大小,这个值经过了文件对齐处理。
6. PointerToRawData:区段的文件偏移,也就是这个区段在磁盘文件中的起始位置,之前已经讲过文件偏移的概念。
7. Characteristics:这一区段的属性,属性的具体值可以参考《黑客免杀攻防》121 页。
8. 这个结构体一共有 10 个成员,其中 4 个没什么用,有用的是 6 个。这个结构体的大小是 40 字节,也就是 0x28。

使用方式
1. 虽然区段头表就在 NT 头的后面,但是找它还是有点麻烦。系统提供了一个宏可以方便地找到它的位置,即 `IMAGE_FIRST_SECTION(pNTHeader)`,参数是 NT 头的指针。


2. 用于相对虚拟地址(RVA)和文件偏移(Offset)的转换,这是解析数据目录表的基础。
在之前提到的那些结构里,有很多相对虚拟地址(RVA),实际上这些地址都在 PE 主体的某个区段中。但当我们想在文件里找到对应的位置时,不能直接用相对虚拟地址(RVA),之前说过需要进行转换。这里给出转换的方法:
要转换的相对虚拟地址肯定会落在某个区段中,这时我们要看看它落在了哪个区段,就要分别和各个区段起始的相对虚拟地址(RVA)作比较(也就是和 `VirtualAddress` 比较)。如果落在了某个区段中,就用要转换的相对虚拟地址减去这个区段起始的相对虚拟地址,得到这个地址相对于该区段的偏移。然后用这个偏移加上区段在文件中的起始位置,也就是 `PointerToRawData` 成员的值,就得到了要转换的相对虚拟地址在磁盘文件中的位置,也就是文件偏移。
用公式表示就是:`Offset(转换) = RVA(转换) - RVA(区段) + Offset(区段)`
这里给出一个转换函数,这个函数就是上面这段话的代码形式。同样假设已经把目标文件读入内存,首地址是 `pFile`,是 `void` 类型的指针,可以把 `pFile` 看作一个全局变量,实际上在编写工具时,它是 PE 处理类里的一个数据成员。

DWORD CalcOffset(DWORD Rva) {//1获取NT头PIMAGE_NT_HEADERS32 pNTHeader =(PIMAGE_NT_HEADERS32)((long)pFile + ((PIMAGE_DOS_HEADER)pFile)->e_lfanew);//2获取区段头表PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNTHeader);//3循环比较它在哪一个区段中,不在这个区段就继续循环,注意假如VirtualAddress比SizeOfRawData大的话,说明大出来的部分是未初始化的数据,所以这里用要用SizeOfRawDatawhile(!(Rva >= pSectionHeader->VirtualAddress && Rva < pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)) {++pSectionHeader;//防止错误的PE文件引发崩溃。if(pSectionHeader->PointerToRawData == 0)return 0;}return Rva - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
}

        LoadPE中有一个功能(位置计算器),用这个函数就可以实现。`VA`是用镜像基址+`RVA`。偏移量,可以用上面的方法算出,附加信息也可以在之前那个函数中改动一下,可以一起查找到。


3. 区段信息的循环获取,其实和上面的代码非常像,只是在循环体中输出数据即可。

void ViewSectionInfo() {//1获取NT头PIMAGE_NT_HEADERS32 pNTHeader =(PIMAGE_NT_HEADERS32)((long)pFile + ((PIMAGE_DOS_HEADER)pFile)->e_lfanew);//2 获取区段头表PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNTHeader);//3循环输出,区段表的信息,可以用两种方式判断结束,一个是文件头给出了区段的数量,可以用那个,也可以判断最后一个全零的区段头while (pSectionHeader->PointerToRawData) {//输出或者获取每一个pSectionHeader中的成员++pSectionHeader;}
}

        区段表上显示的名称对应叫区段名称,voffset 对应叫起始相对虚拟地址,VSize对应叫加载后的区段大小,RDffset对应叫文件偏移,RSize对应叫文件中的区段大小,特征对应是区段的标志属性。

        上面介绍的就是PE文件所有头部信息,接下来讲讲PE文件的主体部分。当PE文件主体加载到内存时,会依据区段表,一块一块地进行加载。多数情况下,我们无需直接处理区段,因为PE文件的关键信息都包含在文件头里。借助文件头的引导,我们就能对主体中的数据展开解析。像之前未深入分析的数据目录表,后续将重点解析导出表、导入表、资源表以及重定位表等数据。 

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

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

相关文章

谷粒微服务高级篇学习笔记整理---异步线程池

多线程回顾 多线程实现的4种方式 1. 继承 Thread 类 通过继承 Thread 类并重写 run() 方法实现多线程。 public class MyThread extends Thread {Overridepublic void run() {System.out.println("线程运行: " Thread.currentThread().getName());} }// 使用 pub…

网络运维学习笔记(DeepSeek优化版) 024 HCIP-Datacom OSPF域内路由计算

文章目录 OSPF域内路由计算&#xff1a;单区域的路由计算一、OSPF单区域路由计算原理二、1类LSA详解2.1 1类LSA的作用与结构2.2 1类LSA的四种链路类型 三、OSPF路由表生成验证3.1 查看LSDB3.2 查看OSPF路由表3.3 查看全局路由表 四、2类LSA详解4.1 2类LSA的作用与生成条件4.2 2…

飞桨PP系列新成员PP-DocLayout开源,版面检测加速大模型数据构建,超百页文档图像一秒搞定

背景介绍 文档版面区域检测技术通过精准识别并定位文档中的标题、文本块、表格等元素及其空间布局关系&#xff0c;为后续文本分析构建结构化上下文&#xff0c;是文档图像智能处理流程的核心前置环节。随着大语言模型、文档多模态及RAG&#xff08;检索增强生成&#xff09;等…

以科技赋能,炫我云渲染受邀参加中关村文化科技融合影视精品创作研讨会!

在文化与科技深度融合的时代浪潮下&#xff0c;影视创作行业经历着前所未有的变革。影视创作行业发展态势迅猛&#xff0c; 同时也面临着诸多挑战。为促进影视创作行业的创新发展&#xff0c;加强业内交流与合作&#xff0c; 3月25日下午&#xff0c;海淀区文化创意产业协会举办…

NFS挂载异常排查记录

互相PING服务器看是否通&#xff1b;在ubuntu下看下服务器是否正常运行。导出目录是否导出了。最后发现在挂载目录的地方目录路径和后面没有加空格。

flutter 专题 七十一 Flutter 自定义单选控件

在Flutter 应用开发中&#xff0c;经常会遇到各种单选效果&#xff0c;虽然官方提供了Radio组件&#xff0c;但是并不能满足我们实际的开发需求&#xff0c;所以往往还需要自定义控件才能满足平时的开发需求。下面就平时开发中用到的单选进行介绍&#xff1a; 自定义SegmentBa…

在Cesium中使用ThreeJs材质(不是场景融合哦)

在Cesium中使用ThreeJs材质(不是场景融合哦&#xff09;_哔哩哔哩_bilibili

浅谈Thread类及常见方法与线程的状态(多线程编程篇2)

目录 前言 1.Thread类及常见方法 Thread类中常见的属性 1. getId() 2. getName() 3. getState() 4. getPriority() 5. isDaemon() 6. isAlive() 7. isInterrupted() 2.Thread类中常见的方法 Thread.interrupt() (中断线程) Thread.start()(启动线程) 1. 覆写 run…

Elasticsearch:人工智能时代的公共部门数据治理

作者&#xff1a;来自 Elastic Darren Meiss 人工智能&#xff08;AI&#xff09;和生成式人工智能&#xff08;GenAI&#xff09;正在迅速改变公共部门&#xff0c;从理论探讨走向实际应用。正确的数据准备、管理和治理将在 GenAI 的成功实施中发挥关键作用。 我们最近举办了…

使用事件监听器来处理并发环境中RabbitMQ的同步响应问题

RabbitListener 是 Spring AMQP 提供的核心注解&#xff0c;用于简化 RabbitMQ 消息监听器的创建。以下是对 RabbitListener(queues "balloonWords.queue") 的详细解析&#xff1a; 一、基础功能 队列监听 通过 queues 属性指定监听的队列名称&#xff08;如 "…

2025年数智化电商产业带发展研究报告260+份汇总解读|附PDF下载

原文链接&#xff1a;https://tecdat.cn/?p41286 在数字技术与实体经济深度融合的当下&#xff0c;数智化产业带正成为经济发展的关键引擎。 从云南鲜花产业带的直播热销到深圳3C数码的智能转型&#xff0c;数智化正重塑产业格局。2023年数字经济规模突破53.9万亿元&#xff…

自动驾驶04:点云预处理03

点云组帧 感知算法人员在完成点云的运动畸变补偿后&#xff0c;会发现一个问题&#xff1a;激光雷达发送的点云数据包中的点云数量其实非常少&#xff0c;完全无法用来进行后续感知和定位层面的处理工作。 此时&#xff0c;感知算法人员就需要对这些数据包进行点云组帧的处理…

Servlet注解与使用模板方法设计模式优化oa项目

一、Servlet注解&#xff0c;简化配置 分析oa项目中的web.xml文件 现在只是一个单标的CRUD&#xff0c;没有复杂的业务逻辑&#xff0c;很简单的一丢丢功能。web.xml文件中就有如此多的配置信息。如果采用这种方式&#xff0c;对于一个大的项目来说&#xff0c;这样的话web.xml…

污水处理厂人员定位方案-UWB免布线高精度定位

1. 方案概述 本方案采用免布线UWB基站与北斗卫星定位融合技术&#xff0c;结合UWBGNSS双模定位工卡&#xff0c;实现污水处理厂室内外人员高精度定位&#xff08;亚米级&#xff09;。系统通过低功耗4G传输数据&#xff0c;支持实时位置监控、电子围栏、聚集预警、轨迹回放等功…

【C++初阶】第12课—list

文章目录 1. list的构造2. list迭代器的常见接口2.1 list遍历的迭代器接口2.2 list修改数据的迭代器接口2.3 list排序、逆序、合并相关操作的成员函数 3. 模拟实现list3.1 模拟实现list的构造3.2 模拟实现list的尾插3.3 模拟实现迭代器iterator3.4 模拟实现list的插入删除3.5 模…

Java进阶

Java进阶 注解什么是注解&#xff1f;内置注解元注解自定义注解 对象克隆&#xff08;对象复制&#xff09;如何实现克隆&#xff1f;浅克隆深克隆 设计模式统一建模语言&#xff08;UML&#xff09;类接口类之间的关系 面向对象设计原则1. 单一职责2. 开闭原则3. 里氏替换原则…

AB包介绍及导出工具实现+AB包资源简单加载

Resource原理 项目中建立Resources目录&#xff0c;资源导入内部 生成项目包 资源文件存储路径 结论&#xff1a;存储在Resources下的资源&#xff0c;最终会存储在游戏的主体包中&#xff0c;发送给用户&#xff0c;手机系统上&#xff0c;如果需要做资源的更新&#xff0c;是…

全包圆玛奇朵样板间亮相,极简咖啡风引领家装新潮流

在追求品质生活的当下&#xff0c;家居装修风格的选择成为了许多消费者关注的焦点。近日&#xff0c;全包圆家居装饰有限公司精心打造的玛奇朵样板间正式对外开放&#xff0c;以其独特的咖啡色系极简风格&#xff0c;为家装市场带来了一股清新的潮流。玛奇朵样板间不仅展示了全…

算法基础——模拟

目录 1 多项式输出 2.蛇形方阵 3.字符串的展开 模拟&#xff0c;顾名思义&#xff0c;就是题⽬让你做什么你就做什么&#xff0c;考察的是将思路转化成代码的代码能⼒。这类题⼀般较为简单&#xff0c;属于竞赛⾥⾯的签到题&#xff08;但是&#xff0c;万事⽆绝对&#xff…

Java---类与对象

类与对象 前言&#xff1a;一、面向对象二、类的定义1.类的定义格式2.访问修饰限定符 三、类的实例化四、this引用1.this引用2.this引用的原因 五、对象的构造和初始化1.初始化对象2.构造方法(1).构造方法的概念&#xff1a;(2).特性&#xff1a;(3).this调用:3.就地初始化4.默…