飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

楼主: 千里之外

千里之外加入PYG54小组学习

[复制链接]

该用户从未签到

 楼主| 发表于 2007-5-17 19:34:37 | 显示全部楼层

这是我从网上找的一篇相关文章 不过看的不是很明白

在 Win32汇编中,我们经常要和 Api 打交道,另外也会常常使用自己编制的类似于 Api 的带参数的子程序,本文要讲述的是在子程序调用的过程中进行参数传递的概念和分析。一般在程序中,参数的传递是通过堆栈进行的,也就是说,调用者把要传递给子程序(或者被调用者)的参数压入堆栈,子程序在堆栈取出相应的值再使用,比如说,如果你要调用 SubRouting(Var1,Var2,Var3),编译后的最终代码可能是

push Var3
push Var2
push Var1
call SubRouting
add esp,12

也就是说,调用者首先把参数压入堆栈,然后调用子程序,在完成后,由于堆栈中先前压入的数不再有用,调用者或者被调用者必须有一方把堆栈指针修正到调用前的状态。参数是最右边的先入堆栈还是最左边的先入堆栈、还有由调用者还是被调用者来修正堆栈都必须有个约定,不然就会产生不正确的结果,这就是我在前面使用“可能”这两个字的原因:各种语言中调用子程序的约定是不同的,它们的不同点见下表:

上文的图:
Codz:
+------------------+---------+------------+-----------+---------+----------+--------+
      C   SysCall   StdCall   Basic   Fortran   Pascal   
+------------------+---------+------------+-----------+---------+----------+--------+
参数从左到右               是   是   是
+------------------+---------+------------+-----------+---------+----------+--------+
参数从右到左   是   是   是
+------------------+---------+------------+-----------+---------+----------+--------+
调用者清除堆栈   是
+------------------+---------+------------+-----------+---------+----------+--------+
允许使用vararg   是   是   是
+------------------+---------+------------+-----------+---------+----------+--------+


VARARG 表示参数的个数可以是不确定的,有一个例子就是 C 中的 printf 语句,在上表中,StdCall 的定义有个要说明的地方,就是如果 StdCall 使用 :VARARG 时,是由调用者清除堆栈的,而在没有:VARARG时是由被调用者清除堆栈的。
在 Win32 汇编中,约定使用 StdCall 方式,所以我们要在程序开始的时候使用 .model stdcall 语句。也就是说,在 API 或子程序中,最右边的参数先入堆栈,然后子程序在返回的时候负责校正堆栈,举例说明,如果我们要调用 MessageBox 这个 API,因为它的定义是 MessageBox(hWnd,lpText,lpCaption,UType) 所以在程序中要这样使用:

push MB_OK
push offset szCaption
push offset szText
push hWnd
call MessageBox
...

我们不必在 API 返回的时候加上一句 add sp,4*4 来修正堆栈,因为这已经由 MessageBox 这个子程序做了。在 Windows API 中,唯一一个特殊的 API 是 wsprintf,这个 API 是 C 约定的,它的定义是 wsprintf(lpOut,lpFormat,Var1,Var2...),所以在使用时就要:

push 1111
push 2222
push 3333
push offset szFormat
push offset szOut
call wsprintf
add esp,4*5

上文的图:
Codz:
.
+---------------+
x   ...     起始堆栈
+---------------+
x-4   EBP + C   参数2
+---------------+
x-8   EBP + 8   参数1
+---------------+
x-c   EBP + 4   返回地址
+---------------+
x-10   EBP     保存的EBP
+---------------+
x-14   EBP - 4   局部变量1
+---------------+
x-18   EBP - 8   局部变量2
+---------------+
...   ...
+---------------+
...   ESP     现在的堆栈指针
+---------------+



MyProc proto Var1,Var2 ;有两个参数
local lVar1,lVar2 ;有两个局部变量

注意,这里的两个 local 变量实际上没有被用到,只是为了演示用,具体实现的代码是:

MyProc proc

push ebp
mov ebp,esp

sub esp,8

mov eax,dword ptr [ebp + 8]
sub eax,dword ptr [ebp + c]

add esp,8

pop ebp
ret 8

MyProc endp

现在对这个子程序分析一下,push ebp/mov ebp,esp 是例行的保存和设置 EBP 的代码,sub esp,8 在堆栈中留出两个局部变量的空间,mov /add 语句完成相加,add esp,8 修正两个局部变量使用的堆栈,ret 8 修正两个参数使用的堆栈,相当于 ret / add esp,8 两句代码的效果。可以看出,这是一个标准的 Stdcall 约定的子程序,使用时最后一个参数先入堆栈,返回时由子程序进行堆栈修正。当然,这个子程序为了演示执行过程,使用了手工保存 ebp 并设置局部变量的方法,实际上,386 处理器有两条专用的指令是完成这个功能用的,那就是 Enter 和 Leave,Enter 语句的作用就是 push ebp/mov ebp,esp/sub esp,xxx,这个 xxx 就是 Enter 的,Leave 则完成 add esp,xxx/pop ebp 的功能,所以上面的程序可以改成:

