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)

本文章首发在 网安wangan.com 网站上。

上一篇 下一篇
讨论数量: 0
只看当前版本


暂无话题~