| 1 | + | import idc |
| 2 | + | import idaapi |
| 3 | + | import idautils |
| 4 | + | |
| 5 | + | #Simple function to fix strings in current function |
| 6 | + | #Mostly based on "Tim 'diff' Strazzere" ideas |
| 7 | + | |
| 8 | + | def parseOp(operand): |
| 9 | + | if operand.type == idaapi.o_displ or operand.type == idaapi.o_phrase: |
| 10 | + | if operand.reg == 4: #esp/rsp |
| 11 | + | return True, operand.addr |
| 12 | + | return False, 0 |
| 13 | + | |
| 14 | + | def convert_operand(operand, size, num, pos): |
| 15 | + | if operand.type == idaapi.o_displ or operand.type == idaapi.o_phrase: |
| 16 | + | if operand.reg == 4: #esp/rsp |
| 17 | + | if operand.addr < size: |
| 18 | + | idc.OpHex(pos, num) |
| 19 | + | |
| 20 | + | #Well for now I don't know how determine ptr size ;[ |
| 21 | + | def is_this_a_real_string(next_pos, instr, size_data): |
| 22 | + | #Common scenario is when we mov offset into register |
| 23 | + | #and after that either fill local string variable or push string as argument |
| 24 | + | #so we just check that we use esp |
| 25 | + | next_instr = idautils.DecodeInstruction(next_pos) |
| 26 | + | if next_instr.get_canon_mnem() == "mov": |
| 27 | + | is_stack_used, ptr_addr = parseOp(next_instr.Op1) |
| 28 | + | if is_stack_used is True: |
| 29 | + | #Check if we really place our offset |
| 30 | + | if next_instr.Op2.type == idaapi.o_reg and next_instr.Op2.reg == instr.Op1.reg: |
| 31 | + | next_pos += next_instr.size |
| 32 | + | next_instr = idautils.DecodeInstruction(next_pos) |
| 33 | + | if next_instr.get_canon_mnem() == "mov": |
| 34 | + | is_stack_used, size_addr = parseOp(next_instr.Op1) |
| 35 | + | #if we filling string or at least smthng looking very similar |
| 36 | + | if is_stack_used is True and (size_addr - ptr_addr == size_data): |
| 37 | + | #for now explicitly set 0x1000 as max string size |
| 38 | + | if next_instr.Op2.type == idaapi.o_imm and next_instr.Op2.value < 0x1000: |
| 39 | + | return True, next_instr.Op2.value |
| 40 | + | return False, 0 |
| 41 | + | |
| 42 | + | def make_string(addr, siz): |
| 43 | + | print "Creating string at %x %d size" % (addr, siz) |
| 44 | + | idc.MakeUnknown(addr, siz, idc.DOUNK_SIMPLE) |
| 45 | + | idc.MakeStr(addr, addr+siz) |
| 46 | + | |
| 47 | + | def get_bitness_bytes(addr): |
| 48 | + | if idc.GetSegmentAttr(addr, idc.SEGATTR_BITNESS) == 2: |
| 49 | + | return 8 |
| 50 | + | return 4 |
| 51 | + | |
| 52 | + | def stringify(): |
| 53 | + | ea = idc.here() |
| 54 | + | size_data = get_bitness_bytes(ea) |
| 55 | + | f = idaapi.get_func(ea) |
| 56 | + | frsize = idc.GetFrameLvarSize(ea) |
| 57 | + | position = f.startEA |
| 58 | + | size = 0 |
| 59 | + | while position < f.endEA: |
| 60 | + | instr = idautils.DecodeInstruction(position) |
| 61 | + | if instr is None: |
| 62 | + | print "%x: Not and instruction found" % position |
| 63 | + | break |
| 64 | + | mnem = instr.get_canon_mnem() |
| 65 | + | if mnem == "mov": |
| 66 | + | if instr.Op2.type == idaapi.o_imm and instr.Op1.type == idaapi.o_reg: #this may be string load |
| 67 | + | is_string, size_s = is_this_a_real_string(position + instr.size, instr, size_data) |
| 68 | + | if is_string is True: |
| 69 | + | make_string(instr.Op2.value, size_s) |
| 70 | + | elif mnem == "lea": |
| 71 | + | if instr.Op2.type == idaapi.o_mem and instr.Op1.type == idaapi.o_reg: |
| 72 | + | is_string, size_s = is_this_a_real_string(position + instr.size, instr, size_data) |
| 73 | + | if is_string is True: |
| 74 | + | make_string(instr.Op2.addr, size_s) |
| 75 | + | position += instr.size |
| 76 | + | |