当前位置: 首页 > news >正文

微软detours代码借鉴点备注

comeasy

借鉴点1 Loadlibray的时间选择

注入库wrotei.dll,为了获取istream的接口,需要loadlibrary,但是在dllmain中是不建议这样做的。因此,动态库在dllmain的时候直接挂载了comeasy.exe的入口

//获取入口

TrueEntryPoint = (int (WINAPI *)(VOID))DetourGetEntryPoint(NULL);

...

//挂载入口

DetourAttach(&(PVOID&)TrueEntryPoint, TimedEntryPoint);

从加载顺序上看

红色箭头指向的wrotei64.dll在ole32.dll之前就已经启动了,而要挂载的函数在ole32.dll里,因此在不调用的loadlibary的情况挂载这些函数可以挂载exe的entrypoint,在exe加载完毕所有dll后运行entrypoint时再调用钩子函数进行ole32函数的挂载。

借鉴点2挂载虚函数

获取istream直接挂载指定的虚函数,直接对虚函数进行挂载,而不是挂载CreateInstance等函数返回一个对象。

CreateStreamOnHGlobal(NULL, TRUE, &pStream);

...
DetourAttach(&(PVOID&)RealIStreamWrite, MineIStreamWrite);

注意MineIStreamWrite的第一个参数是IStream *this。这是因为this是c++方法的第一个默认对象。

commem

借鉴点:虚函数挂载

一个标准的com虚函数挂载样例,演示了虚函数直接调用的方式,充分说明了虚函数的第一个参数this的使用。

Disas

借鉴点:指令拷贝

每个机器指令都有自己的长度,本用例演示了如何从指定的位置拷贝一个完整的指令。

主要使用了

DetourCodeFromPointer和DetourCopyInstruction

Dtest

演示了hook 0个参数1个参数到多个参数,可变参数的hook方法,同时演示了多个detours hook同一个函数时的调用效果

Dumpe

借鉴点:导出表遍历

使用detour函数遍历DLL的导出表,并给出导出函数的序号,位置(RVA),名称。

主要演示了导出表遍历的回调处理。

Dumpi

借鉴点:导入表遍历

使用detour函数遍历exe的导入表,并给出导入函数的模块和名称。

主要演示了导入表遍历的回调处理。

dynamic_alloc

借鉴点,动态分配内存并拷贝代码作为detour运行。

注意该函数还不完整,因为没有调用trampoline。

detours前

// return a non-nullptr value.
void *target_function() {
00007FF6A50511E0  sub         rsp,28h  std::cout << '+' << __FUNCTION__ << std::endl;
00007FF6A50511E4  mov         dl,2Bh  
00007FF6A50511E6  lea         rcx,[std::cout (07FF6A50A1640h)]  
00007FF6A50511ED  call        std::operator<<<std::char_traits<char> > (07FF6A5051D50h)  
00007FF6A50511F2  lea         rdx,[__xt_z+8h (07FF6A508A420h)]  
00007FF6A50511F9  mov         rcx,rax  
00007FF6A50511FC  call        std::operator<<<std::char_traits<char> > (07FF6A50520C0h)  
00007FF6A5051201  lea         rdx,[std::endl<char,std::char_traits<char> > (07FF6A5053330h)]  
00007FF6A5051208  mov         rcx,rax  
00007FF6A505120B  call        std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF6A5054E70h)  return nullptr;
00007FF6A5051210  xor         eax,eax  
}
00007FF6A5051212  add         rsp,28h  
00007FF6A5051216  ret  

准备的地址,00007FF66504FFF0,如下

00007FF66504FFEE  nop  
00007FF66504FFEF  ret  
00007FF66504FFF0  nop  
00007FF66504FFF1  nop  
00007FF66504FFF2  mov         rax,0DEADBEEF00000000h  
00007FF66504FFFC  nop  
00007FF66504FFFD  ret  

detours之后

