用指针来"爬栈"

用指针来"爬栈"

转自:http://dododododo.blog.sohu.com/4627612.html

 

分类: Programing 2006-06-16 13:04

指针是个好东西,她能在内存中随意的游走.下面来介绍一个有趣的应用--爬栈.

爬栈就是用指针,从子函数开始,顺着堆栈向下找母函数的过程.

先给出一段代码:

/////////////////////////////////////////

int papa(int a)
{

 int i = 2;
 int *ptr ;
 int EBP;
 i = a;
 ptr = &i;
 EBP = *(ptr+1);
 return 1;
}


int main(int argc, char* argv[])
{
 int ret = 0;
 int e = 3;

 ret = papa(e);

 return ret;
}

/////////////////////////////////////////

运行起来,跟到papa()里面,单步运行,ebp = 0x12ff20 看堆栈:

/////////////////////////////////////////

0x12ff1c:02 00 00 00 //变量i

0x12ff20:80 ff 12 00 //main()的EBP;

0x12ff24:df 84 40 00 //main()中下一条指令地址

0x12ff28:03 00 00 00 //传递给papa()的参数e

.....................

/////////////////////////////////////////

我们用"ptr = &i" 来得到变量i的地址,也就是0x12ff1c,然后ptr+1就可以得到papa()的EBP值,也就是0x12ff20;然后mian()的EBP就是存放在0x12ff20里面的值;然后存放在0x12ff28中的就是main()函数中下一条指令的地址.简单吧.......

然后,顺着EBP看:

/////////////////////////////////////////

0x12ff80:c0 ff 12 00 //mainCRTStartup 的 EBP

         49 11 40 00

.....................

0x12ffc0:f0 ff 12 00 //这里就没有了,新进程吗,与主进程(比如explorer.exe)没关系了

         4f 6d 81 7c //顺着这个再向上找

.....................

0x12fff0:00 00 00 00

         00 00 00 00

.....................

/////////////////////////////////////////

顺着0x7c816d4f向上找的话,你会进入到kernel32.dll,哈哈,好,我们来看看这段代码:

////////////////////////////////////////

7C816D2A   90               NOP
7C816D2B   90               NOP
7C816D2C   6A 0C            PUSH 0C
7C816D2E   68 586D817C      PUSH kernel32.7C816D58
7C816D33   E8 93B7FEFF      CALL kernel32.7C8024CB
7C816D38   8365 FC 00       AND DWORD PTR SS:[EBP-4],0
7C816D3C   6A 04            PUSH 4
7C816D3E   8D45 08          LEA EAX,DWORD PTR SS:[EBP+8]
7C816D41   50               PUSH EAX
7C816D42   6A 09            PUSH 9
7C816D44   6A FE            PUSH -2
7C816D46   FF15 A013807C    CALL DWORD PTR DS:[<&ntdll.NtSetInformat>; ntdll.ZwSetInformationThread
7C816D4C   FF55 08          CALL DWORD PTR SS:[EBP+8]  //喂,在这里!!
7C816D4F   50               PUSH EAX
7C816D50   E8 545FFFFF      CALL kernel32.ExitThread
7C816D55   90               NOP
7C816D56   90               NOP
7C816D57   90               NOP

///////////////////////////////////////

再向上走的话,你会发现,一个你很熟悉的函数CreateRemoteThread,最后是CreateThread!;

它由运行该exe的父进程调用!.

以上这些意味着,我用子函数的指针就可以对母函数的数据进行任意操作,如改改父函数的局部变量,从父函数偷点子函数不能获得的数据,甚至直接跳到父函数去执行都是可以的......

//顺序基本运算算法 #include <stdio.h> #include <malloc.h> #define MaxSize 100 typedef char ElemType; typedef struct { ElemType data[MaxSize]; int top; //指针 } SqStack; //顺序类型 //创建顺序InitStack void InitStack(SqStack * &s){ s=(SqStack *)malloc(sizeof(SqStack)); s->top=-1; } bool pdtrue(){ return true; } //判断顺序是否为空StackEmpty bool StackEmpty_1(SqStack * s){ return s->top==-1; } //入Push void StackEmpty(SqStack * s) { if(s->top==-1){ printf("顺序为空\n"); } else{ printf("顺序不为空\n"); } } //出Pop bool Pop(SqStack * &s, ElemType e){ if (s->top == MaxSize - 1){ printf("顺序已满,无法入\n"); } s->top++; s->data[s->top] = e; printf("元素%d完成入\n",e); return true; } //按顺序输出整个顺序 void PrintStack(SqStack * s) { if (StackEmpty(s)) { printf("顺序为空\n"); return; } for (int i = 0; i <= s->top; i++) { printf("%d ", s->data[i]); } printf("\n"); } //销毁顺序 void DestroyStack(SqStack * &s) { free(s); s = NULL; } //提高性项目:基于的特性,实现十进制转八进制的代码实现。 //步骤: //①定义顺序 //②使用辗转相除法将该十进制数除以八,将余数依次入 //③将中元素依次出 //④销毁顺序 void DecToOct(int num) { SqStack s; InitStack(&s); while (num > 0) { Push(&s, num % 8); num /= 8; } printf("十进制 %d 转换为八进制是: ", num); ElemType e; while (Pop(&s, e)) { printf("%d", e); } printf("\n"); DestroyStack(&s); } void main(){ //顺序的初始化InitStack SqStack *s=NULL; InitStack(s); printf("顺序表地址为%p\n",s); //判断顺序是否为空StackEmpty bool as; as=pdtrue(); if(as==true){ printf("as的值为true"); } //入Push StackEmpty(s); //出Pop ElemType e=10; Pop(s,e); printf("顶元素为%d\n",s->data[s->top]); //按顺序输出整个顺序 PrintStack(s); //销毁顺序 DestroyStack(s); //提高性项目:基于的特性,实现十进制转八进制的代码实现。 DecToOct(2025269509); }
最新发布
10-27
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值