HyperDbg Debugger
Loading...
Searching...
No Matches
callstack.cpp File Reference

Callstack related routines. More...

#include "pch.h"

Functions

BOOLEAN CallstackReturnAddressToCallingAddress (UCHAR *ReturnAddress, PUINT32 IndexOfCallFromReturnAddress)
 Walkthrough the stack.
 
VOID CallstackShowFrames (PDEBUGGER_SINGLE_CALLSTACK_FRAME CallstackFrames, UINT32 FrameCount, DEBUGGER_CALLSTACK_DISPLAY_METHOD DisplayMethod, BOOLEAN Is32Bit)
 Show stack frames.
 

Variables

BOOLEAN g_AddressConversion
 Whether converting addresses to object names or not.
 

Detailed Description

Callstack related routines.

Author
Sina Karvandi (sina@.nosp@m.hype.nosp@m.rdbg..nosp@m.org)
Version
0.1
Date
2022-03-06

Function Documentation

◆ CallstackReturnAddressToCallingAddress()

BOOLEAN CallstackReturnAddressToCallingAddress ( UCHAR * ReturnAddress,
PUINT32 IndexOfCallFromReturnAddress )

Walkthrough the stack.

This code is borrowed from here : https://github.com/electronicarts/EAThread/blob/master/source/x86/eathread_callstack_x86.cpp