void *target_function() {
00007FF6A50511E0  jmp         00007FF665030178  std::cout << '+' << __FUNCTION__ << std::endl;
00007FF6A50511E5  int         3  
00007FF6A50511E6  lea         rcx,[std::cout (07FF6A50A1640h)]  
00007FF6A50511ED  call        std::operator<<<std::char_traits<char> > (07FF6A5051D50h)  
00007FF6A50511F2  lea         rdx,[__xt_z+8h (07FF6A508A420h)]  
00007FF6A50511F9  mov         rcx,rax  
00007FF6A50511FC  call        std::operator<<<std::char_traits<char> > (07FF6A50520C0h)  
00007FF6A5051201  lea         rdx,[std::endl<char,std::char_traits<char> > (07FF6A5053330h)]  
00007FF6A5051208  mov         rcx,rax  
00007FF6A505120B  call        std::basic_ostream<char,std::char_traits<char> >::operator<< (07FF6A5054E70h)  return nullptr;
00007FF6A5051210  xor         eax,eax  
}
00007FF6A5051212  add         rsp,28h  
00007FF6A5051216  ret  
00007FF665030178  jmp         qword ptr [7FF665030170h]

最终跳转到00007FF66504FFF0,得到一个非空的返回值,输出如下

1. target_function() without Detour+target_function
0000000000000000
detour: 00007FF6A50511E0 --> 00007FF66504FFF0 (trampoline: 00007FF665030120 )
2. target_function() with Detour
DEADBEEF00000000
3. target_function() without Detour
+target_function
0000000000000000

虽然有tranmpoline但是没调用,因为detours函数没有调用trampoline。

echo

借鉴点:挂接exe的导出表

有意思的是exe导出了echo,而注入dll,依赖exe以及其导出函数echo。

einst

借鉴点:动态库特征查找

通过插入.detours段,并在里面放置guid,然后遍历所有dll,并在dll里查找.detours段,遍历里面的section,查找数据结构中的guid。

execp

借鉴点:异常捕获的detours处理

获取异常处理函数KiUserExceptionDispatcher,NtContinue。

对KiUserExceptionDispatcher进行hook。该hook是一个通用的处理,用户可以自己设置自己的异常处理函数,而且仅关注业务 就可以了。 在真正的hook处理Detour_KiUserExceptionDispatcher中,需要进行一些异常的处理,然后调用用户自己的异常处理函数,Detour_KiUserExceptionDispatcher根据用户的返回值决定继续还是调用下一个,或是交给调试器。

借鉴点:异常的三种处理方法

程序开始申请了一个可写内存,写入数据,然后将该内存设置为只读。随后顺序调用了safe和raw两个方法,这两个方法会调用BadCode方法,该方法会做两个赋值,位置一个正确但是只读,一个是错误的内存,两处都会触发异常。异常会进入KiUserExceptionDispatcher,由于已经HOOK,因此会进入Detour_KiUserExceptionDispatcher中。在该函数中会调用自己编写的MyVirtualFaultFilter异常处理,MyVirtualFaultFilter会根据异常的类型“访问被拒绝”,以及根据指针是否我们要访问的只读的指针,如果是则将只读的变量值修改为可写,返回continue标志,如果不是则返回查找下一个异常处理函数。如果是要访问的地址,则Detour_KiUserExceptionDispatcher根据continue标志会调用NtContinue继续处理。如果不是要访问的地址,则Detour_KiUserExceptionDispatcher会查找下一个异常处理函数,在safe函数调用中由于包含try catch,会自行正常处理并继续。在raw函数中不包含try catch,程序会异常退出。如果是调试模式则该异常会再次传递给调试器。

注意,NtContinue 是一个系统级调用,它用于在 Windows 内核模式下恢复线程的执行。这个调用通常与异常处理和上下文切换相关。当 NtContinue 被调用时,它实际上是在修改当前线程的上下文,以便线程可以从之前保存的某个点继续执行。以下是exception处理函数CONTEXT参数的内容

NtContinue 不需要返回,因为它实际上是在改变线程的执行流程,而不是像常规函数调用那样执行一些操作然后返回到调用者。当 NtContinue 被调用时,它使用提供的上下文信息来恢复线程的状态,并导致线程从该状态继续执行。这通常意味着线程将从之前保存的某个指令地址开始执行,而不是从 NtContinue 调用之后的点继续。

