/******************************************************/
//下面这段代码是VC6.0调试器反汇编后的结果
//原本是想随便写个小程序观察反汇编代码
//问题的出现:当用OD调试(debug文件夹的fread_fwrite.exe)的时候,提示打开文件失败
//提出问题:为什么同一个程序在VC和OD的调试下会出现不同结果?
//如果读者愿意和我一起度过这个旅途的话,请不要忘记在程序文件夹下建立这个文件"zhang.pdf"(文件随便即可);最好源程序和这里一样,调试时方便对照.
/*******************************************************/
1:    // fread_fwrite.cpp : Defines the entry point for the console application.
2:    //
3:
4:    #include "stdafx.h"
5:    #include "iostream.h"
6:    #include "stdio.h"
7:    #include <windows.h>
8:
9:    int main(int argc, char* argv[])
10:   {
00401040   push        ebp
00401041   mov         ebp,esp
00401043   sub         esp,60h
00401046   push        ebx
00401047   push        esi
00401048   push        edi
00401049   lea         edi,[ebp-60h]
0040104C   mov         ecx,18h
00401051   mov         eax,0CCCCCCCCh
00401056   rep stos    dword ptr [edi]
11:       FILE *f_open=fopen("zhang.pdf","rb");
00401058   push        offset string "rb" (00428064)
0040105D   push        offset string "zhang.pdf" (00428058)
00401062   call        fopen (00404800)
00401067   add         esp,8
0040106A   mov         dword ptr [ebp-4],eax
12:       FILE *f_write=fopen("test3.pdf","wb+");
0040106D   push        offset string "wb+" (00428054)
00401072   push        offset string "test3.pdf" (00428048)
00401077   call        fopen (00404800)
0040107C   add         esp,8
0040107F   mov         dword ptr [ebp-8],eax
13:
14:       if(f_open==NULL)
00401082   cmp         dword ptr [ebp-4],0
00401086   jne         main+0B1h (004010f1)
15:       {
16:           cout<<"OPEN--WRONG!"<<endl;
00401088   push        offset @ILT+10(endl) (0040100f)
0040108D   push        offset string "OPEN--WRONG!" (00428038)
00401092   mov         ecx,offset cout (0042b9c0)
00401097   call        ostream::operator<< (00401720)
0040109C   mov         ecx,eax
0040109E   call        @ILT+0(ostream::operator<< ) (00401005)
17:           getchar();
004010A3   mov         eax,[__iob+4 (0042ade4)]
004010A8   sub         eax,1
004010AB   mov         [__iob+4 (0042ade4)],eax
004010B0   cmp         dword ptr [__iob+4 (0042ade4)],0
004010B7   jl          main+9Ah (004010da)
004010B9   mov         ecx,dword ptr [__iob (0042ade0)]
004010BF   movsx       edx,byte ptr [ecx]
004010C2   and         edx,0FFh
004010C8   mov         dword ptr [ebp-1Ch],edx
004010CB   mov         eax,[__iob (0042ade0)]
004010D0   add         eax,1
004010D3   mov         [__iob (0042ade0)],eax
004010D8   jmp         main+0AAh (004010ea)
004010DA   push        offset __iob (0042ade0)
004010DF   call        _filbuf (004043e0)
004010E4   add         esp,4
004010E7   mov         dword ptr [ebp-1Ch],eax
18:           exit(0);
004010EA   push        0
004010EC   call        exit (00404250)
19:       }
20:
21:       if(f_write==NULL)
004010F1   cmp         dword ptr [ebp-8],0
004010F5   jne         main+123h (00401163)
22:       {
23:           cout<<"WRITE--WRONG!"<<endl;
004010F7   push        offset @ILT+10(endl) (0040100f) //可看作特征字串
004010FC   push        offset string "WRITE--WRONG!" (00428028)
00401101   mov         ecx,offset cout (0042b9c0)) //可看作特征字串
00401106   call        ostream::operator<< (00401720) //输出经过push的字串
0040110B   mov         ecx,eax //以每一个push为一个输出单位,且指针后移
0040110D   call        @ILT+0(ostream::operator<< ) (00401005)
             //可以这么说,在cout流中有几个输出项会对应几个push项和call ostream项
24:           getchar();
00401112   mov         ecx,dword ptr [__iob+4 (0042ade4)]
00401118   sub         ecx,1
0040111B   mov         dword ptr [__iob+4 (0042ade4)],ecx
00401121   cmp         dword ptr [__iob+4 (0042ade4)],0
00401128   jl          main+10Ch (0040114c)
0040112A   mov         edx,dword ptr [__iob (0042ade0)]
00401130   movsx       eax,byte ptr [edx]
00401133   and         eax,0FFh
00401138   mov         dword ptr [ebp-20h],eax
0040113B   mov         ecx,dword ptr [__iob (0042ade0)]
00401141   add         ecx,1
00401144   mov         dword ptr [__iob (0042ade0)],ecx
0040114A   jmp         main+11Ch (0040115c)
0040114C   push        offset __iob (0042ade0)
00401151   call        _filbuf (004043e0)
00401156   add         esp,4
00401159   mov         dword ptr [ebp-20h],eax
25:           exit(0);
0040115C   push        0
0040115E   call        exit (00404250)
26:       }
27:
28:       fseek(f_open,0,2);//用OD调试时会在这里出现错误,提示exception:str!=NULL;
00401163   push        2
00401165   push        0
00401167   mov         edx,dword ptr [ebp-4]
0040116A   push        edx
0040116B   call        fseek (004040e0)
00401170   add         esp,0Ch
29:
30:       long length=ftell(f_open);
00401173   mov         eax,dword ptr [ebp-4]
00401176   push        eax
00401177   call        ftell (00403e50)
0040117C   add         esp,4
0040117F   mov         dword ptr [ebp-0Ch],eax
31:       cout<<"length:"<<length<<endl;
00401182   push        offset @ILT+10(endl) (0040100f)
00401187   mov         ecx,dword ptr [ebp-0Ch]
0040118A   push        ecx
0040118B   push        offset string "length:" (0042801c)
00401190   mov         ecx,offset cout (0042b9c0)
00401195   call        ostream::operator<< (00401720)
0040119A   mov         ecx,eax
0040119C   call        ostream::operator<< (004013f0)
004011A1   mov         ecx,eax
004011A3   call        @ILT+0(ostream::operator<< ) (00401005)
32:       rewind(f_open);
004011A8   mov         edx,dword ptr [ebp-4]
004011AB   push        edx
004011AC   call        rewind (00403d80)
004011B1   add         esp,4
33:
34:       char *buffer=new char[length];
004011B4   mov         eax,dword ptr [ebp-0Ch]
004011B7   push        eax
004011B8   call        operator new (00403d60)
004011BD   add         esp,4
004011C0   mov         dword ptr [ebp-14h],eax
004011C3   mov         ecx,dword ptr [ebp-14h]
004011C6   mov         dword ptr [ebp-10h],ecx
35:       fread(buffer,length,1,f_open);
004011C9   mov         edx,dword ptr [ebp-4]
004011CC   push        edx
004011CD   push        1
004011CF   mov         eax,dword ptr [ebp-0Ch]
004011D2   push        eax
004011D3   mov         ecx,dword ptr [ebp-10h]
004011D6   push        ecx
004011D7   call        fread (00403b90)
004011DC   add         esp,10h
36:       fwrite(buffer,length,1,f_write);
004011DF   mov         edx,dword ptr [ebp-8]
004011E2   push        edx
004011E3   push        1
004011E5   mov         eax,dword ptr [ebp-0Ch]
004011E8   push        eax
004011E9   mov         ecx,dword ptr [ebp-10h]
004011EC   push        ecx
004011ED   call        fwrite (00403970)
004011F2   add         esp,10h
37:
38:       delete buffer;
004011F5   mov         edx,dword ptr [ebp-10h]
004011F8   mov         dword ptr [ebp-18h],edx
004011FB   mov         eax,dword ptr [ebp-18h]
004011FE   push        eax
004011FF   call        operator delete (004038e0)
00401204   add         esp,4
39:       fclose(f_open);
00401207   mov         ecx,dword ptr [ebp-4]
0040120A   push        ecx
0040120B   call        fclose (00403800)
00401210   add         esp,4
40:       fclose (f_write);
00401213   mov         edx,dword ptr [ebp-8]
00401216   push        edx
00401217   call        fclose (00403800)
0040121C   add         esp,4
41:
42:       return 0;
0040121F   xor         eax,eax
43:   }
00401221   pop         edi
00401222   pop         esi
00401223   pop         ebx
00401224   add         esp,60h
00401227   cmp         ebp,esp
00401229   call        __chkesp (00404820)
0040122E   mov         esp,ebp
00401230   pop         ebp
00401231   ret
*****************************************************
/*来自00401062   call  fopen (00404800)的调用
fopen:
00404800   push        ebp
00404801   mov         ebp,esp
00404803   push        40h //shflag
00404805   mov         eax,dword ptr [mode]
00404808   push        eax //指向打开文件的模式"rb"
00404809   mov         ecx,dword ptr [file]
0040480C   push        ecx //指向文件名"zhang.pdf"
0040480D   call        _fsopen (00404710)
00404812   add         esp,0Ch
00404815   pop         ebp
-------------------------------------------------------
//函数原型:FILE *_fsopen( const char *filename, const char *mode, int shflag ); shflag:Type of sharing allowed
//Each of these functions returns a pointer to the stream. A NULL pointer value indicates an error.
The _fsopen function opens the file specified by filename as a stream and prepares the file for subsequent shared reading or writing, as defined by the mode and shflag arguments.(来自MSDN)
********************************************************
/*来自0040480D  call  _fsopen (00404710)的调用
_fsopen:
00404710   push        ebp
00404711   mov         ebp,esp
00404713   sub         esp,8
00404716   push        ebx
00404717   push        esi
00404718   push        edi
------------------------------------------------------------
//接下来有4段类似于此段的代码,我的判断是检测要打开的文件名和打开的类型
00404719   cmp         dword ptr [file],0//判断文件名是否为空
0040471D   jne         _fsopen+2Dh (0040473d) //文件名不为空跳转
0040471F   push        offset string "file != NULL" (00428204)
00404724   push        0
00404726   push        35h
00404728   push        offset string "fopen.c" (004281fc)
0040472D   push        2
0040472F   call        _CrtDbgReport (00408800)
00404734   add         esp,14h
00404737   cmp         eax,1
0040473A   jne         _fsopen+2Dh (0040473d)
0040473C   int         3
0040473D   xor         eax,eax
0040473F   test        eax,eax
00404741   jne         _fsopen+9 (00404719)
/* _CrtDbgReport(int reportType, const char *filename, int linenumber, const char *moduleName, const char *format [, argument] ... );
Generates a report with a debugging message and sends the report to three possible destinations (debug version only).具体参见MSDN*/
----------------------------------------------------------
00404743   mov         ecx,dword ptr [file]
00404746   movsx       edx,byte ptr [ecx]
00404749   test        edx,edx
0040474B   jne         _fsopen+5Bh (0040476b)
0040474D   push        offset string "*file != _T('\\0')" (004281e8)
00404752   push        0
00404754   push        36h
00404756   push        offset string "fopen.c" (004281fc)
0040475B   push        2
0040475D   call        _CrtDbgReport (00408800)
00404762   add         esp,14h
00404765   cmp         eax,1
00404768   jne         _fsopen+5Bh (0040476b)
0040476A   int         3
0040476B   xor         eax,eax
0040476D   test        eax,eax
0040476F   jne         _fsopen+33h (00404743)
-----------------------------------------------------------------
00404771   cmp         dword ptr [mode],0
00404775   jne         _fsopen+85h (00404795)
00404777   push        offset string "mode != NULL" (004281d8)
0040477C   push        0
0040477E   push        37h
00404780   push        offset string "fopen.c" (004281fc)
00404785   push        2
00404787   call        _CrtDbgReport (00408800)
0040478C   add         esp,14h
0040478F   cmp         eax,1
00404792   jne         _fsopen+85h (00404795)
00404794   int         3
00404795   xor         ecx,ecx
00404797   test        ecx,ecx
00404799   jne         _fsopen+61h (00404771)
----------------------------------------------------------
0040479B   mov         edx,dword ptr [mode]
0040479E   movsx       eax,byte ptr [edx]
004047A1   test        eax,eax
004047A3   jne         _fsopen+0B3h (004047c3)
004047A5   push        offset string "*mode != _T('\\0')" (004281c4)
004047AA   push        0
004047AC   push        38h
004047AE   push        offset string "fopen.c" (004281fc)
004047B3   push        2
004047B5   call        _CrtDbgReport (00408800)
004047BA   add         esp,14h
004047BD   cmp         eax,1
004047C0   jne         _fsopen+0B3h (004047c3)
004047C2   int         3
004047C3   xor         ecx,ecx
004047C5   test        ecx,ecx
004047C7   jne         _fsopen+8Bh (0040479b)
----------------------------------------------------------
004047C9   call        _getstream (00409630)
//Retrieves the current buffered stream.具体参见MSDN 
//关键!!!此时EAX=0x0042AE40,注意后面代码中出现这个值!!!
//就我个人观点OD对VC程序中函数的识别效果不是很好,就像在这里OD仅仅给出CALL fread_fw.0040479B,如果贸然跟进必然会弄的一头雾水.
004047CE   mov         dword ptr [stream],eax//从后面的代码可以推断这里的几句代码是位分配文件的句柄做准备
004047D1   cmp         dword ptr [stream],0
004047D5   jne         _fsopen+0CBh (004047db)
004047D7   xor         eax,eax
004047D9   jmp         _fsopen+0E9h (004047f9)
004047DB   mov         edx,dword ptr [stream]
004047DE   push        edx  //流指针入栈(0x42AE40)
004047DF   mov         eax,dword ptr [shflag]
004047E2   push        eax  //不知是什么标志?? (40)            
004047E3   mov         ecx,dword ptr [mode]
004047E6   push        ecx  //指向打开文件的模式"rb"
004047E7   mov         edx,dword ptr [file]
004047EA   push        edx  //指向文件名"zhang.pdf"
004047EB   call        _openfile (004092a0)
//此处OD给出的是CALL fread_fw.004092A0;Be careful!!
004047F0   add         esp,10h 
//当程序执行到这里,看到_openfile的返回值为0;判定问题是出在_openfile中
//重新载入调试,进入_openfile()函数体
004047F3   mov         dword ptr [retval],eax
004047F6   mov         eax,dword ptr [retval]
004047F9   pop         edi
004047FA   pop         esi
004047FB   pop         ebx
004047FC   mov         esp,ebp
004047FE   pop         ebp
004047FF   ret
*******************************************************
/*来自004047EB  call  _openfile (004092a0)的调用
_openfile:
004092A0   push        ebp
004092A1   mov         ebp,esp
004092A3   sub         esp,24h
004092A6   push        ebx
004092A7   push        esi
004092A8   push        edi
004092A9   mov         eax,[__commode (0042bbc0)]
004092AE   mov         dword ptr [streamflag],eax
004092B1   mov         dword ptr [commodeset],0
004092B8   mov         dword ptr [scanset],0
//这里又是三段类似的变量检测
004092BF   cmp         dword ptr [filename],0
004092C3   jne         _openfile+43h (004092e3)
004092C5   push        offset string "filename != NULL" (00428d0c)
004092CA   push        0
004092CC   push        47h
004092CE   push        offset string "_open.c" (00428d04)
004092D3   push        2
004092D5   call        _CrtDbgReport (00408800)
004092DA   add         esp,14h
004092DD   cmp         eax,1
004092E0   jne         _openfile+43h (004092e3)
004092E2   int         3
004092E3   xor         ecx,ecx
004092E5   test        ecx,ecx
004092E7   jne         _openfile+1Fh (004092bf)
004092E9   cmp         dword ptr [mode],0
004092ED   jne         _openfile+6Dh (0040930d)
004092EF   push        offset string "mode != NULL" (004281d8)
004092F4   push        0
004092F6   push        48h
004092F8   push        offset string "_open.c" (00428d04)
004092FD   push        2
004092FF   call        _CrtDbgReport (00408800)
00409304   add         esp,14h
00409307   cmp         eax,1
0040930A   jne         _openfile+6Dh (0040930d)
0040930C   int         3
0040930D   xor         edx,edx
0040930F   test        edx,edx
00409311   jne         _openfile+49h (004092e9)
00409313   cmp         dword ptr [str],0
00409317   jne         _openfile+97h (00409337)
00409319   push        offset string "str != NULL" (00428154)
0040931E   push        0
00409320   push        49h
00409322   push        offset string "_open.c" (00428d04)
00409327   push        2
00409329   call        _CrtDbgReport (00408800)
0040932E   add         esp,14h
00409331   cmp         eax,1
00409334   jne         _openfile+97h (00409337)
00409336   int         3
00409337   xor         eax,eax
00409339   test        eax,eax
0040933B   jne         _openfile+73h (00409313)
0040933D   mov         ecx,dword ptr [mode]
00409340   mov         dl,byte ptr [ecx]
00409342   mov         byte ptr [ebp-20h],dl
00409345   cmp         byte ptr [ebp-20h],61h
00409349   je          _openfile+0DCh (0040937c)
0040934B   cmp         byte ptr [ebp-20h],72h
0040934F   je          _openfile+0B9h (00409359)
00409351   cmp         byte ptr [ebp-20h],77h
00409355   je          _openfile+0CAh (0040936a)
00409357   jmp         _openfile+0EEh (0040938e)
00409359   mov         dword ptr [modeflag],0
00409360   mov         eax,dword ptr [streamflag]
00409363   or          al,1
00409365   mov         dword ptr [streamflag],eax
00409368   jmp         _openfile+0F5h (00409395)
0040936A   mov         dword ptr [modeflag],301h
00409371   mov         ecx,dword ptr [streamflag]
00409374   or          ecx,2
00409377   mov         dword ptr [streamflag],ecx
0040937A   jmp         _openfile+0F5h (00409395)
0040937C   mov         dword ptr [modeflag],109h
00409383   mov         edx,dword ptr [streamflag]
00409386   or          edx,2
00409389   mov         dword ptr [streamflag],edx
0040938C   jmp         _openfile+0F5h (00409395)
0040938E   xor         eax,eax
00409390   jmp         $L1486+0A0h (004095b6)
00409395   mov         dword ptr [whileflag],1
//这里开始进入迷茫区,是一个大的循环.(不要放弃!!核心部分即将出现!! )
0040939C   mov         eax,dword ptr [mode]
0040939F   add         eax,1
004093A2   mov         dword ptr [mode],eax
004093A5   mov         ecx,dword ptr [mode]
004093A8   movsx       edx,byte ptr [ecx]
004093AB   test        edx,edx
004093AD   je          $L1486+29h (0040953f)
004093B3   cmp         dword ptr [whileflag],0
004093B7   je          $L1486+29h (0040953f)
004093BD   mov         eax,dword ptr [mode]
004093C0   movsx       ecx,byte ptr [eax]
004093C3   mov         dword ptr [ebp-24h],ecx
004093C6   mov         edx,dword ptr [ebp-24h]
004093C9   sub         edx,2Bh
004093CC   mov         dword ptr [ebp-24h],edx
004093CF   cmp         dword ptr [ebp-24h],49h
004093D3   ja          $L1486+1Dh (00409533)
004093D9   mov         ecx,dword ptr [ebp-24h]
004093DC   xor         eax,eax
004093DE   mov         al,byte ptr  (004095e5)[ecx]
004093E4   jmp         dword ptr [eax*4+4095BDh]
$L1462:
004093EB   mov         edx,dword ptr [modeflag]
004093EE   and         edx,2
004093F1   test        edx,edx
004093F3   je          $L1462+13h (004093fe)
004093F5   mov         dword ptr [whileflag],0
004093FC   jmp         $L1462+35h (00409420)
004093FE   mov         eax,dword ptr [modeflag]
00409401   or          al,2
00409403   mov         dword ptr [modeflag],eax
00409406   mov         ecx,dword ptr [modeflag]
00409409   and         ecx,0FEh
0040940C   mov         dword ptr [modeflag],ecx
0040940F   mov         edx,dword ptr [streamflag]
00409412   or          dl,80h
00409415   mov         dword ptr [streamflag],edx
00409418   mov         eax,dword ptr [streamflag]
0040941B   and         al,0FCh
0040941D   mov         dword ptr [streamflag],eax
00409420   jmp         $L1486+24h (0040953a)
$L1465:
00409425   mov         ecx,dword ptr [modeflag]
00409428   and         ecx,0C000h
0040942E   test        ecx,ecx
00409430   je          $L1465+16h (0040943b)
00409432   mov         dword ptr [whileflag],0
00409439   jmp         $L1465+1Fh (00409444)
0040943B   mov         edx,dword ptr [modeflag]
0040943E   or          dh,80h
00409441   mov         dword ptr [modeflag],edx
00409444   jmp         $L1486+24h (0040953a)
$L1468:
00409449   mov         eax,dword ptr [modeflag]
0040944C   and         eax,0C000h
00409451   test        eax,eax
00409453   je          $L1468+15h (0040945e)
00409455   mov         dword ptr [whileflag],0
0040945C   jmp         $L1468+1Eh (00409467)
0040945E   mov         ecx,dword ptr [modeflag]
00409461   or          ch,40h
00409464   mov         dword ptr [modeflag],ecx
00409467   jmp         $L1486+24h (0040953a)
$L1471:
0040946C   cmp         dword ptr [commodeset],0
00409470   je          $L1471+0Fh (0040947b)
00409472   mov         dword ptr [whileflag],0
00409479   jmp         $L1471+1Fh (0040948b)
0040947B   mov         dword ptr [commodeset],1
00409482   mov         edx,dword ptr [streamflag]
00409485   or          dh,40h
00409488   mov         dword ptr [streamflag],edx
0040948B   jmp         $L1486+24h (0040953a)
$L1474:
00409490   cmp         dword ptr [commodeset],0
00409494   je          $L1474+0Fh (0040949f)
00409496   mov         dword ptr [whileflag],0
0040949D   jmp         $L1474+1Fh (004094af)
0040949F   mov         dword ptr [commodeset],1
004094A6   mov         eax,dword ptr [streamflag]
004094A9   and         ah,0BFh
004094AC   mov         dword ptr [streamflag],eax
004094AF   jmp         $L1486+24h (0040953a)
$L1477:
004094B4   cmp         dword ptr [scanset],0
004094B8   je          $L1477+0Fh (004094c3)
004094BA   mov         dword ptr [whileflag],0
004094C1   jmp         $L1477+1Fh (004094d3)
004094C3   mov         dword ptr [scanset],1
004094CA   mov         ecx,dword ptr [modeflag]
004094CD   or          ecx,20h
004094D0   mov         dword ptr [modeflag],ecx
004094D3   jmp         $L1486+24h (0040953a)
$L1480:
004094D5   cmp         dword ptr [scanset],0
004094D9   je          $L1480+0Fh (004094e4)
004094DB   mov         dword ptr [whileflag],0
004094E2   jmp         $L1480+1Fh (004094f4)
004094E4   mov         dword ptr [scanset],1
004094EB   mov         edx,dword ptr [modeflag]
004094EE   or          edx,10h
004094F1   mov         dword ptr [modeflag],edx
004094F4   jmp         $L1486+24h (0040953a)
$L1483:
004094F6   mov         eax,dword ptr [modeflag]
004094F9   and         eax,1000h
004094FE   test        eax,eax
00409500   je          $L1483+15h (0040950b)
00409502   mov         dword ptr [whileflag],0
00409509   jmp         $L1483+1Eh (00409514)
0040950B   mov         ecx,dword ptr [modeflag]
0040950E   or          ch,10h
00409511   mov         dword ptr [modeflag],ecx
00409514   jmp         $L1486+24h (0040953a)
$L1486:
00409516   mov         edx,dword ptr [modeflag]
00409519   and         edx,40h
0040951C   test        edx,edx
0040951E   je          $L1486+13h (00409529)
00409520   mov         dword ptr [whileflag],0
00409527   jmp         $L1486+1Bh (00409531)
00409529   mov         eax,dword ptr [modeflag]
0040952C   or          al,40h
0040952E   mov         dword ptr [modeflag],eax
00409531   jmp         $L1486+24h (0040953a)
00409533   mov         dword ptr [whileflag],0
0040953A   jmp         _openfile+0FCh (0040939c) //大循环到此为止
0040953F   push        1A4h
00409544   mov         ecx,dword ptr [shflag]
00409547   push        ecx
00409548   mov         edx,dword ptr [modeflag]
0040954B   push        edx
0040954C   mov         eax,dword ptr [filename]
0040954F   push        eax
00409550   call        _sopen (0040f6e0)
//int _sopen( const char *filename, int oflag, int shflag [, int pmode ] );
//Each of these functions returns a file handle for the opened file. A return value of –1 indicates an error.具体资料参见MSDN
//此处关键所在.由于我调试时是VC和OD两个调试器同时交叉前进的,到这里就产生不同.
//从理论上这个函数应该返回一个句柄.VC调试器返回EAX=3(不同机子可能会不同),而OD返回的是EAX=0XFFFFFFFF.这里产生一个问题系统是如何分配句柄???
00409555   add         esp,10h
00409558   mov         dword ptr [filedes],eax
0040955B   cmp         dword ptr [filedes],0//在此处判断_sopen产生的文件句柄 
0040955F   jge         $L1486+4Fh (00409565)//从这里开始VC和OD有了截然不同的命运
00409561   xor         eax,eax
//OD的命运:EAX清零,决定了f_open=fopen("zhang.pdf","rb")失败的返回标志为EAX=0;
00409563   jmp         $L1486+0A0h (004095b6) //跳转到返回代码处
//1.dword ptr [__cflush (0042ba50)]----->ECX--->+1--->dword ptr [__cflush (0042ba50)];
00409565   mov         ecx,dword ptr [__cflush (0042ba50)] //VC的命运(成功)
0040956B   add         ecx,1
0040956E   mov         dword ptr [__cflush (0042ba50)],ecx
//2.dword ptr [str]---->EDX---->dword ptr [stream]---->EAX;流文件中的指针重定位
//这里又产生问题:流stream具体是如何工作的,下面的str又代表什么样的结构
00409574   mov         edx,dword ptr [str]
00409577   mov         dword ptr [stream],edx
0040957A   mov         eax,dword ptr [stream]
//3.dword ptr [streamflag]--->ECX--->dword ptr [EAX+0Ch];设置标志位(DWORD)
0040957D   mov         ecx,dword ptr [streamflag]
00409580   mov         dword ptr [eax+0Ch],ecx
//在stream中设置_sopen返回的handle值(不知该称为句柄还是ID,应该是ID吧)
00409583   mov         edx,dword ptr [stream]
00409586   mov         dword ptr [edx+4],0
0040958D   mov         eax,dword ptr [stream]
00409590   mov         dword ptr [eax],0
00409596   mov         ecx,dword ptr [stream]
00409599   mov         dword ptr [ecx+8],0
004095A0   mov         edx,dword ptr [stream]
004095A3   mov         dword ptr [edx+1Ch],0
004095AA   mov         eax,dword ptr [stream]
004095AD   mov         ecx,dword ptr [filedes]
004095B0   mov         dword ptr [eax+10h],ecx
004095B3   mov         eax,dword ptr [stream] //用EAX保存返回值,即文件句柄
//上面这段代码处理的后的内存堆栈情况(红色标记表示streamflag;蓝色标记表示filedes):
0042AE40  00 00 00 00 00 00  ......
0042AE46  00 00 00 00 00 00  ......
0042AE4C  01 00 00 00 03 00  ......
0042AE52  00 00 00 00 00 00  ......
0042AE58  00 00 00 00 00 00  ......
0042AE5E  00 00 00 00 00 00  ......
0042AE64  00 00 00 00 00 00 
streamflag:01 00 00 00 
filedes:03 00 00 00
----------------------------------------------------
004095B6   pop         edi
004095B7   pop         esi
004095B8   pop         ebx
004095B9   mov         esp,ebp
004095BB   pop         ebp
004095BC   ret
***************************************************************
总结:
分析流程:fopen( )--> _fsopen( ) -->_openfile( ) -->_sopen( )
遗留下来的问题
1.str的结构和stream的工作原理.
2._sopen()函数体的分析和_fsopen( )模块中的迷茫区
3.至于系统是如何分配句柄的,我想读者可以根据_getstream及其代码的上下部分可以了解个大概.需要注意一点的是句柄和指针一样本质都是地址.

最后回到本篇开始时提出的问题:为什么同一个程序在VC和OD的调试下会出现不同结果?
经过上面的分析,我想答案已经很明确.
_sopen()返回的file handle不同,OD的返回的结果表明要打开的文件资源("zhang.pdf")没有被找到而且程序已经给这个文件准备好要分配的句柄(0x0042AE40),而事实上这个文件确实存在.哎~~,这不是很明显的事,用0D调试程序相当于直接执行debug文件夹的fread_fwrite.exe,要不试试会出现什么问题---呵呵,当然是"OPEN--WRONG!"
其实debug文件夹中的可执行文件只检测该文件夹中是否存在资源文件,如果把"zhang.pdf"放到debug文件夹下,程序就能正常处理.
其实这应该很早就想到,但我的脑子是一条筋,转不过弯,每办法!!
(11个小时+一份外买+一包泡面+一杯水+饮料N瓶)-->一次漫长的旅途==我喜欢
为了保证完整性,有些额外的反汇编代码没有去掉,我想这样方便大家学习.
如果大家对这个话题有兴趣,请各抒己见,共同探讨遗留下来的问题.

  • 标 题: 答复
  • 作 者:doskey
  • 时 间:2005-03-27 22:14

fopen( )--> _fsopen( ) -->_openfile( ) -->_sopen( )

补充
-->kernel32.CreateFile() --> ntdll.NtCreateFile() --> int 2e (EAX = 0x25) --> ntoskrnl.ZwCreateFile --> win32k.sys