本文为看雪论坛优秀文章
看雪论坛作者ID:1manity
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;
}
@Override
public 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对象需要一个文件对象
git clone https://github.com/NickstaDB/SerializationDumper.git
E:\web-Tools\SerializationDumper> build.bat
E:\IntelliJ IDEA 2018.2.7\project\java_security>java -jar SerializationDumper.jar
Usage:
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.txt
STREAM_MAGIC - 0xac ed
STREAM_VERSION - 0x00 05
Contents
TC_OBJECT - 0x73
TC_CLASSDESC - 0x72
className
Length - 15 - 0x00 0f
Value - main$innerClass - 0x6d61696e24696e6e6572436c617373
serialVersionUID - 0xca 3e 75 e0 69 b7 50 c5
newHandle 0x00 7e 00 00
classDescFlags - 0x02 - SC_SERIALIZABLE
fieldCount - 3 - 0x00 03
Fields
0:
Int - I - 0x49
fieldName
Length - 5 - 0x00 05
Value - years - 0x7965617273
1:
Object - L - 0x4c
fieldName
Length - 4 - 0x00 04
Value - name - 0x6e616d65
className1
TC_STRING - 0x74
newHandle 0x00 7e 00 01
Length - 18 - 0x00 12
Value - Ljava/lang/String; - 0x4c6a6176612f6c616e672f537472696e673b
2:
Object - L - 0x4c
fieldName
Length - 4 - 0x00 04
Value - test - 0x74657374
className1
TC_REFERENCE - 0x71
Handle - 8257537 - 0x00 7e 00 01
classAnnotations
TC_ENDBLOCKDATA - 0x78
superClassDesc
TC_NULL - 0x70
newHandle 0x00 7e 00 02
classdata
main$innerClass
values
years
(int)123546 - 0x00 01 e2 9a
name
(object)
TC_STRING - 0x74
newHandle 0x00 7e 00 03
Length - 3 - 0x00 03
Value - 123 - 0x313233
test
(object)
TC_STRING - 0x74
newHandle 0x00 7e 00 04
Length - 4 - 0x00 04
Value - 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);
}
进阶的一些小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;
}
@Override
public 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 ed
STREAM_VERSION - 0x00 05
Contents
TC_OBJECT - 0x73
TC_CLASSDESC - 0x72
className
Length - 15 - 0x00 0f
Value - main$innerClass - 0x6d61696e24696e6e6572436c617373
serialVersionUID - 0xca 3e 75 e0 69 b7 50 c5
newHandle 0x00 7e 00 00
classDescFlags - 0x03 - SC_WRITE_METHOD | SC_SERIALIZABLE
fieldCount - 3 - 0x00 03
Fields
0:
Int - I - 0x49
fieldName
Length - 5 - 0x00 05
Value - years - 0x7965617273
1:
Object - L - 0x4c
fieldName
Length - 4 - 0x00 04
Value - name - 0x6e616d65
className1
TC_STRING - 0x74
newHandle 0x00 7e 00 01
Length - 18 - 0x00 12
Value - Ljava/lang/String; - 0x4c6a6176612f6c616e672f537472696e673b
2:
Object - L - 0x4c
fieldName
Length - 4 - 0x00 04
Value - test - 0x74657374
className1
TC_REFERENCE - 0x71
Handle - 8257537 - 0x00 7e 00 01
classAnnotations
TC_ENDBLOCKDATA - 0x78
superClassDesc
TC_NULL - 0x70
newHandle 0x00 7e 00 02
classdata
main$innerClass
values
years
(int)123546 - 0x00 01 e2 9a
name
(object)
TC_STRING - 0x74
newHandle 0x00 7e 00 03
Length - 3 - 0x00 03
Value - 123 - 0x313233
test
(object)
TC_STRING - 0x74
newHandle 0x00 7e 00 04
Length - 4 - 0x00 04
Value - test - 0x74657374
objectAnnotation
TC_STRING - 0x74
newHandle 0x00 7e 00 05
Length - 16 - 0x00 10
Value - This is a object - 0x546869732069732061206f626a656374
TC_ENDBLOCKDATA - 0x78
objectAnnotation
TC_STRING - 0x74
newHandle 0x00 7e 00 05
Length - 16 - 0x00 10
Value - This is a object - 0x546869732069732061206f626a656374
TC_ENDBLOCKDATA - 0x78
看雪ID:1manity
https://bbs.pediy.com/user-home-952353.htm
KCTF官网:https://ctf.pediy.com
# 往期推荐
球分享
球点赞
球在看
点击“阅读原文”,了解更多!