return __tmainCRTStartup();
004016D8 call __tmainCRTStartup (4016E0h)
}
004016DD pop ebp
7C816FD4 call dword ptr [ebp+8]
7C816FD7 push eax
The font in black is where the stack pointer to, in visual stduio 2005 you will see a yellow pointer on the left
of the line in black:
Have you seen that all the CallStack Items(We have 5 row, meaning 5 items) ? Every Item is the address after a instruction like:
Call XXXX. If we push the five item's address into an empty stack, they look like:
004010CD mov ecx,dword ptr ---- Top Of Stack. ESP Point To Here.
00401187 xor eax,eax
00401913 add esp,0Ch
004016DD pop ebp
7C816FD7 push eax ------- Stack Bottom. ESP Point To Here
Remember when a function call happends, the program will save the EIP of next instructions on the stack so that
after the function call, our program can come back. The EIP is our Call Stack Item, this is the essential of the call stack.
Every Call Stack Item Represens For One EIP IF YOUR PROGRAM DO NOT USE OPTIMIZE.
Gather All The Item In All, Then We Got A Whole Call Stack.
2、TRACE THE CALLSTACK IN YOUR PROGRAM.
Let's do it now. You've understood the essential of the call stack, what are you waiting for?
Suppose you have written your program and you want to see the call stack yourself.
Think about it, you have all Function B in your Function A:
void A()
{
B();
C();
}
In the stack frame of function B:
EBP+4 Point To EIP In Stack Frame.(Address Of C)
EBP Point To Last EBP(Before Function B Called, the value of EBP).
Yes? So we can get the EIP In Stack Frame According To The Current Value Of EBP.
Can we can get the "last EBP" from the Current EBP, then get the "last EIP" from the "Last EBP".......
That's why we have the code below:
_asm
{
PUSH EBP // Save Our Stack Frame Point
L1:
// The Two Parameter Pass To IsBadReadPtr
PUSH 4; // The Size Of The Memory Is 4 BYTES 32 BIT.
MOV EAX, EBP
ADD EAX, 04H
PUSH EAX
// CALL IsBadReadPtr
CALL pIsBadPTR // pIsBadPTR Point To The Address Of IsBadReadPtr.
TEST EAX, 1
JNZ L2
Mov EAX, [EBP+4] // EIP
Mov EAX, [EBP] //Last EBP
Push EAX
Pop EBP
JMP L1
L2: POP EBP // Restore Our Stack Frame Point.
}
Is that all? Of course not.
First: we only get the EIP Address, no symbol at all.
I mean the code above can not get function name, yes?
What we get is only:
004010CD
00401187
00401913
004016DD
7C816FD7
Not:
stackFrame.exe!callex(char * buffer=0x0013ff3c, int a=0x00000001, int b=0x00000002) Line 65 C++
> stackFrame.exe!main(int argc=0x00000001, char * * argv=0x00b23c28) Line 76 C++
stackFrame.exe!__tmainCRTStartup() Line 318 + 0x19 bytes C
stackFrame.exe!mainCRTStartup() Line 187 C
kernel32.dll!_BaseProcessStart@4() + 0x23 bytes
Second: something gets worse, do you remember FIO? The method of getting call stack is only based on the fact that the program do not use FIO at all. It doesn't work at all if your program use FIO.
Even if you are the hacker who has greate talent, you understand how FIO works.
You have to write 4 functions according to different Visual C++ Version: 6.0, 2002, 2003, 2005.
Awful, don't you think so?
It's enough today, aren't tired?
My topics today is only trace the stack, not walking the stack.
Yes, I gonna let you know how we will walk the stack next time.
Written By Jim Secretes.
2007/05/12.
Figour -1.
// stackFrame.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "vector"
using namespace std;
#include
#include
#include "windows.h"
#include "tchar.h"
typedef BOOL (WINAPI *PFNDEBUGACTIVEPROCESSSTOP)(DWORD);
#define MAXSIZE 1024
void GetCallStack()
{
;
}
PFNDEBUGACTIVEPROCESSSTOP pIsBadPTR = NULL;
int __stdcall callex(char *buffer, int a, int b)
{
/* This prints the input variables to the screen:*/
// Let's Get Calling Stack Now.
// No Opitimized Code
HINSTANCE oHinstance = NULL;
oHinstance = LoadLibrary(_T("Kernel32.dll"));
if (oHinstance)
{
pIsBadPTR = (PFNDEBUGACTIVEPROCESSSTOP)GetProcAddress\
((HMODULE)oHinstance, _T("IsBadReadPtr"));
if (pIsBadPTR)
{
_asm
{
Mov EDX, pIsBadPTR
}
}
}
_asm
{
PUSH EBP
L1:
// The Two Parameter Pass To IsBadReadPtr
MOV ECX, 0
PUSH 4;
MOV EAX, EBP
ADD EAX, 04H
PUSH EAX
// CALL IsBadReadPtr
CALL pIsBadPTR
TEST EAX, 1
JNZ L2
Mov EAX, [EBP+4] // EIP
Mov EAX, [EBP] //Last EBP
Push EAX
Pop EBP
INC ECX
INC ECX
JMP L1
L2: POP EBP
}
printf("%s %d %d\n",buffer,a, b);
int result = 0;
result = a + b;
return result;
}
int main(int argc, char **argv)
{
char buffer[15]="Hello Buffer" /* a 15-byte character buffer with 12 characters filled*/
int int1=1, int2=2; /* two four-byte integers */
callex(buffer,int1,int2); /*call our function*/