Java謎題5:球(ball)-解決方案
如果你不能投球,那就沒什麼樂趣了。但擴充套件Throwable也使它實現了可序列化,這就是真正有趣的開始。使用序列化,我們可以建立一個球,該球應該被捕獲的次數與序列化資料宣告的次數相同。
這場比賽似乎破壞了樂趣。你不能丟擲它;但更重要的是你不能序列化它。如果您試圖直接將球序列化,它也將嘗試序列化它所附加到的遊戲,從而導致NotSerializableException。
請注意,從技術上講,從球到其比賽的參考只是一個類似於 this$0的欄位。我說的“附加”是指指定給那個欄位。因此,這個問題相當於序列化一個具有不可序列化的正常欄位的物件。
問題在於我們根本不需要序列化遊戲和球。我們只需要將球反序列化,並將其附加到遊戲中。該Game例項不需要直接來自序列化流。我們可以在它的位置放置替代品,並覆蓋readResolve,在它附著到球之前用一個game替換它。
在實踐中作弊
有多種方法可以建立包含附加到替代遊戲的球的原始資料(位元組陣列)。我們建立了一個類似於ball(ba)的類。我們給它和ball一樣的serialversionuid和我們期望的caught值。它附加到我們的替代實現readResolve(Player)上。我們將其序列化,並將ba類的名稱替換為ball類。將byte[]轉換為一個String並返回,允許我們使用string.replace。
選擇ba這個名稱是為了讓play.player$ba的長度與game.game$ball的長度相同。否則,直接用一個替換另一個會損壞流。
package play; import game.Game; import game.Game.Ball; import java.io.*; public class Player implements Serializable { public static void main(String[] args) throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); new ObjectOutputStream(bos).writeObject(new Player().new Ba()); byte[] bytes = new String(bos.toByteArray(), "ISO-8859-1") .replace("play.Player$Ba", "game.Game$Ball") .getBytes("ISO-8859-1"); Ball ball = (Ball) new ObjectInputStream(new ByteArrayInputStream(bytes)) .readObject(); ball.caught(); } class Ba implements Serializable { static final long serialVersionUID = -7172046060844866133L; private long caught = -1; } Object readResolve() { return new Game(); } } |
這就是發生的情況:
- 在呼叫時readObject(),首先Ball獲取反序列化,然後caught設定為-1。
- Ball.this$0反序列化的值是一個例項Player。
- 在Player分配給該欄位之前(因為它的型別錯誤,它將失敗),readResolve呼叫其方法,建立一個新Game的score0
- 這Game被分配給Ball.this$0,readObject()返回Ball。
- ball.catched()是用catched=-1和這個$0.score==0來呼叫的,你作弊就被抓住了!
結論
建立具有對不可序列化物件的引用的可序列化物件是一個壞主意,因為您無法對它們進行序列化。但是,你仍然可以反序列化它們。
Java序列化充滿了令人討厭的意外可能性。關於這一點你可以做一系列的謎題。但是,如果你真的陷入此種境地,那麼你需要做的就是檢視過去幾年的JDK安全漏洞。
相關文章
- Java謎題5:球(ball)Java
- Java謎題1:小丑 - 解決方案Java
- Java謎題7:餅乾-解決方案Java
- Java謎題3:汽車 - 解決方案Java
- Java謎題6:雞與蛋-解決方案Java
- nginx /Java 解決跨域問題方案NginxJava跨域
- Java™ 教程(常見問題及其解決方案)Java
- 平方謎題(5)
- Java謎題:小丑Java
- 乘法◆除法◆謎題(5)
- ●六數謎題●(5)
- Java 8 的日期與時間問題解決方案Java
- 工作中碰到的Java問題整理及解決方案Java
- Java限流及常用解決方案Java
- 跨域問題,解決方案 – CORS方案跨域CORS
- 在 Linux 命令列中使用 nudoku 解決謎題Linux命令列
- Java 謎題 2:夢境Java
- Java謎題3:汽車Java
- Java 之 Map 的鍵,值多重排序問題解決方案Java排序
- java.lang.OutOfMemoryError及解決方案JavaError
- Java定時任務解決方案Java
- h5移動端常見的問題及解決方案H5
- 解謎遊戲謎題設計研究(三):推理類謎題設計遊戲
- 解謎遊戲謎題設計研究(一):物品類謎題設計遊戲
- JAVA | Java 解決跨域問題Java跨域
- H5定位終極解決方案H5
- 程式設計謎題:提升你解決問題的訓練場程式設計
- 跨域問題及解決方案跨域
- HA腦裂問題解決方案
- SpringBoot跨域問題解決方案Spring Boot跨域
- 解謎遊戲謎題設計研究(二):機關類謎題設計遊戲
- Java謎題6:雞與蛋Java
- Java 謎題 7:餅乾(Cookie)JavaCookie
- Java 謎題4:液體(Liquid)JavaUI
- Java解決跨域問題Java跨域
- F5新型資料中心防火牆解決方案——一鍵解決企業網路安全問題防火牆
- JAVA程式設計題-用java解決兔子問題Java程式設計
- thinkphp 5 跨域問題解決PHP跨域