Java安全小白的入门心得 - java反序列化
本文为看雪论坛优秀文章
看雪论坛作者ID:1manity
JSON和XML是通用数据交互格式,通常用于不同语言、不同环境下数据的交互,比如前端的JavaScript通过JSON和后端服务通信、微信服务器通过XML和公众号服务器通信。但这两个数据格式都有一个共同的问题:不支持复杂的数据类型。大多数处理方法中,JSON和XML支持的数据类型就是基本数据类型,整型、浮点型、字符串、布尔等,如果开发者希望在传输数据的时候直接传输一个对象,那么就不得不想办法扩展基础的JSON(XML)语法。
快速入门
public class main {private static class innerClass implements Serializable {String name;String test;int years;public innerClass(){}public innerClass(String name, String test, int years) {this.name = name;this.test = test;this.years = years;}@Overridepublic String toString() {return "innerClass{" +"name='" + name + '\'' +", test='" + test + '\'' +", years=" + years +'}';}}public static void main(String[] args) throws Exception {innerClass ic = new innerClass();//创建对象ic.name="123";ic.test="test";ic.years=123546;File f = new File("java_security/1.txt");// 模块名/文件名if(f.exists()) {System.out.println("文件存在");}else{//否则创建新文件f.createNewFile();}try{FileOutputStream fos=new FileOutputStream(f);ObjectOutputStream oos=new ObjectOutputStream(fos);oos.writeObject(ic);//将ic对象序列化写入文件oos.flush();oos.close();fos.close();}catch (Exception e) {System.out.println(e);}}}
1、序列化对象需要实现Serializable接口2、序列化需要使用ObjectOutputStream对象创建对象输出流3、ObjectOutputStream对象序列化所用方法writeObject()4、ObjectOutputStream对象需要文件输出流作为输出目标5、FileOutputStream对象需要一个文件对象
SerializationDumper
git clone https://github.com/NickstaDB/SerializationDumper.gitE:\web-Tools\SerializationDumper> build.batE:\IntelliJ IDEA 2018.2.7\project\java_security>java -jar SerializationDumper.jarUsage:SerializationDumper <hex-ascii-data>SerializationDumper -f <file-containing-hex-ascii>SerializationDumper -r <file-containing-raw-data>Rebuild a dumped stream:SerializationDumper -b <input-file> <output-file>
E:\IntelliJ IDEA 2018.2.7\project\java_security>java -jar SerializationDumper.jar -r 1.txt > 2.txtSTREAM_MAGIC - 0xac edSTREAM_VERSION - 0x00 05ContentsTC_OBJECT - 0x73TC_CLASSDESC - 0x72classNameLength - 15 - 0x00 0fValue - main$innerClass - 0x6d61696e24696e6e6572436c617373serialVersionUID - 0xca 3e 75 e0 69 b7 50 c5newHandle 0x00 7e 00 00classDescFlags - 0x02 - SC_SERIALIZABLEfieldCount - 3 - 0x00 03Fields0:Int - I - 0x49fieldNameLength - 5 - 0x00 05Value - years - 0x79656172731:Object - L - 0x4cfieldNameLength - 4 - 0x00 04Value - name - 0x6e616d65className1TC_STRING - 0x74newHandle 0x00 7e 00 01Length - 18 - 0x00 12Value - Ljava/lang/String; - 0x4c6a6176612f6c616e672f537472696e673b2:Object - L - 0x4cfieldNameLength - 4 - 0x00 04Value - test - 0x74657374className1TC_REFERENCE - 0x71Handle - 8257537 - 0x00 7e 00 01classAnnotationsTC_ENDBLOCKDATA - 0x78superClassDescTC_NULL - 0x70newHandle 0x00 7e 00 02classdatamain$innerClassvaluesyears(int)123546 - 0x00 01 e2 9aname(object)TC_STRING - 0x74newHandle 0x00 7e 00 03Length - 3 - 0x00 03Value - 123 - 0x313233test(object)TC_STRING - 0x74newHandle 0x00 7e 00 04Length - 4 - 0x00 04Value - test - 0x74657374
反序列化
try{FileInputStream fis=new FileInputStream("java_security/1.txt");ObjectInputStream ois = new ObjectInputStream(fis);innerClass ic2=(innerClass)ois.readObject();System.out.println(ic2);ois.close();fis.close();}catch(Exception e) {System.out.println(e);}
复写readObject和writeObject
进阶的一些小trick
public final void writeObject(Object obj) throws IOException {if (enableOverride) {writeObjectOverride(obj);return;}try {writeObject0(obj, false);} catch (IOException ex) {if (depth == 0) {writeFatalException(ex);}throw ex;}}
if (obj instanceof String) {writeString((String) obj, unshared);} else if (cl.isArray()) {writeArray(obj, desc, unshared);} else if (obj instanceof Enum) {writeEnum((Enum<?>) obj, desc, unshared);} else if (obj instanceof Serializable) {writeOrdinaryObject(obj, desc, unshared);} else {if (extendedDebugInfo) {throw new NotSerializableException(cl.getName() + "\n" + debugInfoStack.toString());} else {throw new NotSerializableException(cl.getName());}}
instanceof 是java的保留关键字。他的作用就是测试左边的对象是不是右边类的实例,是的话就返回true,不是的话返回false。
private void writeOrdinaryObject(Object obj,ObjectStreamClass desc,boolean unshared){......if (desc.isExternalizable() && !desc.isProxy()) {writeExternalData((Externalizable) obj);} else {writeSerialData(obj, desc);}......}
private void writeSerialData(Object obj, ObjectStreamClass desc)throws IOException{ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();for (int i = 0; i < slots.length; i++) {ObjectStreamClass slotDesc = slots[i].desc;if (slotDesc.hasWriteObjectMethod()) {...}}......}
boolean hasWriteObjectMethod() {requireInitialized();return (writeObjectMethod != null);}
/** class-defined writeObject method, or null if none */private Method writeObjectMethod;
if (slotDesc.hasWriteObjectMethod()) {//如果目标类重写了writeObject方法PutFieldImpl oldPut = curPut;curPut = null;SerialCallbackContext oldContext = curContext;if (extendedDebugInfo) {debugInfoStack.push("custom writeObject data (class \"" +slotDesc.getName() + "\")");}try {curContext = new SerialCallbackContext(obj, slotDesc);bout.setBlockDataMode(true);//利用反射执行类中的writeObject方法slotDesc.invokeWriteObject(obj, this);bout.setBlockDataMode(false);bout.writeByte(TC_ENDBLOCKDATA);} finally {curContext.setUsed();curContext = oldContext;if (extendedDebugInfo) {debugInfoStack.pop();}}curPut = oldPut;} else {//没重新,执行默认反序列化方法defaultWriteFields(obj, slotDesc);}
private static class innerClass implements Serializable {String name;String test;int years;public innerClass(){}public innerClass(String name, String test, int years) {this.name = name;this.test = test;this.years = years;}@Overridepublic String toString() {return "innerClass{" +"name='" + name + '\'' +", test='" + test + '\'' +", years=" + years +'}';}private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException { // 自定义反序列化实现System.out.println("readObject execute");is.defaultReadObject();String message = (String) is.readObject(); System.out.println(message);}private void writeObject(ObjectOutputStream is) throws IOException, ClassNotFoundException { // 自定义序列化实现System.out.println("writebject execute");is.defaultWriteObject();is.writeObject("This is a object");}}
STREAM_MAGIC - 0xac edSTREAM_VERSION - 0x00 05ContentsTC_OBJECT - 0x73TC_CLASSDESC - 0x72classNameLength - 15 - 0x00 0fValue - main$innerClass - 0x6d61696e24696e6e6572436c617373serialVersionUID - 0xca 3e 75 e0 69 b7 50 c5newHandle 0x00 7e 00 00classDescFlags - 0x03 - SC_WRITE_METHOD | SC_SERIALIZABLEfieldCount - 3 - 0x00 03Fields0:Int - I - 0x49fieldNameLength - 5 - 0x00 05Value - years - 0x79656172731:Object - L - 0x4cfieldNameLength - 4 - 0x00 04Value - name - 0x6e616d65className1TC_STRING - 0x74newHandle 0x00 7e 00 01Length - 18 - 0x00 12Value - Ljava/lang/String; - 0x4c6a6176612f6c616e672f537472696e673b2:Object - L - 0x4cfieldNameLength - 4 - 0x00 04Value - test - 0x74657374className1TC_REFERENCE - 0x71Handle - 8257537 - 0x00 7e 00 01classAnnotationsTC_ENDBLOCKDATA - 0x78superClassDescTC_NULL - 0x70newHandle 0x00 7e 00 02classdatamain$innerClassvaluesyears(int)123546 - 0x00 01 e2 9aname(object)TC_STRING - 0x74newHandle 0x00 7e 00 03Length - 3 - 0x00 03Value - 123 - 0x313233test(object)TC_STRING - 0x74newHandle 0x00 7e 00 04Length - 4 - 0x00 04Value - test - 0x74657374objectAnnotationTC_STRING - 0x74newHandle 0x00 7e 00 05Length - 16 - 0x00 10Value - This is a object - 0x546869732069732061206f626a656374TC_ENDBLOCKDATA - 0x78
objectAnnotationTC_STRING - 0x74newHandle 0x00 7e 00 05Length - 16 - 0x00 10Value - This is a object - 0x546869732069732061206f626a656374TC_ENDBLOCKDATA - 0x78
总结
看雪ID:1manity
https://bbs.pediy.com/user-home-952353.htm
KCTF官网:https://ctf.pediy.com
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!