首页
社区
课程
招聘
[求助]关于printf函数异常的汇编跟踪
发表于: 2009-5-22 20:36 6463

[求助]关于printf函数异常的汇编跟踪

2009-5-22 20:36
6463
首先,来看下这段代码

#include <stdio.h>
#include <string.h>

int main()
{
__int64 i = 0xffffffffff; // 长度超过4个字节就异常
//__int64 i = 0xffffffff; // 长度不超过4个字节就正常
printf("%d %s", i ,"hello");
return 0;
}


由于在windows下看不到printf函数的资源文件,我就试图用vc的反汇编看了下代码,异常到了这里

00401A66 cmp dword ptr [precision],0FFh
00401A6D jne $L1748+15h (00401a7b)
00401A6F mov dword ptr [ebp-2A4h],7FFFFFFFh
00401A79 jmp $L1748+21h (00401a87)
00401A7B mov eax,dword ptr [precision]
00401A81 mov dword ptr [ebp-2A4h],eax
00401A87 mov ecx,dword ptr [ebp-2A4h]
00401A8D mov dword ptr ,ecx
00401A93 lea edx,[argptr]
00401A96 push edx
00401A97 call get_int_arg (004023e0)
00401A9C add esp,4
00401A9F mov dword ptr [text],eax
00401AA2 mov eax,dword ptr [flags]
00401AA5 and eax,810h
00401AAA test eax,eax
00401AAC je $L1748+0B0h (00401b16)
00401AAE cmp dword ptr [text],0
00401AB2 jne $L1748+57h (00401abd)
00401AB4 mov ecx,dword ptr [___wnullstring (00425a50)]
00401ABA mov dword ptr [text],ecx
00401ABD mov dword ptr [bufferiswide],1
00401AC4 mov edx,dword ptr [text]
00401AC7 mov dword ptr [pwch],edx
00401ACD mov eax,dword ptr
00401AD3 mov ecx,dword ptr
00401AD9 sub ecx,1
00401ADC mov dword ptr ,ecx
00401AE2 test eax,eax
00401AE4 je $L1748+0A0h (00401b06)
00401AE6 mov edx,dword ptr [pwch]
00401AEC xor eax,eax
00401AEE mov ax,word ptr [edx]
00401AF1 test eax,eax
00401AF3 je $L1748+0A0h (00401b06)
00401AF5 mov ecx,dword ptr [pwch]
00401AFB add ecx,2
00401AFE mov dword ptr [pwch],ecx
00401B04 jmp $L1748+67h (00401acd)
00401B06 mov edx,dword ptr [pwch]
00401B0C sub edx,dword ptr [text]
00401B0F sar edx,1
00401B11 mov dword ptr [textlen],edx
00401B14 jmp $L1748+10Ah (00401b70)
00401B16 cmp dword ptr [text],0
00401B1A jne $L1748+0BEh (00401b24)
00401B1C mov eax,[___nullstring (00425a4c)]
00401B21 mov dword ptr [text],eax
00401B24 mov ecx,dword ptr [text]
00401B27 mov dword ptr

,ecx
00401B2D mov edx,dword ptr
00401B33 mov eax,dword ptr
00401B39 sub eax,1
00401B3C mov dword ptr ,eax
00401B42 test edx,edx
00401B44 je $L1748+0FEh (00401b64)
00401B46 mov ecx,dword ptr


00401B4C movsx edx,byte ptr [ecx] ;到这句话挂掉了
00401B4F test edx,edx
00401B51 je $L1748+0FEh (00401b64)
00401B53 mov eax,dword ptr


00401B59 add eax,1
00401B5C mov dword ptr

,eax
00401B62 jmp $L1748+0C7h (00401b2d)
00401B64 mov ecx,dword ptr


00401B6A sub ecx,dword ptr [text]
00401B6D mov dword ptr [textlen],ecx
00401B70 jmp COMMON_INT+272h (00401fd7)



我跟了2个小时,还是没有找到原因,请高手指点下,让我这个周末没有遗憾

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (13)
雪    币: 508
活跃值: (89)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
2
自己狠狠顶一下
2009-5-22 21:17
0
雪    币: 184
活跃值: (65)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
3
printf("%I64d %s", i ,"hello");
2009-5-22 21:20
0
雪    币: 508
活跃值: (89)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
4
楼上是一种解决方法,但不是我想问的,楼下继续
2009-5-22 21:35
0
雪    币: 184
活跃值: (65)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
5
__int64 i = 0xffffffffff;  
的时候你看他传了几个参数给printf
00401028 |. C745 F8 FFFFFFFF mov [local.2],-1
0040102F |. C745 FC FF000000 mov [local.1],0FF ;以上2句 i = 0xffffffffff
00401036 |. 68 24004200 push 12313213.00420024 ; ASCII "hello"
0040103B |. 8B45 FC mov eax,[local.1]
0040103E |. 50 push eax ; /<%s>
0040103F |. 8B4D F8 mov ecx,[local.2] ; |
00401042 |. 51 push ecx ; |<%d>
00401043 |. 68 840F4200 push 12313213.00420F84 ; |format = "%d %s"
00401048 |. E8 33000000 call 12313213.printf ; \printf


