├── example ├── README.md └── test ├── README.md └── IDA_MIPS_EMU.py /example/README.md: -------------------------------------------------------------------------------- 1 | ## calc example 2 | -------------------------------------------------------------------------------- /example/test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/H4lo/IDA_MIPS_EMU/HEAD/example/test -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## IDA_MIPS_EMU 2 | 3 | a IDA plugin, use for emulating mips code and patch function/code in IDA pro. 4 | 5 | ### Install 6 | 7 | ``` 8 | sudo pip install unicorn --user 9 | ``` 10 | 11 | ### Usage 12 | 13 | - begin emulating: 14 | ``` 15 | a = EmuMips() 16 | a.configEmu(0x400000,0x401000,[1,2,3]) # set startaddr,endaddr and paramters 17 | 18 | a.beginEmu() 19 | a.showRegs() 20 | ``` 21 | 22 | - fill data 23 | 24 | fill data into addr 0x401000 25 | ``` 26 | a.fillData("test123",0x401000) 27 | 28 | Python>a.fillData("MTIzNDUK",0xbfffe000) 29 | [*] Data mapping address: 0xbfffe000 30 | ``` 31 | 32 | - read content from memory address 33 | 34 | ``` 35 | a.readMemContent(0x10008000,[size]) 36 | 37 | Python>a.readMemContent(0xbfffe000,50) 38 | [*] Dest memory content: MTIzNDUK 39 | ``` 40 | 41 | - show registers content 42 | 43 | ``` 44 | a.showRegs() 45 | 46 | Python>a.showRegs() 47 | [*] regs: 48 | [*] A0 = 0xbfffe000 A1 = 0x8 A2 = 0xbffff000 49 | SP = 0xbfff8000 RA = 0x0 FP = 0x0 50 | ``` 51 | 52 | - show hook info 53 | 54 | ``` 55 | a.showTrace() 56 | 57 | >>> Tracing instruction at 0x4435a4, instruction size = 0x4 58 | >>> Tracing instruction at 0x4435a8, instruction size = 0x4 59 | >>> Tracing instruction at 0x4435ac, instruction size = 0x4 60 | >>> Tracing instruction at 0x4435b0, instruction size = 0x4 61 | >>> Tracing instruction at 0x4435b4, instruction size = 0x4 62 | ... 63 | ``` 64 | 65 | ### Example 66 | 67 | 68 | - source code 69 | 70 | ``` 71 | #include 72 | 73 | int calc(int a,int b){ 74 | int sum; 75 | sum = a+b; 76 | return sum; 77 | 78 | } 79 | 80 | int main(){ 81 | cala(2,3); 82 | } 83 | ``` 84 | 85 | - calc function 86 | 87 | ``` 88 | .text:00400640 .globl calc 89 | .text:00400640 calc: # CODE XREF: main+18↓p 90 | .text:00400640 91 | .text:00400640 var_10 = -0x10 92 | .text:00400640 var_4 = -4 93 | .text:00400640 arg_0 = 0 94 | .text:00400640 arg_4 = 4 95 | .text:00400640 96 | .text:00400640 addiu $sp, -0x18 97 | .text:00400644 sw $fp, 0x18+var_4($sp) 98 | .text:00400648 move $fp, $sp 99 | .text:0040064C sw $a0, 0x18+arg_0($fp) 100 | .text:00400650 sw $a1, 0x18+arg_4($fp) 101 | .text:00400654 lw $v1, 0x18+arg_0($fp) 102 | .text:00400658 lw $v0, 0x18+arg_4($fp) 103 | .text:0040065C addu $v0, $v1, $v0 104 | .text:00400660 sw $v0, 0x18+var_10($fp) 105 | .text:00400664 lw $v0, 0x18+var_10($fp) 106 | .text:00400668 move $sp, $fp 107 | .text:0040066C lw $fp, 0x18+var_4($sp) 108 | .text:00400670 addiu $sp, 0x18 109 | .text:00400674 jr $ra 110 | .text:00400678 nop 111 | .text:00400678 # End of function calc 112 | ``` 113 | 114 | #### IDA emu 115 | 116 | 117 | 1. Create a emu object 118 | 119 | ``` 120 | Python>a = EmuMips() 121 | 122 | ``` 123 | 124 | 2. Configure address and registers 125 | 126 | ``` 127 | Python>a.configEmu(0x00400640,0x00400678,[2,3]) 128 | [*] Init registers success... 129 | [*] Init code and data segment success! 130 | [*] Init Stack success... 131 | [*] set args... 132 | ``` 133 | 134 | 135 | 3. Show registers info 136 | 137 | ``` 138 | Python>a.showRegs() 139 | [*] regs: 140 | [*] A0 = 0x2 A1 = 0x3 A2 = 0x0 141 | SP = 0xbfff8000 RA = 0x0 FP = 0x0 V0 = 0x0 142 | ``` 143 | 144 | 4. Start emulate 145 | 146 | ``` 147 | Python>a.beginEmu() 148 | [*] emulating... 149 | 150 | [*] Done! Emulate result return: 0x5 151 | ``` 152 | 153 | 5. print result 154 | 155 | ``` 156 | Python>a.showRegs() 157 | [*] regs: 158 | [*] A0 = 0x2 A1 = 0x3 A2 = 0x0 159 | SP = 0xbfff8000 RA = 0x0 FP = 0x0 V0 = 0x5 160 | ``` 161 | 162 | - 2+3 = 5, the result stored in v0 register 163 | 164 | ### other functions 165 | 166 | 1. set register value 167 | 168 | ``` 169 | setRegValue("a0",1) 170 | ``` 171 | 172 | 2. map new memory 173 | 174 | - default mapping 0x1000 space 175 | 176 | ``` 177 | mapNewMemory(0x1000) 178 | ``` 179 | -------------------------------------------------------------------------------- /IDA_MIPS_EMU.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # __Author__: H4lo 3 | from __future__ import print_function 4 | from unicorn import * 5 | from unicorn.mips_const import * 6 | from idaapi import * 7 | 8 | CODE_ADDR = None 9 | CODE_SIZE = 0x100000 10 | 11 | STACK_ADDR = 0xbfff0000 12 | STACK_SIZE = 0x10000 13 | 14 | DATA_ADDR = 0x10000000 15 | DATA_SIZE = 0x10000 16 | 17 | 18 | 19 | class EmuMips(object): 20 | def __init__(self): 21 | 22 | self.stack = STACK_ADDR 23 | self.stack_size = STACK_SIZE 24 | #self.start 25 | self.regs = dict() 26 | self.uc = None 27 | self.DEBUG_INFO = "" 28 | self.startAddr = None 29 | self.endAddr = None 30 | print("[+] Init...") 31 | 32 | def getTextSegmentSize(self): 33 | ''' 34 | for seg in idautils.Segments(): 35 | if idc.SegName(seg) == ".text": 36 | return(idc.SegEnd(seg)-get_imagebase()) 37 | ''' 38 | mapSize = (get_inf_structure().get_maxEA() - get_inf_structure().get_minEA()) 39 | return mapSize 40 | 41 | 42 | def initCodeAndData(self): 43 | CODE_ADDR = get_imagebase() # set CODE_ADDR equal with image base 44 | code_bytes = GetManyBytes(CODE_ADDR,self.getTextSegmentSize()) # default mapping 0x10000 space 45 | self.uc.mem_map(CODE_ADDR,CODE_SIZE) 46 | self.uc.mem_write(CODE_ADDR,code_bytes) 47 | 48 | self.uc.mem_map(DATA_ADDR,DATA_SIZE) 49 | 50 | self.printInfo("Init code and data segment success! ") 51 | 52 | def initRegs(self): 53 | 54 | self.regs['a0'] = UC_MIPS_REG_A0 55 | 56 | #reg_read(UC_MIPS_REG_A0) 57 | self.regs['a1'] = UC_MIPS_REG_A1 58 | self.regs['a2'] = UC_MIPS_REG_A2 59 | self.regs['sp'] = UC_MIPS_REG_SP 60 | self.regs['ra'] = UC_MIPS_REG_RA 61 | self.regs['fp'] = UC_MIPS_REG_FP 62 | self.regs['v0'] = UC_MIPS_REG_V0 63 | 64 | for reg_k,reg_v in self.regs.items(): 65 | self.uc.reg_write(reg_v,0) # init registers 66 | 67 | #self.uc.reg_write(self.regs['a2'],0x4f1390) 68 | 69 | self.printInfo("Init registers success...") 70 | 71 | 72 | def initStack(self): 73 | self.uc.mem_map(STACK_ADDR,STACK_SIZE) # map and set stack space 74 | self.uc.reg_write(self.regs['sp'],STACK_ADDR+STACK_SIZE-0x800) 75 | self.uc.reg_write(self.regs['fp'],STACK_ADDR+STACK_SIZE-0x800) 76 | 77 | self.printInfo("Init Stack success...") 78 | 79 | def showRegs(self): # handle call 80 | regs_list = [] 81 | self.printInfo(" regs: ") 82 | #print(self.regs) 83 | for reg_k,reg_v in self.regs.items(): 84 | #print(reg_k) 85 | regs_list.append(self.uc.reg_read(reg_v)) 86 | self.printInfo(" A0 = 0x%x A1 = 0x%x A2 = 0x%x\n SP = 0x%x RA = 0x%x FP = 0x%x V0 = 0x%x\n"% ( 87 | regs_list[4],regs_list[3],regs_list[5],regs_list[2],regs_list[6],regs_list[0],regs_list[1])) 88 | 89 | def readMemContent(self,address,size=100): 90 | content = self.uc.mem_read(address,size) 91 | self.printInfo("Dest memory content: %s" % (content)) 92 | 93 | 94 | def printInfo(self,info): 95 | print("[*] {inf}".format(inf=info)) 96 | 97 | def showTrace(self): 98 | print(self.DEBUG_INFO) 99 | 100 | def fillData(self,data,addr = DATA_ADDR+DATA_SIZE/2): # handle call 101 | default_map_addr = DATA_ADDR+DATA_SIZE/2 102 | if ((data != None) and (addr == DATA_ADDR+DATA_SIZE/2)): 103 | self.uc.mem_write(default_map_addr,data) 104 | self.printInfo("Data mapping address: 0x%x"% (default_map_addr)) 105 | if (addr != DATA_ADDR+DATA_SIZE/2): 106 | self.uc.mem_write(addr,data) 107 | self.printInfo("Data mapping address: 0x%x"% (addr)) 108 | #print(1) 109 | 110 | def setRegValue(self,reg_name,value): 111 | self.uc.reg_write(self.regs[reg_name],value) 112 | self.printInfo("Write register success!") 113 | 114 | def mapNewMemory(self,mem_addr,size=0x1000): 115 | self.uc.mem_map(mem_addr,size) 116 | self.uc.mem_write(mem_addr,"\x00"*size) 117 | self.printInfo("Map memory success!") 118 | 119 | def hook_code(self,uc, address, size, user_data): 120 | self.DEBUG_INFO += ">>> Tracing instruction at 0x%x, instruction size = 0x%x\n" %(address, size) 121 | #print("AAAA") 122 | 123 | def getArchFromIDA(self): # get arch and endian information from IDA, api: idaapi.get_inf_structure() 124 | return UC_ARCH_MIPS 125 | 126 | def getModeFromIDA(self): 127 | #return UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN 128 | if get_inf_structure().is_be(): # executable file is big endian 129 | return UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN 130 | else: 131 | return UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN 132 | 133 | def parseParams(self,args): 134 | try: 135 | self.printInfo("set args...") 136 | 137 | self.uc.reg_write(self.regs['a0'],args[0]) 138 | 139 | self.uc.reg_write(self.regs['a1'],args[1]) 140 | self.uc.reg_write(self.regs['a2'],args[2]) 141 | except Exception as e: 142 | pass 143 | 144 | def configEmu(self,startAddr,endAddr,args=[]): 145 | arch = self.getArchFromIDA() 146 | mode = self.getModeFromIDA() 147 | 148 | self.uc = Uc(arch,mode) 149 | self.initRegs() 150 | self.initCodeAndData() 151 | self.initStack() 152 | 153 | self.uc.hook_add(UC_HOOK_CODE,self.hook_code) 154 | 155 | self.startAddr = startAddr 156 | self.endAddr = endAddr 157 | 158 | self.parseParams(args) 159 | #self.beginEmu(startAddr,endAddr) 160 | 161 | def beginEmu(self): 162 | startAddr = self.startAddr 163 | endAddr = self.endAddr 164 | self.printInfo("emulating...\n") 165 | try: 166 | self.uc.emu_start(startAddr,endAddr) 167 | 168 | emu_result = self.uc.reg_read(self.regs['v0']) # result value 169 | 170 | self.printInfo("Done! Emulate result return: 0x%x" % (emu_result)) 171 | except UcError as e: 172 | self.printInfo("ERROR: {e}".format(e=e)) 173 | 174 | def patchFunc(self,callFuncAddr_list): # patch fucntions to `nop` 175 | for callFuncAddr in callFuncAddr_list: 176 | self.uc.mem_write(callFuncAddr,"\x00\x00\x00\x00") 177 | 178 | self.printInfo("Patch function success! ") 179 | 180 | 181 | def fuzzFunc(self,data): 182 | print(1) 183 | 184 | banner = ''' 185 | $$$$$$\$$$$$$$\ $$$$$$\ $$\ $$\$$$$$$\$$$$$$$\ $$$$$$\ $$$$$$$$\$$\ $$\$$\ $$\ 186 | \_$$ _$$ __$$\$$ __$$\ $$$\ $$$ \_$$ _$$ __$$\$$ __$$\ $$ _____$$$\ $$$ $$ | $$ | 187 | $$ | $$ | $$ $$ / $$ | $$$$\ $$$$ | $$ | $$ | $$ $$ / \__| $$ | $$$$\ $$$$ $$ | $$ | 188 | $$ | $$ | $$ $$$$$$$$ | $$\$$\$$ $$ | $$ | $$$$$$$ \$$$$$$\ $$$$$\ $$\$$\$$ $$ $$ | $$ | 189 | $$ | $$ | $$ $$ __$$ | $$ \$$$ $$ | $$ | $$ ____/ \____$$\ $$ __| $$ \$$$ $$ $$ | $$ | 190 | $$ | $$ | $$ $$ | $$ | $$ |\$ /$$ | $$ | $$ | $$\ $$ | $$ | $$ |\$ /$$ $$ | $$ | 191 | $$$$$$\$$$$$$$ $$ | $$ | $$ | \_/ $$ $$$$$$\$$ | \$$$$$$ | $$$$$$$$\$$ | \_/ $$ \$$$$$$ | 192 | \______\_______/\__| \__$$$$$$\__| \__\______\__| \______$$$$$$\________\__| \__|\______/ 193 | \______| \______| 194 | 195 | ''' 196 | print("="*0x68) 197 | print(banner) 198 | print("="*0x68) 199 | #a = EmuMips() 200 | #a.configEmu(0x1000,0x2000) 201 | --------------------------------------------------------------------------------