逆向把字符串输入到指定文件的程序

这个程序是我们刚开始学C语言文件操作的一个小程序了,应该很熟悉了,这篇分析文章中大量的运用到了上一篇笔记(分析getchar和while的搭配)所介绍的知识,所以,上一篇算是一个,铺垫吧!
本次分析出现大量的形如此的代码,就是上一篇我们介绍的代码:
0040103F  |> \A1 5C904000   mov eax,dword ptr ds:[40905C]                      ;  
00401044  |.  48            dec eax
00401045  |.  A3 5C904000   mov dword ptr ds:[40905C],eax
0040104A  |.  78 0F         js short asm.0040105B                              ;  
0040104C  |.  A1 58904000   mov eax,dword ptr ds:[409058]                      ;  
00401051  |.  8A18          mov bl,byte ptr ds:[eax]                           ;  
00401053  |.  40            inc eax
00401054  |.  A3 58904000   mov dword ptr ds:[409058],eax                      ;  
00401059  |.  EB 0F         jmp short asm.0040106A
0040105B  |>  68 58904000   push asm.00409058                                  ;  
00401060  |.  E8 C0020000   call asm.00401325                                  ;  
00401065  |.  83C4 04       add esp,4
00401068  |.  8AD8          mov bl,al
0040106A  |>  80FB 23       cmp bl,23                                          ;  

我也写了那么一点注释,不过由于经过上篇的介绍,大家对这样的代码已经有点熟悉了吧,接下来看点注释,不懂的要多思考,上OD独立分析。

程序源代码:

#include "stdio.h"
main()
{ 
    //文件指针,字符,文件名
    FILE *fp;
    char ch,filename[10];

    //打开文件
    scanf("%s",filename);
    if((fp=fopen(filename,"w"))==NULL)
    {
        printf("cannot open file/n");
        exit(0);
    }
    
    //循环接收字符,直到收到#退出
    ch=getchar();
    
    while(ch!='#')
    {
    fputc(ch,fp);//打印在文件
    putchar(ch);//打印在屏幕
    ch=getchar();//接收字符
    }
    //释放文件
    fclose(fp);
    system("pause");
}
OD反汇编代码:
00401000  /$  83EC 0C       sub esp,0C                                         ;  malloc->12个字节
00401003  |.  8D4424 00     lea eax,dword ptr ss:[esp]                         ;  eax=12个字节缓冲区首地址
00401007  |.  53            push ebx
00401008  |.  57            push edi
00401009  |.  50            push eax                                           ;  只有本条和下面一条压栈指令是参数传递,上面的两条是保存寄存器
0040100A  |.  68 50904000   push asm.00409050                                  ;  ASCII "%s"
0040100F  |.  E8 09060000   call asm.0040161D                                  ;  //这一句执行之后40905c变成了1,尽管我输入的是c:\d.txt
00401014  |.  8D4C24 10     lea ecx,dword ptr ss:[esp+10]                      ;  esp+10H就是esp+16,就是跳过之前压入的4个寄存器,来到12字节缓冲区,就是字符串存放的地方了
00401018  |.  68 4C904000   push asm.0040904C                                  ;  在数据窗口看到是00000077h->119D->ascii"w"
0040101D  |.  51            push ecx                                           ;  文件名了
0040101E  |.  E8 E7050000   call asm.0040160A                                  ;  fopen
00401023  |.  8BF8          mov edi,eax                                        ;  fopen返回文件指针或错误判断值到eax
00401025  |.  83C4 10       add esp,10                                         ;  终于舍得恢复4个变量的堆栈了(至此之前压入的参数已经恢复,ebx和edi还没恢复)
00401028  |.  85FF          test edi,edi
0040102A  |.  75 13         jnz short asm.0040103F                             ;  跳不过去的话就输出错误信息然后退出程序
0040102C  |.  68 38904000   push asm.00409038                                  ;  ASCII "cannot open file/n"
00401031  |.  E8 83050000   call asm.004015B9                                  ;  printf
00401036  |.  57            push edi
00401037  |.  E8 A8040000   call asm.004014E4                                  ;  exit
0040103C  |.  83C4 08       add esp,8
0040103F  |>  A1 5C904000   mov eax,dword ptr ds:[40905C]                      ;  又是你!40905C,存放的是字符串的字符数(为什么?我已经在上个笔记说过了,you know,getchar与while的那篇)
00401044  |.  48            dec eax
00401045  |.  A3 5C904000   mov dword ptr ds:[40905C],eax
0040104A  |.  78 0F         js short asm.0040105B                              ;  这里的运算结果不为负数不是因为没把文件字符串遍历完,而是因为还有一个\n没遍历,所以导致下面最近的一个getchar并不执行,而下面有一个cmp,\n和#自然不同,所以je也没跳转了
0040104C  |.  A1 58904000   mov eax,dword ptr ds:[409058]                      ;  将文件名字符串的首地址传给eax
00401051  |.  8A18          mov bl,byte ptr ds:[eax]                           ;  第一个字节内容给bl
00401053  |.  40            inc eax
00401054  |.  A3 58904000   mov dword ptr ds:[409058],eax                      ;  将第二个字符放到原先的第一个字符的位置去
00401059  |.  EB 0F         jmp short asm.0040106A
0040105B  |>  68 58904000   push asm.00409058                                  ;  我们貌似没有传参到getchar啊,怎么有push?原来getchar隐含地传递了一个指向字符串缓冲区的指针(注意是二级指针)
00401060  |.  E8 C0020000   call asm.00401325                                  ;  getchar
00401065  |.  83C4 04       add esp,4
00401068  |.  8AD8          mov bl,al
0040106A  |>  80FB 23       cmp bl,23                                          ;  ascii"23"是#
0040106D  |.  74 6F         je short asm.004010DE                              ;  等于#的话就退出了,否则就执行循环体的内容吧
0040106F  |.  56            push esi                                           ;  保存esi
00401070  |>  0FBEF3        /movsx esi,bl                                      ;  bl扩展成32位送到esi(bl放的可是当前的字符啊)
00401073  |.  57            |push edi                                          ;  还记得吗?00401023地址处我们将文件的指针赋值给edi了:mov edi,eax
00401074  |.  56            |push esi                                          ;  这里又是一个字符,所以呢。。嘿嘿
00401075  |.  E8 87020000   |call asm.00401301                                 ;  所以这里就是fputc函数了!
0040107A  |.  A1 7C904000   |mov eax,dword ptr ds:[40907C]                     ;  这里存放的又是字符串长度了
0040107F  |.  83C4 08       |add esp,8                                         ;  咦,忘了恢复堆栈,好了,恢复好了。。
00401082  |.  48            |dec eax
00401083  |.  A3 7C904000   |mov dword ptr ds:[40907C],eax
00401088  |.  78 15         |js short asm.0040109F                             ;  字符串长度为负数,那就去getchar吧
0040108A  |.  8B15 78904000 |mov edx,dword ptr ds:[409078]
00401090  |.  881A          |mov byte ptr ds:[edx],bl
00401092  |.  A1 78904000   |mov eax,dword ptr ds:[409078]
00401097  |.  40            |inc eax
00401098  |.  A3 78904000   |mov dword ptr ds:[409078],eax
0040109D  |.  EB 0E         |jmp short asm.004010AD
0040109F  |>  68 78904000   |push asm.00409078                                 ; /Arg2 = 00409078
004010A4  |.  56            |push esi                                          ; |Arg1
004010A5  |.  E8 42010000   |call asm.004011EC                                 ; \注意这里可不是getchar,应该是输出字符到屏幕,就就是putchar函数了
004010AA  |.  83C4 08       |add esp,8
004010AD  |>  A1 5C904000   |mov eax,dword ptr ds:[40905C]
004010B2  |.  48            |dec eax
004010B3  |.  A3 5C904000   |mov dword ptr ds:[40905C],eax
004010B8  |.  78 0F         |js short asm.004010C9
004010BA  |.  A1 58904000   |mov eax,dword ptr ds:[409058]
004010BF  |.  8A18          |mov bl,byte ptr ds:[eax]
004010C1  |.  40            |inc eax
004010C2  |.  A3 58904000   |mov dword ptr ds:[409058],eax
004010C7  |.  EB 0F         |jmp short asm.004010D8
004010C9  |>  68 58904000   |push asm.00409058                                 ;  我们貌似没有传参到getchar啊,怎么有push?原来getchar隐含地传递了一个指向字符串缓冲区的指针(注意是二级指针)
004010CE  |.  E8 52020000   |call asm.00401325                                 ;  getchar
004010D3  |.  83C4 04       |add esp,4
004010D6  |.  8AD8          |mov bl,al
004010D8  |>  80FB 23       |cmp bl,23
004010DB  |.^ 75 93         \jnz short asm.00401070
004010DD  |.  5E            pop esi
004010DE  |>  57            push edi
004010DF  |.  E8 B2000000   call asm.00401196                                  ;  fclose(fp);
004010E4  |.  68 30904000   push asm.00409030                                  ;  ASCII "pause"
004010E9  |.  E8 12000000   call asm.00401100                                  ;  system("pause");
004010EE  |.  83C4 08       add esp,8
004010F1  |.  5F            pop edi
004010F2  |.  5B            pop ebx
004010F3  |.  83C4 0C       add esp,0C
004010F6  \.  C3            retn  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值