PE文件格式分析系列(文章3)----一个PE文件rdata段的分析(Win32工程Release版)(二)
2012-06-23 22:25
621 查看
PE文件格式分析系列(文章3)
一个PE文件rdata段的分析(Win32工程Release版)(二)
下面分析这个PE文件rdata段的常量数据(000050A4---0000543D)
000050A0 | 00 00 00 00 | .... |
000050A8 | FF FF FF FF 27 11 40 00 | '.@. | 这像一个地址00401127
000050B0 | 3B 11 40 00 5F 5F 47 4C | ;.@.__GL |
0040113B 也是
000050B8 | 4F 42 41 4C 5F 48 45 41 | OBAL_HEA | 一段字符
......
000050E0 | 00 00 00 00 72 75 6E 74 | ....runt | 运行时错误?
000050E8 | 69 6D 65 20 65 72 72 6F | ime erro |
000050F0 | 72 20 00 00 0D 0A 00 00 | r ...... |
......
00005128 | 52 36 30 32 38 0D 0A 2D | R6028..- | 好像是错误码
00005130 | 20 75 6E 61 62 6C 65 20 | unable | 不能初始化heap?
00005138 | 74 6F 20 69 6E 69 74 69 | to initi |
00005140 | 61 6C 69 7A 65 20 68 65 | alize he |
00005148 | 61 70 0D 0A 00 00 00 00 | ap...... |
00005150 | 52 36 30 32 37 0D 0A 2D | R6027..- |
00005158 | 20 6E 6F 74 20 65 6E 6F | not eno |
00005160 | 75 67 68 20 73 70 61 63 | ugh spac |
00005168 | 65 20 66 6F 72 20 6C 6F | e for lo |
00005170 | 77 69 6F 20 69 6E 69 74 | wio init |
00005178 | 69 61 6C 69 7A 61 74 69 | ializati |
00005180 | 6F 6E 0D 0A 00 00 00 00 | on...... |
00005188 | 52 36 30 32 36 0D 0A 2D | R6026..- |
00005190 | 20 6E 6F 74 20 65 6E 6F | not eno |
00005198 | 75 67 68 20 73 70 61 63 | ugh spac |
000051A0 | 65 20 66 6F 72 20 73 74 | e for st |
000051A8 | 64 69 6F 20 69 6E 69 74 | dio init |
000051B0 | 69 61 6C 69 7A 61 74 69 | ializati |
000051B8 | 6F 6E 0D 0A 00 00 00 00 | on...... |
000051C0 | 52 36 30 32 35 0D 0A 2D | R6025..- |
000051C8 | 20 70 75 72 65 20 76 69 | pure vi |
000051D0 | 72 74 75 61 6C 20 66 75 | rtual fu |
000051D8 | 6E 63 74 69 6F 6E 20 63 | nction c |
000051E0 | 61 6C 6C 0D 0A 00 00 00 | all..... |
000051E8 | 52 36 30 32 34 0D 0A 2D | R6024..- |
...
00005370 | 4D 69 63 72 6F 73 6F 66 | Microsof | 哈哈, 这个很熟悉哦
00005378 | 74 20 56 69 73 75 61 6C | t Visual |
00005380 | 20 43 2B 2B 20 52 75 6E | C++ Run |
00005388 | 74 69 6D 65 20 4C 69 62 | time Lib |
00005390 | 72 61 72 79 00 00 00 00 | rary.... |
...
000053E0 | 65 50 6F 70 75 70 00 00 | ePopup.. |
000053E8 | 47 65 74 41 63 74 69 76 | GetActiv |
000053F0 | 65 57 69 6E 64 6F 77 00 | eWindow. |
000053F8 | 4D 65 73 73 61 67 65 42 | MessageB |
00005400 | 6F 78 41 00 75 73 65 72 | oxA.user | 怎么也有user32.dll?
00005408 | 33 32 2E 64 6C 6C 00 00 | 32.dll.. |
...
00005428 | 22 3F 40 00 26 3F 40 00 |
00005430 | FF FF FF FF A6 40 40 00 |
00005438 | AA 40 40 00 |
分析过程如下:
OD反汇编了一下代码段, 看到一些指令
00401055 |. 68 A8504000 PUSH OFFSET 004050A8 ; FF FF FF FF
00401B0B |. 68 B4504000 PUSH OFFSET 004050B4 ; |Arg1 = ASCII "__GLOBAL_HEAP_SELECTED"
00401ACC |. 68 CC504000 PUSH OFFSET 004050CC ; |Name = "__MSVCRT_HEAP_SELECT"
00401F46 |. 68 70534000 PUSH OFFSET 00405370 ; ASCII "Microsoft Visual C++ Runtime Library"
00401F1E |. 68 98534000 PUSH OFFSET 00405398 ; ASCII ""
00401F00 |. 68 9C534000 PUSH OFFSET 0040539C ; ASCII "Runtime Error! Program: "
00401EEC |. 68 B8534000 PUSH OFFSET 004053B8 ; ASCII "..."
00401EAA |. 68 BC534000 PUSH OFFSET 004053BC ; ASCII "<program name unknown>"
00403C11 |. 68 D4534000 PUSH OFFSET 004053D4 ; /Procname = "GetLastActivePopup"
00403C09 |. 68 E8534000 PUSH OFFSET 004053E8 ; /Procname = "GetActiveWindow"
00403BF8 |. 68 F8534000 PUSH OFFSET 004053F8 ; /Procname = "MessageBoxA"
00403BE1 |. 68 04544000 PUSH OFFSET 00405404 ; /FileName = "user32.dll"
00403DB5 |. 68 10544000 PUSH OFFSET 00405410 ; |Src
00403D94 |. 68 14544000 PUSH OFFSET 00405414 ; |Src = ""
00403D63 |. 68 18544000 PUSH OFFSET 00405418
00403FB2 |. 68 30544000 PUSH OFFSET 00405430
看到了吗? 看看PUSH后面的地址, 就是对应了rdata段的位置的地址, 对应了响应的字符.
但是找不到 R6028, R6027, R6026, ...在哪里有使用.
00005128 | 52 36 30 32 38 0D 0A 2D | R6028..- | 好像是错误码
00005130 | 20 75 6E 61 62 6C 65 20 | unable | 不能初始化heap?
00005138 | 74 6F 20 69 6E 69 74 69 | to initi |
00005140 | 61 6C 69 7A 65 20 68 65 | alize he |
00005148 | 61 70 0D 0A 00 00 00 00 | ap...... |
其实这个Win32工程就只是一个只有WinMain函数的工程, 为什么会有这么多其他的东西的呢?
很明显, 这些字符常量是VC帮我们加的, WinMain函数并不是PE的入口点.
在VC的安装目录C:\Program Files\Microsoft Visual Studio\VC98\CRT\SRC
搜索"<program name unknown>", 找到了对应的代码在文件CRT0MSG.C中:
void __cdecl _NMSG_WRITE (int rterrnum)
{
int tblindx;
DWORD bytes_written; /* bytes written */
for ( tblindx = 0 ; tblindx < _RTERRCNT ; tblindx++ )
if ( rterrnum == rterrs[tblindx].rterrno )
break;
if ( rterrnum == rterrs[tblindx].rterrno )
{
if ( (__error_mode == _OUT_TO_STDERR) || ((__error_mode ==
_OUT_TO_DEFAULT) && (__app_type == _CONSOLE_APP)) )
{
WriteFile( GetStdHandle(STD_ERROR_HANDLE),
rterrs[tblindx].rterrtxt,
strlen(rterrs[tblindx].rterrtxt),
&bytes_written,
NULL );
}
else if (rterrnum != _RT_CRNL)
{
#define MAXLINELEN 60
char * pch;
char progname[MAX_PATH];
char outmsg[MAXLINELEN+100];
// 看这里
if (!GetModuleFileName(NULL, progname, MAX_PATH))
strcpy(progname, "<program name unknown>");
pch = (char *)progname;
if (strlen(pch) + 1 > MAXLINELEN)
{
pch += strlen(progname) + 1 - MAXLINELEN;
strncpy(pch, "...", 3);
}
// 看这里
strcpy(outmsg, "Runtime Error!\n\nProgram: ");
strcat(outmsg, pch);
// 看这里
strcat(outmsg, "\n\n");
strcat(outmsg, rterrs[tblindx].rterrtxt);
// 看这里
__crtMessageBoxA(outmsg,
"Microsoft Visual C++ Runtime Library",
MB_OK|MB_ICONHAND|MB_SETFOREGROUND|MB_TASKMODAL);
}
....
}
...
}
但还是找不到 R6028, R6027, R6026, ...在哪里有使用.
看看rterrs, rterrs是一个全局变量数组 看该数据的结构
(CRT0MSG.C中)
/* struct used to lookup and access runtime error messages */
struct rterrmsgs
{
int rterrno; /* error number */
char *rterrtxt; /* text of error message */
};
/* runtime error messages */
// 18个
static struct rterrmsgs rterrs[] =
{
/* 2 */ { _RT_FLOAT, _RT_FLOAT_TXT },
/* 8 */ { _RT_SPACEARG, _RT_SPACEARG_TXT },
/* 9 */ { _RT_SPACEENV, _RT_SPACEENV_TXT },
/* 10*/ { _RT_ABORT, _RT_ABORT_TXT },
/* 16*/ { _RT_THREAD, _RT_THREAD_TXT },
/* 17*/ { _RT_LOCK, _RT_LOCK_TXT },
/* 18*/ { _RT_HEAP, _RT_HEAP_TXT },
/* 19*/ { _RT_OPENCON, _RT_OPENCON_TXT },
/* 24*/ { _RT_ONEXIT, _RT_ONEXIT_TXT },
/* 25*/ { _RT_PUREVIRT, _RT_PUREVIRT_TXT },
/* 26*/ { _RT_STDIOINIT, _RT_STDIOINIT_TXT },
/* 27*/ { _RT_LOWIOINIT, _RT_LOWIOINIT_TXT },
/* 28*/ { _RT_HEAPINIT, _RT_HEAPINIT_TXT },
/*120*/ { _RT_DOMAIN, _RT_DOMAIN_TXT },
/*121*/ { _RT_SING, _RT_SING_TXT },
/*122*/ { _RT_TLOSS, _RT_TLOSS_TXT },
/*252*/ { _RT_CRNL, _RT_CRNL_TXT },
/*255*/ { _RT_BANNER, _RT_BANNER_TXT }
};
(CMSGS.H中)
#define EOL "\r\n"
#define _RT_FLOAT_TXT "R6002" EOL "- floating point not loaded" EOL
#define _RT_SPACEARG_TXT "R6008" EOL "- not enough space for arguments" EOL
#define _RT_SPACEENV_TXT "R6009" EOL "- not enough space for environment" EOL
#define _RT_ABORT_TXT "" EOL "abnormal program termination" EOL
#define _RT_THREAD_TXT "R6016" EOL "- not enough space for thread data" EOL
#define _RT_LOCK_TXT "R6017" EOL "- unexpected multithread lock error" EOL
#define _RT_HEAP_TXT "R6018" EOL "- unexpected heap error" EOL
#define _RT_OPENCON_TXT "R6019" EOL "- unable to open console device" EOL
#define _RT_ONEXIT_TXT "R6024" EOL "- not enough space for _onexit/atexit table" EOL
#define _RT_PUREVIRT_TXT "R6025" EOL "- pure virtual function call" EOL
#define _RT_STDIOINIT_TXT "R6026" EOL "- not enough space for stdio initialization" EOL
#define _RT_LOWIOINIT_TXT "R6027" EOL "- not enough space for lowio initialization" EOL
#define _RT_HEAPINIT_TXT "R6028" EOL "- unable to initialize heap" EOL
#define _RT_DOMAIN_TXT "DOMAIN error" EOL
#define _RT_SING_TXT "SING error" EOL
#define _RT_TLOSS_TXT "TLOSS error" EOL
#define _RT_CRNL_TXT EOL
#define _RT_BANNER_TXT "runtime error "
所以rdata中00005128---0000536F, 就是存储这些数据的了
但是没有在代码段中找到这些常量的地址. 为什么?
struct rterrmsgs
{
int rterrno; /* error number */
char *rterrtxt; /* text of error message */
};
因为
static struct rterrmsgs rterrs[] = {...};
代码段中直接用到的是rterrs, 而这些常量通过变量rterrs被间接使用.
rterrs是一个全局变量, 它不存储在rdata段中, 它存储在data中.
所以, 先找到rterrs的地址, 就可以找到这些字符常量的调用地址,
在data段中找rterrs的内容, 地址是什么?
找到_NMSG_WRITE函数的反汇编代码, 如下:
(有点长!!!!!)
for ( tblindx = 0 ; tblindx < _RTERRCNT ; tblindx++ )
if ( rterrnum == rterrs[tblindx].rterrno )
break;
00401E2D /$ 55 PUSH EBP ; AAAAAA.00401E2D(guessed Arg1)
00401E2E |. 8BEC MOV EBP,ESP
00401E30 |. 81EC A4010000 SUB ESP,1A4 ;
0x1A4长度的局部变量
00401E36 |. 8B55 08 MOV EDX,DWORD PTR SS:[EBP + 08] ;
参数rterrnum 赋值到EDX中
00401E39 |. 33C9 XOR ECX,ECX ;
tblindx = 0
00401E3B |. B8 F0604000 MOV EAX,OFFSET 004060F0 ; _RTERRCNT的地址这就是rterrs的地址了(就是在data段)
00401E40 |> 3B10 /CMP EDX,DWORD PTR DS:[EAX] ; if ( rterrnum == rterrs[tblindx].rterrno )
00401E42 |. 74 0B |JE SHORT 00401E4F ; break
00401E44 |. 83C0 08 |ADD EAX,8
; 为什么加8, 因为 8 == sizeof(rterrmsgs)
00401E47 |. 41 |INC ECX ; tblindx++
00401E48 |. 3D 80614000 |CMP EAX,OFFSET 00406180 ; 看有没有超过rterrs数组的范围
00401E4D |.^ 72 F1 \JB SHORT 00401E40 ; 继续循环
; 现在明白了 rterrs变量的地址是004060F0
; rterrs数组项个数是 (00406180 - 004060F0) / 8 = 0x12 (18个)
00401E4F |> 56 PUSH ESI
00401E50 |. 8BF1 MOV ESI,ECX
00401E52 |. C1E6 03 SHL ESI,3
00401E55 |. 3B96 F0604000 CMP EDX,DWORD PTR DS:[ESI+4060F0]
00401E5B |. 0F85 1C010000 JNE 00401F7D
00401E61 |. A1 D8844000 MOV EAX,DWORD PTR DS:[4084D8]
00401E66 |. 83F8 01 CMP EAX,1
00401E69 |. 0F84 E8000000 JE 00401F57
00401E6F |. 85C0 TEST EAX,EAX
00401E71 |. 75 0D JNE SHORT 00401E80
00401E73 |. 833D 44604000 CMP DWORD PTR DS:[406044],1
00401E7A |. 0F84 D7000000 JE 00401F57
00401E80 |> 81FA FC000000 CMP EDX,0FC
00401E86 |. 0F84 F1000000 JE 00401F7D
00401E8C |. 8D85 5CFEFFFF LEA EAX,[LOCAL.105]
00401E92 |. 68 04010000 PUSH 104 ; /Count = 260.
00401E97 |. 50 PUSH EAX ; |Buffer => OFFSET LOCAL.105
00401E98 |. 6A 00 PUSH 0 ; |hModule = NULL
00401E9A |. FF15 28504000 CALL DWORD PTR DS:[<&KERNEL32.GetModuleF ; \KERNEL32.GetModuleFileNameA
00401EA0 |. 85C0 TEST EAX,EAX
00401EA2 |. 75 13 JNE SHORT 00401EB7
00401EA4 |. 8D85 5CFEFFFF LEA EAX,[LOCAL.105]
00401EAA |. 68 BC534000 PUSH OFFSET 004053BC ; ASCII "<program name unknown>"
00401EAF |. 50 PUSH EAX
00401EB0 |. E8 5B050000 CALL 00402410
00401EB5 |. 59 POP ECX
00401EB6 |. 59 POP ECX
00401EB7 |> 8D85 5CFEFFFF LEA EAX,[LOCAL.105]
00401EBD |. 57 PUSH EDI
00401EBE |. 50 PUSH EAX ; /Arg1 => OFFSET LOCAL.105
00401EBF |. 8DBD 5CFEFFFF LEA EDI,[LOCAL.105] ; |
00401EC5 |. E8 F6060000 CALL 004025C0 ; \AAAAAA.004025C0
00401ECA |. 40 INC EAX ; Switch (cases -1..3B, 2 exits)
00401ECB |. 59 POP ECX
00401ECC |. 83F8 3C CMP EAX,3C
00401ECF |. 76 29 JBE SHORT 00401EFA
00401ED1 |. 8D85 5CFEFFFF LEA EAX,[LOCAL.105] ; Default case of switch AAAAAA.401ECA
00401ED7 |. 50 PUSH EAX ; /Arg1 => OFFSET LOCAL.105
00401ED8 |. E8 E3060000 CALL 004025C0 ; \AAAAAA.004025C0
00401EDD |. 8BF8 MOV EDI,EAX
00401EDF |. 8D85 5CFEFFFF LEA EAX,[LOCAL.105]
00401EE5 |. 83E8 3B SUB EAX,3B
00401EE8 |. 6A 03 PUSH 3
00401EEA |. 03F8 ADD EDI,EAX
00401EEC |. 68 B8534000 PUSH OFFSET 004053B8 ; ASCII "..."
00401EF1 |. 57 PUSH EDI
00401EF2 |. E8 691D0000 CALL 00403C60
00401EF7 |. 83C4 10 ADD ESP,10
00401EFA |> 8D85 60FFFFFF LEA EAX,[LOCAL.40] ; Cases -1, 0, .... 3B of switch AAAAAA....
; (不明白这个干嘛)
00401F00 |. 68 9C534000 PUSH OFFSET 0040539C ; ASCII "Runtime Error!
Program: "
00401F05 |. 50 PUSH EAX
00401F06 |. E8 05050000 CALL 00402410
00401F0B |. 8D85 60FFFFFF LEA EAX,[LOCAL.40]
00401F11 |. 57 PUSH EDI
00401F12 |. 50 PUSH EAX
00401F13 |. E8 08050000 CALL 00402420
00401F18 |. 8D85 60FFFFFF LEA EAX,[LOCAL.40]
00401F1E |. 68 98534000 PUSH OFFSET 00405398 ; ASCII "
"
00401F23 |. 50 PUSH EAX
00401F24 |. E8 F7040000 CALL 00402420
00401F29 |. FFB6 F4604000 PUSH DWORD PTR DS:[ESI+4060F4] ; ASCII "HS@"
00401F2F |. 8D85 60FFFFFF LEA EAX,[LOCAL.40]
00401F35 |. 50 PUSH EAX
00401F36 |. E8 E5040000 CALL 00402420
00401F3B |. 68 10200100 PUSH 12010
00401F40 |. 8D85 60FFFFFF LEA EAX,[LOCAL.40]
00401F46 |. 68 70534000 PUSH OFFSET 00405370 ; ASCII "Microsoft Visual C++ Runtime Library"
00401F4B |. 50 PUSH EAX
00401F4C |. E8 831C0000 CALL 00403BD4
00401F51 |. 83C4 2C ADD ESP,2C
00401F54 |. 5F POP EDI
00401F55 |. EB 26 JMP SHORT 00401F7D
00401F57 |> 8D45 08 LEA EAX,[ARG.1]
00401F5A |. 8DB6 F4604000 LEA ESI,[ESI+4060F4] ; ASCII "HS@"
00401F60 |. 6A 00 PUSH 0 ; /pOverlapped = NULL
00401F62 |. 50 PUSH EAX ; |pBytesWritten => OFFSET ARG.1
00401F63 |. FF36 PUSH DWORD PTR DS:[ESI] ; |/Arg1
00401F65 |. E8 56060000 CALL 004025C0 ; |\AAAAAA.004025C0
00401F6A |. 59 POP ECX ; |
00401F6B |. 50 PUSH EAX ; |Size
00401F6C |. FF36 PUSH DWORD PTR DS:[ESI] ; |Buffer
00401F6E |. 6A F4 PUSH -0C ; |/StdHandle = STD_ERROR_HANDLE
00401F70 |. FF15 44504000 CALL DWORD PTR DS:[<&KERNEL32.GetStdHand ; |\KERNEL32.GetStdHandle
00401F76 |. 50 PUSH EAX ; |hFile
00401F77 |. FF15 64504000 CALL DWORD PTR DS:[<&KERNEL32.WriteFile> ; \KERNEL32.WriteFile
00401F7D |> 5E POP ESI
00401F7E |. C9 LEAVE
00401F7F \. C3 RETN
一个PE文件rdata段的分析(Win32工程Release版)(二)
下面分析这个PE文件rdata段的常量数据(000050A4---0000543D)
000050A0 | 00 00 00 00 | .... |
000050A8 | FF FF FF FF 27 11 40 00 | '.@. | 这像一个地址00401127
000050B0 | 3B 11 40 00 5F 5F 47 4C | ;.@.__GL |
0040113B 也是
000050B8 | 4F 42 41 4C 5F 48 45 41 | OBAL_HEA | 一段字符
......
000050E0 | 00 00 00 00 72 75 6E 74 | ....runt | 运行时错误?
000050E8 | 69 6D 65 20 65 72 72 6F | ime erro |
000050F0 | 72 20 00 00 0D 0A 00 00 | r ...... |
......
00005128 | 52 36 30 32 38 0D 0A 2D | R6028..- | 好像是错误码
00005130 | 20 75 6E 61 62 6C 65 20 | unable | 不能初始化heap?
00005138 | 74 6F 20 69 6E 69 74 69 | to initi |
00005140 | 61 6C 69 7A 65 20 68 65 | alize he |
00005148 | 61 70 0D 0A 00 00 00 00 | ap...... |
00005150 | 52 36 30 32 37 0D 0A 2D | R6027..- |
00005158 | 20 6E 6F 74 20 65 6E 6F | not eno |
00005160 | 75 67 68 20 73 70 61 63 | ugh spac |
00005168 | 65 20 66 6F 72 20 6C 6F | e for lo |
00005170 | 77 69 6F 20 69 6E 69 74 | wio init |
00005178 | 69 61 6C 69 7A 61 74 69 | ializati |
00005180 | 6F 6E 0D 0A 00 00 00 00 | on...... |
00005188 | 52 36 30 32 36 0D 0A 2D | R6026..- |
00005190 | 20 6E 6F 74 20 65 6E 6F | not eno |
00005198 | 75 67 68 20 73 70 61 63 | ugh spac |
000051A0 | 65 20 66 6F 72 20 73 74 | e for st |
000051A8 | 64 69 6F 20 69 6E 69 74 | dio init |
000051B0 | 69 61 6C 69 7A 61 74 69 | ializati |
000051B8 | 6F 6E 0D 0A 00 00 00 00 | on...... |
000051C0 | 52 36 30 32 35 0D 0A 2D | R6025..- |
000051C8 | 20 70 75 72 65 20 76 69 | pure vi |
000051D0 | 72 74 75 61 6C 20 66 75 | rtual fu |
000051D8 | 6E 63 74 69 6F 6E 20 63 | nction c |
000051E0 | 61 6C 6C 0D 0A 00 00 00 | all..... |
000051E8 | 52 36 30 32 34 0D 0A 2D | R6024..- |
...
00005370 | 4D 69 63 72 6F 73 6F 66 | Microsof | 哈哈, 这个很熟悉哦
00005378 | 74 20 56 69 73 75 61 6C | t Visual |
00005380 | 20 43 2B 2B 20 52 75 6E | C++ Run |
00005388 | 74 69 6D 65 20 4C 69 62 | time Lib |
00005390 | 72 61 72 79 00 00 00 00 | rary.... |
...
000053E0 | 65 50 6F 70 75 70 00 00 | ePopup.. |
000053E8 | 47 65 74 41 63 74 69 76 | GetActiv |
000053F0 | 65 57 69 6E 64 6F 77 00 | eWindow. |
000053F8 | 4D 65 73 73 61 67 65 42 | MessageB |
00005400 | 6F 78 41 00 75 73 65 72 | oxA.user | 怎么也有user32.dll?
00005408 | 33 32 2E 64 6C 6C 00 00 | 32.dll.. |
...
00005428 | 22 3F 40 00 26 3F 40 00 |
00005430 | FF FF FF FF A6 40 40 00 |
00005438 | AA 40 40 00 |
分析过程如下:
OD反汇编了一下代码段, 看到一些指令
00401055 |. 68 A8504000 PUSH OFFSET 004050A8 ; FF FF FF FF
00401B0B |. 68 B4504000 PUSH OFFSET 004050B4 ; |Arg1 = ASCII "__GLOBAL_HEAP_SELECTED"
00401ACC |. 68 CC504000 PUSH OFFSET 004050CC ; |Name = "__MSVCRT_HEAP_SELECT"
00401F46 |. 68 70534000 PUSH OFFSET 00405370 ; ASCII "Microsoft Visual C++ Runtime Library"
00401F1E |. 68 98534000 PUSH OFFSET 00405398 ; ASCII ""
00401F00 |. 68 9C534000 PUSH OFFSET 0040539C ; ASCII "Runtime Error! Program: "
00401EEC |. 68 B8534000 PUSH OFFSET 004053B8 ; ASCII "..."
00401EAA |. 68 BC534000 PUSH OFFSET 004053BC ; ASCII "<program name unknown>"
00403C11 |. 68 D4534000 PUSH OFFSET 004053D4 ; /Procname = "GetLastActivePopup"
00403C09 |. 68 E8534000 PUSH OFFSET 004053E8 ; /Procname = "GetActiveWindow"
00403BF8 |. 68 F8534000 PUSH OFFSET 004053F8 ; /Procname = "MessageBoxA"
00403BE1 |. 68 04544000 PUSH OFFSET 00405404 ; /FileName = "user32.dll"
00403DB5 |. 68 10544000 PUSH OFFSET 00405410 ; |Src
00403D94 |. 68 14544000 PUSH OFFSET 00405414 ; |Src = ""
00403D63 |. 68 18544000 PUSH OFFSET 00405418
00403FB2 |. 68 30544000 PUSH OFFSET 00405430
看到了吗? 看看PUSH后面的地址, 就是对应了rdata段的位置的地址, 对应了响应的字符.
但是找不到 R6028, R6027, R6026, ...在哪里有使用.
00005128 | 52 36 30 32 38 0D 0A 2D | R6028..- | 好像是错误码
00005130 | 20 75 6E 61 62 6C 65 20 | unable | 不能初始化heap?
00005138 | 74 6F 20 69 6E 69 74 69 | to initi |
00005140 | 61 6C 69 7A 65 20 68 65 | alize he |
00005148 | 61 70 0D 0A 00 00 00 00 | ap...... |
其实这个Win32工程就只是一个只有WinMain函数的工程, 为什么会有这么多其他的东西的呢?
很明显, 这些字符常量是VC帮我们加的, WinMain函数并不是PE的入口点.
在VC的安装目录C:\Program Files\Microsoft Visual Studio\VC98\CRT\SRC
搜索"<program name unknown>", 找到了对应的代码在文件CRT0MSG.C中:
void __cdecl _NMSG_WRITE (int rterrnum)
{
int tblindx;
DWORD bytes_written; /* bytes written */
for ( tblindx = 0 ; tblindx < _RTERRCNT ; tblindx++ )
if ( rterrnum == rterrs[tblindx].rterrno )
break;
if ( rterrnum == rterrs[tblindx].rterrno )
{
if ( (__error_mode == _OUT_TO_STDERR) || ((__error_mode ==
_OUT_TO_DEFAULT) && (__app_type == _CONSOLE_APP)) )
{
WriteFile( GetStdHandle(STD_ERROR_HANDLE),
rterrs[tblindx].rterrtxt,
strlen(rterrs[tblindx].rterrtxt),
&bytes_written,
NULL );
}
else if (rterrnum != _RT_CRNL)
{
#define MAXLINELEN 60
char * pch;
char progname[MAX_PATH];
char outmsg[MAXLINELEN+100];
// 看这里
if (!GetModuleFileName(NULL, progname, MAX_PATH))
strcpy(progname, "<program name unknown>");
pch = (char *)progname;
if (strlen(pch) + 1 > MAXLINELEN)
{
pch += strlen(progname) + 1 - MAXLINELEN;
strncpy(pch, "...", 3);
}
// 看这里
strcpy(outmsg, "Runtime Error!\n\nProgram: ");
strcat(outmsg, pch);
// 看这里
strcat(outmsg, "\n\n");
strcat(outmsg, rterrs[tblindx].rterrtxt);
// 看这里
__crtMessageBoxA(outmsg,
"Microsoft Visual C++ Runtime Library",
MB_OK|MB_ICONHAND|MB_SETFOREGROUND|MB_TASKMODAL);
}
....
}
...
}
但还是找不到 R6028, R6027, R6026, ...在哪里有使用.
看看rterrs, rterrs是一个全局变量数组 看该数据的结构
(CRT0MSG.C中)
/* struct used to lookup and access runtime error messages */
struct rterrmsgs
{
int rterrno; /* error number */
char *rterrtxt; /* text of error message */
};
/* runtime error messages */
// 18个
static struct rterrmsgs rterrs[] =
{
/* 2 */ { _RT_FLOAT, _RT_FLOAT_TXT },
/* 8 */ { _RT_SPACEARG, _RT_SPACEARG_TXT },
/* 9 */ { _RT_SPACEENV, _RT_SPACEENV_TXT },
/* 10*/ { _RT_ABORT, _RT_ABORT_TXT },
/* 16*/ { _RT_THREAD, _RT_THREAD_TXT },
/* 17*/ { _RT_LOCK, _RT_LOCK_TXT },
/* 18*/ { _RT_HEAP, _RT_HEAP_TXT },
/* 19*/ { _RT_OPENCON, _RT_OPENCON_TXT },
/* 24*/ { _RT_ONEXIT, _RT_ONEXIT_TXT },
/* 25*/ { _RT_PUREVIRT, _RT_PUREVIRT_TXT },
/* 26*/ { _RT_STDIOINIT, _RT_STDIOINIT_TXT },
/* 27*/ { _RT_LOWIOINIT, _RT_LOWIOINIT_TXT },
/* 28*/ { _RT_HEAPINIT, _RT_HEAPINIT_TXT },
/*120*/ { _RT_DOMAIN, _RT_DOMAIN_TXT },
/*121*/ { _RT_SING, _RT_SING_TXT },
/*122*/ { _RT_TLOSS, _RT_TLOSS_TXT },
/*252*/ { _RT_CRNL, _RT_CRNL_TXT },
/*255*/ { _RT_BANNER, _RT_BANNER_TXT }
};
(CMSGS.H中)
#define EOL "\r\n"
#define _RT_FLOAT_TXT "R6002" EOL "- floating point not loaded" EOL
#define _RT_SPACEARG_TXT "R6008" EOL "- not enough space for arguments" EOL
#define _RT_SPACEENV_TXT "R6009" EOL "- not enough space for environment" EOL
#define _RT_ABORT_TXT "" EOL "abnormal program termination" EOL
#define _RT_THREAD_TXT "R6016" EOL "- not enough space for thread data" EOL
#define _RT_LOCK_TXT "R6017" EOL "- unexpected multithread lock error" EOL
#define _RT_HEAP_TXT "R6018" EOL "- unexpected heap error" EOL
#define _RT_OPENCON_TXT "R6019" EOL "- unable to open console device" EOL
#define _RT_ONEXIT_TXT "R6024" EOL "- not enough space for _onexit/atexit table" EOL
#define _RT_PUREVIRT_TXT "R6025" EOL "- pure virtual function call" EOL
#define _RT_STDIOINIT_TXT "R6026" EOL "- not enough space for stdio initialization" EOL
#define _RT_LOWIOINIT_TXT "R6027" EOL "- not enough space for lowio initialization" EOL
#define _RT_HEAPINIT_TXT "R6028" EOL "- unable to initialize heap" EOL
#define _RT_DOMAIN_TXT "DOMAIN error" EOL
#define _RT_SING_TXT "SING error" EOL
#define _RT_TLOSS_TXT "TLOSS error" EOL
#define _RT_CRNL_TXT EOL
#define _RT_BANNER_TXT "runtime error "
所以rdata中00005128---0000536F, 就是存储这些数据的了
但是没有在代码段中找到这些常量的地址. 为什么?
struct rterrmsgs
{
int rterrno; /* error number */
char *rterrtxt; /* text of error message */
};
因为
static struct rterrmsgs rterrs[] = {...};
代码段中直接用到的是rterrs, 而这些常量通过变量rterrs被间接使用.
rterrs是一个全局变量, 它不存储在rdata段中, 它存储在data中.
所以, 先找到rterrs的地址, 就可以找到这些字符常量的调用地址,
在data段中找rterrs的内容, 地址是什么?
找到_NMSG_WRITE函数的反汇编代码, 如下:
(有点长!!!!!)
for ( tblindx = 0 ; tblindx < _RTERRCNT ; tblindx++ )
if ( rterrnum == rterrs[tblindx].rterrno )
break;
00401E2D /$ 55 PUSH EBP ; AAAAAA.00401E2D(guessed Arg1)
00401E2E |. 8BEC MOV EBP,ESP
00401E30 |. 81EC A4010000 SUB ESP,1A4 ;
0x1A4长度的局部变量
00401E36 |. 8B55 08 MOV EDX,DWORD PTR SS:[EBP + 08] ;
参数rterrnum 赋值到EDX中
00401E39 |. 33C9 XOR ECX,ECX ;
tblindx = 0
00401E3B |. B8 F0604000 MOV EAX,OFFSET 004060F0 ; _RTERRCNT的地址这就是rterrs的地址了(就是在data段)
00401E40 |> 3B10 /CMP EDX,DWORD PTR DS:[EAX] ; if ( rterrnum == rterrs[tblindx].rterrno )
00401E42 |. 74 0B |JE SHORT 00401E4F ; break
00401E44 |. 83C0 08 |ADD EAX,8
; 为什么加8, 因为 8 == sizeof(rterrmsgs)
00401E47 |. 41 |INC ECX ; tblindx++
00401E48 |. 3D 80614000 |CMP EAX,OFFSET 00406180 ; 看有没有超过rterrs数组的范围
00401E4D |.^ 72 F1 \JB SHORT 00401E40 ; 继续循环
; 现在明白了 rterrs变量的地址是004060F0
; rterrs数组项个数是 (00406180 - 004060F0) / 8 = 0x12 (18个)
00401E4F |> 56 PUSH ESI
00401E50 |. 8BF1 MOV ESI,ECX
00401E52 |. C1E6 03 SHL ESI,3
00401E55 |. 3B96 F0604000 CMP EDX,DWORD PTR DS:[ESI+4060F0]
00401E5B |. 0F85 1C010000 JNE 00401F7D
00401E61 |. A1 D8844000 MOV EAX,DWORD PTR DS:[4084D8]
00401E66 |. 83F8 01 CMP EAX,1
00401E69 |. 0F84 E8000000 JE 00401F57
00401E6F |. 85C0 TEST EAX,EAX
00401E71 |. 75 0D JNE SHORT 00401E80
00401E73 |. 833D 44604000 CMP DWORD PTR DS:[406044],1
00401E7A |. 0F84 D7000000 JE 00401F57
00401E80 |> 81FA FC000000 CMP EDX,0FC
00401E86 |. 0F84 F1000000 JE 00401F7D
00401E8C |. 8D85 5CFEFFFF LEA EAX,[LOCAL.105]
00401E92 |. 68 04010000 PUSH 104 ; /Count = 260.
00401E97 |. 50 PUSH EAX ; |Buffer => OFFSET LOCAL.105
00401E98 |. 6A 00 PUSH 0 ; |hModule = NULL
00401E9A |. FF15 28504000 CALL DWORD PTR DS:[<&KERNEL32.GetModuleF ; \KERNEL32.GetModuleFileNameA
00401EA0 |. 85C0 TEST EAX,EAX
00401EA2 |. 75 13 JNE SHORT 00401EB7
00401EA4 |. 8D85 5CFEFFFF LEA EAX,[LOCAL.105]
00401EAA |. 68 BC534000 PUSH OFFSET 004053BC ; ASCII "<program name unknown>"
00401EAF |. 50 PUSH EAX
00401EB0 |. E8 5B050000 CALL 00402410
00401EB5 |. 59 POP ECX
00401EB6 |. 59 POP ECX
00401EB7 |> 8D85 5CFEFFFF LEA EAX,[LOCAL.105]
00401EBD |. 57 PUSH EDI
00401EBE |. 50 PUSH EAX ; /Arg1 => OFFSET LOCAL.105
00401EBF |. 8DBD 5CFEFFFF LEA EDI,[LOCAL.105] ; |
00401EC5 |. E8 F6060000 CALL 004025C0 ; \AAAAAA.004025C0
00401ECA |. 40 INC EAX ; Switch (cases -1..3B, 2 exits)
00401ECB |. 59 POP ECX
00401ECC |. 83F8 3C CMP EAX,3C
00401ECF |. 76 29 JBE SHORT 00401EFA
00401ED1 |. 8D85 5CFEFFFF LEA EAX,[LOCAL.105] ; Default case of switch AAAAAA.401ECA
00401ED7 |. 50 PUSH EAX ; /Arg1 => OFFSET LOCAL.105
00401ED8 |. E8 E3060000 CALL 004025C0 ; \AAAAAA.004025C0
00401EDD |. 8BF8 MOV EDI,EAX
00401EDF |. 8D85 5CFEFFFF LEA EAX,[LOCAL.105]
00401EE5 |. 83E8 3B SUB EAX,3B
00401EE8 |. 6A 03 PUSH 3
00401EEA |. 03F8 ADD EDI,EAX
00401EEC |. 68 B8534000 PUSH OFFSET 004053B8 ; ASCII "..."
00401EF1 |. 57 PUSH EDI
00401EF2 |. E8 691D0000 CALL 00403C60
00401EF7 |. 83C4 10 ADD ESP,10
00401EFA |> 8D85 60FFFFFF LEA EAX,[LOCAL.40] ; Cases -1, 0, .... 3B of switch AAAAAA....
; (不明白这个干嘛)
00401F00 |. 68 9C534000 PUSH OFFSET 0040539C ; ASCII "Runtime Error!
Program: "
00401F05 |. 50 PUSH EAX
00401F06 |. E8 05050000 CALL 00402410
00401F0B |. 8D85 60FFFFFF LEA EAX,[LOCAL.40]
00401F11 |. 57 PUSH EDI
00401F12 |. 50 PUSH EAX
00401F13 |. E8 08050000 CALL 00402420
00401F18 |. 8D85 60FFFFFF LEA EAX,[LOCAL.40]
00401F1E |. 68 98534000 PUSH OFFSET 00405398 ; ASCII "
"
00401F23 |. 50 PUSH EAX
00401F24 |. E8 F7040000 CALL 00402420
00401F29 |. FFB6 F4604000 PUSH DWORD PTR DS:[ESI+4060F4] ; ASCII "HS@"
00401F2F |. 8D85 60FFFFFF LEA EAX,[LOCAL.40]
00401F35 |. 50 PUSH EAX
00401F36 |. E8 E5040000 CALL 00402420
00401F3B |. 68 10200100 PUSH 12010
00401F40 |. 8D85 60FFFFFF LEA EAX,[LOCAL.40]
00401F46 |. 68 70534000 PUSH OFFSET 00405370 ; ASCII "Microsoft Visual C++ Runtime Library"
00401F4B |. 50 PUSH EAX
00401F4C |. E8 831C0000 CALL 00403BD4
00401F51 |. 83C4 2C ADD ESP,2C
00401F54 |. 5F POP EDI
00401F55 |. EB 26 JMP SHORT 00401F7D
00401F57 |> 8D45 08 LEA EAX,[ARG.1]
00401F5A |. 8DB6 F4604000 LEA ESI,[ESI+4060F4] ; ASCII "HS@"
00401F60 |. 6A 00 PUSH 0 ; /pOverlapped = NULL
00401F62 |. 50 PUSH EAX ; |pBytesWritten => OFFSET ARG.1
00401F63 |. FF36 PUSH DWORD PTR DS:[ESI] ; |/Arg1
00401F65 |. E8 56060000 CALL 004025C0 ; |\AAAAAA.004025C0
00401F6A |. 59 POP ECX ; |
00401F6B |. 50 PUSH EAX ; |Size
00401F6C |. FF36 PUSH DWORD PTR DS:[ESI] ; |Buffer
00401F6E |. 6A F4 PUSH -0C ; |/StdHandle = STD_ERROR_HANDLE
00401F70 |. FF15 44504000 CALL DWORD PTR DS:[<&KERNEL32.GetStdHand ; |\KERNEL32.GetStdHandle
00401F76 |. 50 PUSH EAX ; |hFile
00401F77 |. FF15 64504000 CALL DWORD PTR DS:[<&KERNEL32.WriteFile> ; \KERNEL32.WriteFile
00401F7D |> 5E POP ESI
00401F7E |. C9 LEAVE
00401F7F \. C3 RETN
相关文章推荐
- PE文件格式分析系列(文章2)----一个PE文件rdata段的分析(Win32工程Release版)(一)
- PE文件格式分析系列(文章1)----一个PE文件导入表数据的分析(MFC工程调试版)
- PE文件格式之win32应用程序初探
- PE文件格式分析及修改
- PE文件格式分析
- PE文件格式分析及修改
- 窥探PE文件内幕:Win32 PE 文件格式之旅 2
- (转载)win32 PE 文件格式
- PE文件格式系列(一)——探究PE文件常见Section作用
- win32 PE 文件格式
- PE文件和COFF文件格式分析--MS-DOS 2.0兼容Exe文件段
- PE文件格式之win32应用程序初探
- 一个PE文件的逆向分析
- win32 PE 文件格式
- [Ext4] Ext4文件系统分析系列文章
- PE文件格式分析
- PE文件格式分析及修改
- [Ext4] Ext4文件系统分析系列文章
- CLR探索系列:托管PE/COFF文件格式侧窥
- PE文件格式系列译文之