我記得比賽的時候,misc都是0解。
怎麼不算另類的1血呢?
help_me實在不會,arm看不了一點
消失的鑰匙
先看驗證邏輯,能夠看到generateZipPassword
和decryptFlag
這兩個方法內容不見了
透過在apk中尋找半年,找到一個時間不對的classes3.dex
,檢視hex發現是gz壓縮
匯出解壓一下,拿到了一半的dex
再根據時間線索,找到另一個檔案
將兩個檔案合併,得到完整的dex
getPackageSignature
這個方法hook一下,拿到了返回值748124a9239a8f2d79a0de294fbba042
Java.perform(function () {
Java.choose('com.example.test.MainActivity',{
onMatch: function(instance){
console.log(instance.getPackageSignature())
},
onComplete: function(){}
})
})
這裡可以確定748124a9239a8f2d79a0de294fbba042
是key,com.example.test
的MD5取前16位是iv
最後密碼是對包名後16位進行aes加密,取16-48位,即231287ee4876a3fed4a34bac962d513e
之後解密
採用fridahook的方式,來直接模擬執行其中的方法
Java.perform(function () {
Java.choose('com.example.test.MainActivity', {
onMatch: function (instance) {
var pwd = '231287ee4876a3fed4a34bac962d513e'
var zipContent = instance.zipDecrypt(pwd)
let Flag = Java.use("com.example.test.FlagOuterClass$Flag").$new();
let flagContent = Flag.parseFrom(zipContent)
var key = flagContent.getKey()
var iv = flagContent.getIv()
var keyString = Java.use('java.lang.String').$new(key) //轉成Java中的String,來獲得getBytes方法
var ivString = Java.use('java.lang.String').$new(iv)
let AESUitls = Java.use('com.example.test.AESUtils').$new(keyString.getBytes(),ivString.getBytes())
console.log(AESUitls.decrypt(flagContent.getFlag(),true))
},
onComplete: function () { }
})
})
最後的flag為flag{ISEC-C4n_U_f1nd_th3_10st_2Ip_p455Word}
程式碼吞噬者(尋找病毒進化的密碼)
這題好像是當時平臺答案不對,導致0解
透過反射載入decode.dex,執行程式碼
loadKey中再次反射
在patch目錄下處理dxdiff,但是該檔案不會被保留
考慮到dxdiff已經載入到記憶體,因此直接dump
拿到了程式碼
根據對password的判斷,拿到了輸入的明文
_dict = "9>AG3OCP1N2-4L5K6M7+BQD&EVF=0@8$"
password = '+>M=+K-@MN+-MK-@MN++MK+OM=M&MK'
for i in range(len(_dict)-1,-1,-2):
c2 = _dict[i]
c1 = _dict[i-1]
password = password.replace(c2,c1)
print(bytes.fromhex(password))
# you are awesome
讀取了DIFF_HEX
,又進行了一次更新
但是在更新之前,將update_1_.dex
刪除了
因此對delete進行hook,直接阻止刪除
Java.perform(function () {
let File = Java.use("java.io.File");
File["delete"].implementation = function () {
return 0
};
});
本質上就是對解密後的dict和diff進行md5計算