Newer
Older
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
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
/*
* Copyright (c) 2013, 2014 - University of Virginia
*
* This file may be used and modified for non-commercial purposes as long as
* all copyright, permission, and nonwarranty notices are preserved.
* Redistribution is prohibited without prior written consent from the University
* of Virginia.
*
* Please contact the authors for restrictions applying to commercial use.
*
* THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Author: University of Virginia
* e-mail: jwd@virginia.com
* URL : http://www.cs.virginia.edu/
*
*/
#include "StackLayout.hpp"
#include <cassert>
#include <iostream>
#include "globals.h"
using namespace std;
StackLayout::StackLayout(const std::string &layout_name, const std::string &function_name, unsigned int frame_alloc_size,
unsigned int saved_regs_size, bool frame_pointer,unsigned int out_args_size)
{
assert(out_args_size <= frame_alloc_size);
this->layout_name = layout_name;
this->function_name = function_name;
this->frame_alloc_size = frame_alloc_size;
this->saved_regs_size = saved_regs_size;
this->has_frame_pointer = frame_pointer;
this->out_args_size = out_args_size;
has_out_args = out_args_size > 0;
is_canary_safe = true;
is_padding_safe = true;
//TODO: is static stack hacked in for TNE, needs a redesign
is_static_stack = true;//innocent 'til proven guilty.
is_recursive = false; //innocent 'til proven guilty
//The initial layout is one entry the size of the stack frame.
//The size is minus the out args size, if greater than 0
//an out args memory object is pushed below.
//The offset is following the out args region, if one exists.
PNRange frame;
frame.SetOffset((int)out_args_size);
frame.SetSize((int)frame_alloc_size-(int)out_args_size);
//If there are out args, then it is automatically pushed as a mem_objects
//starting at 0.
if(has_out_args)
{
if(out_args_size != frame_alloc_size)
{
PNRange out_args;
out_args.SetOffset(0);
out_args.SetSize((int)out_args_size);
mem_objects.push_back(out_args);
}
else
{
frame.SetOffset(0);
frame.SetSize((int)out_args_size);
}
}
//Push frame last to ensure the mem_objects vector is sorted
//by offset if there is an out args region
mem_objects.push_back(frame);
}
StackLayout::StackLayout(const StackLayout &layout)
{
this->layout_name = layout.layout_name;
this->function_name = layout.function_name;
this->frame_alloc_size = layout.frame_alloc_size;
this->saved_regs_size = layout.saved_regs_size;
this->out_args_size = layout.out_args_size;
this->has_frame_pointer = layout.has_frame_pointer;
has_out_args = layout.out_args_size > 0;
is_canary_safe = layout.is_canary_safe;
is_padding_safe = layout.is_padding_safe;
is_static_stack = layout.is_static_stack;
is_recursive = layout.is_recursive;
for(unsigned int i=0;i<layout.mem_objects.size();i++)
{
this->mem_objects.push_back(layout.mem_objects[i]);
}
}
void StackLayout::InsertESPOffset(int offset)
{
//No Negative offsets allowed
if(offset < 0)
{
cerr<<"StackLayout: InsertESPOffset(): Negative Offset Encountered, Ignoring Insert"<<endl;
//assert(false);
return;
}
if(verbose_log)
cerr<<"StackLayout: Attempting to insert offset "<<offset<<endl;
if(offset >= (int)frame_alloc_size)
{
//This can happen when an esp offset is accessing stored registers or function parameters
if(verbose_log)
cerr<<"StackLayout: InsertESPOffset(): Offset is larger than or equal to the allocated stack, Ignoring insert"<<endl;
return;
}
if(has_out_args)
{
//If there are out args, mem_objects[0] is assumed to be the out args region
//if the new offset being inserted is in this range, the offset is ignored.
//The out args region is not divided
if(offset < (int)mem_objects[0].getSize())
{
if(verbose_log)
cerr<<"StackLayout: InsertESPOffset(): Offset in out args region, Ignoring insert"<<endl;
return;
}
}
PNRange new_range;
new_range.SetOffset(offset);
int index = GetClosestIndex(offset);
if(index < 0)
{
//TODO: don't assert false, ignore, but for now I want to find when this happens
if(verbose_log)
cerr<<"StackLayout: InsertESPOffset(): Could not Find Range to Insert Into, Asserting False for Now"<<endl;
//TODO: throw exception or ignore?
assert(false);
}
//This should never happen, but just in case, assert false.
if(index > ((int)mem_objects.size())-1)
assert(false); //TODO: throw exception
if(verbose_log)
cerr<<"PNStackLayout: InsertESPOffset(): found offset = "<<
mem_objects[index].getOffset()<<endl;
//If offset is unique, insert it after the closest
//range (closest base address with out going over offset)
if(offset != mem_objects[index].getOffset())
{
if(index+1 == (int)mem_objects.size())
mem_objects.push_back(new_range);
else
mem_objects.insert(mem_objects.begin()+index+1,new_range);
}
//else no need to insert, the offset already exists
else
{
if(verbose_log)
cerr<<"StackLayout: InsertESPOffset(): Offset already exists, ignoring insert"<<endl;
return;
}
//The memory object that was divided has to have its size adjusted
//based on where the new memory object was inserted (its offset).
mem_objects[index].SetSize(mem_objects[index+1].getOffset()-mem_objects[index].getOffset());
//If the location of the newly inserted range is the end of the vector
//then the size will be the difference between the frame size and the
//offset of the new range
if((int)mem_objects.size() == index+2)
mem_objects[index+1].SetSize(((int)frame_alloc_size)-mem_objects[index+1].getOffset());
//Otherwise it is the difference between the next offset and the current offset
else
mem_objects[index+1].SetSize(mem_objects[index+2].getOffset()-mem_objects[index+1].getOffset());
if(verbose_log)
{
cerr<<"Stacklayout: Insert Successful, Post Insert Offsets"<<endl;
for(unsigned int i=0;i<mem_objects.size();i++)
{
cerr<<"\tOffset = "<<mem_objects[i].getOffset()<<endl;
}
}
}
void StackLayout::InsertEBPOffset(int offset)
{
//The size of the saved regs must be taken into consideration when transforming
//the EBP offset to an esp relative offset
if(verbose_log)
cerr<<"StackLayout: InsertEBPOffset(): Offset="<<offset<<" frame alloc size="<<frame_alloc_size<<" saved regs size="<<saved_regs_size<<endl;
int esp_conversion = EBPToESP(offset);//((int)frame_alloc_size+(int)saved_regs_size) - offset;
//It is possible to have ebp offsets that extend beyond the stack pointer. I haven't seen it
//but still. If this occurs, ignore the insert. We currently do not handle this case
if(esp_conversion >= 0)
InsertESPOffset(esp_conversion);
else
{
if(verbose_log)
cerr<<"PNStackLayout: InsertEBPOffset: Coverted EBP offset to negative ESP offset, ignoring insert"<<endl;
}
}
unsigned int StackLayout::GetClosestIndex(int loc) const
{
int high = ((int)mem_objects.size())-1;
int low = 0;
int mid;
while(low <= high)
{
mid = (low+high)/2;
if((loc < (mem_objects[mid].getOffset()+(int)mem_objects[mid].getSize())) && (loc >= mem_objects[mid].getOffset()))
return mid;
else if(loc > mem_objects[mid].getOffset())
low = mid +1;
else
high = mid -1;
}
return -1;
}
unsigned int StackLayout::GetAllocSize()
{
return frame_alloc_size;
}
unsigned int StackLayout::GetSavedRegsSize()
{
return saved_regs_size;
}
unsigned int StackLayout::getOutArgsRegionSize()
{
return out_args_size;
}
//TODO: maybe this should be an unsigned int, since I am assuming it is
//positive.
int StackLayout::EBPToESP(int offset)
{
return ((int)frame_alloc_size+(int)saved_regs_size) - offset;
}