因此,从调用者的角度来看,NtContinue 之后的代码可能永远不会被执行,因为线程的执行流程已经被改变。这就是为什么 NtContinue 不需要(也不会)返回到调用它的代码位置的原因。实际上,如果 NtContinue 调用成功,那么线程将继续执行,就好像它从未停止过一样,只是现在的状态可能与之前有所不同。

需要注意的是,直接调用或依赖于 NtContinue 这样的低级系统调用通常是不安全的,并且可能破坏系统的稳定性。这些调用通常只在操作系统内核、驱动程序或非常底层的系统级软件中使用。在应用程序级别的代码中直接使用这些调用是不推荐的,除非你对系统的内部工作原理有深入的了解,并且知道你在做什么。

借鉴点:自己处理堆栈

一般情况下不需要用户处理堆栈,但是由于此处的处理特殊性,使用了__declspec(naked)修饰符来自己处理堆栈。因此函数在开始处自己维护堆栈信息。

findfunc

借鉴点:未导出函数的hook

未导出的函数可通过加载符号表的方式找到函数指针然后再hook。

impmunge

借鉴点:隐藏导入库和导入函数

使用方法:

修改导入库和导入表

impmunge.exe /m /o:2.exe 1.exe

注意命令行最后是被修改的文件,顺序不能错。变换如下

  file    KERNEL32.dll                     mf_KERNEL32.dll
  symbol  CreateFileA                      ms_CreateFileA
  symbol  CloseHandle                      ms_CloseHandle

恢复导入表

impmunge.exe /r /o:2.exe 1.exe

member

借鉴点:使用相似类的成员直接Hook

要点:两个类没有成员,可以直接用。如果有成员变量,则需要相同的结构,一边在hook的成员函数中使用目标对象的成员变量。

类成员的指针

static void (CMyTest ::* Real_Target)(void);
这是一个静态成员函数指针,它指向CMyTest类的一个没有参数并且返回类型为void的成员函数。
由于它是静态的,所以你可以在没有CMyTest类的对象的情况下访问它,但你需要一个对象来通过它调用实际的成员函数(因为它是一个成员函数指针,不是指向静态成员函数的指针)。
语法可能看起来有点复杂,但基本上它定义了一个指针,该指针可以指向类CMyTest的任何非静态成员函数,该函数没有参数并返回void。
使用这种成员函数指针的一种常见情况是实现回调函数或策略模式,其中你可以在运行时改变对象的行为。
注意:虽然Real_Target是一个静态成员,但它指向的成员函数可以是非静态的。静态成员只是意味着你不需要类的对象来访问该静态成员本身(在这种情况下是成员函数指针),但你仍然需要一个对象来调用该静态成员所指向的非静态成员函数。

opengl

中规中矩的hook例子,演示如何hook opengl的函数

region待补充

setdll

将dll插入到其他二进制的导入表中,这样该二进制启动的时候会自动加载该dll

simple

中规中矩的hook例子,演示如何hook sleep,并再退出时给出sleep的总毫秒数。

>sleep5.exe
sleep5.exe: Starting.
sleep5.exe: Done sleeping.

>withdll.exe /d:simple64.dll sleep5.exe
withdll.exe: Starting: `sleep5.exe'
withdll.exe:   with `E:\OpenSource\Detours\bin.X64\simple64.dll'
simple64.dll: Starting.
simple64.dll: Detoured SleepEx().
sleep5.exe: Starting.
sleep5.exe: Done sleeping.
simple64.dll: Removed SleepEx() (result=0), slept 5016 ticks.

simple_safe

同simple,区别:

//  The difference between simple and simple_safe is that simple_safe
//  uses the C++ 14 overloads which help prevent mismatching types.
 

slept

中规中矩的hook例子,以上内容的借鉴点包含此例子的内容。

syelog

演示进程间日志记录和处理

syelogd.exe这个可执行文件通常用作一个系统事件日志守护进程(daemon)。它负责接收并记录由 Detours 拦截的 API 调用信息。这些信息对于了解系统行为、调试或分析应用程序非常有用。syelogd.exe 通常与 Detours 库的其他部分一起使用,以提供实时的 API 调用跟踪和日志记录功能。

