1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 import json
28
29 from IdaProxy import IdaProxy
30
31 import JsonHelper
32
33
34
35
36
37
38
39
40
41
42
43
44
46 """
47 This class handles instruction coloring.
48 """
49
50
51 layout_color_map = {"tag": {"base_color": 0x112233, "highlight_color": 0x445566}}
52
54 print ("loading DocumentationHelper")
55 self.ida_proxy = IdaProxy()
56
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
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
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
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
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
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
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
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
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
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
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
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
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
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