强网杯WriteUp | pictureLock

本文介绍了解密一款特殊APK的过程,重点在于分析其AES加密及异或操作,并提供了解密代码实现。文章详细记录了作者如何通过动态调试找出密钥并最终还原加密内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

通往结果的路途是最美好的!珍惜在这过程中你所遇到的人和经历。不负遇见!

分析

这道题我感觉只是套了个apk的外壳,一点都没有做Android题目的感觉。本质上是一个aes和一个异或的解密。难受。
这里写图片描述
j()用于获取apk签名的MD5值
这里写图片描述
关键是这个enc()是一个native方法。动态调。
动态调试可以参考这篇文章
http://blog.csdn.net/qq_33438733/article/details/79516372
主要就是这个sub_5fa37a48这个函数
这里写图片描述
进去之后就是一大堆加密算法。看了下特征,发现一个类似S盒的数据块,猜测是aes加密。
这里写图片描述
fread在读取数据时会按着指定序列读取,这个序列也就是签名的MD5值。这个值可以通过动态调smali的方法拿到。刚开始我用smali插桩的方法,导致我在尝试aes解密的时候,密匙出错,所以卡了很久。因为如果修改了smali,重新打包后签名会变化,所以得到的密匙也就不一样。
这里写图片描述
这是获取二次打包的密钥的截图。正确的密钥其实可以字节从内存中获取。
这里写图片描述
比较关键地方,v32是用于AES的密匙,在这里他做了判断
这里写图片描述
if ( !(v28 & 1) )
也就是每次的密匙都会发生变化,查看&dword_5FA3C008;和&dword_5FA3C004;的内容可以看到他这里对原本32位的MD5值分别取了前半段和后半段。
这里写图片描述
这一大段就是AES,不用管。(估计应该是用标准的AES进行加密的,如果不是那就GG)
这里写图片描述
这里就是进行异或加密了,这里只对数据的前16个字节进行了aes加密,而后对剩余的字节进行异或加密。根据加密的过程写出解密代码。

# -*- coding: UTF-8 -*-
from Crypto.Cipher import AES
from binascii import b2a_hex
from binascii import a2b_hex
from aes_util import *
def dec_xor_data(cipher):
        plain=[]
        for i in range(16,len(cipher)):
                temp=chr(ord(cipher[i]) ^ ord(akey[i%32]))
                plain.append(temp)
        return "".join(plain)
akey="f8c49056e4ccf9a11e090eaf471f418d"
dword_5FA3C00C=[0x66,0x38,0x63,0x34,0x39,0x30,0x35,0x36,0x65,0x34,0x63,0x63,0x66,0x39,0x61,0x31,0x31,0x65,0x30,0x39,0x30,0x65,0x61,0x66,034,0x37,0x31,0x66,0x34,0x31,0x38,0x64]
def main():
        fp_enc=open("flag.jpg.lock","rb")
        fp_dec=open("de.jpg","wb")
        i=0
        while 1:
                v24 = ord(akey[i&0x1f])
                cipher=fp_enc.read(v24)
                cipher_aes=b2a_hex(cipher[:16])
                if  (v24&0x1)==0:
                        hkey=akey[:16]
                        plain_aes=decrypt_ECB(cipher_aes,hkey)
                else:
                        hkey=akey[16:]
                        plain_aes=decrypt_ECB(cipher_aes,hkey)
                if len(plain_aes) < 16:
                        plain_aes+=chr(0)*(16-len(plain_aes))
                fp_dec.write(plain_aes)
                plain_xor=dec_xor_data(cipher)
                fp_dec.write(plain_xor)
                i=i+1
                if len(cipher)<1:
                        break
        fp_dec.close()        
if __name__=="__main__":
        main()

总结

这题最难的地方是解aes加密,刚开始也不确定,所以就自己加密了一张图片,然后测试前16个字节进行比对。拿github上的aes尝试了一下,不对,然后找了一个python的解密脚本,成了!
最后解密图片,拿到flag

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值