import time import struct import socket HR = 80*'-' # Rename Flags: # 32 = SN_AUTO # 256 = SN_NOWARN # 2048 = SN_FORCE FLGS = 32+256+2048 # socket sa_family names SA_FAMILY_NAMES = [ 'AF_UNSPEC', 'AF_UNIX', 'AF_INET', 'AF_AX25', 'AF_IPX', 'AF_APPLETALK', 'AF_NETROM', 'AF_BRIDGE', 'AF_AAL5', 'AF_X25', 'AF_INET6', 'AF_MAX' ] # known api haseh from reference cobalt strike set KNOWN_API_NAMES = [ [0xc99cc96a,'dnsapi.dll_DnsQuery_A'], [0x528796c6,'kernel32.dll_CloseHandle'], [0xe27d6f28,'kernel32.dll_ConnectNamedPipe'], [0xd4df7045,'kernel32.dll_CreateNamedPipeA'], [0xfcddfac0,'kernel32.dll_DisconnectNamedPipe'], [0x56a2b5f0,'kernel32.dll_ExitProcess'], [0x5de2c5aa,'kernel32.dll_GetLastError'], [0x0726774c,'kernel32.dll_LoadLibraryA'], [0xcc8e00f4,'kernel32.dll_lstrlenA'], [0xe035f044,'kernel32.dll_Sleep'], [0xbb5f9ead,'kernel32.dll_ReadFile'], [0xe553a458,'kernel32.dll_VirtualAlloc'], [0x315e2145,'user32.dll_GetDesktopWindow'], [0x3b2e55eb,'wininet.dll_HttpOpenRequestA'], [0x7b18062d,'wininet.dll_HttpSendRequestA'], [0xc69f8957,'wininet.dll_InternetConnectA'], [0x0be057b7,'wininet.dll_InternetErrorDlg'], [0xa779563a,'wininet.dll_InternetOpenA'], [0xe2899612,'wininet.dll_InternetReadFile'], [0x869e4675,'wininet.dll_InternetSetOptionA'], [0xe13bec74,'ws2_32.dll_accept'], [0x6737dbc2,'ws2_32.dll_bind'], [0x614d6e75,'ws2_32.dll_closesocket'], [0x6174a599,'ws2_32.dll_connect'], [0xff38e9b7,'ws2_32.dll_listen'], [0x5fc8d902,'ws2_32.dll_recv'], [0xe0df0fea,'ws2_32.dll_WSASocketA'], [0x006b8029,'ws2_32.dll_WSAStartup'] ] # api block names X86_API_CALL_BLOCK_NAMES = [ [0x15,'next_mod'], [0x1E,'loop_mod_name'], [0x27,'not_lowercase'], [0x4A,'get_next_func'], [0x54,'loop_func_name'], [0x68,'finish'], [0x88,'get_next_mod_1'], [0x89,'get_next_mod_2'] ] X64_API_CALL_BLOCK_NAMES = [ [0x21,'next_mod'], [0x2D,'loop_mod_name'], [0x37,'not_lowercase'], [0x6E,'get_next_func'], [0x7D,'loop_func_name'], [0xB1,'finish'], [0xC6,'get_next_mod_1'], [0xC7,'get_next_mod_2'] ] # x86 payloads block names X86_DNS_BLOCK_NAMES = [ [0x8F,'alloc_space'], [0xAF,'load_dnsapi'], [0xCA,'process_dnsquery'], [0xD8,'dnsquery'], [0x10E,'dnsname_fix'], [0x10F,'dnsname_fix1'], [0x115,'dnsname_ok'], [0x145,'goto_process_query'], [0x18A,'dnsquery_next_try_or_exit'], [0x19E,'sleep_before_next_try'], [0x1B5,'get_query_result'], [0x1C5,'copy_piece_to_heap'], [0x1D9,'check_length'], [0x1F9,'prepare_payload'], [0x1FB,'jump_to_payload'] ] X86_SMB_BLOCK_NAMES = [ [0x8F,'alloc_space'], [0xAD,'process_pipe'], [0x102,'read_next_chunk'], [0x12B,'disconnect_pipe'], [0x14A,'call_exitprocess'], [0x151,'jump_to_payload'], [0x155,'goto_process_pipe'] ] X86_TCP_BIND_BLOCK_NAMES = [ [0x8F,'bind_tcp'], [0xD0,'try_connect'], [0xF9,'call_exitprocess'], [0x100,'recv'], [0x10F,'alloc_space'], [0x122,'read_more'], [0x143,'jump_to_payload'] ] X86_TCP_REVERSE_BLOCK_NAMES = [ [0x8F,'reverse_tcp'], [0xD0,'try_connect'], [0xE4,'call_exitprocess'], [0xEB,'recv'], [0xFA,'alloc_space'], [0x10D,'read_more'] ] X86_HTTP_BLOCK_NAMES = [ [0x8F,'load_wininet'], [0xA2,'call_internetopena'], [0xB5,'call_internetconnecta'], [0xCE,'call_httpopenrequesta'], [0xE9,'call_httpsendrequesta'], [0x10A,'check_error_1'], [0x113,'check_error_2'], [0x139,'goto_internetconnecta_1'], [0x13E,'goto_httpopenrequesta'], [0x2C3,'call_exitprocess'], [0x2CA,'alloc_space'], [0x2DE,'download_prep'], [0x2EA,'download_more'], [0x305,'jump_to_payload'], [0x307,'goto_internetconnecta_2'] ] X86_HTTPS_BLOCK_NAMES = [ [0x8F,'load_wininet'], [0xA2,'call_internetopena'], [0xBA,'call_internetconnecta'], [0xD2,'goto_httpopenrequesta_1'], [0xD7,'call_httpopenrequesta'], [0xED,'call_internetsetoptiona'], [0x107,'call_httpsendrequesta'], [0x128,'check_error_1'], [0x131,'check_error_2'], [0x157,'goto_alloc_space'], [0x15E,'goto_internetconnecta_1'], [0x163,'goto_httpopenrequesta_2'], [0x2E8,'call_exitprocess'], [0x2EF,'alloc_space'], [0x303,'download_prep'], [0x30F,'download_more'], [0x32A,'jump_to_payload'], [0x32C,'goto_internetconnecta_2'] ] # x64 payloads block names X64_TCP_BIND_BLOCK_NAMES = [ [0xD2,'bind_tcp'], [0x17E,'call_exitprocess'], [0x185,'recv'], [0x1A5,'alloc_space'], [0x1C4,'read_more'], [0x1E9,'jump_to_payload'] ] X64_TCP_REVERSE_BLOCK_NAMES = [ [0xD2,'reverse_tcp'], [0x151,'call_exitprocess'], [0x158,'recv'], [0x178,'alloc_space'], [0x197,'read_more'] ] X64_HTTP_BLOCK_NAMES = [ [0xD2,'load_wininet'], [0xEF,'call_internetopena'], [0x109,'call_internetconnecta'], [0x128,'call_httpopenrequesta'], [0x14F,'call_httpsendrequesta'], [0x17C,'goto_internetconnecta_1'], [0x181,'goto_httpopenrequesta'], [0x306,'call_exitprocess'], [0x30E,'alloc_space'], [0x32A,'download_prep'], [0x331,'download_more'], [0x35A,'jump_to_payload'], [0x365,'goto_internetconnecta_2'] ] X64_HTTPS_BLOCK_NAMES = [ [0xD2,'load_wininet'], [0xEF,'call_internetopena'], [0x10C,'call_internetconnecta'], [0x12B,'call_httpopenrequesta'], [0x152,'call_internetsetoptiona'], [0x157,'goto_alloc_space'], [0x172,'call_httpsendrequesta'], [0x19F,'goto_internetconnecta_1'], [0x1A4,'goto_httpopenrequesta'], [0x329,'call_exitprocess'], [0x331,'alloc_space'], [0x34D,'download_prep'], [0x354,'download_more'], [0x37D,'jump_to_payload'], [0x388,'goto_internetconnecta_2'] ] # find all sequences def find_all_seq(what): ret = [] ea = ida_ida.cvar.inf.min_ea while ea != ida_idaapi.BADADDR: ea = ida_search.find_binary(ea, ida_idaapi.BADADDR, what, 16, ida_search.SEARCH_DOWN | ida_search.SEARCH_CASE | ida_search.SEARCH_NEXT) if ea != ida_idaapi.BADADDR: ret.append(ea) return ret # find one sequence def find_seq(what): return ida_search.find_binary(ida_ida.cvar.inf.min_ea, ida_idaapi.BADADDR, what, 16, ida_search.SEARCH_DOWN) # check payload architecture def check_arch(): pattern_x86 = 'FC E8 89 00 00 00 60 89' pattern_x64 = 'FC 48 83 E4 F0 E8 C8 00' is_x86 = find_seq(pattern_x86) if is_x86 != ida_idaapi.BADADDR: return ['x86', is_x86] is_x64 = find_seq(pattern_x64) if is_x64 != ida_idaapi.BADADDR: return ['x64', is_x64] # unknown return ['unknown', -1] # check payload type by api hash def check_payload_type(): pattern_types = [ # x86 ['6A C9 9C C9 FF D5', 'DNS'], ['45 70 DF D4 FF D5', 'SMB'], ['C2 DB 37 67 FF D5', 'TCP_BIND'], ['99 A5 74 61 FF D5', 'TCP_REVERSE'], ['75 46 9E 86 FF D5', 'HTTPS'], ['3A 56 79 A7 FF D5', 'HTTP'], ] for pattern in pattern_types: offset = find_seq(pattern[0]) if offset != ida_idaapi.BADADDR: return pattern[1] return 'unknown' # add comment def add_comment(ea,cmt): ida_bytes.set_cmt(ea,cmt,1) # create api hashes enum def enum_create(name): idx = ida_enum.get_enum(name) if idx == ida_idaapi.BADADDR: idx = ida_enum.add_enum(ida_idaapi.BADADDR, name, ida_bytes.hex_flag()) for crc in KNOWN_API_NAMES: enum_add_member(idx,crc[1],crc[0]) return idx else: return idx # add member to enum def enum_add_member(idx,name,value): ida_enum.add_enum_member(idx,name,value,ida_idaapi.BADADDR) # apply enum def enum_apply(arch,idx,ea): if arch == 'x86': return ida_bytes.op_enum(ea, 0, idx, 0) #PUSH value elif arch == 'x64': return ida_bytes.op_enum(ea, 1, idx, 0) #MOV r, value else: print('Error: Unknown arch..') return -1 # find offset for api hashes def find_offsets(arch): pattern_hash = '' if arch == 'x86': pattern_hash = '68 ?? ?? ?? ?? FF D5' elif arch == 'x64': pattern_hash = '41 ?? ?? ?? ?? ?? FF D5' else: print('Error: Unknown arch..') return -1 return find_all_seq(pattern_hash) # find api hashes and print api table def find_api_hashes(arch,idx,start_offset): size = 0 if arch == 'x86': size = 1 elif arch == 'x64': size = 2 else: print('Error: Unknown arch..') return -1 offsets = find_offsets(arch) hit = False print(HR) print('Offset\tHash value\t\tAPI name') for offset in offsets: api_hash = idaapi.get_dword(offset+size) for i in range(len(KNOWN_API_NAMES)): if KNOWN_API_NAMES[i][0] == api_hash: hit = True print('%s\t%s\t\t%s' % (hex(offset), hex(api_hash), KNOWN_API_NAMES[i][1])) enum_apply(arch,idx,offset) if not hit: print('[!] unknown hash', hex(api_hash), hex(offset)) else: hit = False # exitprocess fix on x64 payloads.. # tcp reverse if arch == 'x64' and ida_bytes.get_dword(start_offset+0x151) == 0xA2B5F068: print('%s\t%s\t\t%s' % (hex(start_offset+0x151), '0x56a2b5f0', 'kernel32.dll_ExitProcess')) enum_apply('x86',idx,start_offset+0x151) # tcp bind if arch == 'x64' and ida_bytes.get_dword(start_offset+0x17E) == 0xA2B5F068: print('%s\t%s\t\t%s' % (hex(start_offset+0x17E), '0x56a2b5f0', 'kernel32.dll_ExitProcess')) enum_apply('x86',idx,start_offset+0x17E) print(HR) # apply predefined function names def add_func_names(start_offset, func_array): for func in func_array: ida_name.set_name(start_offset+func[0],func[1],FLGS) # check and print watermark / customer id def check_watermark(arch, p_type, start_offset): ea_max = ida_ida.cvar.inf.max_ea p_size = 0x1000 if arch == 'x86': if p_type == 'DNS': p_size = start_offset+0x203 if p_type == 'SMB': p_size = start_offset+0x15A + ida_bytes.get_item_size(start_offset+0x15A) if p_type == 'TCP_BIND': p_size = start_offset+0x14B + ida_bytes.get_item_size(start_offset+0x14B) if p_type == 'TCP_REVERSE': p_size = start_offset+0x122 + ida_bytes.get_item_size(start_offset+0x122) if p_type == 'HTTP': p_size = start_offset+0x30C + ida_bytes.get_item_size(start_offset+0x30C) if p_type == 'HTTPS': p_size = start_offset+0x331 + ida_bytes.get_item_size(start_offset+0x331) if arch == 'x64': if p_type == 'TCP_BIND': p_size = start_offset+0x1FE + ida_bytes.get_item_size(start_offset+0x1FE) if p_type == 'TCP_REVERSE': p_size = start_offset+0x1D1 + ida_bytes.get_item_size(start_offset+0x1D1) if p_type == 'HTTP': p_size = start_offset+0x36A + ida_bytes.get_item_size(start_offset+0x36A) if p_type == 'HTTPS': p_size = start_offset+0x38D + ida_bytes.get_item_size(start_offset+0x38D) if ea_max > p_size: ida_name.set_name(p_size,'watermark',FLGS) ida_bytes.create_byte(p_size, ea_max-p_size) wb = ida_bytes.get_bytes(p_size, ea_max-p_size) wf = '\\x'.join(format(x, '02x') for x in wb) print('watermark:\t\t\\x' + wf) else: print('watermark:\t\tnot found') # set FUNC_NORET flags def set_noret_flag(ea): func = ida_funcs.get_func(ea) if not func: print('0x%x get_func error!' % ea) return 0 else: func.flags = 0x1 #FUNC_NORET ida_funcs.update_func(func) return 1 def payload_analysis(): # check x86 / x64 arch, start_offset = check_arch() if start_offset == -1: print('Payload not found..') return 0 # check payload type payload_type = check_payload_type() if payload_type == 'unknown': print('Unknown payload type..') return 0 # check execution environments architecture # https://www.programcreek.com/python/example/85151/idaapi.get_inf_structure env = idaapi.dbg_get_registers() if env[17][0] == 'RAX' and arch == 'x86': print('This is x86 payload, please load it with IDA 32-bit version.') return 0 if env[17][0] == 'EAX' and arch == 'x64': print('This is x64 payload, please load it with IDA 64-bit version.') return 0 print(HR) print('Start offset:\t0x%x' % start_offset) print('Architecture:\t%s' % arch) print('Payload type:\t%s' % payload_type) print(HR) # create enums idx = enum_create('Cobalt_Strike') # undefine all ida_bytes.del_items(start_offset,FF_UNK,0x1000) # add 'start' entry on 0x0 ida_entry.add_entry(0,start_offset,'payload_start',1) # make code and wait for result idaapi.auto_wait() # x86 if arch == 'x86': # set end of payload_start function ida_funcs.set_func_end(start_offset, start_offset+0x6) # set api_call function ida_funcs.add_func(start_offset+0x6,ida_idaapi.BADADDR) ida_name.set_name(start_offset+0x6,'api_call',FLGS) # rename local names in api_call function add_func_names(start_offset, X86_API_CALL_BLOCK_NAMES) add_comment(start_offset+ 0x86,'Jump into the required function') if payload_type == 'DNS': add_func_names(start_offset, X86_DNS_BLOCK_NAMES) # set FUNC_NORET flag to process_dnsquery function set_noret_flag(start_offset+0xCA) # comment DnsQuery_A parameters dns_record_type = ida_bytes.get_byte(start_offset+0x12C) dns_query_options = struct.unpack('H', ida_bytes.get_bytes(start_offset+0xCC,2,1))[0] # print values print('sin_addr:\t\t%s' % ip) print('sin_port:\t\t%s' % port) print('sa_family:\t\t%s' % sa_family) # apply predefined function names if payload_type == 'TCP_BIND': add_func_names(start_offset,X86_TCP_BIND_BLOCK_NAMES) else: add_func_names(start_offset,X86_TCP_REVERSE_BLOCK_NAMES) # add comments add_comment(start_offset+0xC4, 'sin_ip: '+ip) add_comment(start_offset+0xC9,'sin_port: '+port+'\nsa_family: '+sa_family) # check watermark check_watermark(arch,payload_type,start_offset) if payload_type == 'HTTP': # set FUNC_NORET flags set_noret_flag(start_offset+0x8F) set_noret_flag(start_offset+0xB5) set_noret_flag(start_offset+0xCE) set_noret_flag(start_offset+0xE9) # fix config blog data ida_bytes.del_items(start_offset+0x143,DELIT_SIMPLE|DELIT_EXPAND|DELIT_DELNAMES,0x17F) idaapi.auto_wait() idc.create_insn(start_offset+0x2c3) # create url_query string ida_bytes.create_strlit(start_offset+0x143,0,ida_nalt.STRTYPE_TERMCHR) ida_name.set_name(start_offset+0x143,'request_query',FLGS) q_size = ida_bytes.get_item_size(start_offset+0x143) for i in range(0x50-q_size+1): ida_bytes.create_byte(start_offset+0x143+q_size,i) idaapi.auto_wait() # create request headerer string ida_bytes.create_strlit(start_offset+0x193,0,ida_nalt.STRTYPE_TERMCHR) ida_name.set_name(start_offset+0x193,'request_header',FLGS) u_size = ida_bytes.get_item_size(start_offset+0x193) for i in range(0x12F-u_size+1): ida_bytes.create_byte(start_offset+0x193+u_size,i) idaapi.auto_wait() # fix http_c2 and watermark blob ida_funcs.set_func_end(start_offset+0x307, start_offset+0x30C) ida_bytes.del_items(start_offset+0x30C,DELIT_SIMPLE|DELIT_EXPAND|DELIT_DELNAMES,0x100) idaapi.auto_wait() # create http_c2 string ida_bytes.create_strlit(start_offset+0x30C,0,ida_nalt.STRTYPE_TERMCHR) ida_name.set_name(start_offset+0x30C,'request_addr',FLGS) h_size = ida_bytes.get_item_size(start_offset+0x30C) # get port value from InternetConnectA API port = ida_bytes.get_dword(start_offset+0xBF) add_comment(start_offset+0xBE, 'port: '+str(port)) # apply predefined function names add_func_names(start_offset,X86_HTTP_BLOCK_NAMES) # print full c2 url and user-agent strings http_c2 = ida_bytes.get_strlit_contents(start_offset+0x30C,h_size,ida_nalt.STRTYPE_TERMCHR) url_query = ida_bytes.get_strlit_contents(start_offset+0x143,q_size,ida_nalt.STRTYPE_TERMCHR) request_header = ida_bytes.get_strlit_contents(start_offset+0x193,u_size,ida_nalt.STRTYPE_TERMCHR).decode('utf-8').strip().split('\r\n') print('request_addr:\t%s' % http_c2.decode('UTF-8')) print('request_query:\t%s' % url_query.decode('UTF-8')) print('request_port:\t%i' % port) hdrs = '' for h in request_header: if h != '': hdrs += '\t%s\n\t' % h print('request_header:%s' % hdrs[:-2]) print(HR) print('full c2 ulr: \thttp://%s:%i%s' % (http_c2.decode('UTF-8'), port, url_query.decode('UTF-8'))) print(HR) # check watermark check_watermark(arch,payload_type,start_offset) if payload_type == 'HTTPS': # set FUNC_NORET flags set_noret_flag(start_offset+0x8F) set_noret_flag(start_offset+0xBA) set_noret_flag(start_offset+0xD7) # fix config blog data ida_funcs.set_func_end(start_offset+0x163, start_offset+0x168) idaapi.auto_wait() ida_bytes.del_items(start_offset+0x168,DELIT_SIMPLE|DELIT_EXPAND|DELIT_DELNAMES,0x17F) idaapi.auto_wait() ida_ua.create_insn(start_offset+0x2E8) if ida_funcs.get_func(start_offset+0x2E8) == None: ida_funcs.add_func(start_offset+0x2E8) set_noret_flag(start_offset+0x2E8) # create url_query string ida_bytes.create_strlit(start_offset+0x168,0,ida_nalt.STRTYPE_TERMCHR) ida_name.set_name(start_offset+0x168,'request_query',FLGS) q_size = ida_bytes.get_item_size(start_offset+0x168) for i in range(0x50-q_size+1): ida_bytes.create_byte(start_offset+0x168+q_size,i) idaapi.auto_wait() # create request headerer string ida_bytes.create_strlit(start_offset+0x1B8,0,ida_nalt.STRTYPE_TERMCHR) ida_name.set_name(start_offset+0x1B8,'request_header',FLGS) u_size = ida_bytes.get_item_size(start_offset+0x1B8) for i in range(0x12F-u_size+1): ida_bytes.create_byte(start_offset+0x1B8+u_size,i) idaapi.auto_wait() # fix http_c2 and watermark blob ida_funcs.set_func_end(start_offset+0x32C, start_offset+0x331) ida_bytes.del_items(start_offset+0x331,DELIT_SIMPLE|DELIT_EXPAND|DELIT_DELNAMES,0x100) idaapi.auto_wait() # create http_c2 string ida_bytes.create_strlit(start_offset+0x331,0,ida_nalt.STRTYPE_TERMCHR) ida_name.set_name(start_offset+0x331,'request_addr',FLGS) h_size = ida_bytes.get_item_size(start_offset+0x331) # get port value from InternetConnectA API port = ida_bytes.get_dword(start_offset+0xC4) add_comment(start_offset+0xC3, 'port: '+str(port)) # apply predefined function names add_func_names(start_offset,X86_HTTPS_BLOCK_NAMES) # print full c2 url and user-agent strings http_c2 = ida_bytes.get_strlit_contents(start_offset+0x331,h_size,ida_nalt.STRTYPE_TERMCHR) url_query = ida_bytes.get_strlit_contents(start_offset+0x168,q_size,ida_nalt.STRTYPE_TERMCHR) request_header = ida_bytes.get_strlit_contents(start_offset+0x1B8,u_size,ida_nalt.STRTYPE_TERMCHR).decode('utf-8').strip().split('\r\n') print('request_addr:\t%s' % http_c2.decode('UTF-8')) print('request_query:\t%s' % url_query.decode('UTF-8')) print('request_port:\t%i' % port) hdrs = '' for h in request_header: if h != '': hdrs += '\t%s\n\t' % h print('request_header:%s' % hdrs[:-2]) print(HR) print('full c2 ulr: \thttps://%s:%i%s' % (http_c2.decode('UTF-8'), port, url_query.decode('UTF-8'))) print(HR) # check watermark check_watermark(arch,payload_type,start_offset) # x64 if arch == 'x64': # set end of payload_start function ida_funcs.set_func_end(start_offset+0x0, start_offset+0xA) # set api_call function ida_funcs.add_func(start_offset+0xA,ida_idaapi.BADADDR) ida_name.set_name(start_offset+0xA,'api_call',FLGS) # rename local names in api_call function add_func_names(start_offset, X64_API_CALL_BLOCK_NAMES) add_comment(start_offset+0xC4,'Jump into the required function') if payload_type == 'TCP_BIND' or payload_type == 'TCP_REVERSE': # parse IP ip = '%d.%d.%d.%d' % struct.unpack('BBBB', ida_bytes.get_bytes(start_offset+0xF2,4,1)) # parse sa_family sa_family_value = ida_bytes.get_word(start_offset+0xEE) try: sa_family = SA_FAMILY_NAMES[sa_family_value] except KeyError: sa_family = 'unknown' # parse port port = '%i' % struct.unpack('>H', ida_bytes.get_bytes(start_offset+0xF0,2,1))[0] # print values print('sin_addr:\t\t%s' % ip) print('sin_port:\t\t%s' % port) print('sa_family:\t\t%s' % sa_family) # apply predefined function names if payload_type == 'TCP_BIND': add_func_names(start_offset,X64_TCP_BIND_BLOCK_NAMES) else: add_func_names(start_offset,X64_TCP_REVERSE_BLOCK_NAMES) # add comments add_comment(start_offset+0xEC, 'sin_ip: '+ip+'\nsin_port: '+port+'\nsa_family: '+sa_family) # check watermark check_watermark(arch,payload_type,start_offset) if payload_type == 'HTTP': # set end of payload_start function ida_funcs.set_func_end(start_offset+0x0, start_offset+0xA) # set api_call function ida_funcs.add_func(start_offset+0xA,ida_idaapi.BADADDR) ida_name.set_name(start_offset+0xA,'api_call',FLGS) # rename local names in api_call function add_func_names(start_offset, X64_API_CALL_BLOCK_NAMES) add_comment(start_offset+0xC4,'Jump into the required function') # fix config blog data ida_bytes.del_items(start_offset+0x186,DELIT_SIMPLE|DELIT_EXPAND|DELIT_DELNAMES,0x180) idaapi.auto_wait() # create url_query string ida_bytes.create_strlit(start_offset+0x186,0,ida_nalt.STRTYPE_TERMCHR) ida_name.set_name(start_offset+0x186,'request_query',FLGS) q_size = ida_bytes.get_item_size(start_offset+0x186) for i in range(0x50-q_size+1): ida_bytes.create_byte(start_offset+0x186+q_size,i) idaapi.auto_wait() # create request headerer string ida_bytes.create_strlit(start_offset+0x1D6,0,ida_nalt.STRTYPE_TERMCHR) ida_name.set_name(start_offset+0x1D6,'request_header',FLGS) u_size = ida_bytes.get_item_size(0x1D6) for i in range(start_offset+0x12F-u_size+1): ida_bytes.create_byte(start_offset+0x1D6+u_size,i) idaapi.auto_wait() # fix http_c2 and watermark blob ida_funcs.set_func_end(start_offset+0x365, start_offset+0x36A) idaapi.auto_wait() ida_bytes.del_items(start_offset+0x36A,DELIT_SIMPLE|DELIT_EXPAND|DELIT_DELNAMES,0x100) idaapi.auto_wait() # create http_c2 string ida_bytes.create_strlit(start_offset+0x36A,0,ida_nalt.STRTYPE_TERMCHR) ida_name.set_name(start_offset+0x36A,'request_addr',FLGS) h_size = ida_bytes.get_item_size(start_offset+0x36A) # get port value from InternetConnectA API port = ida_bytes.get_dword(0x10F) add_comment(start_offset+0x10D, 'port: '+str(port)) # apply predefined function names add_func_names(start_offset,X64_HTTP_BLOCK_NAMES) # print full c2 url and user-agent strings http_c2 = ida_bytes.get_strlit_contents(start_offset+0x36A,h_size,ida_nalt.STRTYPE_TERMCHR) url_query = ida_bytes.get_strlit_contents(start_offset+0x186,q_size,ida_nalt.STRTYPE_TERMCHR) request_header = ida_bytes.get_strlit_contents(start_offset+0x1D6,u_size,ida_nalt.STRTYPE_TERMCHR).decode('utf-8').strip().split('\r\n') print('request_addr:\t%s' % http_c2.decode('UTF-8')) print('request_query:\t%s' % url_query.decode('UTF-8')) print('request_port:\t%i' % port) hdrs = '' for h in request_header: if h != '': hdrs += '\t%s\n\t' % h print('request_header:%s' % hdrs[:-2]) print(HR) print('full c2 ulr: \thttp://%s:%i%s' % (http_c2.decode('UTF-8'), port, url_query.decode('UTF-8'))) print(HR) # check watermark check_watermark(arch,payload_type,start_offset) if payload_type == 'HTTPS': # set end of payload_start function ida_funcs.set_func_end(start_offset+0x0, start_offset+0xA) # set api_call function ida_funcs.add_func(start_offset+0xA,ida_idaapi.BADADDR) ida_name.set_name(start_offset+0xA,'api_call',FLGS) # rename local names in api_call function add_func_names(start_offset, X64_API_CALL_BLOCK_NAMES) add_comment(start_offset+0xC4,'Jump into the required function') # fix config blog data ida_bytes.del_items(start_offset+0x1A9,DELIT_SIMPLE|DELIT_EXPAND|DELIT_DELNAMES,0x17F) idaapi.auto_wait() # create url_query string ida_bytes.create_strlit(start_offset+0x1A9,0,ida_nalt.STRTYPE_TERMCHR) ida_name.set_name(start_offset+0x1A9,'request_query',FLGS) q_size = ida_bytes.get_item_size(start_offset+0x1A9) for i in range(0x50-q_size+1): ida_bytes.create_byte(start_offset+0x1A9+q_size,i) idaapi.auto_wait() # create request headerer string ida_bytes.create_strlit(start_offset+0x1F9,0,ida_nalt.STRTYPE_TERMCHR) ida_name.set_name(start_offset+0x1F9,'request_header',FLGS) u_size = ida_bytes.get_item_size(start_offset+0x1F9) for i in range(0x12F-u_size+1): ida_bytes.create_byte(start_offset+0x1F9+u_size,i) idaapi.auto_wait() # fix http_c2 and watermark blob ida_funcs.set_func_end(start_offset+0x388, start_offset+0x38D) idaapi.auto_wait() ida_bytes.del_items(start_offset+0x38D,DELIT_SIMPLE|DELIT_EXPAND|DELIT_DELNAMES,0x100) idaapi.auto_wait() # create http_c2 string ida_bytes.create_strlit(start_offset+0x38D,0,ida_nalt.STRTYPE_TERMCHR) ida_name.set_name(start_offset+0x38D,'request_addr',FLGS) h_size = ida_bytes.get_item_size(start_offset+0x38D) # get port value from InternetConnectA API port = ida_bytes.get_dword(start_offset+0x112) add_comment(start_offset+0x110, 'port: '+str(port)) # apply predefined function names add_func_names(start_offset,X64_HTTPS_BLOCK_NAMES) # print full c2 url and user-agent strings http_c2 = ida_bytes.get_strlit_contents(start_offset+0x38D,h_size,ida_nalt.STRTYPE_TERMCHR) url_query = ida_bytes.get_strlit_contents(start_offset+0x1A9,q_size,ida_nalt.STRTYPE_TERMCHR) request_header = ida_bytes.get_strlit_contents(start_offset+0x1F9,u_size,ida_nalt.STRTYPE_TERMCHR).decode('utf-8').strip().split('\r\n') print('request_addr:\t%s' % http_c2.decode('UTF-8')) print('request_query:\t%s' % url_query.decode('UTF-8')) print('request_port:\t%i' % port) hdrs = '' for h in request_header: if h != '': hdrs += '\t%s\n\t' % h print('request_header:%s' % hdrs[:-2]) print(HR) print('full c2 ulr: \thttps://%s:%i%s' % (http_c2.decode('UTF-8'), port, url_query.decode('UTF-8'))) print(HR) # check watermark check_watermark(arch,payload_type,start_offset) find_api_hashes(arch,idx,start_offset) return 1 if __name__ == '__main__': payload_analysis()