-
Notifications
You must be signed in to change notification settings - Fork 4
/
FunctionGraph.cpp
235 lines (211 loc) · 9.49 KB
/
FunctionGraph.cpp
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
#include "FunctionGraph.h"
#include <list>
#include <set>
#include <stdio.h>
struct previous_edge_struct_s
{
ULONG_PTR source;
ULONG_PTR targetfalse;
ULONG_PTR targettrue;
};
#define TEXTLEN 256
static char vcg_params[] = "manhattan_edges: yes\n"
"layoutalgorithm: mindepth\n"
"finetuning: no\n"
"layout_downfactor: 100\n"
"layout_upfactor: 0\n"
"layout_nearfactor: 0\n"
"xlspace: 12\n"
"yspace: 30\n"
"colorentry 32: 0 0 0\n"
"colorentry 33: 0 0 255\n"
"colorentry 34: 0 0 255\n"
"colorentry 35: 128 128 128\n"
"colorentry 36: 128 128 128\n"
"colorentry 37: 0 0 128\n"
"colorentry 38: 0 0 128\n"
"colorentry 39: 0 0 255\n"
"colorentry 40: 0 0 255\n"
"colorentry 41: 0 0 128\n"
"colorentry 42: 0 128 0\n"
"colorentry 43: 0 255 0\n"
"colorentry 44: 0 128 0\n"
"colorentry 45: 255 128 0\n"
"colorentry 46: 0 128 0\n"
"colorentry 47: 128 128 255\n"
"colorentry 48: 255 0 0\n"
"colorentry 49: 128 128 0\n"
"colorentry 50: 1 1 1\n"
"colorentry 51: 192 192 192\n"
"colorentry 52: 0 0 255\n"
"colorentry 53: 0 0 255\n"
"colorentry 54: 0 0 255\n"
"colorentry 55: 128 128 128\n"
"colorentry 56: 128 128 255\n"
"colorentry 57: 0 128 0\n"
"colorentry 58: 0 0 128\n"
"colorentry 59: 0 0 255\n"
"colorentry 60: 128 0 128\n"
"colorentry 61: 0 128 0\n"
"colorentry 62: 0 128 0\n"
"colorentry 63: 0 128 64\n"
"colorentry 64: 0 0 128\n"
"colorentry 65: 0 0 128\n"
"colorentry 66: 255 0 255\n"
"colorentry 67: 128 128 0\n"
"colorentry 68: 0 0 128\n"
"colorentry 69: 0 0 255\n"
"colorentry 70: 0 0 128\n"
"colorentry 71: 0 0 255\n"
"colorentry 72: 0 0 0\n"
"colorentry 73: 255 255 255\n"
"colorentry 74: 192 187 175\n"
"colorentry 75: 0 255 255\n"
"colorentry 76: 0 0 0\n"
"colorentry 77: 128 0 0\n"
"colorentry 78: 128 128 128\n"
"colorentry 79: 128 128 0\n"
"colorentry 80: 255 0 255\n"
"colorentry 81: 0 0 0\n"
"colorentry 82: 0 0 255\n"
"colorentry 83: 100 255 255\n";
//escape comments
static void sanitize(const char* comment, char* cleaned)
{
char* t;
for(t = cleaned; *comment; comment++)
{
if(*comment == '"')
{
*t++ = '\\';
*t = '"';
}
else if(*comment == '\\')
{
*t++ = '\\';
*t = '\\';
}
else
{
*t = *comment;
}
t++;
}
*t = '\0';
}
bool make_flowchart(ULONG_PTR start, ULONG_PTR end, const wchar_t* szTargetFile, GETINSTRINFO getInstrInfo)
{
HANDLE temp_file = CreateFileW(szTargetFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if(temp_file == INVALID_HANDLE_VALUE)
return false;
char buffer[TEXTLEN * 2 + 4];
ULONG_PTR currentnode = start;
int writelen = sprintf(buffer, "graph: {\ntitle: \"Graph of %p\"\n", start);
DWORD len_written;
WriteFile(temp_file, buffer, (DWORD) writelen, &len_written, NULL);
WriteFile(temp_file, vcg_params, (DWORD) strlen(vcg_params), &len_written, NULL);
writelen = sprintf(buffer, "node: { title: \"%p\" vertical_order: 0 color: 83 fontname: \"courR12\" label: \"%p:", currentnode, currentnode);
WriteFile(temp_file, buffer, (DWORD) writelen, &len_written, NULL);
std::set<ULONG_PTR> nodelist; //list of node addresses, just to make sure we are not handling nodes multiple times
std::list<instr_info> disasmlist;
ULONG_PTR psize = 0;
ULONG_PTR current_addr = start;
// first pass - disassemble instructions and enumerate nodes
do
{
current_addr += psize;
//get instr_info
instr_info disasm_result;
ULONG_PTR next_addr = getInstrInfo(current_addr, &disasm_result);
psize = next_addr - current_addr;
if(psize <= 0)
psize = 1;
//add instr_info to list
disasmlist.push_back(disasm_result);
// enumerate nodes
if(currentnode == 0)
{
currentnode = current_addr;
nodelist.insert(currentnode);
}
if((disasm_result.jmpaddr >= start) && (disasm_result.jmpaddr < end))
{
// this is a jump - start of an edge and pointer to a node
nodelist.insert(disasm_result.jmpaddr);
currentnode = 0; // update current_addrnode on next pass
}
}
while(current_addr + psize <= end);
// walk through saved disasm list and split into nodes
currentnode = start;
bool orphannode = true;
previous_edge_struct_s previous_edge;
memset(&previous_edge, 0, sizeof(previous_edge_struct_s));
std::string edgelist;
for(std::list<instr_info>::iterator i = disasmlist.begin(); i != disasmlist.end(); ++i)
{
instr_info disasm_result = *i;
current_addr = disasm_result.addr;
//node contents (address)
if(nodelist.find(current_addr) != nodelist.end()) //found current_addr in set
{
if(orphannode)
{
writelen = sprintf(buffer, "edge: { sourcename: \"%p\" targetname: \"%p\" }\n", currentnode, current_addr);
edgelist += buffer;
}
orphannode = true;
currentnode = current_addr;
writelen = sprintf(buffer, "\" }\n");
WriteFile(temp_file, buffer, (DWORD) writelen, &len_written, NULL);
writelen = sprintf(buffer, "node: { title: \"%p\" color: 83 fontname: \"courR12\" label: \"%p:", current_addr, current_addr);
WriteFile(temp_file, buffer, (DWORD) writelen, &len_written, NULL);
}
//node contents (disassembly)
if(disasm_result.comment.length())
{
char clean_comment[TEXTLEN * 2];
sanitize(disasm_result.comment.c_str(), clean_comment);
writelen = sprintf(buffer, "\n%s\t; %s", disasm_result.instrText.c_str(), clean_comment);
}
else
{
writelen = sprintf(buffer, "\n%s", disasm_result.instrText.c_str());
}
WriteFile(temp_file, buffer, (DWORD)writelen, &len_written, NULL);
if(previous_edge.source != 0)
{
// append stored edge info with currentnode info to edgelist buffer
previous_edge.targetfalse = currentnode;
writelen = sprintf(buffer, "edge: { sourcename: \"%p\" targetname: \"%p\" label: \"false\" color: red }\n", previous_edge.source, previous_edge.targetfalse);
edgelist += buffer;
writelen = sprintf(buffer, "edge: { sourcename: \"%p\" targetname: \"%p\" label: \"true\" color: darkgreen }\n", previous_edge.source, previous_edge.targettrue);
edgelist += buffer;
previous_edge.source = 0;
}
if((disasm_result.jmpaddr >= start) && (disasm_result.jmpaddr < end))
{
// this is a jump - start of an edge and pointer to a node
orphannode = false;
previous_edge.source = currentnode;
previous_edge.targettrue = disasm_result.jmpaddr;
previous_edge.targetfalse = 0;
if(!_stricmp(disasm_result.instrText.substr(0, 3).c_str(), "jmp"))
{
// straight jmp, no true/false
writelen = sprintf(buffer, "edge: { sourcename: \"%p\" targetname: \"%p\" }\n", previous_edge.source, previous_edge.targettrue);
edgelist += buffer;
previous_edge.source = 0;
}
}
}
// close last node
writelen = sprintf(buffer, "\" vertical_order: %d }\n", nodelist.size());
WriteFile(temp_file, buffer, (DWORD)writelen, &len_written, NULL);
// write edgelist
WriteFile(temp_file, edgelist.c_str(), (DWORD)edgelist.length(), &len_written, NULL);
writelen = sprintf(buffer, "}\n");
WriteFile(temp_file, buffer, (DWORD)writelen, &len_written, NULL);
CloseHandle(temp_file);
return true;
}