首页
社区
课程
招聘
Dissecting The Stack Part2-----TRACE THE CALL STACK.
发表于: 2007-5-17 08:45 2978

Dissecting The Stack Part2-----TRACE THE CALL STACK.

2007-5-17 08:45
2978
http://advdbg.org/blogs/advdbg_system/articles/335.aspx

Do not know how to paste picture here, the link above has picture.

  Breaking The Secretes —— Dissecting The Stack Part2                                    

  TRACE THE CALL STACK.

         Welcome back everyone.  Today we gonna discuss how we could walk the call stack.

Huge topics!  I need to cover several problems today, get ready? Let's Go!

1、What is Call Stack?

    I should not talk about this topics in Breaking The Secrets since it's too easy to answer, do you think so?

I'm afraid this time you are wrong.  

   Let's see the code below again(Figour1):

Note: Compile with Visual C++ without optimize.

What do you think of the callstack look like if you put a breakpoint at the code in red:

printf("%s %d %d\n",buffer,a, b);

Let's take a picutre to see what's happending:

We are familiar with it, call stack window.  This time I'm using visual studio 2005.

If you double click on every row in the callstack window and using disassembly

window, you gonna see:

printf("%s %d %d\n",buffer,a, b);
004010CD mov ecx,dword ptr

  

00401182 call callex (40100Fh)

return 0;
00401187 xor eax,eax

mainret = _tmain(__argc, _targv, _tenviron);
004018FA mov eax,dword ptr [__environ (468980h)]
004018FF push eax
00401900 mov ecx,dword ptr [___argv (468978h)]
00401906 push ecx
00401907 mov edx,dword ptr [___argc (468974h)]
0040190D push edx
0040190E call @ILT+5(_main) (40100Ah)
00401913 add esp,0Ch
00401916 mov dword ptr [ebp-38h],eax

  

__security_init_cookie();
004016D3 call __security_init_cookie (405320h)

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*/

return 0;
}

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (3)
雪    币: 97697
活跃值: (200839)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
2
I See it,and I like it.
2007-5-18 00:11
0
雪    币: 97697
活跃值: (200839)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
3
This is a very interesting tool, I anticipate its development.
2007-5-18 00:23
0
雪    币: 207
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
So Do I.
Windebug Is Cool.
2007-5-24 17:52
0
游客
登录 | 注册 方可回帖
返回
//