|
| 1 | +import golanganalyzerextension as gae |
| 2 | +import java.nio.ByteBuffer |
| 3 | +import ghidra.program.model.scalar.Scalar as Scalar |
| 4 | +import ghidra.program.model.address.Address as Address |
| 5 | +import array |
| 6 | +import ghidra.program.model.symbol.SourceType as SourceType |
| 7 | +import re |
| 8 | + |
| 9 | + |
| 10 | +def get_obfus_str(file_line): |
| 11 | + value_list = [] |
| 12 | + inst = getInstructionAt(file_line.get_func_addr().add(file_line.get_offset())) |
| 13 | + addr_end = file_line.get_func_addr().add(file_line.get_offset()).add(file_line.get_size()) |
| 14 | + start = -1 |
| 15 | + while inst != None and inst.getAddress().getOffset() < addr_end.getOffset(): |
| 16 | + if inst.getNumOperands() <2 or len(inst.getOpObjects(1)) < 1: |
| 17 | + inst = inst.next |
| 18 | + continue |
| 19 | + |
| 20 | + if isinstance(inst.getOpObjects(1)[0], Scalar): |
| 21 | + arr = scalar_to_array(inst.getOpObjects(1)[0]) |
| 22 | + offset = 0 |
| 23 | + if inst.getOperandType(0) == 512: |
| 24 | + inst = inst.next |
| 25 | + if len(inst.getOpObjects(0)) < 2: |
| 26 | + offset = 0 |
| 27 | + else: |
| 28 | + offset = inst.getOpObjects(0)[1].getValue() |
| 29 | + else: |
| 30 | + if len(inst.getOpObjects(0)) < 2: |
| 31 | + offset = 0 |
| 32 | + else: |
| 33 | + offset = inst.getOpObjects(0)[1].getValue() |
| 34 | + if start == -1: |
| 35 | + start = offset |
| 36 | + value_list.append((arr, offset - start)) |
| 37 | + |
| 38 | + if "XMM" in inst.getOpObjects(0)[0].toString() and isinstance(inst.getOpObjects(1)[0], Address): |
| 39 | + arr = getBytes(inst.getOpObjects(1)[0], inst.getOpObjects(0)[0].getNumBytes()) |
| 40 | + inst = inst.next |
| 41 | + offset = inst.getOpObjects(0)[1].getValue() |
| 42 | + if start == -1: |
| 43 | + start = offset |
| 44 | + value_list.append((arr, offset - start)) |
| 45 | + inst = inst.next |
| 46 | + return value_list |
| 47 | + |
| 48 | +def scalar_to_array(scal): |
| 49 | + size = scal.bitLength()/8 |
| 50 | + buf = java.nio.ByteBuffer.allocate(8) |
| 51 | + arr = buf.putLong(scal.getValue()).array() |
| 52 | + arr = arr[8-size:] |
| 53 | + arr.reverse() |
| 54 | + return arr |
| 55 | + |
| 56 | +def resolve_func_name(addr, func_list): |
| 57 | + for f in func_list: |
| 58 | + if addr == f.get_func_addr(): |
| 59 | + return f.get_func_name() |
| 60 | + return "" |
| 61 | + |
| 62 | +def check_gobfus_str_func(gofunc, func_list): |
| 63 | + if ".func" not in gofunc.get_func_name(): |
| 64 | + return False |
| 65 | + inst = getInstructionAt(gofunc.get_func_addr()) |
| 66 | + addr_end = gofunc.get_func_addr().add(gofunc.get_func_size()) |
| 67 | + count = 0 |
| 68 | + slicebytetostring_count = 0 |
| 69 | + while inst != None and inst.getAddress().getOffset() < addr_end.getOffset(): |
| 70 | + if not inst.getFlowType().isCall(): |
| 71 | + inst = inst.next |
| 72 | + continue |
| 73 | + for addr in inst.getFlows(): |
| 74 | + func_name=resolve_func_name(addr, func_list) |
| 75 | + if func_name == "runtime.slicebytetostring": |
| 76 | + slicebytetostring_count += 1 |
| 77 | + elif func_name != "runtime.morestack_noctxt" and func_name != gofunc.get_func_name(): |
| 78 | + return False |
| 79 | + inst = inst.next |
| 80 | + return slicebytetostring_count == 1 |
| 81 | + |
| 82 | +def deobfuscate(arr1, arr2): |
| 83 | + ret = array.array("b", []) |
| 84 | + for i in range(len(arr1)): |
| 85 | + ret.append(arr1[i] ^ arr2[i]) |
| 86 | + return ret.tostring() |
| 87 | + |
| 88 | +def main(): |
| 89 | + consumer_list = currentProgram.getConsumerList() |
| 90 | + service = consumer_list[0].getService(gae.service.GolangAnalyzerExtensionService) |
| 91 | + func_list = service.get_function_list() |
| 92 | + for f in func_list: |
| 93 | + try: |
| 94 | + if not check_gobfus_str_func(f, func_list): |
| 95 | + continue |
| 96 | + |
| 97 | + keys = f.get_file_line_comment_map().keys() |
| 98 | + keys.sort() |
| 99 | + if len(keys) < 3: |
| 100 | + continue |
| 101 | + file_line1 = f.get_file_line_comment_map()[keys[1]] |
| 102 | + file_line2 = f.get_file_line_comment_map()[keys[2]] |
| 103 | + value1_list = get_obfus_str(file_line1) |
| 104 | + value2_list = get_obfus_str(file_line2) |
| 105 | + if len(value1_list) != len(value2_list): |
| 106 | + continue |
| 107 | + |
| 108 | + orig_str = "" |
| 109 | + for v in range(len(value1_list)): |
| 110 | + orig_str = orig_str[:value1_list[v][1]] + deobfuscate(value1_list[v][0], value2_list[v][0]) |
| 111 | + print("find: %s [%s]" % (f.get_func_addr(), orig_str)) |
| 112 | + rename_func = getFunctionAt(f.get_func_addr()) |
| 113 | + rename_func.setName("gobfus_" + re.sub("[^a-zA-Z0-9]", "_", orig_str.replace(" ", "_").replace("\n", "_").replace("\r", "_").replace("\x90", "_")) + "_" + rename_func.getName(), SourceType.USER_DEFINED) |
| 114 | + setPlateComment(f.get_func_addr(), "\"\"\"" + orig_str + "\"\"\"") |
| 115 | + except IndexError: |
| 116 | + pass |
| 117 | + |
| 118 | + |
| 119 | +if __name__ == "__main__": |
| 120 | + main() |
0 commit comments