MyPorc proc
enter 8,0

mov eax,dword ptr [ebp + 8]
sub eax,dword ptr [ebp + c]

leave
ret 8
MyProc endp


好了,说到这儿,参数传递的原理也应该将清楚了,还要最后说的是,在使用 Masm32 编 Win32 汇编程序的时候,我们并不需要记住 [ebp + xx] 等麻烦的地址,或自己计算局部变量需要预留的堆栈空间,还有在 ret 时计算要加上的数值,Masm32 的宏指令都已经把这些做好了,如在 Masm32 中,上面的程序只要写成为:

MyProc proc Var1,Var2
local lVar1,lVar2

mov eax,Var1
sub eax,Var2
ret

MyProc endp

编译器会自动的在 mov eax,Var1 前面插上一句 Enter 语句,它的参数会根据 local 定义的局部变量的多少自动指定,在 ret 前会自动加上一句 Leave,同样,编译器会根据参数的多少把 ret 替换成 ret xxx,把 mov eax,Var1 换成 mov eax,dword ptr [ebp + 8] 等等。

最后是使用 Masm32 的 invoke 宏指令,在前面可以看到,调用带参数的子程序时,我们需要用 push 把参数压入堆栈,如果不小心把参数个数搞错了,就会使堆栈不平衡,从而使程序从堆栈中取出错误的返回地址引起不可预料的后果,所以有必要有一条语句来完成自动检验的任务,invoke 就是这样的语句,实际上,它是自动 push 所有参数,检测参数个数、类型是否正确,并使用 call 来调用的一个宏指令,对于上面的 push/push/call MyProc 的指令,可以用一条指令完成就是:

invoke MyProc,Var1,Var2

当然,当程序编译好以后你去看机器码会发现它被正确地换成了同样的 push/push/call 指令。但是,在使用 invoke 之前,为了让它进行正确的参数检验,你需要对函数进行申明,就象在 C 中一样,申明的语句是:

MyProc proto :DWORD,:DWORD

语句中 proto 是关键字,表示申明,:DWORD 表示参数的类型是 double word 类型的,有几个就表示有几个参数,在 Win32 中参数都是 double word 型的,申明语句要写在 invoke 之前,所以我们一般把它包括在 include 文件中,好了,综合一下,在 Masm32 中使用一个带参数的子程序或者 Api ,我们只需用:

...
MyProc proto :dword,:dword
...
.data
x dd ?
y dd ?
dwResult dd ?
...
mov x,1
mov y,2
invoke MyProc x,y
mov dwResult,eax
...

就行了,如何,是不是很简单啊?不过我可苦了,这篇文章整整花了我一个晚上 ...
PYG19周年生日快乐!

该用户从未签到

发表于 2007-5-17 20:31:50 | 显示全部楼层
很厉害啊,/:09

根据这篇文章内容,巩固一下堆栈知识,用自己的话回答下面问题。
出栈入栈有什么样的规律,跟ESP有什么关系?
PYG19周年生日快乐!

该用户从未签到

 楼主| 发表于 2007-5-17 21:01:03 | 显示全部楼层
我理解的是堆栈是个先进后出的区域 也可以说是后进先出   比如
push a
push b
......
pop  c
pop d


这样的话就是 b先被弹出 送给c  a后被弹出 送给d 这样结果就是 c=b  d=a

这个ESP嘛 是指针寄存器  它总是指向堆栈的顶端(这个我也不是很明白)
至于出栈入栈跟ESP有什么关系不是很明白 [ESP+1][ESP+2]只类的到底指向什么数据 不懂/:02
PYG19周年生日快乐!

该用户从未签到

发表于 2007-5-18 10:59:34 | 显示全部楼层
分析反汇编代码会用到三个地方:汇编指令,堆栈操作,寄存器
汇编指令可以查子典,边分析边查字典都没关系;
寄存器是固定的;
关键点__堆栈操作!


堆栈的出栈入栈跟垒砖头一样,最后放的是最先拿下来的,
esp是堆栈指针,如图:



你现在的任务是,能够分析反汇编代码,告别简单爆破!

  1. push    1
  2. push    2
  3. push    3
  4. push    4
  5. add     esp, 4
  6. pop     eax
  7. mov     ebx, dword ptr [esp-8]
