Package IDAscope :: Package idascope :: Package core :: Module DocumentationHelper
[hide private]
[frames] | no frames]

Source Code for Module IDAscope.idascope.core.DocumentationHelper

  1  #!/usr/bin/python 
  2  ######################################################################## 
  3  # Copyright (c) 2012 
  4  # Daniel Plohmann <daniel.plohmann<at>gmail<dot>com> 
  5  # Alexander Hanel <alexander.hanel<at>gmail<dot>com> 
  6  # All rights reserved. 
  7  ######################################################################## 
  8  # 
  9  #  This file is part of IDAscope 
 10  # 
 11  #  IDAscope is free software: you can redistribute it and/or modify it 
 12  #  under the terms of the GNU General Public License as published by 
 13  #  the Free Software Foundation, either version 3 of the License, or 
 14  #  (at your option) any later version. 
 15  # 
 16  #  This program is distributed in the hope that it will be useful, but 
 17  #  WITHOUT ANY WARRANTY; without even the implied warranty of 
 18  #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 19  #  General Public License for more details. 
 20  # 
 21  #  You should have received a copy of the GNU General Public License 
 22  #  along with this program.  If not, see 
 23  #  <http://www.gnu.org/licenses/>. 
 24  # 
 25  ######################################################################## 
 26   
 27  import json 
 28   
 29  from IdaProxy import IdaProxy 
 30   
 31  import JsonHelper 
 32   
 33   
 34      ## 6 nice opposing colors as used in IDAscope standard config 
 35      ## 
 36      ## Red:      0xFF3333 - 0xFFB3B3 -> Registry 
 37      ## Violet:   0x7A24B4 - 0x9E7EB4 -> Execution 
 38      ## Blue:     0x2779C1 - 0x87A6C1 -> Network 
 39      ## Green:    0x32BD26 - 0x89BD84 -> Crypto 
 40      ## Yellow:   0xFFFF33 - 0xFFFFB3 -> Memory Manipulation 
 41      ## Orange:   0xFFA733 - 0xFFDFB3 -> Files 
 42      ## Notice: IDA uses BBGGRR 
 43   
 44   
