|
| 1 | +import idautils |
| 2 | +from Cryptodome.Cipher import AES |
| 3 | +from Cryptodome.Util.Padding import pad |
| 4 | +import hashlib |
| 5 | +import base64 |
| 6 | + |
| 7 | +def KSA(key: bytes) -> bytes: |
| 8 | + S = bytearray(256) |
| 9 | + for i in range(256): |
| 10 | + S[i] = i |
| 11 | + j = 0 |
| 12 | + for i in range(256): |
| 13 | + j = (j + S[i] + key[i % len(key)]) % 256 |
| 14 | + temp = S[i] |
| 15 | + S[i] = S[j] |
| 16 | + S[j] = temp |
| 17 | + return S |
| 18 | + |
| 19 | +def PRGA(key: bytes, ci: bytes) -> bytes: |
| 20 | + S = KSA(key) |
| 21 | + a = 0 |
| 22 | + b = 0 |
| 23 | + pl = bytearray(len(ci)) |
| 24 | + for i in range(len(ci)): |
| 25 | + a = (a+1) % 256 |
| 26 | + b = (b + S[a]) % 256 |
| 27 | + temp = S[a] |
| 28 | + S[a] = S[b] |
| 29 | + S[b] = temp |
| 30 | + K = S[(S[a] + S[b]) % 256] |
| 31 | + pl[i] = ci[i] ^ K |
| 32 | + return pl |
| 33 | + |
| 34 | +def rc4_decrypt_str(citext, key): |
| 35 | + citext = bytearray.fromhex(citext.decode('utf-8')) |
| 36 | + pltext = PRGA(key, citext) |
| 37 | + return pltext |
| 38 | + |
| 39 | + |
| 40 | + return pltext |
| 41 | + |
| 42 | +def xor_decrypt_str(citext, key): |
| 43 | + citext = bytearray.fromhex(citext.decode('utf-8')) |
| 44 | + pltext = bytearray() |
| 45 | + |
| 46 | + for i in range(0, len(citext)): |
| 47 | + pltext.append(citext[i] ^ key[(i+1) % len(key)]) |
| 48 | + |
| 49 | + return pltext |
| 50 | + |
| 51 | +def prepad(size): |
| 52 | + pre_pad = [] |
| 53 | + nonce = 0 |
| 54 | + for i in range(0, size, 16) : |
| 55 | + nonce +=1 |
| 56 | + padding = nonce.to_bytes(16, 'little') |
| 57 | + pre_pad += padding |
| 58 | + return bytearray(pre_pad) |
| 59 | + |
| 60 | +def aes_decrypt(citext, password): |
| 61 | + salt = b'SaltVb6CryptoAes' |
| 62 | + key = hashlib.pbkdf2_hmac('sha1', password, salt, 1000, dklen=32) |
| 63 | + aes_stream = prepad(len(citext)) |
| 64 | + aes_stream.extend(citext) |
| 65 | + cipher = AES.new(key, AES.MODE_ECB) |
| 66 | + xor_key = cipher.encrypt(pad(aes_stream, 16)) |
| 67 | + plaintext = bytearray(len(citext)) |
| 68 | + for i in range(len(citext)) : plaintext[i] = xor_key[i] ^ citext[i] |
| 69 | + return plaintext |
| 70 | + |
| 71 | +def aes_decrypt_str(citext, password): |
| 72 | + citext = bytearray.fromhex(citext.decode('utf-8')) |
| 73 | + citext = base64.b64decode(citext) |
| 74 | + return aes_decrypt(citext, password) |
| 75 | + |
| 76 | +def get_str(addr): |
| 77 | + res = bytearray() |
| 78 | + length = 0 |
| 79 | + data = idc.get_wide_word(addr+length) |
| 80 | + |
| 81 | + while data: |
| 82 | + res.append(data) |
| 83 | + length += 2 |
| 84 | + data = idc.get_wide_word(addr+length) |
| 85 | + return res |
| 86 | + |
| 87 | +def decrypt_all_strs(hex_func, decrypt_func, algo=0, patch=1): |
| 88 | + #List of addreses required manual provision |
| 89 | + citext_exception = [] |
| 90 | + key_exception = [] |
| 91 | + citext_addrs = [] |
| 92 | + key_addrs = [] |
| 93 | + strings = [] |
| 94 | + |
| 95 | + for addr in idautils.XrefsTo(hex_func, flags=0): |
| 96 | + citext_addr = addr.frm |
| 97 | + while True: |
| 98 | + citext_addr = idc.prev_head(citext_addr) |
| 99 | + if idc.print_insn_mnem(citext_addr) == "mov" and idc.get_operand_type(citext_addr, 1) == 0x5 : |
| 100 | + temp = idc.get_operand_value(citext_addr, 1) |
| 101 | + if temp not in citext_exception: |
| 102 | + citext_addrs.append(temp) |
| 103 | + break |
| 104 | + |
| 105 | + for addr in idautils.XrefsTo(decrypt_func, flags=0): |
| 106 | + key_addr = addr.frm |
| 107 | + while True: |
| 108 | + key_addr = idc.prev_head(key_addr) |
| 109 | + if idc.print_insn_mnem(key_addr) == "mov" and idc.get_operand_type(key_addr, 1) == 0x5 and idc.get_operand_value(key_addr, 0) == 0x2: |
| 110 | + temp = idc.get_operand_value(key_addr, 1) |
| 111 | + if temp not in key_exception: |
| 112 | + key_addrs.append(temp) |
| 113 | + break |
| 114 | + |
| 115 | + decrypted = [] |
| 116 | + size = min(len(key_addrs), len(citext_addrs)) |
| 117 | + citext_addrs = citext_addrs[:size] |
| 118 | + citext_addrs.extend(citext_exception) |
| 119 | + key_addrs = key_addrs[:size] |
| 120 | + key_addrs.extend(key_exception) |
| 121 | + |
| 122 | + for i in range(0, size+len(citext_exception)) : |
| 123 | + if citext_addrs[i] not in decrypted: |
| 124 | + decrypted.append(citext_addrs[i]) |
| 125 | + else: |
| 126 | + continue |
| 127 | + |
| 128 | + print(f"{hex(citext_addrs[i])} {hex(key_addrs[i])}") |
| 129 | + if algo == 1: |
| 130 | + pltext = xor_decrypt_str(get_str(citext_addrs[i]), get_str(key_addrs[i])) |
| 131 | + elif algo == 2: |
| 132 | + pltext = rc4_decrypt_str(get_str(citext_addrs[i]), get_str(key_addrs[i])) |
| 133 | + else: |
| 134 | + pltext = aes_decrypt_str(get_str(citext_addrs[i]), get_str(key_addrs[i])) |
| 135 | + print(pltext) |
| 136 | + |
| 137 | + if pltext not in strings: |
| 138 | + idc.set_cmt(citext_addrs[i], pltext.decode('utf-8'), 1) |
| 139 | + strings.append(pltext) |
| 140 | + if patch: |
| 141 | + for idx in range(len(pltext)) : |
| 142 | + idc.patch_word(citext_addrs[i] + idx*2, pltext[idx]) |
| 143 | + for pad_idx in range(idx + 1, idx*2) : |
| 144 | + idc.patch_word(citext_addrs[i] + pad_idx*2, 0x00) |
| 145 | + return strings |
| 146 | + |
| 147 | +'''' |
| 148 | +Please provide the address of the following functions |
| 149 | +hex_func as Proc_1_3 |
| 150 | +decrypt_func as Proc_1_5 |
| 151 | +
|
| 152 | +(void (__fastcall *)(char *, const wchar_t *))_vbaStrCopy)( |
| 153 | + v165, |
| 154 | + L"9FB61391D8974B3D8AD01F88F3CECED5B4E9100A3C10C6A37AC8670C078E23B9C0C7"); |
| 155 | + v8 = Proc_1_3(v165); |
| 156 | + ((void (__fastcall *)(int *, int))_vbaStrMove)(&v162, v8); |
| 157 | + ((void (__fastcall *)(char *, const wchar_t *))_vbaStrCopy)(v163, L"OMSkahFpbDoSRbwObPrXoXrL"); |
| 158 | + v120 = v162; |
| 159 | + v162 = 0; |
| 160 | + ((void (__fastcall *)(char *, int))_vbaStrMove)(v164, v120); |
| 161 | + v156 = Proc_1_5(v164, v163); |
| 162 | +
|
| 163 | +Please apply an IDC Script generated from http://sandsprite.com/vbdec/ to help fix up all functions |
| 164 | +''' |
| 165 | +hex_func = |
| 166 | +decrypt_func = |
| 167 | +strings = decrypt_all_strs(hex_func, decrypt_func, patch=0) |
| 168 | + |
| 169 | +#Decrypt payload from resource file example |
| 170 | +#citext = bytearray(open('CUSTOM101', 'rb').read()) |
| 171 | +#password = b'DDDJJFHHDII8387474765HHFNNFBGGFJJRKJKERJ439485TH8THTJMNBGJTIGH4I5YYIU45VBIUG4I7I1123405TY' |
| 172 | +#open('payload.bin', 'wb').write(aes_decrypt(citext, password)) |
0 commit comments