Parameters
ReturnAddress
IndexOfCallFromReturnAddress
Returns
BOOLEAN
31{
32 //
33 // While negative array indices can be considered non-idiomatic it
34 // was felt that they are semantically appropriate as this code bases
35 // its comparisons from the return address and that it would be cleaner
36 // than using *(ReturnAddress - index).
37 //
38
39 //
40 // Three op-codes are used for the call instruction, 9A, E8, and FF.
41 // For a reference on the IA32 instruction format, see:
42 // http://www.cs.princeton.edu/courses/archive/spr06/cos217/reading/ia32vol2.pdf
43 //
44
45 //
46 // 9A cp - CALL ptr16:32 (7-byte)
47 //
48 if (ReturnAddress[-7] == 0x9A)
49 {
50 *IndexOfCallFromReturnAddress = 7;
51 return TRUE;
52 }
53 // E8 cd - CALL rel32 (5-byte)
54 else if (ReturnAddress[-5] == 0xE8)
55 {
56 *IndexOfCallFromReturnAddress = 5;
57 return TRUE;
58 }
59 else
60 {
61 //
62 // The third opcode to specify "call" instructions is FF.
63 // Unfortunately this instruction also needs the succeeding ModR/M
64 // byte to fully determine instruction length. The SIB value is
65 // another byte used for extending the range of addressing modes
66 // supported by the ModR/M byte. The values of this ModR/M byte
67 // used in conjunction with the call instruction are as follows:
68 //
69 // 7-byte call:
70 // FF [ModR/M] [SIB] [4-byte displacement]
71 // * ModR/M is either 0x94 or 0x9C
72 //
73 // 6-byte call:
74 // FF [ModR/M] [4-byte displacement]
75 // * ModR/M can be:
76 // * 0x90 - 0x9F EXCLUDING 0x94 or 0x9C
77 // * 0x15 or 0x1D
78 //
79 // 4-byte call:
80 // FF [ModR/M] [SIB] [1-byte displacement]
81 // * ModR/M is either 0x54 or 0x5C
82 //
83 // 3-byte call:
84 // FF [ModR/M] [1-byte displacement]
85 // * ModR/M can be:
86 // * 0x50 - 0x5F EXCLUDING 0x54 or 0x5C
87 // FF [ModR/M] [SIB]
88 // * ModR/M is either 0x14 or 0x1C
89 //
90 // 2-byte call:
91 // FF [ModR/M]
92 // * ModR/M can be:
93 // * 0xD0 - 0xDF
94 // * 0x10 - 0x1F EXCEPT 0x14, 0x15, 0x1C, or 0x1D
95 //
96
97 //
98 // The mask of F8 is used because we want to mask out the bottom
99 // three bits (which are most often used for register selection)
100 //
101 const unsigned char RmMask = 0xF8;
102
103 //
104 // 7-byte format:
105 //
106 if (ReturnAddress[-7] == 0xFF &&
107 (ReturnAddress[-6] == 0x94 || ReturnAddress[-6] == 0x9C))
108 {
109 *IndexOfCallFromReturnAddress = 7;
110 return TRUE;
111 }
112
113 //
114 // 6-byte format:
115 // FF [ModR/M] [4-byte displacement]
116 //
117 else if (ReturnAddress[-6] == 0xFF &&
118 ((ReturnAddress[-5] & RmMask) == 0x90 || (ReturnAddress[-5] & RmMask) == 0x98) &&
119 (ReturnAddress[-5] != 0x94 && ReturnAddress[-5] != 0x9C))
120 {
121 *IndexOfCallFromReturnAddress = 6;
122 return TRUE;
123 }
124
125 //
126 // Alternate 6-byte format:
127 //
128 else if (ReturnAddress[-6] == 0xFF &&
129 (ReturnAddress[-5] == 0x15 || ReturnAddress[-5] == 0x1D))
130 {
131 *IndexOfCallFromReturnAddress = 6;
132 return TRUE;
133 }
134
135 //
136 // 4-byte format:
137 // FF [ModR/M] [SIB] [1-byte displacement]
138 //
139 else if (ReturnAddress[-4] == 0xFF &&
140 (ReturnAddress[-3] == 0x54 || ReturnAddress[-3] == 0x5C))
141 {
142 *IndexOfCallFromReturnAddress = 4;
143 return TRUE;
144 }
145
146 //
147 // 3-byte format:
148 // FF [ModR/M] [1-byte displacement]
149 //
150 else if (ReturnAddress[-3] == 0xFF &&
151 ((ReturnAddress[-2] & RmMask) == 0x50 || (ReturnAddress[-2] & RmMask) == 0x58) &&
152 (ReturnAddress[-2] != 0x54 && ReturnAddress[-2] != 0x5C))
153 {
154 *IndexOfCallFromReturnAddress = 3;
155 return TRUE;
156 }
157
158 //
159 // Alternate 3-byte format:
160 // FF [ModR/M] [SIB]
161 //
162 else if (ReturnAddress[-3] == 0xFF &&
163 (ReturnAddress[-2] == 0x14 || ReturnAddress[-2] == 0x1C))
164 {
165 *IndexOfCallFromReturnAddress = 3;
166 return TRUE;
167 }
168
169 //
170 // 2-byte calling format:
171 // FF [ModR/M]
172 //
173 else if (ReturnAddress[-2] == 0xFF &&
174 ((ReturnAddress[-1] & RmMask) == 0xD0 || (ReturnAddress[-1] & RmMask) == 0xD8))
175 {
176 *IndexOfCallFromReturnAddress = 2;
177 return TRUE;
178 }
179
180 //
181 // Alternate 2-byte calling format:
182 // FF [ModR/M]
183 //
184 else if (ReturnAddress[-2] == 0xFF &&
185 ((ReturnAddress[-1] & RmMask) == 0x10 || (ReturnAddress[-1] & RmMask) == 0x18) &&
186 (ReturnAddress[-1] != 0x14 && ReturnAddress[-1] != 0x15 &&
187 ReturnAddress[-1] != 0x1C && ReturnAddress[-1] != 0x1D))
188 {
189 *IndexOfCallFromReturnAddress = 2;
190 return TRUE;
191 }
192 else
193 {
194 return FALSE;
195 }
196 }
197
198 return FALSE;
199}
#define TRUE
Definition BasicTypes.h:55
#define FALSE
Definition BasicTypes.h:54

◆ CallstackShowFrames()

VOID CallstackShowFrames ( PDEBUGGER_SINGLE_CALLSTACK_FRAME CallstackFrames,
UINT32 FrameCount,
DEBUGGER_CALLSTACK_DISPLAY_METHOD DisplayMethod,
BOOLEAN Is32Bit )

Show stack frames.

