逆向getchar与while循环的经典搭配

今天分析了两三个程序,连连受挫!

其中有一个程序是这样的:让用户输入一个字符串,统计字符串中字母,数字,空格,其他字符的个数并分别输出,源码:

#include <stdio.h>
#include <stdlib.h>
main()
{
//字符 英文字母字符个数,空格字符个数,数字字符个数,其他字符个数
char c;
int letters=0,space=0,digit=0,others=0;
printf("please input some characters\n");
//输入为\n就结束循环
while((c=getchar())!='\n')
{
if(c>='a'&&c<='z'||c>='A'&&c<='Z')//如果输入为a-z或A-Z字符
   letters++;
else if(c==' ')  //如果输入为空格字符
  space++;
else if(c>='0'&&c<='9') //如果是数字字符
   digit++;
else//如果是其他字符
   others++;
}
printf("all in all:char=%d space=%d digit=%d others=%d\n",letters,space,digit,others);//输出结果
}

再看看OD反汇编我就晕死了:(注:先不要看下面这一段,否则会打击你自信心。。)

00401000    53              push ebx

00401001    55              push ebp

00401002    56              push esi

00401003    57              push edi

00401004    68 60604000     push asm.00406060                                   ; ASCII "please input some characters

"

00401009    33ED            xor ebp,ebp

0040100B    33DB            xor ebx,ebx

0040100D    33FF            xor edi,edi

0040100F    33F6            xor esi,esi

00401011    E8 0C020000     call asm.00401222

00401016    83C4 04         add esp,4

00401019    A1 84604000     mov eax,dword ptr ds:[406084]

0040101E    48              dec eax

0040101F    A3 84604000     mov dword ptr ds:[406084],eax

00401024    78 11           js short asm.00401037

00401026    8B0D 80604000   mov ecx,dword ptr ds:[406080]                       ; asm.00406E40

0040102C    8A01            mov al,byte ptr ds:[ecx]

0040102E    41              inc ecx

0040102F    890D 80604000   mov dword ptr ds:[406080],ecx

00401035    EB 0D           jmp short asm.00401044

00401037    68 80604000     push asm.00406080

0040103C    E8 4F000000     call asm.00401090

00401041    83C4 04         add esp,4

00401044    3C 0A           cmp al,0A

00401046    74 28           je short asm.00401070

00401048    3C 61           cmp al,61

0040104A    7C 04           jl short asm.00401050

0040104C    3C 7A           cmp al,7A

0040104E    7E 08           jle short asm.00401058

00401050    3C 41           cmp al,41

00401052    7C 07           jl short asm.0040105B

00401054    3C 5A           cmp al,5A

00401056    7F 03           jg short asm.0040105B

00401058    45              inc ebp

00401059  ^ EB BE           jmp short asm.00401019

0040105B    3C 20           cmp al,20

0040105D    75 03           jnz short asm.00401062

0040105F    43              inc ebx

00401060  ^ EB B7           jmp short asm.00401019

00401062    3C 30           cmp al,30

00401064    7C 07           jl short asm.0040106D

00401066    3C 39           cmp al,39

00401068    7F 03           jg short asm.0040106D

0040106A    47              inc edi

0040106B  ^ EB AC           jmp short asm.00401019

0040106D    46              inc esi

0040106E  ^ EB A9           jmp short asm.00401019

00401070    56              push esi

00401071    57              push edi

00401072    53              push ebx

00401073    55              push ebp

00401074    68 30604000     push asm.00406030                                   ; ASCII "all in all:char=%d space=%d digit=%d others=%d

"

00401079    E8 A4010000     call asm.00401222

0040107E    83C4 14         add esp,14

00401081    5F              pop edi

00401082    5E              pop esi

00401083    5D              pop ebp

00401084    5B              pop ebx

00401085    C3              retn

-----------------------------------------------------------

00401016    83C4 04         add esp,4

到这来的时候我还能说句,so far so good

之后的代码真的是一头雾水了,虽然知道那连续的jg jmp跳转正是嵌套的 if else,但却早已经被类似下面的这些代码击溃了我的自信心了,所以下面的代码自然:无眼睇啦!

00401019    A1 84604000     mov eax,dword ptr ds:[406084]

0040101E    48              dec eax

0040101F    A3 84604000     mov dword ptr ds:[406084],eax

00401024    78 11           js short asm.00401037

00401026    8B0D 80604000   mov ecx,dword ptr ds:[406080]      

然后我放下这个程序,又拿起另外一个程序来分析,谁知道又是上面的这些鬼代码,不知所云,但是至此我已经找到一个共同点了,就是这些我分析不通的程序都有这样的一个程序框架:

while((c=getchar())!='\n')

{

跳转………

跳过来………

又跳过去………

又跳回来…………

再跳过去………………

………………………………

}

看来产生那些我看不懂的汇编代码的罪归祸首就是while((c=getchar())!='\n')

而下面的函数体中的跳转只是作了一个干扰我的思路的东西

于是我把函数体全部删去,于是源码成了这样:

//字符 英文字母字符个数,空格字符个数,数字字符个数,其他字符个数

char c;

int letters=0,space=0,digit=0,others=0;

printf("please input some characters\n");

//输入为\n就结束循环

while((c=getchar())!='\n')

{

}

printf("end");//输出结果

}

再反汇编分析一下,情况就明朗多了!

00401000    68 34604000     push asm.00406034                                   ; ASCII "please input some characters

"

00401005    E8 D8010000     call asm.004011E2                                   ; 输出字符串

0040100A    83C4 04         add esp,4                                           ; 恢复堆栈

0040100D    A1 5C604000     mov eax,dword ptr ds:[40605C]                       ; 可见此处为字符串的字符个数

00401012    48              dec eax

00401013    A3 5C604000     mov dword ptr ds:[40605C],eax                       ; 字符个数减1

00401018    78 11           js short asm.0040102B                               ; 如果是字符个数是负数的话就要去getchar

0040101A    8B0D 58604000   mov ecx,dword ptr ds:[406058]                       ; 莫非是将getchar存放字符的那片缓冲区首地址赋值给ecx?事实证明是的

00401020    8A01            mov al,byte ptr ds:[ecx]                            ; 取第一个字符到al

00401022    41              inc ecx                                             ; ecx++

00401023    890D 58604000   mov dword ptr ds:[406058],ecx                       ; 把第二个字符放到第一个字符那里

00401029    EB 0D           jmp short asm.00401038                              ; 如果js跳转语句执行时,S0,即运算结果为正数时,将导致执行到此处,即跳过了getchar()

0040102B    68 58604000     push asm.00406058

00401030    E8 1B000000     call asm.00401050                                   ; getchar()

00401035    83C4 04         add esp,4

00401038    3C 0A           cmp al,0A                                           ; 上次的笔记已经说过了,0A就是换行符 呵呵

0040103A  ^ 75 D1           jnz short asm.0040100D                              ; 不是换行符就给我继续循环下去!

0040103C    68 30604000     push asm.00406030                                   ; ASCII "end"

00401041    E8 9C010000     call asm.004011E2                                   ; 输出end

00401046    59              pop ecx

00401047    C3              retn

总结下:

我怎么知道40605C地址处为字符个数呢??因为在OD里看的。。。我输入了abcde,这个地址在数据窗口中就显示了5,输入ab就显示2,所以嘛,搞逆向就要心静,注意哪些数据可疑的,值得关注的,通常要两只眼睛看四个个窗口,you know,汇编代码窗口,寄存器窗口,堆栈窗口,数据窗口,当然,那个注释窗口也挺重要的,不过它只跟踪了当前执行指令的一些数据情况



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值