picture-lock
安卓题,和加密勒索软件的套路有点像,输入一个文件,输出其加密后的结果。目标是将某个加密后的文件解密出来,flag 就在里面。
java 层基本没东西,算一下签名的md5,将原本文件、加密后文件、md5带入 native。
没有init_array,没有JNI_OnLoad,直接看JNI 方法。
一进来先初始化了 AES 的 SBox,比较骚的地方在于他初始化了2组 AES 的 SBox,也就是相当于有2个 AES_Cipher,使用的 key 不同,这部分其实我看不大懂,只是调试时候发现的。
if ( new_fd )
{
old_file_buffer = (char *)malloc(0x100u);
newFile = (char *)old_fd;
bbb_1024 = malloc(0x100u);
for ( i = 0; ; ++i )
{
v26 = md5String[i & 0x1F];
nextChar = fread(old_file_buffer, 1u, md5String[i & 0x1F], (FILE *)newFile);
dataLen = nextChar;
if ( !nextChar )
goto done;
if ( nextChar <= 0xF )
{
v29 = &old_file_buffer[nextChar];
if ( 16 != (dataLen & 0xF) )
{
_aeabi_memset(v29, 16 - (dataLen & 0xF), 16 - (dataLen & 0xF));
v29 = &old_file_buffer[16 - (dataLen & 0xF) + dataLen];
}
newFile = (char *)old_fd;
dataLen = 16;
*v29 = 0;
}
然后开始读文件,每次读取 md5[i&0x1F]
个字节,如果长度小于16,就 PKCS5 到16字节。
left_or_right = (int **)&g_buf_0x180_p0x30;
if ( !(v26 & 1) )
left_or_right = &g_buf_0x180;
if ( dataLen >= 0x11 )
{
kk = 16;
p_md5String_1 = md5String;
do
{
bbb_1024[kk] = old_file_buffer[kk] ^ p_md5String_1[kk % 32];
++kk;
}
while ( kk < dataLen );
}
if ( fwrite(bbb_1024, 1u, dataLen, new_fd) != dataLen )
break;
16字节以后的, plain[index]逐位 xor上 md5[index] 。之后将这些 byte 写到加密后的文件里。
写一点 testcase 验证一下我们的猜想,发现是正确的,下文是解密的 python 脚本。
from Crypto.Cipher import AES
md5 = "f8c49056e4ccf9a11e090eaf471f418d"
odd_key = "1e090eaf471f418d"
even_key = "f8c49056e4ccf9a1"
odd_cipher = AES.new(odd_key, AES.MODE_ECB)
even_cipher = AES.new(even_key, AES.MODE_ECB)
with open('/Users/leadroyal/CTF/2018/qwb/assets/flag.jpg.lock') as f:
data = f.read()
offset = 0
i = 0
output = ""
count = 0
while True:
count += 1
current = data[offset:offset + ord(md5[i])]
if current == '':
break
offset += ord(md5[i])
if ord(md5[i]) % 2 == 0:
left = even_cipher.decrypt(current[0:16])
output += left
else:
left = odd_cipher.decrypt(current[0:16])
output += left
for j in range(16, len(current)):
output += chr(ord(current[j]) ^ ord(md5[j % 32]))
i += 1
i %= 32
print len(data)
print len(output)
# print output.encode('hex')
with open('/tmp/flag.jpg', 'wb') as fd:
fd.write(output)