traceapi

借鉴点:使用syelogd.exe输出日志

使用方式:启动syelogd.exe或syelogd.exe output.log或start syelogd.exe output.log将日志输出到屏幕或日志文件。

启动程序并注入监控dll,监控dll会将api的调用信息输出给syelogd.

withdll.exe /d:trcapi64.dll testapi.exe

trcbld 

借鉴点:跟踪进程启动,以及子进程,输出进程的命令行参数。

Runs the build commands and figures out which files have dependencies..

举例:

tracebld /o:tracenotepad  notepad.exe

启动notepad.exe,然后通过notepad.exe的打开对话框启动mspaint等程序。

最后退出这些程序,可以得到一个tracenotepad.xml文件,该文件记录了notepad CreateProcess,CloseProcess,DeviceIoControl的调用及其参数,通过这些信息可以分析程序的行为以及子进程。

tracelnk

演示枚举模块和各个模块的导入函数枚举

tracemem

跟踪heapalloc

tracereg、traceser、tracessl、tracetcp

标准的hook例子

tryman

c# managed hook例子

withdll

借鉴点:修改程序导入表,插入新的动态库

使用方法 withdll /d:extends.dll findfunc.exe

将extends.exe插入到findfunc.exe

API说明

DetourGetEntryPoint  得到主程序的入口,方法获取module的基地址,此处是PIMAGE_DOS_HEADER,根据这个信息查找PIMAGE_NT_HEADERS,从里面获取entrypoint的地址,一个例外是如果存在PDETOUR_CLR_HEADER,则获取模块MSCOREE.DLL,返回该dll的函数_CorExeMain。

DetourCodeFromPointer  调用了detour_skip_jmp,跳过几个jmp指令ff25,eb等
DetourCopyInstruction  从src拷贝完整的指令到目标位置

detour_find_jmp_bounds  根据给出的指令地址,找出一个可以放置detours tramplines的位置,该函数解析了目标函数的第一个指令,如果是相对跳转,则根据相对跳转的指令的位置,重新计算tramplines的位置。位置使用目标指令位置前后2GB的位置区间。

detour_alloc_trampoline_allocate_new 以目标地址和给定的区间申请一个地址。在区间中查找地址,并使用VirtualAlloc尝试在给定的位置申请空间。

相关文章:

微软detours代码借鉴点备注

comeasy 借鉴点1 Loadlibray的时间选择 注入库wrotei.dll&#xff0c;为了获取istream的接口&#xff0c;需要loadlibrary&#xff0c;但是在dllmain中是不建议这样做的。因此&#xff0c;动态库在dllmain的时候直接挂载了comeasy.exe的入口 //获取入口 TrueEntryPoint (i…...

【c++】类和对象(七)

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好&#xff0c;本篇文章来到类和对象的最后一部分 目录 1.static成员1.1特性 2.友元2.1引入&#xff1a;<<和>>的重载2.2友元函数2.3友元类 3.内部类4.匿名对象5.拷…...

oracle pdb从12.1迁移到19.20

oracle pdb从12.1迁移到19.20 1 unplug &#xff08;12c的环境执行&#xff09; SQL> alter pluggable database VINCENT_TEST close immediate; SQL> alter pluggable database VINCENT_TEST unplug into /u01/backup/temp_20240401/VINCENT_TEST.xml;2 plug &#xf…...

[Python GUI PyQt] PyQt5快速入门

PyQt5快速入门 PyQt5的快速入门0. 写在前面1. 思维导图2. 第一个PyQt5的应用程序3. PyQt5的常用基本控件和布局3.1 PyQt5的常用基本控件3.1.1 按钮控件 QPushButton3.1.2 文本标签控件 QLabel3.1.3 单行输入框控件 QLineEdit3.1.4 A Quick Widgets Demo 3.2 PyQt5的常用基本控件…...

vue3中播放flv流视频,以及组件封装超全

