day1
Win32 SDK运行流程及框架
Win32 SDK编程即使用Win32 SDK来编写窗体应用程序,这种方式不使用任何框架,仅用操作系统提供的API来编写程序,虽然流程繁琐,编写复杂,但有助于理解Windows应用程序实 质的执行情况。
Win32程序的入口点为WinMain函数,与控制台程序的main类似,它们都是由链接器来决定的。WinMain函数有4个参数,分别是hInstance,hPrevInstance,szCmdLine,iCmdShow。hInstance表示当前程序的实例句柄,它的实质为映像文件的基地址;hPrevInstance如今只起兼容作用,一般为NULL;szCmdLine是命令行指针,在启动函数调用WinMain函数前会使用GetCommandLine获取完整命令行,忽略文件名后将剩余部分传递给该参数,iCmdShow则是窗口显示的方式,比如最大化和最小化显示,用在ShowWindow函数中。
程序运行的流程:1.注册窗口类 2.创建窗口 3.显示窗口 4.消息循环 5.消息处理
要创建一个窗口,我们首先得注册一个窗口类,WNDCLASS定义如下:
1 typedef struct tagWNDCLASSA { 2 UINT style; 3 WNDPROC lpfnWndProc; 4 int cbClsExtra; 5 int cbWndExtra; 6 HINSTANCE hInstance; 7 HICON hIcon; 8 HCURSOR hCursor; 9 HBRUSH hbrBackground; 10 LPCSTR lpszMenuName; 11 LPCSTR lpszClassName; 12 } WNDCLASSA;
创建一个窗口类实例并进行初始化后,就可调用RegisterClass函数注册该窗口类。然后就可以调用CreateWindow函数来创建一个窗口,但这时仅仅表示某块内存保存了窗口的所有信息数据,并不会显示在屏幕上,CreateWindow返回一个窗口句柄,有了窗口句柄我们便能通过API来对该窗口进行一系列操作,于是我们就可调用ShowWindow函数使该窗口显示在屏幕上。
Win32程序是基于消息机制的,消息作为驱动来使程序运行。所以MSG这个消息结构是一个十分重要的结构,定义如下:
1 typedef struct{ 2 HWND hWnd; //窗口句柄 3 UINT message;//消息内容 4 WPARAM wParam; 5 LPARAM lParam; 6 DWORD time;//产生时间 7 POINT pt;//位置 8 } MSG;
操作系统维护了一个消息队列,当产生了消息后,便会将新产生的消息加入队列中,调用GetMessage函数可以获得队头消息,然后通过DispatchMessage函数将该消息传给操作系统,然后作为参数传给CALLBACK消息处理函数处理。所以消息循环通常由以下代码构成:
1 while (GetMessage(&msg, NULL, 0, 0)) 2 { 3 TranslateMessage(&msg); 4 DispatchMessage(&msg); 5 }
通常把这种消息称为队列消息,然而还存在非队列消息,这些非队列消息一般是由函数调用引起的,如CreateWindow时会传递WM_CREATE消息,UpdateWindow会传递WM_PAINT消息等。
MFC框架执行流程
MFC是微软提供的一个C++框架。当建立一个单文档工程时,vc便会自动为我们创建5个类,分别是CAboutDlg,CMainFrame,C$ProjectName$App,C$ProjectName$Doc,C$ProjectName$View。CMainFrame是框架窗口,即窗口的最外层,
执行流程:我们难以在MFC程序中找到WinMain函数,但程序实际运行时,依然会调用WinMain函数。首先创建了全局的C$ProjectName$App对象,C$ProjectName$App是CWinApp的子类,继承了其构造函数,调用其父类构造函数后,才进入WinMain函数,WinMain函数调用了AfxWinMain函数,在AfxWinMain函数中,获取了C$ProjectName$App全局对象的指针,然后调用其InitInstance方法,接着调用了run方法。在InitInstance中完成了窗口类的注册,窗口的显示和更新。在run方法中完成了消息循环。
TLS,PEB,TEB结构
TLS是线程局部存储,TLS是各线程的独立的数据存储空间,使用TLS技术可在线程内部独立使用或修改进程的全局数据或静态数据,在PE文件中有单独的数据目录表指向该结构,定义如下:
1 typedef struct _IMAGE_TLS_DIRECTORY32 { 2 DWORD StartAddressOfRawData; 3 DWORD EndAddressOfRawData; 4 DWORD AddressOfIndex; // PDWORD 5 DWORD AddressOfCallBacks; // PIMAGE_TLS_CALLBACK * 6 DWORD SizeOfZeroFill; 7 union { 8 DWORD Characteristics; 9 struct { 10 DWORD Reserved0 : 20; 11 DWORD Alignment : 4; 12 DWORD Reserved1 : 8; 13 } DUMMYSTRUCTNAME; 14 } DUMMYUNIONNAME; 15 } IMAGE_TLS_DIRECTORY32;
其中AddressCallBacks是回调函数起始地址,TLS回调函数常用于反调试。在调用main函数前都会先依次调用所有回调函数,结束时会再调用一次。
回调函数的声明方式void NTAPI TLS_CALLBACK(PVOID DllHandle, DWORD Reason, PVOID Reserved);
第一个参数是模块句柄(实质为加载地址),第二个参数是调用原因
有如下4中调用原因:
1 #pragma data_seg(".CRT$XLX") 2 //存储回调函数地址 3 PIMAGE_TLS_CALLBACK pTLS_CALLBACKs[] = { TLS_CALLBACK1/*func_name*/, TLS_CALLBACK2/*func_name*/, 0 }; 4 #pragma data_seg()
PEB为进程控制块,是由操作系统为每个进程维护的一个数据结构。定义如下:
1 typedef struct _PEB { 2 BYTE Reserved1[2]; 3 BYTE BeingDebugged; //被调试状态 4 BYTE Reserved2[1]; 5 PVOID Reserved3[2]; 6 PPEB_LDR_DATA Ldr; 7 PRTL_USER_PROCESS_PARAMETERS ProcessParameters; 8 BYTE Reserved4[104]; 9 PVOID Reserved5[52]; 10 PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine; 11 BYTE Reserved6[128]; 12 PVOID Reserved7[1]; 13 ULONG SessionId; 14 } PEB
有许多保留字段,我们忽略它。剩下的分别是BeingDebugged,Ldr,ProcessParameters,PostProcessInitRoutine和SessionId四个字段。
BeingDebugged标志表示程序的调试状态,IsDebuggerPresent()函数便是检查这个标志来返回一个布尔值的,常常用于反调试。
Ldr字段是指向关于进程加载模块的双向链表头的指针。
ProcessParameters指向了进程的参数信息结构,其中包含命令行参数等。
PostProcessInitRoutine不支持。
SessionId表示当前终端服务对话标识符。
TEB为线程环境块,我们通常通过该环境块来获得当前进程环境块。
Windows在创建线程前,会为该线程分配TEB,通常FS段寄存器指向该结构。TEB偏移0x00处是TIB(线程信息块),线程信息块偏移0x18处存在反身指针指向该TEB本身。
TEB偏移0x30处为PEB指针,由此可通过FS寄存器获取PEB。
明日:基本sql注入方式,floor报错注入,information_schema.tables。Win32 WM_PAINT消息和GDI简介