




已阅读5页,还剩14页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
main 函数位于 suricata c 文件 其主要流程如下 1 定义并初始化程序的全局实例变量 SCInstance 类型的 suri 变量用来保存程序当前的一些 状态 标志等上下文环境 通常是用来作为参数传递 给各个模块的子函数 因此为了更好的封装性而放到 一个结构体变量中 而不是使用零散的长串参数或一 堆全局变量 SCInstanceInit 函数 顾名思义 即是对 suri 中各个 字段进行初始化 注意 这里对所有字段都进行了显 示初始化 因为虽然一个 memset 清零已经基本达到 目的了 但显示地将各个成员设成 0 NULL FALSE 对 于可读性来说还是有好处的 可以明确地说明各个字 段的初始值 且对扩展性也会有好处 例如若后续初 始化需要设置一些非 0 值 如用 1 表示无效值 直 接更改就好了 2 初始化 sc set caps 为 FALSE 标识是否对主线程进行 特权去除 drop privilege 主要是出于安全性考虑 3 初始化原子变量 engine stage 记录程序当前的运行阶段 SURICATA INIT SURICATA RUNTIME SURICATA FINALIZE 4 初始化日志模块 因为后续的执行流程中将使用日志输出 所以需要最先初始化该模块 5 设置当前主线程名字为 Suricata Main 线程名字 还是挺重要的 至少在 gdb 调试时 info threads 可以看到各个线程名 从而可以精确地找到想要查看的线程 另外 在top H 时 也能够显示出线程名字 然而ps efL 时貌似还是只是显示进程名 6 初始化 ParserSize 模块 使用正则表达式来解析类似 10Mb 这种大小参数 其中 正则引擎用的是 pcre 因此初始化时就是调用 pcre compile pcre study 对已经写好的正 则表达式进行编译和预处理 7 注册各种运行模式 Suricata 对 运行模式 这个概念也进行了封装 运行模式存储在 runmodes 数组中 定义为 RunModes runmodes RUNMODE USER MAX 首先 数组中每一项 例如 runmodes RUNMODE PCAP DEV 对应一组运 行模式 模式组包括 RunModes 类型 IDS Pcap 模式组 File Pcap 模式组 UnixSocket 模式组等 另外还有其他一些内部模 式 如 列出关键字 模式 打印版本号 模式 等 这些没有存储在 runmodes 数组中 然后 每一个模式组 其中可以包含若干个运行模式 RunMode 类型 例如 single auto autofp workers 运行模式的注册 则是为各个模式组 如 RunModeIdsPcapRegister 添加其所支持的运行模 式 通过调用 RunModeRegisterNewRunMode 并定义改组的默认运行模式 以及非常重要的 注册 各个模式下的初始化函数 如 RunModeIdsPcapSingle 等后续初始化阶段确定 了具体的运行模式后 就会调用这里注册的对应的初 始化函数 对该模式下的运行环境进行进一步配置 8 初始化引擎模式为 IDS 模式 引擎模式只有两种 IDS IPS 初始默认为 IDS 而在 nfq 或 ipfw 启用时 就会切换成 IPS 模式 该模式下能够执行 Drop 操作 即拦截数据 包 9 初始化配置模块 为 配置节点树 建立 root 节点 10 解析命令行参数 其中 与包捕获相关的选项 如 i 都会调用 LiveRegisterDevice 以注册一个数据包捕获设备接口 如eth0 全局的所有已注册的设 备接口存储在变量 live devices 中 类型为 LiveDevice 注意 用 多设备同时捕获数据包这 个特性在 Suricata 中目前还只是实验性的 v 选项可多次使用 每个 v 都能将当前日志 等级提升一级 11 若运行模式为内部模式 则进入该模式执行 完毕后退出程序 12 FinalizeRunMode 即为运行模式的处理划上句号 主要是设置offline 标志 对 unknown 运行模式进行报错 以及设置全局的run mode 变量 13 若运行模式为 单元测试模式 则跑 用户通过正则表达式指定的 单元测试 并输出测试 结果 14 检查当前模式是否与 daemon 标志冲突 Pcap 文件模式及单元测试模式都不能在 daemon 开启下进行 15 初始化全局变量 包括 数据包队列 trans q 数据队列 data queues 干嘛的 对应的 mutex 和 cond 建立小写字母表 16 初始化时间 包括 获取当前时间所用的spin lock 以及设置时区 调用 tzset 即可 17 为快速模式匹配 注册关键字 调用 SupportFastPatternForSigMatchList 函数 按照 优 先级大小插入到 sm fp support smlist list 链表中 18 若用户未在输入参数中指定配置文件 则使用默认配置文件 etc suricata suricata yaml 19 调用 LoadYamlConfig 读取 Yaml 格式配置文件 Yaml 格式解析是通过 libyaml 库来 完成的 解析的结果存储在配置节点树 见conf c 中 对 include 机制的支持 在第一遍 调用 ConfYamlLoadFile 载入主配置文件 后 将在当前配置节点树中搜寻 include 节点 并对其每个子节点的值 即通过include 语句所指定的 子配置文件 路径 同样调用 ConfYamlLoadFile 进行载入 20 再次初始化日志模块 这次 程序将会根据配置文件中日志输出配置 logging outputs 填充 SCLogInitData 类型的结构体 调用 SCLogInitLogModule 重 新初始化日志模块 21 打印版本信息 这是 Suricata 启动开始后 第一条打印信息 22 打印当前机器的 CPU 核个数 这些信息是通过 sysconf 系统函数获取的 23 若运行模式为 DUMP CONFIG 则调用 ConfDump 打印出当前的所有配置信息 ConfDump 通过递归调用 ConfNodeDump 函数实现对配置节点树的 DFS 深度优先遍历 24 执行 PostConfLoadedSetup 即运行那些需要在 配置载入完成 后就立马执行的函数 这里面涉及的流程和函数非常多 MpmTableSetup 设置多模式匹配表 该表中每一 项就是一个实现了某种多模式匹配算法 如 WuManber AC 的匹配器 以注册 AC 匹配器为例 MpmTableSetup 会调用 MpmACRegister 函数实现 AC 注册 函数内部其实只是填充 mpm table 中对应 AC 的那一项 mpm table MPM AC 的各个字段 如 匹配器名称 ac 初始化函数 SCACInitCtx 增加模式函数 SCACAddPatternCS 实际的搜索执行函数 SCACSearch 设置 rule reload 标志 如果配置文件中对应选项打 开 则会设置该标志 表示可以进行 规则热重载 即能够在程序运行时载入或替换规则集 AppLayerDetectProtoThreadInit 初始化应用层协 议检测模块 其中 AlpProtoInit 函数初始化该模块 所用到的多模式匹配器 RegisterAppLayerParsers 函数注册各种应用层协议的解析器 如 RegisterHTPParsers 函数对应 HTTP 协议 而 AlpProtoFinalizeGlobal 函数完成一些收尾工作 包 括调用匹配器的预处理 Prepare 函数 建立模式 ID 和规则签名之间的映射等 AppLayerParsersInitPostProcess 这个函数内部建 立了一个解析器之间的映射 还不太懂其用途 设置并验证日志存储目录是否存在 若配置文件中未 指定 则使用默认目录 linux 下默认为 var log suricata 获取与包捕获相关的一些配置参数 目前包括 max pending packets default packet size 设置 host mode 主机模式 两种模式 router 和 sniffer only 而如果设置为 auto 则会进行 自动选择 IPS 模式下运行为 router 否则为 sniffer only SCHInfoLoadFromConfig 从配置文件中载入 host os policy 主机 OS 策略 信息 网络入侵通常是针对某 些特定 OS 的漏洞 因此如果能够获取部署环境中主 机的 OS 信息 肯定对入侵检测大有裨益 具体这些 信息是怎么使用的 暂时也还不清楚 DefragInit 初始化 IP 分片重组模块 SigTableSetup 初始化检测引擎 主要是注册检测 引擎所支持的规则格式 跟 Snort 规则基本一致 中 的关键字 比如 sid priority msg within distance 等等 TmqhSetup 初始化 queue handler 队列处理函 数 这个是衔接线程模块和数据包队列之间的桥梁 目前共有 5 类 handler simple nfq packetpool flow ringbuffer 每类 handler 内部都有一个 InHandler 和 OutHandler 一个用于从上一级队列 中获取数据包 另一个用于处理完毕后将数据包送入 下一级队列 StorageInit 初始化存储模块 这个模块可以用来临 时存储一些数据 数据类型目前有两种 host flow 具体在何种场景下用 目前未知 CIDRInit 初始化 CIDR 掩码数组 cidrs i 对应前 i 位 为 1 的掩码 SigParsePrepare 为规则签名解析器的正则表达式进 行编译 pcre compile 和预处理 pcre study SCPerfInitCounterApi 初始化性能计数器模块 这 个模块实现了累加计数器 例如统计收到的数据包个 数 字节数 平均值计数器 统计平均包长 处理 时间 最大计数器 最大包长 处理时间 基于 时间间隔的计数器 当前流量速率 等 默认输出到 日志目录下的 stats log 文件 几个 Profiling 模块的初始化函数 Profiling 模块提 供内建的模块性能分析功能 可以用来分析模块性能 各种锁的实际使用情况 竞争时间 规则的性能等 SCReputationInitCtx 初始化 IP 声望模块 IP 声望 数据在内部是以 Radix tree 的形式存储的 但目前还 不知道数据源是从哪来的 而且也没看到这个模块的 函数在哪调用 SCProtoNameInit 读取 etc protocols 文件 建立 IP 层所承载的上层协议号和协议名的映射 如 6 TCP 17 UDP TagInitCtx ThresholdInit 与规则中的 tag threshould 关键字的实现相关 这里用到了 Storage 模块 调用 HostStorageRegister 和 FlowStorageRegister 注册了几个 与流 主机绑定的 存储区域 DetectAddressTestConfVars DetectPortTestConf Vars 检查配置文件中 vars 选项下所预定义的一些 IP 地址 如局域网地址块 端口变量 如 HTTP 端 口号 是否符合格式要求 RegisterAllModules 这是个非常重要的函数 里 面注册了 Suricata 所支持的所有线程模块 Thread Module 以 pcap 相关模块为例 TmModuleReceivePcapRegister 函数注册了 Pcap 捕获模块 而 TmModuleDecodePcapRegister 函数 注册了 Pcap 数据包解码模块 所谓注册 就是在 tmm modules 模块数组中对应的那项中填充 TmModule 结构的所有字段 这些字段包括 模块名 字 线程初始化函数 包处理或包获取函数 线程退 出清理函数 一些标志位等等 AppLayerHtpNeedFileInspection 设置 suricata 内 部模块与 libhtp HTTP 处理库 对接关系的函数 具体细节暂时不管 DetectEngineRegisterAppInspectionEngines 名 字都这么长了 肯定很复杂 暂时不管 若设置了 rule reload 标志 则注册相应的信号处理 函数 目前设置的函数都是些提示函数 没有做实际 重载 这里用的是比较惯用的 SIGUSR2 信号来触发 rule reload StorageFinalize 关闭 storage 模块的注册 为已注 册的 storage 实际分配存储空间 TmModuleRunInit 调用之前注册的线程模块的初始 化函数进行初始化 25 检查是否进入 Daemon 模式 若需要进入 Daemon 模式 则会检测 pidfile 是否已经 存在 daemon 下只能有一个实例运行 然后进行Daemonize 最后创建一个 pidfile Daemonize 的主要思路是 fork 子进程调用 setsid 创建一个新的 session 关 闭 stdin stdout stderr 并告诉父进程 父进程等待子进程通知 然后退出 子进 程继续执行 26 初始化信号 handler 首先为 SIGINT ctrl c 触发 和 SIGTERM 不带参数 kill 时触 发 这两个常规退出信号分别注册handler 对 SIGINT 的处理是设置程序的状态标志为 STOP 即让程序优雅地退出 而对SIGTERM 是设置为 KILL 即强杀 接着 程序会忽略 SIGPIPE 这个信号通常是在 Socket 通信时向已关闭的连接另一端发送数据时收到 和 SIGSYS 当进程尝试执行一个不存在的系统调用时收到 信号 以加强程序的容错性和健壮性 27 获取配置文件中指定的 Suricata 运行时的 user 和 group 如果命令行中没有指定的话 然后 将指定的 user 和 group 通过 getpwuid getpwnam getgrnam 等函数转换为 uid 和 gid 为后续的实际设置 uid 和 gid 做准备 注意 这段代码也是在 InitSignalHandler 中执行的 不知道为什么放这里 跟信号有关系么 28 初始化 Packet pool 即预分配一些 Packet 结构体 分配的数目 由之前配置的 max pending packets 确定 而数据包的数据大小由default packet size 确定 一个包的 总占用空间为 default packet size sizeof Packet 在调用 PacketGetFromAlloc 新建 并初始化一个数据包后 再调用PacketPoolStorePacket 将该数据包存入 ringbuffer Suricata 中用于数据包池的 Ring Buffer 类型为 RingBuffer16 即容量为 2 16 65536 但为什么 max pending packets 的最大值被限定为 65534 呢 29 初始化 Host engine 这货好像 跟之前的 host 类型的 storage 有关系 具体怎么用后 面再看看吧 30 初始化 Flow engine 跟前面的 host engine 类似 不过这个的用处就很明显了 就是 用来表示一条 TCP UDP ICMP SCTP 流的 程序当前所记录的所有流便组成了流表 在 flow 引擎中 流表为 flow hash 这个全局变量 其类型为 FlowBucket 而 FlowBucket 中则能够存储一个 Flow 链表 典型的一张 chained hash Table 在初始化函数 FlowInitConfig 中 首先会使用配置文件信息填充flow config 然后会按照配置中的 hash size 为流表实际分配内存 接着按照 prealloc 进行流的预分配 FlowAlloc FlowEnqueue 存储在 flow spare q 这个 FlowQueue 类型的队列中 最后调用 FlowInitFlowProto 为流表所用于的各种 流协议进行配置 主要是设置 timeout 时间 31 初始化 Decect engine 若配置文件中未指定 mpm 多模式匹配器 则默认使用 AC 即使用 mpm table 中 AC 那一项 SRepInit 函数 与前面的 SCReputationInitCtx 不同 会初始化检测 引擎中域 reputaion 相关信息 即从配置文件中指定的文件中读取声望数据 其余配置比较复杂 暂不关注 32 读取和解析 classification config 和 reference config 这两个文件用于支持规则格式中 的 classification 规则分类 和 refercence 规则参考资料 字段 33 设置规则的 动作优先级 顺序 默认为 Pass Drop Reject Alert 举例来说 若有一 条 Pass 规则和 Drop 规则都匹配到了某个数据库 则会优先应用Pass 规则 34 初始化 Magic 模块 Magic 模块只是对 libmagic 库进行了一层封装 通过文件中的 magic 字段来检测文件的类型 如 PDF 1 3 对应 PDF 文件 35 设置是否延迟检测 若 delayed detect 为 yes 则系统将在载入 规则集之前 就开始处理 数据包 这样能够在 IPS 模式下将 少系统的 down time 宕机时间 36 如果没有设置延迟检测 就调用LoadSignatures 载入规则集 37 如果设置了 live reload 则重新注册用于规则重载的 SIGUSR2 信号处理函数 这次是 设置为真正的重载处理函数 放在这里是为了防止在初次载入规则集时就被触发重载 38 初始化 ASN 1 解码模块 Wikipedia ASN 1 Abstract Syntax Notation One 是一 套标准 是描述数据的表示 编码 传输 解码的灵活的记法 应用层协议如 X 400 email X 500 和 LDAP 目录服务 H 323 VoIP 和 SNMP 使用 ASN 1 描 述它们交互的协议数据单元 39 处理 CoreDump 相关配置 Linux 下可用 prctl 函数获取和设置进程 dumpable 状态 设置 corefile 大小则是通过通用的 setrlimit 函数 40 调用 gettimeofday 保存当前时间 存储在 suri start time 中 作为系统的启动时间 41 去除主线程的权限 这个是通过libcap ng 实现的 首先调用 capng clear 清空所有权 限 然后根据运行模式添加一些必要权限 主要是为了抓包 最后调用 capng change id 设置新的 uid 和 gid 主线程的权限应该会被新建的子线程继承 因此只需 要在主线程设置即可 42 初始化所有 Output 模块 这些模块之前在线程模块注册函数里已经都注册了 这里会 根据配置文件再进行配置和初始化 最后把当前配置下启用了的output 模块放到 RunModeOutputs 链表中 43 若当前抓 包模式下未指定设备接口 通过 i 或 pcap 等方式 则解析 配置文件中指定的 Interface 并调用 LiveRegisterDevice 对其进行注册 44 若当前的模式为 CONF TEST 即测试配置文件是否有效 则现在就可以退出了 这也说 明 程序运行到这里 配置工作已经基本完成了 45 初始化运行模式 首先 根据配置文件和程序中的默认值来配置运行模式 single auto 这些 而运行模式类型 PCAP DEV PCAPFILE 这些 也在之前已经确 定了 因此运行模式已经固定下来 可以从runmodes 表中获取到特定的 RunMode 了 接 着就调用 RunMode 中的 RunModeFunc 进入当前运行模式的初始化函数 以 PCAP DEV 类型下的 autofp 模式为例 该模式的初始化函数为 RunModeIdsPcapAutoFp 这个函数的执行流程为 调用 RunModeInitialize 进行通用的运行模式初始化 目前主要是设置 CPU affinity 和 threading detect ratio 调用 RunModeSetLiveCaptureAutoFp 设置该模式 下的模块组合 确实参数 接口个数 nlive 线程个数 thread max 由用户指定 或 CPU 个数决定 RunmodeAutoFpCreatePickupQueuesString 创建一个包含 thread max 个接收队列名字的字符 串 如 pickup1 pickup2 pickup3 ParsePcapConfig 解析 pcap 接口相关配置 如 buffer size bpf filter promisc 等 PcapConfigGeThreadsCount 获取 pcap 接口 配置中指定的 threads 抓包线程个数 默认为 1 保存到 threads count 变量 创造 threads count 个抓包线程 TmThreadCreatePacketHandler 函数专门 用于创建包处理线程 函数内部会调用通用的 TmThreadCreate 创建线程 并将线程类型设 置为 TVT PPT 线程名字为 RxPcap 接口名 i 如 RxPcapeth01 inq inqh 都设置为 packetpool 表示将从 数据包池 而不是某个数据包队列 中获取包 outqh 设置为 flow 表示使用之前注册的 flow 类型的 queue handler 作为线程的输出 队列处理器 这个类型可以保证同一条 flow 的 包都会输出给同一个 queue 具体的包调度策 略取决于 autop scheduler 指定的算法 outq 设置为前面所设置的接收队列名字符串 而之前的 flow 类型 handler 的 TmqhOutputFlowSetupCtx 函数将会解析队 列名字符串 并创建出相应个数 threads max 的队列 slots 函数设置为 pktacqloop 表示这个线 程的插槽类型为 pktacqloop 这样在 TmThreadSetSlots 函数中就会将线程执行函 数 tm func 设置为针对该插槽类型的 TmThreadsSlotPktAcqLoop 函数 最终线程 在被 pthread create 执行时传入的回调函数就 是这个线程执行函数 TmSlotSetFuncAppend 将 ReceivePcap 和 DecodePcap 这两个线程 模块嵌入到前面创建的每个抓包线程的插槽中 去 TmThreadSetCPU 设置线程的 CPU 相关参 数 TmThreadSpawn 按照之前所填充好的 ThreadVars 生成实际的线程 并将该线程添加 到全局线程数组 tv root 中去 创造 thread max 个检测线程 线程名字为 Detect i 每个线程都有与一个 输入队列绑定 即 inq 设置为 pickup i 队列 inqh 设置为 flow 即使用 flow 类型 与前 面的抓包线程相匹配 的 queue handler 作为 线程的输入队列处理器 outq outqh 都设置为 packetpool 表示这 个线程的包处理完后会直接回收到 packet pool 中去 slots 函数设置为 varslot 表示这个线程的插 槽类型为 varslot 对应的执行函数为 TmThreadsSlotVar 接着 跟上面类似 把 StreamTcp 用于 TCP 会话跟踪 重组等 Detect 调用检 测引擎进行实际的入侵检测 和 RespondReject 用于通过主动应答来拒绝 连接 这三个线程模块嵌入进去 不过 这里 在插入 Detect 模块时 调用的是 TmSlotSetFuncAppendDelayed 用于支持 delayed detect 功能 SetupOutputs 由于这组检测线程是处理数 据包的完结之处 因此这里需要把输出模块也 嵌入到这些线程中去 方式也是通过 TmSlotSetFuncAppend 函数 对象是 RunModeOutputs 中存储的输出模块 46 若 unix command 为 enable 状态 则创建 Unix socket 命令线程 可与 suricata 客 户端使用 JSON 格式信息进行通信 命令线程的创建是通过 TmThreadCreateCmdThread 函数 创建的线程类型为 TVT CMD 线程执行函数为 UnixManagerThread 47 创建 Flow 管理线程 用于对流表进行超时删除处理 管理线程创建是通过 TmThreadCreateMgmtThread 函数 类型为 TVT MGMT 执行函数为 FlowManagerThread 48 初始化 Stream TCP 模块 其中调用了 StreamTcpReassembleInit 函数进行 重组模块 初始化 49 创建性能计数 相关线程 包括一个定期对各计数器进行同步的唤醒线程 SCPerfWakeupThread 和一个定期输出计数值的管理线程 SCPerfMgmtThread 50 检查数据包队列的状态是否有效 每个数据包队列都应该至少有一个reader 和一个 writer 在前面线程绑定 inq 时会增加其 reader cnt 绑定 outq 时会增加其 writer cnt 51 等待子线程初始化完成 检查是否初始化完成的方式是遍历tv root 调用 TmThreadsCheckFlag 检查子线程的状态标志 52 更新 engine stage 为 SURICATA RUNTIME 即程序已经 初始化完成 进入运转状态 这里的更新用的是原子 CAS 操作 防止并发更新导致状态不一致 但目前没在代码中只到 到主线程有更新 engine stage 操作 不存在并发更新 53 让目前处于 paused 状态的线程 继续执行 在 TmThreadCreate 中 线程的初始状态设 置为了 PAUSE 因此初始化完成后就会等待主线程调用TmThreadContinue 让其继续 从 这以后 各线程就开始正式执行其主流程了 54 若设置了 delayed detect 则现在开始调用 LoadSignature
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年春季中国石油大庆石化分公司高校毕业生招聘15人(黑龙江)考前自测高频考点模拟试题带答案详解
- 2025春季内蒙古包头市东河区机关所属事业单位引进高层次和紧缺急需人才51人模拟试卷及答案详解(易错题)
- 2025年中国光大银行社会招聘模拟试卷及答案详解(全优)
- 2025河北沧州市任丘园区产业发展集团有限公司招聘10人模拟试卷有完整答案详解
- 2025广东湛江市霞山区司法局招聘司法协理员拟聘用人员(第一批)模拟试卷及答案详解(夺冠)
- 2025年洛阳宜阳县选聘县属国有集团公司部长10名模拟试卷及答案详解(名校卷)
- 2025年湖北正源电力集团有限公司招聘146名高校毕业生(第三批)考前自测高频考点模拟试题附答案详解
- 2025贵州黔晨综合发展有限公司招聘录用人员模拟试卷附答案详解(黄金题型)
- 2025广西梧州市公安局第二批公开招聘警务辅助人员160人考前自测高频考点模拟试题及一套答案详解
- 2025年“才聚齐鲁成就未来”山东土地乡村振兴集团有限公司招聘2人考前自测高频考点模拟试题及答案详解(考点梳理)
- 铝电解工(铝电解操作工)职业技能考试题(附答案)
- 2024微信小程序技术支持与维护服务合同3篇
- 新闻记者职业资格《新闻采编实务》考试题库(含答案)
- 常用公司员工请假条模板
- 河北美术版小学六年级上册书法练习指导教案
- 高中化学-金属钠的性质及应用教学设计学情分析教材分析课后反思
- 工程量清单及招标控制价编制方案
- 04S519小型排水构筑物(含隔油池)图集
- 工程施工人员安全教育培训【共55张课件】
- 双碱法脱硫操作专项规程
- 人教版七年级上学期英语第一次月考试卷(含答案解析)
评论
0/150
提交评论