实现以上功能的播放&#xff0c;只需要传入一个流的地址即可&#xff0c;当然组件也只有简单的实时播放功能 下面直接上组件 里面的flvjs通过npm i flv.js直接下载 <template><div class"player" style"position: relative;"><p style&…...

【浅尝C++】继承机制=>虚基表/菱形虚继承/继承的概念、定义/基类与派生类对象赋值转换/派生类的默认成员函数等详解

&#x1f3e0;专栏介绍&#xff1a;浅尝C专栏是用于记录C语法基础、STL及内存剖析等。 &#x1f3af;每日格言&#xff1a;每日努力一点点&#xff0c;技术变化看得见。 文章目录 继承的概念及定义继承的概念继承的定义定义格式继承关系与访问限定符 基类和派生类对象赋值转换继…...

tomcat中的web项目配置指引

文章目录 目录结构I server.xml 配置文件1.1 Host标签1.2 contex标签1.3 server.xml 的端口配置1.4 appBase和docBase的区别1.5 Engine标签1.6 Connector标签II Tomcat应用的配置2.1 配置虚拟路径2.2 配置连接数2.3 使用线程池2.4 配置内存大小III 预备知识...

如果你正在投简历,一定要试试这款AI工具!

今天给大家分享一款AI简历神器 - BitBitFly AI 简历助手&#xff0c;这个工具可以帮助大家快速、精准投简历&#xff0c;并且提供职位匹配度分析报告&#xff0c;提供专业优化简历建议提高简历和职位匹配度&#xff0c;轻松拿下offer。 如果你在找工作的时候遇到以下问题&…...

Unity:2D SpriteShape

1.1 简介 Sprite Shape 可以很灵活的更改sprite的轮廓。比如&#xff1a; 它由两部分组成&#xff1a;Sprite Shape Profile、Sprite Shape Controller&#xff0c;需要导入2D Sprite Shape Package. 1.1.1 Sprite导入要求 Texture Type - ‘Sprite (2D and UI)’.Sprite Mo…...

Web大并发集群部署之集群介绍

一、传统web访问模型 传统web访问模型完成一次请求的步骤 1&#xff09;用户发起请求 2&#xff09;服务器接受请求 3&#xff09;服务器处理请求&#xff08;压力最大&#xff09; 4&#xff09;服务器响应请求 传统模型缺点 单点故障&#xff1b; 单台服务器资源有限&…...

Linux_进程的优先级环境变量上下文切换

文章目录 一、进程的优先级二、进程的四个重要概念三、上下文切换四、环境变量4.1 查看当前shell环境下的环境变量与内容 一、进程的优先级 什么是优先级&#xff1f; 指定一个进程获取某种资源的先后顺序本质是进程获取cpu资源的优先顺序 为什么要有优先级 进程访问的资源&am…...

【Rust】语言特点介绍

Rust 教程 Rust 语言是一种高效、可靠的通用高级语言。其高效不仅限于开发效率&#xff0c;它的执行效率也是令人称赞的&#xff0c;是一种少有的兼顾开发效率和执行效率的语言。 Rust 语言由 Mozilla 开发&#xff0c;最早发布于 2014 年 9 月。Rust 的编译器是在 MIT Licens…...

接口冒烟测试方法

接口冒烟测试方法 今年遇到了几个问题&#xff0c;与接口的功能和性能相关&#xff0c;恰巧最近公司也在组织以冒烟测试为主题的活动&#xff0c;于是乎突发奇想&#xff0c;寻思着能否将接口测试与冒烟测试结合起来&#xff0c;发掘一些新的接口测试思路与方法。 平时对接口…...

Redis 全景图(3)--- Redis 应用于缓存

前言 这是关于 Redis 全景图的最后一篇文章。因为一次写太多会限流&#xff0c;我也是没办法&#xff0c;才分成三篇文章来写。这篇文章是关于 Redis 应用于缓存的。 其实为什么要讲这个话题呢&#xff1f; Redis 应用在很多地方呀&#xff0c;为什么一定要挑着这个话题来讲呢…...

vue中splice方法总结