复制代码

试着回答ebx,eax是多少!

----------------------------------------------------------------------------------------------------
今天是星期五了,明天后天休息,希望星期一来时,兄弟对堆操作理解透彻!
本版仅是第一课负责人,6月开课。
兄弟已达第二课水平,本期第二课群牛共舞,欢迎兄弟加入学习!
但在6月开课之前,本版乐意对任何知识和层面内容对兄弟等进行指导,
如无变故,可到6月。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入我们

x
PYG19周年生日快乐!

该用户从未签到

发表于 2007-5-18 17:25:49 | 显示全部楼层
看来是我误解fonge了。。

这样也不错,呵
PYG19周年生日快乐!

该用户从未签到

 楼主| 发表于 2007-5-18 20:57:43 | 显示全部楼层
谢谢大哥指点啊 /:09   我写了个示意图 大哥看看对不对
这是内存中的存储示意图
4-------esp              eax=4   (pop eax)
3-------esp+4h
2-------esp+8h         ebx=2  (esp-8)后来到这个位置
1-------esp+ch   
.--------esp+10h  (add esp,4)
.
最后
eax=4   ebx=2
PYG19周年生日快乐!

该用户从未签到

发表于 2007-5-18 21:45:11 | 显示全部楼层
eax=3,ebx=4




++++++++++++++++++++++++++++++++++++++++++++++
PUSH(Push Word or Doubleword onto Stack)

指令格式:PUSH Reg/Mem

一个字进栈,系统自动完成两步操作:SP←SP-2,(SP)←操作数;

一个双字进栈,系统自动完成两步操作:ESP←ESP-4,(ESP)←操作数。
POP(Pop Word or Doubleword off Stack)

指令格式:POP Reg/Mem

弹出一个字,系统自动完成两步操作:操作数←(SP),SP←SP+2;

弹出一个双字,系统自动完成两步操作:操作数←(ESP),ESP←ESP+4。

______________________________________________________________
esp永远指向栈顶,但esp可以变化,变化之后指向的还是栈顶,但[esp+4]却指向的
不是原来的数据了,POP和push将会引起esp的变化,esp是一个寄存器一样的东西,
是可以参与运算的!




-------------------------------------
兄弟很有天赋,继续努力,你将是我带走得最远的人,也可能是我唯一带那么远的人
最大遗憾的是,再远也只有到6月,
6月我只带第一课,且只有一届







))))))))))))))))))))))))))
在6年前,我也曾是hacker!

[ 本帖最后由 fonge 于 2007-5-18 21:49 编辑 ]
PYG19周年生日快乐!

该用户从未签到

发表于 2007-5-18 21:51:39 | 显示全部楼层
OD里输入命令,运行一遍就知道了
PYG19周年生日快乐!

该用户从未签到

发表于 2007-5-18 21:59:09 | 显示全部楼层
LZ看好了

  1. NE365全称为:Not Exclusive in 365 days

  2.   由jamesjoo于2004年5月创建。


  3. 初建立时,是一个纯粹的病毒研究组织,随着组织不断壮大,研究方向也随之扩展。事实证明这是非常正确的(老大英名神武,千秋万载,一统江湖)。
  4.   目前研究方向:病毒、系统内核、逆向破解、.net技术等

  5. 现有成员10人:
  6.     jamesjoo
  7.     tankaiha(hmx)
  8.     shadow3(风间水月)
  9.     ificanfly(恋人之秋雨)
  10.     turbowang
  11.     lkjop
  12.     海风月影
  13.     tsukihime
  14.     nbw
  15.     EA(据说是NE365最帅的…)

  16.     在此期间,我们也有幸得到了一些业内高手的帮助和支持,他们有:
  17.     Luocong Vxk pker linhanshi 菩提 hexpe laoqian 等朋友


复制代码


看到没,真正的牛人关注你了~
努力啊,兄弟/:09
PYG19周年生日快乐!

该用户从未签到

 楼主| 发表于 2007-5-18 23:01:14 | 显示全部楼层
先谢谢斑竹 海风月影 /:09 斑竹的话让我很受鼓舞啊  呵呵  我会继续努力的 明天去图书馆借本书 搞明白 堆栈操作
再次谢谢 斑竹 的指导 你的这段话给我指明了学习方向啊

/:09 分析反汇编代码会用到三个地方:汇编指令,堆栈操作,寄存器
汇编指令可以查子典,边分析边查字典都没关系;
寄存器是固定的;
关键点__堆栈操作!/:09
永远支持PYG
PYG19周年生日快乐!
您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

快速回复 返回顶部 返回列表