继续上反汇编
源代码
程序2-1 SCRNSIZE
SCRNSIZE.C
/*---------------------------------------------------------------------------
SCRNSIZE.C -- Displays screen size in a message box
(c) Charles Petzold, 1998
----------------------------------------------------------------------------*/
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
int CDECL MessageBoxPrintf (TCHAR * szCaption, TCHAR * szFormat, ...)
{
TCHAR szBuffer [1024] ;
va_list pArgList ;
// The va_start macro (defined in STDARG.H) is usually equivalent to:
// pArgList = (char *) &szFormat + sizeof (szFormat) ;
va_start (pArgList, szFormat) ;
// The last argument to wvsprintf points to the arguments
_vsntprintf ( szBuffer, sizeof (szBuffer) / sizeof (TCHAR),
szFormat, pArgList) ;
// The va_end macro just zeroes out pArgList for no good reason
va_end (pArgList) ;
return MessageBox (NULL, szBuffer, szCaption, 0) ;
}
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
int cxScreen, cyScreen ;
cxScreen = GetSystemMetrics (SM_CXSCREEN) ;
cyScreen = GetSystemMetrics (SM_CYSCREEN) ;
MessageBoxPrintf ( TEXT ("ScrnSize"),
TEXT ("The screen is %i pixels wide by %i pixels high."),
cxScreen, cyScreen) ;
return 0 ;
}
49:
50: int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
51:
52: PSTR szCmdLine, int iCmdShow) 53: // windows 程序 入口函数 WINAPI 宏定义 #define WINAPI __stdcall 遵从标准函数调 由子程序平衡堆栈 参数从右向左压栈
54: {
004010D0 push ebp //ebp压栈
004010D1 mov ebp,esp //ebp作为esp的副本。
004010D3 sub esp,48h //堆栈开辟48h的空间
004010D6 push ebx
004010D7 push esi
004010D8 push edi //保存现场
004010D9 lea edi,[ebp-48h] //12h的字节写入0cccccccch 防止堆栈溢出 同时可作为局部变量缓冲区
004010DC mov ecx,12h
004010E1 mov eax,0CCCCCCCCh
004010E6 rep stos dword ptr [edi]
55:
56: int cxScreen, cyScreen ;
57:
58: cxScreen = GetSystemMetrics (SM_CXSCREEN) ;
004010E8 mov esi,esp
004010EA push 0 //0作为参数压栈 代表获取x值
004010EC call dword ptr [__imp__GetSystemMetrics@4 (0042a2b0)] //调用win32api GetSystemMetrics() 返回值eax
004010F2 cmp esi,esp //GetSystemMetrics是一个能用来获得Windows中不同对象的尺寸信息的函数
004010F4 call __chkesp (00401270) //检测修复堆栈平衡
004010F9 mov dword ptr [ebp-4],eax //ebp-4处 局部变量cxScreen 地址 保存在那里
59:
60: cyScreen = GetSystemMetrics (SM_CYSCREEN) ;
004010FC mov esi,esp
004010FE push 1 //1作为参数压栈 代表获取y值
00401100 call dword ptr [__imp__GetSystemMetrics@4 (0042a2b0)]
00401106 cmp esi,esp
00401108 call __chkesp (00401270)
0040110D mov dword ptr [ebp-8],eax //ebp-8处为局部变量cxScreen地址
61:
62:
63: MessageBoxPrintf ( TEXT ("ScrnSize"),
64:
65: TEXT ("The screen is %i pixels wide by %i pixels high."),
66:
67: cxScreen, cyScreen) ;
00401110 mov eax,dword ptr [ebp-8] // 取cyScreen
00401113 push eax
00401114 mov ecx,dword ptr [ ebp-4] // 取 cxScreen
00401117 push ecx
00401118 push offset string "The screen is %i pixels wide by "... (00422028) //取格式字符串
0040111D push offset string "ScrnSize" (0042201c) // 取对话框标题参数
00401122 call @ILT+0(_MessageBoxPrintf) (00401005) //调用 _MessageBoxPrintf子函数
跟入 子程序 来到 00401005处
00401005 jmp MessageBoxPrintf (00401020) //一条跳转指令 这种调用形式是由于 输入地址表iat造成的 编译器无法识别普通函数调用和输入函数调用。所以统一格式,子程序调用。
跟入 来到子程序处 11: #include <windows.h>
12:
13: #include <tchar.h>
14:
15: #include <stdio.h>
16:
17: int CDECL MessageBoxPrintf (TCHAR * szCaption, TCHAR * szFormat, ...)
18:
19: {
00401020 push ebp
00401021 mov ebp,esp
00401023 sub esp,444h
00401029 push ebx
0040102A push esi
0040102B push edi
0040102C lea edi,[ebp-444h]
00401032 mov ecx,111h
00401037 mov eax,0CCCCCCCCh //分许同上
0040103C rep stos dword ptr [edi]
20:
21: TCHAR szBuffer [1024] ;
22:
23: va_list pArgList ;
24:
25:
26: // The va_start macro (defined in STDARG.H) is usually equivalent to:
27:
28: // pArgList = (char *) &szFormat + sizeof (szFormat) ;
29:
30:
31: va_start (pArgList, szFormat) ;
0040103E lea eax,[ebp+10h] //ebp+10h处开始,是传入的参数 ,这里将参数地址传给eax 33: 00401041 mov dword ptr [ebp-404h],eax //将参数保存在局部变量内,即pArgList
34: // The last argument to wvsprintf points to the arguments
35:
36:
37: _vsntprintf ( szBuffer, sizeof (szBuffer) / sizeof (TCHAR),
38:
39: szFormat, pArgList) ;
00401047 mov ecx,dword ptr [ebp-404h] //取pArgList 入栈
0040104D push ecx
0040104E mov edx,dword ptr [ebp+0Ch] //取倒数第三个参数入栈,即格式字符串地址
00401051 push edx
00401052 push 400h // 大小
00401057 lea eax,[ebp-400h] //缓冲区
0040105D push eax
0040105E call _vsnprintf (00401170) //调用_vsnprintf
00401063 add esp,10h //_vsnprintf为 _cdel 规则调用 由调用者平衡堆栈 eax返回值为 格式化显示后的字符串长度
40:
41:
42: // The va_end macro just zeroes out pArgList for no good reason
43:
44: va_end (pArgList) ;
00401066 mov dword ptr [ebp-404h],0 //将 pArgList置清0
45:
46: return MessageBox (NULL, szBuffer, szCaption, 0);
00401070 mov esi,esp
00401072 push 0
00401074 mov ecx,dword ptr [ebp+8]
00401077 push ecx
00401078 lea edx,[ebp-400h]
0040107E push edx
0040107F push 0
00401081 call dword ptr [__imp__MessageBoxA@16 (0042a2b4)]
00401087 cmp esi,esp
00401089 call __chkesp (00401270)
47:
48: }
0040108E pop edi
0040108F pop esi
00401090 pop ebx
00401091 add esp,444h //int CDECL MessageBoxPrintf 是_cdecl调用 由调用者平衡堆栈 ,这里调用者是编译器?windows?
00401097 cmp ebp,esp
00401099 call __chkesp (00401270)
0040109E mov esp,ebp
004010A0 pop ebp
004010A1 ret 至此 返回 主程序 winmain中
00401127 add esp,10h
68:
69: return 0 ;
0040112A xor eax,eax //eax返回0
70:
71: }
0040112C pop edi
0040112D pop esi
0040112E pop ebx
0040112F add esp,48h
00401132 cmp ebp,esp
00401134 call __chkesp (00401270)
00401139 mov esp,ebp
0040113B pop ebp
0040113C ret 10h
由反汇编总结 va_start(pArgList,szFormat)宏的具体作用是取szFormat的地址保存在pArgList里,而va_list pArgList只是告诉编译器应该分配多大的指针空间。
va_end(pArgList)则是将pArgList所用空间清零。