本文没有目录&#xff0c;很简单的几句话总结一下 1&#xff0c;参数解释2&#xff0c;使用方法 splice(index,len,item)是vue中对数组进行操作的方法之一&#xff0c;可以用来 删除&#xff0c; 更新&#xff0c;和 增加数组内容。 1&#xff0c;参数解释 index&#xff1a…...

【HTML】CSS样式(二)

上一篇我们学习了CSS基本样式和选择器&#xff0c;相信大家对于样式的使用有了初步认知。 本篇我们继续来学习CSS中的扩展选择器及CSS继承性&#xff0c;如何使用这些扩展选择器更好的帮助我们美化页面。 下一篇我们将会学习CSS中常用的属性。 喜欢的 【点赞】【关注】【收藏】…...

Java 学习和实践笔记(51):二分法查找(折半检索)

二分法查找&#xff08;折半检索&#xff09;又叫binary search. 要在一堆数据中查找是否存在某一个已知数&#xff0c;二分法查找的步骤&#xff1a; 第一步&#xff0c;对数据实现排序 第二步&#xff0c;将该数与排序后的数据集的中间一个数进行比较 第三步&#xff0c;…...

echarts 地图 自己圈地图 乡镇街道

这个是方式是我实在不愿意做的&#xff01; 如果有现成的最好&#xff0c;没有办法的情况下再用这个东西。 今天公司有一个项目&#xff0c;地方划分了一块区域&#xff0c;但是国家没有审核&#xff0c;但是项目里面用到了一个地图展示数据&#xff01;然后就需要我们自己把…...

12-1-CSS 常用样式属性

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 CSS 常用样式属性1 CSS 三角形2 CSS 用户界面样式2.1 什么是界面样式2.2 鼠标…...

微信小程序短链接工具推荐

现在微信小程序大行其道&#xff0c;但工作中大部分人选择了短链接的方式来推广微信小程序&#xff0c;那么微信小程序短链接工具哪个好?今天就分享一篇从网上看到的关于《微信小程序短链接工具推荐》文&#xff0c;作者是souki&#xff0c;一起来看看吧! 一、缩链 1、生成方…...

[Spring Cloud] gateway全局异常捕捉统一返回值

