Skip to content

Instantly share code, notes, and snippets.

@physics-sec
Created May 27, 2020 01:14
Show Gist options
  • Save physics-sec/ad39736f162a2a3984b10c20675afb5d to your computer and use it in GitHub Desktop.
Save physics-sec/ad39736f162a2a3984b10c20675afb5d to your computer and use it in GitHub Desktop.
Little Python3 script that decrypts and encrypts the JS files contained in the Android apps made with Appcelerator
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import struct
from Crypto.Cipher import AES
def unpad(s):
if len(s) % 16 != 0:
raise Exception('Bad Padding!')
pad_len = s[-1]
if pad_len > 16 or pad_len < 1:
raise Exception('Bad Padding!')
for i in range(1, pad_len + 1):
if s[-i] != pad_len:
raise Exception('Bad Padding!')
return s[:-pad_len]
def pad(s, pad_len=16):
s_len = len(s)
resto = s_len % pad_len
b_len = pad_len - resto
pad = bytes([ b_len ]) * b_len
return s + pad
def xor(x1, x2):
assert len(x1) == len(x2)
r = b''
for i in range(len(x1)):
r += bytes([ x1[i] ^ x2[i] ])
return r
def encrypt_AES_ECB(plaintext, key):
assert len(key) == 128/8
cipher = AES.new(key, AES.MODE_ECB)
assert len(plaintext) % 16 == 0
ct = cipher.encrypt(plaintext)
return ct
def encrypt_AES_CBC(plaintext, key, iv):
n = 16
assert len(key) == n
assert len(iv) == n
plaintext = pad(plaintext)
blocks = [plaintext[i:i+n] for i in range(0, len(plaintext), n)]
ct = b''
previus_block = iv
for block in blocks:
block_x = xor(block, previus_block)
block_en = encrypt_AES_ECB(block_x, key)
previus_block = block_en
ct += block_en
return ct
def decrypt_AES_ECB(data, key):
assert len(key) == 128/8
cipher = AES.new(key, AES.MODE_ECB)
pt = cipher.decrypt(data)
return pt
def decrypt_AES_CBC(ciphertext, key, iv):
n = 16
assert len(key) == n
assert len(iv) == n
ciphertext_len = len(ciphertext)
assert ciphertext_len % n == 0
blocks = [ciphertext[i:i+n] for i in range(0, ciphertext_len, n)]
pt = b''
previus_block = iv
for block in blocks:
d_block = decrypt_AES_ECB(block, key)
pt_block = xor(d_block, previus_block)
pt += pt_block
previus_block = block
pt = unpad(pt)
return pt
def derive_key_iv(salt):
# $ md5sum libti.cloak.so
# 1f1eb9acca962d57f63d86ce1b476dec libti.cloak.so
# these values are hardcoded in libti.cloak.so
# if the library is different for you, decompile it with ghidra get the new values
xor_bytes = [0xfe, 0xe7, 0x32, 0x23, 0x42, 0x25, 0x71, 0x7f, 0xc0, 0x61, 0x07, 0xec, 0x35, 0x00, 0x09, 0xc7]
key = b''
iv = b''
for i in range(16):
byte = salt[i]
byte = struct.pack('b', byte)
iv += byte
byte = ord(byte)
byte = byte ^ xor_bytes[i]
key += bytes( [byte] )
return (key, iv)
def main():
fh = open('encrypted_js_file.bin', 'rb')
cipher_text = fh.read()
fh.close()
# hardcoded in AssetCryptImpl.java
# change this!
salt = [-51, 20, 45, -50, 61, 10, -51, -108, -100, 121, -55, -27, -83, -11, 59, 22]
key, iv = derive_key_iv(salt)
js_code = decrypt_AES_CBC(cipher_text, key, iv)
print(js_code.decode('utf-8'))
# modify js_code
cipher_text = encrypt_AES_CBC(js_code, key, iv)
fh = open('encrypted_js_file.bin', 'wb')
fh.write(cipher_text)
fh.close()
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment