闲来无事,随便逆逆。
首先编译器编译的时候会使用CraeteFileW创建源文件,这个断点我们可以OD打开一个编译器,直接对所有文件操作的函数下断就能断下来了。先看第一个,创建源文件:

代码:
0044F680  /$  53            PUSH EBX
0044F681  |.  8B4424 08     MOV EAX,DWORD PTR SS:[ESP+8]
0044F685  |.  8B5C24 0C     MOV EBX,DWORD PTR SS:[ESP+C]
0044F689  |.  6A 00         PUSH 0                                             ; /hTemplateFile = NULL
0044F68B  |.  6A 00         PUSH 0                                             ; |Attributes = 0
0044F68D  |.  6A 03         PUSH 3                                             ; |Mode = OPEN_EXISTING
0044F68F  |.  6A 00         PUSH 0                                             ; |pSecurity = NULL
0044F691  |.  6A 01         PUSH 1                                             ; |ShareMode = FILE_SHARE_READ
0044F693  |.  68 00000080   PUSH 80000000                                      ; |Access = GENERIC_READ
0044F698  |.  50            PUSH EAX                                           ; |目标源文件
0044F699  |.  FF15 4CD05100 CALL DWORD PTR DS:[<&KERNEL32.CreateFileW>]        ; \CreateFileW
0044F69F  |.  8903          MOV DWORD PTR DS:[EBX],EAX                         ;  返回句柄
0044F6A1  |.  833B FF       CMP DWORD PTR DS:[EBX],-1                          ;  判断是否为空
0044F6A4  |.  75 08         JNZ SHORT 0044F6AE
0044F6A6  |.  FF15 18CF5100 CALL DWORD PTR DS:[<&KERNEL32.GetLastError>]       ; [GetLastError
0044F6AC  |.  EB 02         JMP SHORT 0044F6B0
然后使用先前分配的内存,把源代码文件映射到内存,这个内存大小分配可能是解析自己格式文件的出来的,比如vc有.dsw。
CreateFile之后就ReadFile读取前4字节,前4字节一般就是#inc,然后比较这4字节是否等于0xFFFEFEFF,这个字符我们弄到十六进制编辑器里面会发现是空白,
代码:
0x0FEFF
之后循重复比较读取字节的长度是否为3,2长度,比较是否为空白,不是就设置文件指针指向文件开始。再然后清除读取的源代码,GetFileSizeEx获得源代码的大小,
代码:
00450168  |.  50            PUSH EAX                                           ; /Arg1
00450169  |.  E8 82F7FFFF   CALL 0044F8F0                                      ; \再次获得文件大小
0045016E  |.  85D2          TEST EDX,EDX
00450170  |.  72 10         JB SHORT 00450182
00450172  |.  77 07         JA SHORT 0045017B
00450174  |.  3D 00000080   CMP EAX,80000000                                   ;  原代码大小
00450179  |.  76 07         JBE SHORT 00450182                                 ;  小于等于这个数就跳
0045017B  |>  B8 05000020   MOV EAX,20000005                                   ;  不然设置EAX为这个数字,后返回
00450180  |.  EB 57         JMP SHORT 004501D9
之后就是使用读取PE文件那两个函数映射源代码文件到内存。
读取之后判断是否为UTF8编码,相关代码如下:
代码:
004B2A6B  |.  56            PUSH ESI                                           ;  原代码大小
004B2A6C  |.  8B45 E4       MOV EAX,DWORD PTR SS:[EBP-1C]
004B2A6F  |.  50            PUSH EAX                                           ;  指向原代码内存的指针
004B2A70  |.  FF15 F0D65100 CALL DWORD PTR DS:[<&support._IsEncodingUTF8>]     ;  support._IsEncodingUTF8
然后从源文件开始查找第一个换行或者回车。查找到之后就用MultiByteToWideChar转换为宽字符,期间分配了另外的内存空间。
代码:
004B2DDA  |> /46            /INC ESI                                           ;  ESI指向内存中的源代码字符,
004B2DDB  |> |3B75 FC        CMP ESI,DWORD PTR SS:[EBP-4]
004B2DDE  |. |73 16         |JNB SHORT 004B2DF6
004B2DE0  |. |8A06          |MOV AL,BYTE PTR DS:[ESI]
004B2DE2  |. |3C 0A         |CMP AL,0A
004B2DE4  |. |74 10         |JE SHORT 004B2DF6                                 ;  比较是否为换行,查找第一个换行或者第一个回车
004B2DE6  |. |3C 0D         |CMP AL,0D
004B2DE8  |. |74 0C         |JE SHORT 004B2DF6                                 ;  比较是否为回车
004B2DEA  |. |89F0          |MOV EAX,ESI
004B2DEC  |. |2B45 F8       |SUB EAX,DWORD PTR SS:[EBP-8]
004B2DEF  |. |3D 00100000   |CMP EAX,1000
004B2DF4  |.^\7C E4         \JL SHORT 004B2DDA
004B2DF6  |>  3B75 F8       CMP ESI,DWORD PTR SS:[EBP-8]                       ;  查找到第一个换行或者回车之后就跳
映射之后
代码:
004B2E04  |.  803E 0D       CMP BYTE PTR DS:[ESI],0D                           ;  判断是否为回车
004B2E07  |.  75 0F         JNZ SHORT 004B2E18
004B2E09  |.  807E 01 0A    CMP BYTE PTR DS:[ESI+1],0A                         ;  换行
004B2E0D  |.  75 09         JNZ SHORT 004B2E18
004B2E0F  |.  834B 18 0C    OR DWORD PTR DS:[EBX+18],0C
004B2E13  |.  83C6 02       ADD ESI,2                                          ;  是就字符+2
然后在宽字符内存空间的后面添加一个换行符。
之后继续循环比较,从换行和回车后面开始比较。
这个过程就是检查头文件语法。因为#include <windows>这后面是回车换行,
上面这个过程转换为宽字符,其中还有些处理。剩下的。。。。