From 6604a71d0757b14dc2d70bccad11618fa317c9fc Mon Sep 17 00:00:00 2001 From: Wither OrNot Date: Sun, 6 Aug 2023 13:09:22 -0400 Subject: [PATCH] finish code decryption and reloc impl --- notes2.txt | 2 +- obfu_block.py | 112 +++++++++++++++++++++++++++++++++++++++++--------- peacestone.py | 11 +++-- 3 files changed, 102 insertions(+), 23 deletions(-) diff --git a/notes2.txt b/notes2.txt index 1070201..72c4fa8 100644 --- a/notes2.txt +++ b/notes2.txt @@ -20,5 +20,5 @@ edx <- STUB_FRAME (??) val_3 -> {???}{7 bits select offset for something}{12 bits size decrypted data} offset_1 -> key1 -offset_2 -> {byte1:last_bit = skip_verify_offset_1}{verify_byte}{key2 as word} +offset_2 -> {byte1:last_bit = no_derive_key_from_mac}{verify_byte}{key2 as word} offset_3 -> some addr? \ No newline at end of file diff --git a/obfu_block.py b/obfu_block.py index 147c1bd..3cd08b4 100644 --- a/obfu_block.py +++ b/obfu_block.py @@ -5,21 +5,10 @@ from keystone import * import pefile import json import re -import numpy as np # Set to binary name BIN_NAME = "sppsvc.exe" -# Set to function to be analyzed -# ANLZ_FUNC = "?VerifyPKeyByInstalledPidConfig@CSLSLicenseManager@@IBEJPAVCSLPKey@@PBGPAUtagPKEY_BASIC_INFO@@PAPAGPAUDECODED_PKEY_DATA@@@Z" -ANLZ_FUNC = "_wmain" - -# These magic regexes are derived from the byte markers in notes.txt -PUSH_REGEX = rb"(?:\x8dd\$\xfc\x89[\x04\x0c\x14\x1c,4<]\$|[PQRSUVW]){2}\x8d[x\x05\r\x15\x1d-5=].{4}" -STUB_RET4_REGEX = rb"\x8b[DLT\\lt\|]\$\x04\xc2\x04\x00" -STUB_RET0_REGEX = rb"\x87[\x04\x0c\x14\x1c,4<]\$\xc3" -STUB_MAX_SIZE = 0x40 # Maximum size of jump stub - REG_NAMES = { 19: "EAX", 20: "EBP", @@ -42,13 +31,30 @@ ks = Ks(KS_ARCH_X86, KS_MODE_32) md = Cs(CS_ARCH_X86, CS_MODE_32) md.detail = True md.skipdata = True -ql = Qiling(["./rootfs/sppsvc.exe"], "./rootfs") +ql = Qiling(["./rootfs/sppsvc.exe"], "./rootfs", verbose=QL_VERBOSE.OFF) image_start = ql.loader.images[0].base image_end = ql.loader.images[0].end image_size = image_end - image_start pe = pefile.PE(data=ql.mem.read(image_start, image_size)) -num_obd = ql.unpack(ql.mem.read(sym_data_inv["?g_nNumObfuscatedBlockData@WARBIRD@@3KA"], 4)) +def mem_read_int(addr): + return ql.unpack(ql.mem.read(addr, 4)) + +def array_read_int(array, offset): + return int.from_bytes(array[offset:offset+4], "little") + +def array_write_int(array, offset, val): + arr_copy = list(array) + val_bytes = val.to_bytes(4, "little") + + for i in range(4): + arr_copy[offset + i] = val_bytes[i] + + return arr_copy + +stub_frame = 0x010BE265 + +num_obd = mem_read_int(sym_data_inv["?g_nNumObfuscatedBlockData@WARBIRD@@3KA"]) obd_addr = sym_data_inv["?g_ObfuscatedBlockData@WARBIRD@@3PAU_OBFUSCATED_BLOCK_DATA@1@A"] obd = [] @@ -56,11 +62,17 @@ for i in range(num_obd): obf_block = [] for j in range(5): - obf_block.append(ql.unpack(ql.mem.read(obd_addr + 4*(5*i + j), 4))) + obf_block.append(mem_read_int(obd_addr + 4*(5*i + j))) obd.append(obf_block) -stub_frame = 0x120f989 +num_relocs = mem_read_int(sym_data_inv["?g_PrivateRelocationsTable@WARBIRD@@3VCPrivateRelocationsTable@1@B"]) +reloc_addr = sym_data_inv["?g_PrivateRelocationsTable@WARBIRD@@3VCPrivateRelocationsTable@1@B"] + 4 +private_relocs = [] + +for i in range(num_relocs): + private_relocs.append(mem_read_int(reloc_addr + 4*i)) + stub_frame_offset = stub_frame - image_start first = 0 @@ -87,6 +99,9 @@ while True: last_prev = last sum_diff = (obd[index][0] + obd[index][3]) % (1 << 32) + if first > last: + raise Exception("Offset not found in block table!") + print(f"XOR {hex(xor_value)} SUMDIFF {hex(sum_diff)} INDEX {hex(index)}") val1 = (obd[index][1] + obd[index][0]) % (1 << 32) @@ -101,9 +116,16 @@ enc_bytes = ql.mem.read(xor_plus_binstart, data_size + 1) dec_bytes = [0] * data_size chksum = 0xa5 -for i in range(data_size - 1, 0, -1): +if val2 & 0x1000000 == 0: + raise Exception("USES MAC-DERIVED KEY") + +for i in range(data_size - 1, -1, -1): enc_byte = enc_bytes[i] - b = enc_bytes[i - 1] + + if i > 0: + b = enc_bytes[i - 1] + else: + b = 0 if i % 2 == 1: if (enc_byte ^ val1_bytes[3]) % 2 == 1: @@ -127,5 +149,57 @@ for i in range(data_size - 1, 0, -1): dec_byte = (a ^ b) >> 1 chksum ^= dec_byte - print(hex(dec_byte)) - dec_bytes[i] = dec_byte \ No newline at end of file + dec_bytes[i] = dec_byte + +if chksum != val2_bytes[2]: + raise Exception("CHECKSUM FAILED!") + +print(dec_bytes) + +first = 0 +last = num_relocs - 1 + +while last >= first: + index = (first + last) // 2 + addr = private_relocs[index] & 0xFFFFFFF + + if xor_value >= addr: + if xor_value == addr: + first = (first + last) // 2 + break + + first = index + 1 + else: + last = index - 1 + +index = first + +while index < num_relocs: + addr = private_relocs[index] & 0xFFFFFFF + + if addr >= (xor_value + data_size): + break + + offset = 0 + ofmode = (private_relocs[index] >> 28) & 3 + + if ofmode == 1: + offset = -xor_plus_binstart % (1 << 32) + elif ofmode == 2: + offset = xor_plus_binstart + elif ofmode == 3: + offset = 0 + + if ((private_relocs[index] >> 30) & 3) == 2: + print(hex(addr - xor_value), hex(offset)) + val = array_read_int(dec_bytes, addr - xor_value) + val = (val + offset) % (1 << 32) + dec_bytes = array_write_int(dec_bytes, addr - xor_value, val) + print(dec_bytes) + + index += 1 + +dec_bytes = bytes(dec_bytes) + +for instr in md.disasm(dec_bytes, 0): + print(instr) \ No newline at end of file diff --git a/peacestone.py b/peacestone.py index 3f8ed71..e5c5a0e 100644 --- a/peacestone.py +++ b/peacestone.py @@ -92,7 +92,7 @@ if __name__ == "__main__": ret = 0 for i, instr in enumerate(instrs): - print(instr) + # print(instr) if instr.mnemonic == "ret" and instr.op_str == "4": ret = i @@ -138,7 +138,7 @@ if __name__ == "__main__": jmp_insert_addr = 0 for inst in instrs[max(0,stub_start_index-4):stub_start_index][::-1]: - print(inst) + # print(inst) if inst.bytes in push_instrs: # ql.mem.write(inst.address, NOP * len(inst.bytes)) jmp_insert_addr = inst.address @@ -165,7 +165,12 @@ if __name__ == "__main__": print("JUMP TARGET @ " + hex(next_addr)) print(ql.arch.regs.esp) - f.write(f"J R4 S {hex(jmp_insert_addr)} H {hex(handler_addr)} N {hex(next_addr)}\n") + if handler_addr in sym_data: + handler_name = sym_data[handler_addr] + else: + handler_name = hex(handler_addr) + + f.write(f"J R4 S {hex(jmp_insert_addr)} H {handler_name} N {hex(next_addr)}\n") # input() print() \ No newline at end of file