def find_unusual_xors(functions):
# TODO find xors in tight loops
candidate_functions = []
for fva in functions:
cva = fva
while cva != idaapi.BADADDR and cva < idc.FindFuncEnd(fva):
if idc.GetMnem(cva) == "xor":
if idc.GetOpnd(cva, 0) != idc.GetOpnd(cva, 1):
g_logger.debug("suspicious XOR instruction at 0x%08X in function 0x%08X: %s", cva, fva,
idc.GetDisasm(cva))
ph = idc.PrevHead(cva)
nh = idc.NextHead(cva)
ip = idc.GetDisasm(ph)
ia = idc.GetDisasm(nh)
if ip and ia:
g_logger.debug("Instructions: %s; %s; %s", ip, idc.GetDisasm(cva), ia)
if ph or nh:
if is_security_cookie(cva, ph, nh):
g_logger.debug("XOR related to security cookie: %s", idc.GetDisasm(cva))
else:
g_logger.debug("unusual XOR: %s", idc.GetDisasm(cva))
candidate_functions.append(fva)
break
cva = idc.NextHead(cva)
return candidate_functions
python类GetOpnd()的实例源码
def find_suspicous_movs(functions):
candidate_functions = []
regs = ["esp", "ebp", "rsp", "rbp"]
for fva in functions:
for (loopStart, loopEnd) in find_tight_loops(fva):
cva = loopStart
while cva <= loopEnd:
if idc.GetMnem(cva) == "mov":
if is_list_item_in_s(regs, idc.GetOpnd(cva, 0)):
cva = idc.NextHead(cva)
continue
# identify register dereferenced writes to memory, e.g. mov [eax], cl
if idc.GetOpType(cva, 0) == OP_TYPE.BASE_INDEX.value:
if idc.GetOpType(cva, 1) not in [OP_TYPE.IMMEDIATE.value, OP_TYPE.IMMEDIATE_FAR.value,
OP_TYPE.IMMEDIATE_NEAR.value]:
g_logger.debug("suspicious MOV instruction at 0x%08X in function 0x%08X: %s", cva, fva,
idc.GetDisasm(cva))
candidate_functions.append(fva)
break
cva = idc.NextHead(cva)
return candidate_functions
def color_head(ea):
flags = idc.GetFlags(ea)
if not idc.isCode(flags):
return
mnem = idc.GetMnem(ea)
if mnem == 'call':
logger.debug('call: 0x%x', ea)
idc.SetColor(ea, idc.CIC_ITEM, CALL_COLOR)
elif mnem == 'xor':
if idc.GetOpnd(ea, 0) != idc.GetOpnd(ea, 1):
logger.debug('non-zero xor: 0x%x', ea)
idc.SetColor(ea, idc.CIC_ITEM, ENCRYPT_COLOR)
elif mnem in ('sdit', 'sgdt', 'sldt', 'smsw', 'str', 'in', 'cpuid'):
logger.debug('anti-vm: 0x%x', ea)
idc.SetColor(ea, idc.CIC_ITEM, ANTIANALYSIS_COLOR)
elif mnem == 'in':
if idc.GetOpnd(ea, 0) in ("3", "2D"):
logger.debug('anti-debug: 0x%x', ea)
idc.SetColor(ea, idc.CIC_ITEM, ANTIANALYSIS_COLOR)
elif mnem in ('rdtsc', 'icebp'):
logger.debug('anti-debug: 0x%x', ea)
idc.SetColor(ea, idc.CIC_ITEM, ANTIANALYSIS_COLOR)
def revise_syscall(rename=False):
if not rename:
print('Change the function name with `CGCHeler.revise_syscall(True)`.')
# visit all instructions
start_ea, end_ea = utils.get_seg_range('.text')
eax = -1
ip = start_ea
while ip < end_ea and ip != idaapi.BADADDR:
if 'int' in idc.GetMnem(ip) and '80h' == idc.GetOpnd(ip, 0):
if eax != -1:
# fix comment and function name
print('{}: {}'.format(hex(ip), syscall_table[eax]))
idc.MakeComm(ip, 'CGC syscall: {}'.format(syscall_table[eax]))
if rename:
print('Change {} to {}'.format(idc.GetFunctionName(ip), syscall_table[eax]))
idc.MakeName(idc.GetFunctionAttr(ip, idc.FUNCATTR_START), syscall_table[eax])
elif 'mov' in idc.GetMnem(ip) and 'eax' == idc.GetOpnd(ip, 0) and 5 == idc.GetOpType(ip, 1):
value = idc.GetOpnd(ip, 1)
if re.search('^[0-9]+$', value) != None:
eax = int(value)
if eax > 7 or eax < 1:
eax = -1
ip = idc.NextHead(ip)
def create_call_map(self, ftype):
assert_ida_available()
import idc
import idautils
seg_mapping = {idc.SegName(x): (idc.SegStart(x), idc.SegEnd(x)) for x in idautils.Segments()}
imports = seg_mapping[".idata"] if ftype == PE else seg_mapping['.plt']
start, stop = seg_mapping[".text"]
current = start
while current <= stop:
inst = current
if idc.GetMnem(inst) in ["call", "jmp"]:
value = idc.GetOperandValue(inst, 0)
name = idc.GetOpnd(inst, 0)
if imports[0] <= value <= imports[1]:
entry = self.config.call_map.add()
entry.address = inst
entry.name = name
current = idc.NextHead(current, stop)
def get_call_name(head):
instruction_type = GetInstructionType(head)
if instruction_type == CALL_INSTRUCTION:
opnd = idc.GetOpnd(head, 0)
if opnd not in registers:
opnd = opnd.replace("ds:","")
return opnd
else:
opnd = idc.GetDisasm(head)
opnd = opnd[opnd.find(";") + 1:]
opnd = opnd.replace(" ", "")
if opnd != None:
return opnd
return None
def highlight_non_zero_xor(self, ea):
highlight_eas = []
if self.get_mnem(ea) == "xor":
if idc.GetOpnd(ea, 0) != idc.GetOpnd(ea, 1):
ph = idc.PrevHead(ea)
nh = idc.NextHead(ea)
ip = idc.GetDisasm(ph)
ia = idc.GetDisasm(nh)
if ph or nh:
if not self.is_security_cookie(ea, ph, nh):
highlight_eas.append(ea)
MySetColor(ea, self.color)
return highlight_eas
def is_security_cookie(self, va, ph, nh):
# for security cookie check the xor should use ESP or EBP
if idc.GetOpnd(va, 1) not in ["esp", "ebp", "rsp", "rbp"]:
return False
if "security" in idc.GetOpnd(ph, 1):
return True
elif "security" in idc.GetDisasm(nh):
return True
elif "security" in idc.GetDisasm(idc.NextHead(nh)):
return True
return False
def is_security_cookie(va, ph, nh):
# for security cookie check the xor should use ESP or EBP
if idc.GetOpnd(va, 1) not in ["esp", "ebp", "rsp", "rbp"]:
return False
if "security" in idc.GetOpnd(ph, 1):
return True
elif "security" in idc.GetDisasm(nh):
return True
elif "security" in idc.GetDisasm(idc.NextHead(nh)):
return True
return False
def getDispatchCode(ea):
# get dispatch code out of an instruction
first, second = (idc.GetOpnd(ea, 0), idc.GetOperandValue(ea, 1))
if first == 'eax':
return second
raise ValueError("Search resulted in address %08x, but instruction '%s' does fulfill requested constraints"% (ea, idc.GetMnem(ea)))
def FindLastAssignment(ea, register):
start,end = database.guessrange(ea)
while ea > start:
ea = database.prev(ea)
m = idc.GetMnem(ea)
r = idc.GetOpnd(ea, 0)
if m == 'mov' and r == register:
return ea
continue
raise ValueError('FindLastAssignment(0x%x, %s) Found no matches'% (ea, register))
def get_args(addr):
""" Retreives the passed arguments to the decryption function. We are only interested in the key
and offset to the encrypted string.
addr: (int) Address at which the decryption function was called.
Returns:
key: (int) The key used to decrypt the string.
enc_str: (list) Byte array of encrypted string.
ins_addr: (int) Address at which the encrypted byte array is referenced.
"""
found = False
foundstr = False
foundkey = False
while not found:
addr = idc.PrevHead(addr)
if idc.GetMnem(addr) == "mov" and "r8d" in idc.GetOpnd(addr,0):
#print "[+] Found key: 0x%08x at 0x%016x" % (idc.GetOperandValue(addr,1)& 0xffffffff, addr)
key = idc.GetOperandValue(addr,1) & 0xffffffff
foundkey = True
if idc.GetMnem(addr) == "lea" and "rdx" in idc.GetOpnd(addr,0):
#print "[+] Found str: 0x%016x at 0x%016x" % (idc.GetOperandValue(addr,1), addr)
enc_str_addr = idc.GetOperandValue(addr,1)
enc_str = get_encoded_string(enc_str_addr)
ins_addr = addr
foundstr = True
if foundkey and foundstr:
found = True
return key, enc_str, ins_addr
def main():
base_addr = 0
ea = 0
idc.MakeFunction(ea)
# heuristic
while(true):
mnemonic = idc.GetMnem(ea)
if "LDR" in mnemonic:
base_str = idc.GetOpnd(ea, 1)
base_addr = int(base_str.split("=")[1], 16)
break
ea += 4
print("[+] rebasing to address 0x%x" % (base_addr))
idc.rebase_program(base_addr, idc.MSF_FIXONCE)
idaapi.autoWait()
segment_start = base_addr
segment_end = idc.GetSegmentAttr(segment_start, idc.SEGATTR_END)
ea = segment_start
print("[+] searching and defining functions")
while ea != idc.BADADDR:
ea = idc.FindBinary(ea, idc.SEARCH_DOWN, "BF A9", 16)
if ea != idc.BADADDR:
ea = ea - 2
if (ea % 4) == 0 and idc.GetFlags(ea) < 0x200:
# print("[+] defining a function at 0x%x" % (ea))
idc.MakeFunction(ea)
ea = ea + 4
idc.AnalyzeArea(segment_start, segment_end)
idaapi.autoWait()
def def_functions(s_start):
num_added_functions = 0
s_addr = s_start
s_end = idc.GetSegmentAttr(s_start, SEGATTR_END) #idc.SegEnd(segm)
print "0x%08x 0x%08x" % (s_start, s_end)
while (s_addr < s_end):
print "Testing address 0x%08x" % s_addr
#optimization assumes that function chunks are consecutive (no "function-in-function" monkey business)
if (idaapi.get_func(s_addr)):
next_func = idc.NextFunction(s_addr)
ea = s_addr
for c in idautils.Chunks(s_addr):
#only use chunks in lookahead that do not jump over the next function and that are not smaller than where we are atm.
if (c[1] > ea) and (c[1] <= next_func):
ea = c[1]
if ea == s_addr:
s_addr += 2
else:
s_addr = ea
#s_addr += 4
continue
else:
#This is not a good optimization, there WILL be data refs to function start addresses sometimes.
'''
if sum(1 for _ in (CodeRefsTo(s_addr, 1))) != 0:
s_addr += 4
continue
'''
#also add STMFD
if ((idc.GetMnem(s_addr) == "STM") and ("SP!" in idc.GetOpnd(s_addr, 0)) and ("LR" in idc.GetOpnd(s_addr, 1))) or (((idc.GetMnem(s_addr) == "PUSH") or (idc.GetMnem(s_addr) == "PUSH.W") or (idc.GetMnem(s_addr) == "STR.W") ) and ("LR" in idc.GetOpnd(s_addr, 0))):
print "Found function at 0x%08x" % s_addr
idc.MakeFunction(s_addr)
f = idaapi.get_func(s_addr)
if (type(f) == type(None)):
print "Failed to create function! Undefined instructions?"
s_addr += 2
else:
num_added_functions += 1
ea = -1
for c in idautils.Chunks(s_addr):
if c[1] > ea:
ea = c[1]
if ea != -1:
s_addr = ea
#failed?
else:
s_addr += 2
else:
s_addr += 2
print "finished segment"
return num_added_functions