欢迎光临!
若无相欠,怎会相见

反汇编学习-C语言实例解析精粹-实例3求整数之积

序言

为了提高可读性,我添加了这一段,另外由于我用的是VS2017,会出现一些奇怪的错误,也一并在这里解决。

例如本次出现了这个错误(安全检查错误):错误 C4996 ‘scanf’: This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. Project1 e:\projects\c\project1\project1\no.3.c 17

解决办法:#define _CRT_SECURE_NO_WARNINGS 在代码中加上这个宏定义,最好是在最上方加。其他方法自行问度娘。

C代码

这个实例很简单,就是计算两个整数的乘积,下面看代码:

/*
算法:
{
    提示用户输入数据;
    输入变量x和y的值;
    计算乘积;
    输出乘积;
}
*/

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

int main()
{
    int x, y, m;
    printf("Please input x and y\n");
    scanf("%d %d", &x, &y);
    m = x * y;
    printf("%d * %d = %d\n", x, y, m);
    getchar();
    getchar();
    return 0;
}

我对书中的代码稍稍添加了一些,getchar() 函数防止运行的时候一闪而过。

汇编代码

我在 int main 处下的断点,直接调试查看反汇编代码,如下:

--- e:\projects\c\project1\project1\no.3.c -------------------------------------
     1: /*
     2: 算法:
     3: {
     4:     提示用户输入数据;
     5:     输入变量x和y的值;
     6:     计算乘积;
     7:     输出乘积;
     8: }
     9: */
    10: 
    11: #define _CRT_SECURE_NO_WARNINGS
    12: 
    13: #include <stdio.h>
    14: 
    15: int main()
    16: {
00171920 55                   push        ebp    # 开始老套路,提升堆栈,开辟缓冲区,保存现场
00171921 8B EC                mov         ebp,esp  
00171923 81 EC E8 00 00 00    sub         esp,0E8h  
00171929 53                   push        ebx  
0017192A 56                   push        esi  
0017192B 57                   push        edi  
0017192C 8D BD 18 FF FF FF    lea         edi,[ebp-0E8h]  
00171932 B9 3A 00 00 00       mov         ecx,3Ah  
00171937 B8 CC CC CC CC       mov         eax,0CCCCCCCCh  
0017193C F3 AB                rep stos    dword ptr es:[edi]  
0017193E A1 04 A0 17 00       mov         eax,dword ptr [__security_cookie (017A004h)]  
00171943 33 C5                xor         eax,ebp  
00171945 89 45 FC             mov         dword ptr [ebp-4],eax  
00171948 B9 03 C0 17 00       mov         ecx,offset _00E4A959_no@3@c (017C003h)  
0017194D E8 C5 F8 FF FF       call        @__CheckForDebuggerJustMyCode@4 (0171217h)  
    17:     int x, y, m;
    18:     printf("Please input x and y\n");
00171952 68 30 7B 17 00       push        offset string "Please input x and y\n" (0177B30h) //从内存中取出,压入堆栈中 
00171957 E8 EF F6 FF FF       call        _printf (017104Bh)   //调用函数
0017195C 83 C4 04             add         esp,4   // 外平栈,一个参数+4,就是上面的字符串
    19:     scanf("%d %d", &x, &y);
0017195F 8D 45 E8             lea         eax,[y]   //取局部变量y的地址,存入eax寄存器
00171962 50                   push        eax  //将eax压入堆栈
00171963 8D 4D F4             lea         ecx,[x]   //同上
00171966 51                   push        ecx  
00171967 68 4C 7B 17 00       push        offset string "%d %d" (0177B4Ch)  
0017196C E8 2F F7 FF FF       call        _scanf (01710A0h)  
00171971 83 C4 0C             add         esp,0Ch  // C是十进制的12,也就是由三个参数 
    20:     m = x * y;
00171974 8B 45 F4             mov         eax,dword ptr [x]   //将内存地址为变量x的地址中数据存入eax中
00171977 0F AF 45 E8          imul        eax,dword ptr [y]   //有符号乘法运算,在将Y中的数据与eax进行有符号乘法运算
                                                              //结果存入eax寄存器
0017197B 89 45 DC             mov         dword ptr [m],eax   //将eax中的结果存入变量m的内存地址中
    21:     printf("%d * %d = %d\n", x, y, m);
0017197E 8B 45 DC             mov         eax,dword ptr [m]   //下面的都不难理解,不一一叙说
00171981 50                   push        eax  
00171982 8B 4D E8             mov         ecx,dword ptr [y]  
00171985 51                   push        ecx  
00171986 8B 55 F4             mov         edx,dword ptr [x]  
00171989 52                   push        edx  
0017198A 68 54 7B 17 00       push        offset string "%d * %d = %d\n" (0177B54h)  
0017198F E8 B7 F6 FF FF       call        _printf (017104Bh)  
00171994 83 C4 10             add         esp,10h  
    22:     getchar();
00171997 8B F4                mov         esi,esp  
00171999 FF 15 70 B1 17 00    call        dword ptr [__imp__getchar (017B170h)]  
0017199F 3B F4                cmp         esi,esp  
    22:     getchar();
001719A1 E8 7B F8 FF FF       call        __RTC_CheckEsp (0171221h)  
    23:     getchar();
001719A6 8B F4                mov         esi,esp  
001719A8 FF 15 70 B1 17 00    call        dword ptr [__imp__getchar (017B170h)]  
001719AE 3B F4                cmp         esi,esp  
001719B0 E8 6C F8 FF FF       call        __RTC_CheckEsp (0171221h)  
    24:     return 0;
001719B5 33 C0                xor         eax,eax  
    25: }

就截取这些代码,main函数后的检查esp是否正常的代码就没截取。

0177B30h 内存信息,存着要打印出来的字符串:

新接触了一个指令:imul 指令意思是有符号数乘法运算,拓展一下, mul 是无符号数的乘法运算,指令格式如下:

IMUL al,r/m8 : AX <= AL * r/m
IMUL ax,r/m16 : DX:AX <= AX * r/m
IMUL eax,r/m32 : EDX:EAX <= EAX * r/m
IMUL r16,r/m16 : 字寄存器 <= 字寄存器 * r/m
IMUL r32,r/m32 : 双字寄存器 <= 双字寄存器 * r/m 双字
IMUL r16,r/m16,imm8 : 字寄存器 <= r/m16 * 符号扩展的立即数字节
IMUL r32,r/m32,imm8 : 双字寄存器 r/m32 * 符号扩展的立即数字节
IMUL r16,imm8 : 字寄存器 <= 字寄存器 * 符号扩展的立即数字节
IMUL r32,imm8 : 双字寄存器 <= 双字寄存器 * 符号扩展的立即数字节
IMUL r16,r/m16,imm16 : 字寄存器 <= r/m16 * 立即数字
IMUL r32,r/m32,imm32 : 双字寄存器 <= r/m32 * 立即数双字
IMUL r16,imm16 : 字寄存器 <= r/m16 * 立即数字
IMUL r32,imm32 : 双字寄存器 <= r/m32 * 立即数双字

r表示寄存器,32,16表示位数

m表示内存

imm表示立即数

结语

又学习了一部分,之前还没在反汇编代码中遇到imul,见得太少了,要多加练习。

PS:今天早上接到通知,要出差,很懵逼,第一次出差哎~,还好有同事一块,希望一切顺利!

如有错误,敬请指出,感谢指正!    —2019-05-15 22:00:51    于苏州

赞(0) 打赏
转载请注明:飘零博客 » 反汇编学习-C语言实例解析精粹-实例3求整数之积
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

欢迎光临