45 -class DocumentationHelper():
46 """ 47 This class handles instruction coloring. 48 """ 49 50 # data layout of color maps 51 layout_color_map = {"tag": {"base_color": 0x112233, "highlight_color": 0x445566}} 52
53 - def __init__(self, config_filename):
54 print ("loading DocumentationHelper") 55 self.ida_proxy = IdaProxy() 56 # default colors are grey / light red / red 57 self.default_neutral_color = 0xCCCCCC 58 self.default_base_color = 0xB3B3FF 59 self.default_highlight_color = 0x3333FF 60 self.color_state = "unknown" 61 self.load_config(config_filename) 62 return
63
64 - def load_config(self, config_filename):
65 """ 66 Loads a semantic configuration file and generates a color map from the contained information. 67 @param config_filename: filename of a semantic configuration file 68 @type config_filename: str 69 """ 70 config_file = open(config_filename, "r") 71 config = config_file.read() 72 parsed_config = json.loads(config, object_hook=JsonHelper.decode_dict) 73 self.default_neutral_color = int(parsed_config["default_neutral_color"], 16) 74 self.default_base_color = int(parsed_config["default_base_color"], 16) 75 self.default_highlight_color = int(parsed_config["default_highlight_color"], 16) 76 self.color_map = self._generate_color_map_from_definitions(parsed_config["semantic_definitions"]) 77 return
78
79 - def _generate_color_map_from_definitions(self, definitions):
80 """ 81 Internal function to generate a color map from a semantic definitions config file. 82 @param definitions: the defintions part of a semantic definitions config file. 83 @type definitions: dict 84 @return: a dictionary of a color map, see I{layout_color_map} for a reference 85 """ 86 color_map = {} 87 for definition in definitions: 88 # convert text representation of color codes to numbers 89 color_map[definition["tag"]] = {"base_color": int(definition["base_color"], 16), \ 90 "highlight_color": int(definition["highlight_color"], 16)} 91 return color_map
92
93 - def uncolor_all(self):
94 """ 95 Uncolors all instructions of all segments by changing their color to white. 96 """ 97 for seg_ea in self.ida_proxy.Segments(): 98 for function_address in self.ida_proxy.Functions(self.ida_proxy.SegStart(seg_ea), \ 99 self.ida_proxy.SegEnd(seg_ea)): 100 for block in self.ida_proxy.FlowChart(self.ida_proxy.get_func(function_address)): 101 for head in self.ida_proxy.Heads(block.startEA, block.endEA): 102 self.color_instruction(head, 0xFFFFFF, refresh=False) 103 self.ida_proxy.refresh_idaview_anyway()
104
105 - def color_instruction(self, address, color, refresh=True):
106 """ 107 Colors the instruction at an address with the given color code. 108 @param address: address of the instruction to color 109 @type address: int 110 @param color: color-code to set for the instruction 111 @type color: int (0xBBGGRR) 112 @param refresh: refresh IDA view to ensure the color shows directly, can be omitted for performance. 113 @type refresh: boolean 114 """ 115 self.ida_proxy.SetColor(address, self.ida_proxy.CIC_ITEM, color) 116 if refresh: 117 self.ida_proxy.refresh_idaview_anyway()
118
119 - def color_basic_block(self, address, color, refresh=True):
120 """ 121 Colors the basic block containing a target address with the given color code. 122 @param address: address an instruction in the basic block to color 123 @type address: int 124 @param color: color-code to set for the instruction 125 @type color: int (0xBBGGRR) 126 @param refresh: refresh IDA view to ensure the color shows directly, can be omitted for performance. 127 @type refresh: boolean 128 """ 129 function_chart = self.ida_proxy.FlowChart(self.ida_proxy.get_func(address)) 130 for block in function_chart: 131 if block.startEA <= address < block.endEA: 132 for head in self.ida_proxy.Heads(block.startEA, block.endEA): 133 self.color_instruction(head, color, refresh)
134
135 - def get_next_color_scheme(self):
136 """ 137 get the next color scheme in the three-cycle "individual/mono/uncolored", where individual is semantic coloring 138 @return: next state 139 """ 140 if self.color_state == "individual": 141 return "mono" 142 elif self.color_state == "mono": 143 return "uncolored" 144 elif self.color_state == "uncolored": 145 return "individual" 146 else: 147 return "individual"
148
149 - def select_highlight_color(self, tag):
150 """ 151 automatically chooses the highlight color for a tag based on the current color scheme 152 @return: (int) a color code 153 """ 154 if self.get_next_color_scheme() == "uncolored": 155 return 0xFFFFFF 156 elif self.get_next_color_scheme() == "mono": 157 return self.default_highlight_color 158 else: 159 return self.color_map[tag]["highlight_color"]
160
161 - def select_base_color(self, tagged_addresses_in_block):
162 """ 163 automatically chooses the base color for a block based on the current color scheme 164 @param tagged_addresses_in_block: all tagged addresses in a basic block for which the color shall be chosen 165 @type tagged_addresses_in_block: a list of tuples (int, str) containing pairs of instruction addresses and tags 166 @return: (int) a color code 167 """ 168 if self.get_next_color_scheme() == "uncolored": 169 return 0xFFFFFF 170 elif self.get_next_color_scheme() == "mono": 171 return self.default_base_color 172 else: 173 tags_in_block = [item[1] for item in tagged_addresses_in_block] 174 colors_in_block = set([self.color_map[tags_in_block[index]]["base_color"] \ 175 for index in xrange(len(tags_in_block))]) 176 if len(colors_in_block) == 1: 177 return colors_in_block.pop() 178 else: 179 return self.default_neutral_color
180
181 - def colorize(self, scan_result):
182 """ 183 perform coloring on the IDB, based on a scan performed by SemanticIdentifier 184 @param scan_result: result of a scan as performed by SemanticIdentifier 185 @type scan_result: a dictionary with key/value entries of the following form: (address, [FunctionContext]) 186 """ 187 for function_address in scan_result.keys(): 188 tagged_addresses_in_function = scan_result[function_address].get_all_tagged_addresses() 189 function_chart = self.ida_proxy.FlowChart(self.ida_proxy.get_func(function_address)) 190 for basic_block in function_chart: 191 tagged_addresses_in_block = [(addr, tagged_addresses_in_function[addr]) for addr in \ 192 tagged_addresses_in_function.keys() if addr in xrange(basic_block.startEA, basic_block.endEA)] 193 if len(tagged_addresses_in_block) > 0: 194 base_color = self.select_base_color(tagged_addresses_in_block) 195 self.color_basic_block(basic_block.startEA, base_color, refresh=False) 196 for tagged_address in tagged_addresses_in_block: 197 highlight_color = self.select_highlight_color(tagged_address[1]) 198 self.color_instruction(tagged_address[0], highlight_color, refresh=False) 199 self.color_state = self.get_next_color_scheme() 200 self.ida_proxy.refresh_idaview_anyway()
201
202 - def get_next_non_func_instruction(self, addr):
203 next_instruction = addr 204 while next_instruction != self.ida_proxy.BAD_ADDR: 205 next_instruction = self.ida_proxy.find_not_func(next_instruction, self.ida_proxy.SEARCH_DOWN) 206 flags = self.ida_proxy.GetFlags(next_instruction) 207 if self.ida_proxy.isCode(flags): 208 return next_instruction 209 return self.ida_proxy.BAD_ADDR
210
212 # do a first run to define those areas that have a function prologue 213 next_instruction = self.ida_proxy.minEA() 214 while next_instruction != self.ida_proxy.BAD_ADDR: 215 next_instruction = self.get_next_non_func_instruction(next_instruction) 216 if self.ida_proxy.GetMnem(next_instruction).startswith("push") and \ 217 self.ida_proxy.GetOpType(next_instruction, 0) == 1 and \ 218 self.ida_proxy.GetOperandValue(next_instruction, 0) == 5: 219 instruction_after_push = self.get_next_non_func_instruction(next_instruction) 220 if self.ida_proxy.GetMnem(instruction_after_push).startswith("mov") and \ 221 self.ida_proxy.GetOpType(instruction_after_push, 0) == 1 and \ 222 self.ida_proxy.GetOperandValue(instruction_after_push, 0) == 5 and \ 223 self.ida_proxy.GetOpType(instruction_after_push, 1) == 1 and \ 224 self.ida_proxy.GetOperandValue(instruction_after_push, 1) == 4: 225 print("Fixed undefined code with function prologue (push ebp; mov ebp, esp) to function " \ 226 + "@ [%08x]" % (next_instruction)) 227 self.ida_proxy.MakeFunction(next_instruction) 228 # do a second run to define the rest 229 next_instruction = self.ida_proxy.minEA() 230 while next_instruction != self.ida_proxy.BAD_ADDR: 231 next_instruction = self.get_next_non_func_instruction(next_instruction) 232 print("Fixed undefined code to function @ [%08x]" % \ 233 (next_instruction)) 234 self.ida_proxy.MakeFunction(next_instruction) 235 return
236