你要是
__int64 i = 0xffffffffff;  
printf("%d%d %s", i ,"hello");
这样也不会异常
2009-5-22 22:02
0
雪    币: 508
活跃值: (89)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
6
问题是出在printf的内部,外面push的次数都是一样的,没有明白楼上想表达什么?请指点
2009-5-22 22:08
0
雪    币: 184
活跃值: (65)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
7
int i=1;
printf('%d',i, i);
如果这样为什么出错你理解了,那上面也这个意思。
2009-5-22 22:09
0
雪    币: 184
活跃值: (65)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
8
0040103B       |.  8B45 FC                 mov eax,[local.1]
0040103E       |.  50                      push eax                                        ; /<%s>
这个。eax值是0xff.正常时候是传的字串首地址,现在传了0xff,然后要去访问0xff内存地址上的东西,当然会异常了。
2009-5-22 22:15
0
雪    币: 437
活跃值: (273)
能力值: ( LV12,RANK:240 )
在线值:
发帖
回帖
粉丝
9
http://bbs.pediy.com/showthread.php?t=38234&viewgoodnees=1&prefixid=
2009-5-22 22:21
0
雪    币: 105
活跃值: (10)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
10
去看MSDN中printf format specifications部分的内容,你的格式字段要和参数保持一致,这是个规定。把握不好会出错。
你给的%d字段在32位机中只能是4个字节,你又非要给它8个字去输出,多出来部分怎么办呢,直接给下一个参数吧,而字符串地址就由想要输出的"Hello"变成了前面8个字节的高32位(即为0xff),哪有字符串的地址为0xff呢,系统就直接给出的异常.
你可以用"%d %d %s"来验证64位整数下的输出情况,就晓得了。
2009-5-22 22:43
0
雪    币: 508
活跃值: (89)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
11
开始我也是这样理解的,事实上我通过google给出的解释也是这样的,4个字节的偏移造成的访问地址出错,但我的疑问是当我传
__int64 i = 0xffffffff;        // 长度不超过4个字节就正常
的时候,反汇编代码如下:

00401036 push offset string "hello" (00423fe0)
0040103B mov eax,dword ptr [ebp-4]
0040103E push eax
0040103F mov ecx,dword ptr [ebp-8]
00401042 push ecx
00401043 push offset string "%d %s" (0042301c)
00401048 call printf (00401080)
0040104D add esp,10h



和传>4个字节的值压栈方式没什么区别?那么深一层次的说,问题到底是在哪里不一样了呢?我开始的怀疑是如果是传入<=4 byte的__int64也会当作4个字节来优化处理的,但反汇编代码不是这样的,所以我的疑惑还是没有解决
2009-5-22 22:54
0
雪    币: 184
活跃值: (65)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
12
那是因为你传的0,也就是NULL。相当于
format("%d %s", i的低4字节, NULL, "hello");
2009-5-22 23:24
0
雪    币: 508
活跃值: (89)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
13
了解了一点
楼上能附上关键的汇编代码吗?(有注释的)
2009-5-22 23:53
0
雪    币: 184
活跃值: (65)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
14
内容如下:
00401028 |. C745 F8 FFFFFFFF mov [local.2],-1 ;低4字节0xffffffff
0040102F |. C745 FC 00000000 mov [local.1],0 ;高4字节0,以上2句 i = 0xffffffff;
00401036 |. 68 24004200 push 12313123.00420024 ; ASCII "hello"
0040103B |. 8B45 FC mov eax,[local.1]
0040103E |. 50 push eax ; /<%s> eax = 0
0040103F |. 8B4D F8 mov ecx,[local.2] ; |
00401042 |. 51 push ecx ; |<%d> ecx= 0xffffffff
00401043 |. 68 1C004200 push 12313123.0042001C ; |format = "%d %s"
00401048 |. E8 33000000 call 12313123.printf ; \printf


自己跟踪一遍就明白了。
2009-5-23 00:09
0
游客
登录 | 注册 方可回帖
返回
//