文章目录 处理转发失败的情况全局参数同一返回格式操作消息对象AjaxResult返回值状态描述对象AjaxStatus返回值枚举接口层StatusCode 全局异常处理器自定义通用异常定一个自定义异常覆盖默认的异常处理自定义异常处理工具 在上一篇章时我们有了一个简单的gateway网关 [Spring C…...

网络基础二——TCP可靠性实现机制补充2

验证客户端和服务端三次握手和四次挥手时的状态 三次握手 #include <sys/types.h> #include <sys/socket.h> int listen(int sockfd, int backlog);netstat ntp //查看连接的状态​ 将TCP服务端套接字设置为listen状态之后&#xff0c;此时服务端是处于L…...

SSM项目实战——哈哈音乐(四)前台模块开发

1、项目准备 ①导入依赖和前端资源 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.x…...

Hadoop-入门

资料来源&#xff1a;尚硅谷-Hadoop 一、Hadoop 概述 1.1 Hadoop 是什么 1&#xff09;Hadoop是一个由Apache基金会所开发的分布式系统基础架构。 2&#xff09;主要解决&#xff1a;海量数据的存储和海量数据的分析计算问题。 3&#xff09;广义上来说&#xff0c;Hadoop…...

HarmonyOS(鸿蒙)——单击事件

2.4 实现ClickedListener接口并重写onClick方法 2.5 实现onClick方法中的具体逻辑&#xff0c;以此完成点击事件的相关业务操作 三、测试 3.1 登录远程模拟器 3.2 运行项目 四、精选好文 一、简介 1.1 什么是组件 组件就是文本、按钮、图片等元素的统称 1.2 什么是事件 …...

c# wpf template itemtemplate+dataGrid

1.概要 2.代码 <Window x:Class"WpfApp2.Window8"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schemas.microsoft.com/expression/blend…...

总结UDP协议各类知识点

前言 本篇博客博主将详细地介绍UDP有关知识点&#xff0c;坐好板凳发车啦~ 一.UDP特点 1.无连接 UDP传输的过程类似于发短信&#xff0c;知道对端的IP和端口号就直接进行传输&#xff0c;不需要建立连接&#xff1b; 2.不可靠传输 没有任何的安全机制&#xff0c;发送端发…...

设计模式 --5观察者模式

观察者模式 观察者模式的优缺点 优点 当一个对象改变的时候 需要同时改变其他对象的相关动作的时候 &#xff0c;而且它不知道有多少具体的对象需要改变 应该考虑使用观察者模式 。观察者模式的工作就是解除耦合 让耦合双方都依赖与抽象 而不是具体 是的各自改变都不会影响另…...

跨平台的组播测试工具mping、udp_sender及udp_reciver的源码及使用教程

文章目录 1.前言2.mping工具编译3.mping工具使用3.1 参数说明3.1 组播播发&#xff08;-s&#xff09;3.1 组播播发&#xff08;-r&#xff09;3.3 Linux下mping测试 4.Linux组播udp_sender及udp_reciver使用4.1 udp_sender源码4.1 udp_reciver源码4.3 编译方法4.4 测试使用4.4…...

Linux基础篇:文件系统介绍——根目录下文件夹含义与作用介绍

Linux文件系统介绍——文件夹含义与作用 Linux文件系统是一个组织和管理文件的层次结构。它包括了目录、子目录和文件&#xff0c;这些都是按照一定的规则和标准进行组织的。以下是Linux文件系统的一些关键组成部分&#xff1a; 1./bin&#xff1a; 该目录包含了系统启动和运…...

企业网站如何进行定位/深度优化

2019独角兽企业重金招聘Python工程师标准>>> 又有很长的时间过去了&#xff0c;继续推荐Python Tutorial的进程。 本文主要针对官方Python Tutorial中第5小节的内容进行有选择性的分析&#xff0c;还是遵循本系列文档的风格&#xff0c;所讨论的内容都是给我留下一…...

唐山市住房与城乡建设厅网站/谷歌seo优化排名

很多朋友在用github管理项目的时候&#xff0c;都是直接使用https url克隆到本地&#xff0c;当然也有有些人使用 SSH url 克隆到本地。然而&#xff0c;为什么绝大多数人会使用https url克隆呢&#xff1f; 这是因为&#xff0c;使用https url克隆对初学者来说会比较方便&…...

网站被入侵后需做的检测 1/制作自己的网站

一、Thymeleaf是什么&#xff1f; Thymeleaf是⾯向Web和独⽴环境的现代服务器端Java模板引擎&#xff0c; 能够处理HTML&#xff0c;XML&#xff0c;JavaScript&#xff0c;CSS甚⾄纯⽂本&#xff0c;在Spring Boot中被广泛使用。 Thymeleaf旨在提供⼀个优雅的、 ⾼度可维护的创…...

在百度上做网站多少钱/最近发生的新闻

2019独角兽企业重金招聘Python工程师标准>>> ###第一章 ######与Elasticsearch交互 节点客户端(node client) 节点客户端以无数据节点(none data node)身份加入集群&#xff0c;换言之&#xff0c;它自己不存储任何数据&#xff0c;但是它知道数据在集群中的具体位置…...

企业网站跟微信支付怎么做/云南网络推广seo代理公司

我正在尝试为我的地图集群设置视图.我正在从XML膨胀视图并根据群集大小设置文本,我想显示该视图.在下面的代码中我得到一个空位图作为回报&#xff1a;private Bitmap createClusterBitmap(int clusterSize) {View cluster LayoutInflater.from(context).inflate(R.layout.map…...

工商局网站怎么做增项/足球世界排名国家

【摘要】PHP即“超文本预处理器”&#xff0c;是一种通用开源脚本语言。PHP是在服务器端执行的脚本语言&#xff0c;与C语言类似&#xff0c;是常用的网站编程语言。PHP独特的语法混合了C、Java、Perl以及 PHP 自创的语法。下面是php怎么去掉字符串末尾字符&#xff0c;让我们一…...