Parameters
CallstackFrames
FrameCount
DisplayMethod
Is32Bit
Returns
VOID
216{
217 UINT32 CallLength;
218 UINT64 TargetAddress;
219 UINT64 UsedBaseAddress;
220 BOOLEAN IsCall = FALSE;
221 std::map<UINT64, LOCAL_FUNCTION_DESCRIPTION>::iterator Iterate;
222
223 //
224 // Print callstack frames
225 //
226 for (size_t i = 0; i < FrameCount; i++)
227 {
228 IsCall = FALSE;
229
230 if (CallstackFrames[i].IsValidAddress)
231 {
232 //
233 // Check if it's call or just a simple code address
234 //
235 if (CallstackFrames[i].IsExecutable && CallstackReturnAddressToCallingAddress(
236 (unsigned char *)&CallstackFrames[i].InstructionBytesOnRip[MAXIMUM_CALL_INSTR_SIZE],
237 &CallLength))
238 {
239 //
240 // Computer the "call" instruction address
241 //
242 TargetAddress = CallstackFrames[i].Value - CallLength;
243
244 IsCall = TRUE;
245 }
246 else
247 {
248 //
249 // Check if we wanna show the stack params
250 //
252 {
253 continue;
254 }
255
256 IsCall = FALSE;
257 TargetAddress = CallstackFrames[i].Value;
258 }
259
260 ShowMessages("[$+%03x] ", i * (Is32Bit ? sizeof(UINT32) : sizeof(UINT64)));
261
262 if (IsCall)
263 {
264 if (Is32Bit)
265 {
266 ShowMessages(" %08x (from ", TargetAddress);
267 }
268 else
269 {
270 ShowMessages(" %016llx (from ", TargetAddress);
271 }
272 }
273 else
274 {
275 if (Is32Bit)
276 {
277 ShowMessages(" %08x (addr ", TargetAddress);
278 }
279 else
280 {
281 ShowMessages(" %016llx (addr ", TargetAddress);
282 }
283 }
284
285 //
286 // Show the name of the function if available
287 // Apply addressconversion of settings here
288 //
290 {
291 if (SymbolShowFunctionNameBasedOnAddress(TargetAddress, &UsedBaseAddress))
292 {
293 ShowMessages(" ");
294 }
295 }
296
297 if (Is32Bit)
298 {
299 ShowMessages("<%08x>)\n", TargetAddress);
300 }
301 else
302 {
303 ShowMessages("<%016llx>)\n", TargetAddress);
304 }
305 }
306 else
307 {
308 //
309 // Check if we wanna show the stack params
310 //
312 {
313 continue;
314 }
315
316 ShowMessages("[$+%03x] ", i * (Is32Bit ? sizeof(UINT32) : sizeof(UINT64)));
317
318 if (Is32Bit)
319 {
320 ShowMessages(" %08x\n", CallstackFrames[i].Value);
321 }
322 else
323 {
324 ShowMessages(" %016llx\n", CallstackFrames[i].Value);
325 }
326 }
327 }
328}
UCHAR BOOLEAN
Definition BasicTypes.h:39
unsigned __int64 UINT64
Definition BasicTypes.h:21
unsigned int UINT32
Definition BasicTypes.h:48
#define MAXIMUM_CALL_INSTR_SIZE
maximum size for call instruction in Intel
Definition Constants.h:473
@ DEBUGGER_CALLSTACK_DISPLAY_METHOD_WITHOUT_PARAMS
Definition RequestStructures.h:779
BOOLEAN g_AddressConversion
Whether converting addresses to object names or not.
Definition globals.h:584
BOOLEAN CallstackReturnAddressToCallingAddress(UCHAR *ReturnAddress, PUINT32 IndexOfCallFromReturnAddress)
Walkthrough the stack.
Definition callstack.cpp:30
RequestedActionOfThePacket Value(0x1) 00000000
VOID ShowMessages(const char *Fmt,...)
Show messages.
Definition libhyperdbg.cpp:96
UINT64 Value
Definition RequestStructures.h:765
BOOLEAN SymbolShowFunctionNameBasedOnAddress(UINT64 Address, PUINT64 UsedBaseAddress)
shows the functions' name for the disassembler
Definition symbol.cpp:162

Variable Documentation

◆ g_AddressConversion

BOOLEAN g_AddressConversion
extern

Whether converting addresses to object names or not.

it is enabled by default