不要太武断呀,不然会禁锢思想的,岂不是和电脑一样了。看了帖子:
http://community.csdn.net/Expert/topic/3770/3770688.xml?temp=4.357547E-02
好像很多人都这样认为,希望大家重新认识这个问题。具体方法没什么价值,只希望扩展大家的思维。
以下是代码,操作系统 Windows XP SP1 。#include <iostream>
using namespace std;
//控制台程序,在VC++6、VC.NET Debug模式下,采用编译器默认设置调试成功。
//此方法与具体代码和编译器相关,搞着玩的,没什么实用价值,只作验证。//此函数只有跳出功能,eax移作他用,返回值无意义。
unsigned short breakfunc(unsigned short a)
{
__asm
{
//begin1 手工恢复堆栈现场,使堆栈成为此函数调用前的状态
pop edi;
pop esi;
pop ebx;
mov esp,ebp;
pop ebp;
pop eax;//eax中保存了进程中此函数执行完后下一条将执行的语句的地址。
//end1 --------------------------------------------- add esp,4;//此条语句为了平衡main函数的堆栈。与具体代码相关。
add eax,9;//在eax中存放 cout<<"break out and goto here"<<endl; 语句地址。
jmp eax;//挑转。
}
return 0;
}void main()
{
unsigned short a=123,b;
while(1)
b=breakfunc(a);//不是死循环啊。 cout<<"break out and goto here"<<endl;
cout <<b<<endl;
}各位有何高见尽管发表,洗耳恭听。若您能够提供有价值的 !(常规) 编程方法,50送上。
http://community.csdn.net/Expert/topic/3770/3770688.xml?temp=4.357547E-02
好像很多人都这样认为,希望大家重新认识这个问题。具体方法没什么价值,只希望扩展大家的思维。
以下是代码,操作系统 Windows XP SP1 。#include <iostream>
using namespace std;
//控制台程序,在VC++6、VC.NET Debug模式下,采用编译器默认设置调试成功。
//此方法与具体代码和编译器相关,搞着玩的,没什么实用价值,只作验证。//此函数只有跳出功能,eax移作他用,返回值无意义。
unsigned short breakfunc(unsigned short a)
{
__asm
{
//begin1 手工恢复堆栈现场,使堆栈成为此函数调用前的状态
pop edi;
pop esi;
pop ebx;
mov esp,ebp;
pop ebp;
pop eax;//eax中保存了进程中此函数执行完后下一条将执行的语句的地址。
//end1 --------------------------------------------- add esp,4;//此条语句为了平衡main函数的堆栈。与具体代码相关。
add eax,9;//在eax中存放 cout<<"break out and goto here"<<endl; 语句地址。
jmp eax;//挑转。
}
return 0;
}void main()
{
unsigned short a=123,b;
while(1)
b=breakfunc(a);//不是死循环啊。 cout<<"break out and goto here"<<endl;
cout <<b<<endl;
}各位有何高见尽管发表,洗耳恭听。若您能够提供有价值的 !(常规) 编程方法,50送上。
{
goto jump;
}
jump:
cout<<"break out and goto here"<<endl;
cout <<b<<endl;
http://community.csdn.net/Expert/topic/3770/3770688.xml?temp=4.357547E-02
......
call [breakfunc]
...... JMP Labelbreakfunc:
......
JMP EAX ;如果你在这里JMP到breakfunc之外了,
;当然无法ret了,所以也就不会死循环了。
;但是有可能程序红叉叉啊
......
ret
你这样适合做创造型的工作,例如:hacker
也就是说,在 API 或子程序中,最右边的参数先入堆栈,然后子程序在返回的时候负责校正堆栈,调用者不必平衡堆栈。
唯一一个特殊的win api 是wsprintf,它是C 约定的,所以必须自己平衡堆栈。
以下内容为程序代码:;;
;;测试调用API中堆栈的平衡.wsprintf 是唯一一个特殊,它是C 约定的,所以必须自己平衡堆栈
;; ml /c /coff test.asm link /subsystem:windows test.obj
;; .386
.model flat, stdcall
option casemap :none ; case sensitiveinclude windows.inc
include user32.inc
include kernel32.incincludelib user32.lib
includelib kernel32.lib .data?
szBuffer db 256 dup (?) .data
szFormat db '%d%d',0 .code
SomeFun proc push 9
push 9
push offset szFormat
push offset szBuffer
call wsprintf
;;;;;;;;;;;;;;;;;;;;;
add esp,4*4 ;;必须得平衡堆栈
;;;;;;;;;;;;;;;;;;;;;;;;;;
ret
SomeFun endp
start:
call SomeFun
push 0
push 0
push offset szBuffer
push 0
call MessageBox
invoke ExitProcess,NULLend start
pop edi;
pop esi;
pop ebx;
mov esp,ebp;
pop ebp;
以及add esp,4,
这句什么意思,编译不通过。
//由于主调用函数管理堆栈,所以可以实现变参函数。
void __cdecl test1(int m,int n)
{
return;// pop edi
// pop esi
// pop ebx
// mov esp,ebp
// pop ebp
// ret
}//__stdcall:实参的压栈顺序是从右到左。在主调用函数中负责压栈,在被调用函数中负责平衡堆栈。
//因此不能实现变参函数,因为被调函数不能事先知道弹栈数量。
void __stdcall test2(int m,int n)
{
return;// pop edi
// pop esi
// pop ebx
// mov esp,ebp
// pop ebp
// ret 8 ;平衡堆栈
}void main()
{
int m = 123,n = 321;
test1(m,n);
// mov eax,dword ptr [ebp-8]
// push eax ;进栈
// mov ecx,dword ptr [ebp-4]
// push ecx ;进栈
// call @ILT+655(test1) (00401294)
// add esp,8 ;平衡堆栈
test2(m,n);
// mov edx,dword ptr [ebp-8]
// push edx ;进栈
// mov eax,dword ptr [ebp-4]
// push eax ;进栈
// call @ILT+565(test2) (0040123a)
unsigned short a = 123,b = 234;
static unsigned int c=345;
char d = 12;
while(1)
b = breakfunc(a,c,d);
cout<<"break out and goto here"<<endl;
cout <<b<<endl;
}//由于传递的是变量的地址(类似指针),变量地址为4个字节,所以平衡堆栈时add esp,4*N(N = 变量个数)
这个是平衡breakfunc的堆栈StdCall 方式使用call直接调用,只压栈,不必出栈;C方式使用call直接调用,压栈后还要负责出栈。
//不是不出栈,是被调用者不负责平衡堆栈
PS:这些东西我不敢保证VC里面所有的三角都知道,但是星星们肯定知道,也许我比较菜才会回答,(注意我得昵称 ^o^)而且在VC里面,这所有的东西都是由系统帮你完成的.那些汇编代码都是VC在调试的时候反汇编得到