0%

java transient反序列化

1.前言

遇到ctf题目里面需要反序列化transient关键字的变量
但是transient关键字修饰的变量是不进入反序列的

下面是部分代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public class testC implements Serializable {
private String name;
private String age;
private transient String height;

public testC(String name, String age, String height) {
this.name = name;
this.age = age;
this.height = height;
}

public String getName() {
return this.name;
}

public void setName(String name) {
this.name = name;
}

public String getAge() {
return this.age;
}

public void setAge(String age) {
this.age = age;
}

public String getHeight() {
return this.height;
}

public void setHeight(String height) {
this.height = height;
}

private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
s.defaultReadObject();
this.height = (String)s.readObject();
}

public boolean equals(Object obj) {
if (obj == null) {
return false;
} else if (this == obj) {
return true;
} else if (obj instanceof testC) {
testC user = (testC)obj;
return user.getAge().equals(this.age) && user.getHeight().equals(this.height) && user.getName().equals(this.name);
} else {
return false;
}
}

public String toString() {
return "User{name='" + this.name + '\'' + ", age='" + this.age + '\'' + ", height='" + this.height + '\'' + '}';
}
}

2.transient关键字的作用

在java中,transient主要用来防止成员变量被反序列化。
使用语法如下

1
2
3
@transient
private String var1;
private transient String var2;

@transient用于hibernate entity class中,使用后就会忽略掉这个字段不会让这些变量写入数据库中

3.让transient变量进入反序列化

用下面的代码来解释一下readObject和writeObject方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class User implements Serializable {
private String firstName;
private String lastName;
private int accountNumber;
private Date dateOpened;

public User(String firstName, String lastName, int accountNumber, Date dateOpened) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.accountNumber = accountNumber;
this.dateOpened = dateOpened;
}

public User() {
super();
}

//Setters and Getters

private void readObject(ObjectInputStream aInputStream) throws ClassNotFoundException, IOException
{
firstName = aInputStream.readUTF();
lastName = aInputStream.readUTF();
accountNumber = aInputStream.readInt();
dateOpened = new Date(aInputStream.readLong());
}

private void writeObject(ObjectOutputStream aOutputStream) throws IOException
{
aOutputStream.writeUTF(firstName);
aOutputStream.writeUTF(lastName);
aOutputStream.writeInt(accountNumber);
aOutputStream.writeLong(dateOpened.getTime());
}
}

writeXXX由ObjectOutputStream提供,readXXX同理
读取和写入的顺序必须是一样的
序列化的时候会调用writeXXX把其中的字段写入
反序列化的时候就会调用readXXX,按写入顺序读取(类型要相同)
writeUTF是写入字符串,Int是整数,等等
writeObject可以写入任意的类型

那么在看回最开始的题目,显而易见,只需要在testC中这个类加入writeObject,在进行序列化就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public class testC implements Serializable {
private String name;
private String age;
private transient String height;

public testC(String name, String age, String height) {
this.name = name;
this.age = age;
this.height = height;
}

public String getName() {
return this.name;
}

public void setName(String name) {
this.name = name;
}

public String getAge() {
return this.age;
}

public void setAge(String age) {
this.age = age;
}

public String getHeight() {
return this.height;
}

public void setHeight(String height) {
this.height = height;
}

private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
s.defaultReadObject();
this.height = (String)s.readObject();
}

public boolean equals(Object obj) {
if (obj == null) {
return false;
} else if (this == obj) {
return true;
} else if (obj instanceof testC) {
testC user = (testC)obj;
return user.getAge().equals(this.age) && user.getHeight().equals(this.height) && user.getName().equals(this.name);
} else {
return false;
}
}

private void writeObject(ObjectOutputStream s) throws IOException{
s.defaultWriteObject();
s.writeObject(this.height);
}

public String toString() {
return "User{name='" + this.name + '\'' + ", age='" + this.age + '\'' + ", height='" + this.height + '\'' + '}';
}
}

参考链接

https://www.delftstack.com/howto/java/transient-in-java/

https://howtodoinjava.com/java/serialization/custom-serialization-readobject-writeobject/