A. 函数调用堆栈原理 push ebx push esi push edi是什么作用
[cpp] view plain
int goo(int a, int b)
{
return a + b;
}
void foo()
{
int a[] = {1, 2, 3};
int result = goo(a[1], a[2]);
printf("result: %d", result);
}
VS2010下编译
foo函数部分汇编:
[cpp] view plain
00EB3890 push ebp
00EB3891 mov ebp,esp
00EB3893 sub esp,0E4h
00EB3899 push ebx
00EB389A push esi
00EB389B push edi
00EB389C lea edi,[ebp-0E4h]
00EB38A2 mov ecx,39h
00EB38A7 mov eax,0CCCCCCCCh
00EB38AC rep stos dword ptr es:[edi]
00EB38AE mov eax,dword ptr [___security_cookie (0EB7000h)]
00EB38B3 xor eax,ebp
00EB38B5 mov dword ptr [ebp-4],eax
int a[] = {1, 2, 3};
00EB38B8 mov dword ptr [ebp-14h],1
00EB38BF mov dword ptr [ebp-10h],2
00EB38C6 mov dword ptr [ebp-0Ch],3
int result = goo(a[1], a[2]);
00EB38CD mov eax,dword ptr [ebp-0Ch]
00EB38D0 push eax
00EB38D1 mov ecx,dword ptr [ebp-10h]
00EB38D4 push ecx
00EB38D5 call goo (0EB11E5h)
00EB38DA add esp,8
goo函数完整汇编:
[cpp] view plain
00EB1580 push ebp
00EB1581 mov ebp,esp
00EB1583 sub esp,0C0h
00EB1589 push ebx
00EB158A push esi
00EB158B push edi
00EB158C lea edi,[ebp-0C0h]
00EB1592 mov ecx,30h
00EB1597 mov eax,0CCCCCCCCh
00EB159C rep stos dword ptr es:[edi]
return a + b;
00EB159E mov eax,dword ptr [a]
00EB15A1 add eax,dword ptr [b]
}
00EB15A4 pop edi
00EB15A5 pop esi
00EB15A6 pop ebx
00EB15A7 mov esp,ebp
00EB15A9 pop ebp
00EB15AA ret
foo函数push ebp, mov ebp, esp后
保存原ebp,设定新的ebp为当前esp位置
sub esp, 0E4h
给局部变量分配足够大的栈空间
保存原先的一些寄存器值,每次push,esp继续向下移
为局部变量a数组赋值
调用goo前Push两个参数,esp继续下移
call goo函数时,cpu自动push下一条指令地址,esp继续下移
在goo函数中,同样保存foo函数中的ebp值,设定新的ebp,esp等
在执行玩goo函数最后几句指令时,edi, esi, ebx恢复,esp同时也编程goo中ebp的位置,ebp恢复至foo函数原来的位置(pop ebp)
下一条指令也装入IP(ret指令),esp继续向上一步
foo函数中的add esp, 8将esp值继续往上(清除函数参数)
清除函数参数的工作也可通过ret X在goo函数返回时设定(这样的话不必在每次调用点上加上add esp, X指令缩短了编译出来的文件大小,但在子函数中清除将不能做到printf等的可变参数个数功能,因为子函数不知道具体有多少要参数进入了,只有调用处才知道)
B. 汇编指令 rep movs dword ptr es:[edi],dword ptr ds:[esi]
rep:重复执行指令复
rep movs dword ptr es:[edi],dword ptr ds:[esi]
意思就是制将ESI指向的地址的值以4字节方式拷贝到EDI指向的地址中,重复执行ECX次,每次执行后ESI+4,EDI+4,ECX-1,OD中在这段代码中下断后按F7单步步入就可以观察到这3个寄存器的变化
C. MOV [EDI+ESI],10H可以吗
不可以
1.操作数宽度不明
2.基址/变址寄存器不能同时出现在统一操作数寻址
D. 麻烦找出汇编语言中这个指令的错误:mov [esi],[edi]
MOV指令中,源操作数和目的操作数不能同时为存储器操作数。
E. edi,esi寄存器是什么寄存器有什么作用
EDI和ESI分别是16位寄存器DI和SI的32位扩展
它们是目的变址寄存器和源变址寄存器,用于串操作指令中。
同时,它们也可以作为通用寄存器使用。
F. 这段汇编代码是什么意思,赋值过来又赋值过去的,怎么找到esi edi的来源呢
这就是内存拷贝啊
esi指向原内存首地址,edi指向目标内存首地址,
esi和edi应该是运行是确定的,用gdb调试一下就知道是什么值了
G. MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]什么意思
DWORD PTR ES:[EDI],将来ES:[EDI]这个内存强制转换为源dword双字类型,PTR就是转换符,DWORD为双字类型,在汇编中有BYTE,WORD,DWORD几种变量类型,分别对应1,2,4个字节。
整个语句的意思就是把
DWORD PTR DS:[ESI】内存单元的值传送到DWORD PTR ES:[EDI]单元保存,因为内存单元一般是2个字节的,这里强制转换为4个字节!
MOV 就是传送子令
H. 汇编中eax,ecx,edx,ebx,esp,ebp,esi,edi,eip分别是什么有什么用
这些来是32位的CPU中32位的寄存器的名字自。
寄存器是CPU内部的用于运行中暂存数据的存储单元。
在PC用的16位CPU 8086、8088中,寄存器的名字分别是AX(累加器),BX(基址寄存器),CX(计数寄存器),DX(数据寄存器),SP(堆栈指针),BP(基址指针),SI(源变址寄存器),DI(目的变址寄存器),IP(指令指针),等等……
这些寄存器除了从名字可以看得出来的用途以外,一部分寄存器也可以作为通用的一般数据寄存使用。具体每个寄存器的功能要与各种具体的指令关联起来才能理解清楚。
在386以上的32位CPU中,这些寄存器扩展成了32位的,名字就是在原来16位的名字前面加一个字母E,变成了EAX,EBX,…………
I. 汇编中mov esi,eax是什么意思!!!!
XXXX45A3 lea ecx, [esp+124h]
XXXX45AA push ecx ; IX86ver0.dll
XXXX45AB call ds:LoadLibraryA //加载DLL
XXXX45B1 mov ebp, eax //句柄从eax返回
XXXX45B3 test ebp, ebp
XXXX45B5 jz loc_6FF046F1 //没成功退出
XXXX45BB push offset aCheckrevision ; "CheckRevision" //函数名
XXXX45C0 push ebp ; hMole //DLL句柄
XXXX45C1 call ds:GetProcAddress //加载函数
XXXX45C7 mov esi, eax //执行地址从eax返回
XXXX45C9 test esi, esi
XXXX45CB jnz short loc_6FF045DF //成功转移,到正常主力,否则有些出错处理等操作.
XXXX45CD push offset aErrorFailedT_0 ; "<ERROR: Failed to execute Versioning DL"...
XXXX45D2 call nullsub_1 //错误,提示,等等
XXXX45D7 add esp, 4
XXXX45DA jmp loc_6FF046EA
//就存储空间来说,这里至少少了3~4个指令代码,因该是些有赋值操作,则带参数.
XXXX46E6 call esi ; CheckRevision
XXXX46E8 mov ebx, eax
就这些代码来说CheckRevision是没有带参数.
J. 汇编语言 esi,edi寄存器问题
都属于通用寄存器,所以一般场景下都可以随便用。就是有些传送指令规定了esi是源,edi是目的