exe ファイルの中にある ABCDEFG… は何なのか
exe ファイルやダンプファイルを見ていると、”ABCDEFGHIJKLMN…” といった文字列を目にすることがあります。
これは何なのでしょうか。
動作確認環境
- Windows 11 Home 21H2
- Visual Studio Community 2019
ABCDEFG… の文字列
何の処理もしないプログラム「ctest1.c」を書きます。
int main()
{
return 0;
}
Visual C++ でビルドします。
C:\tmp>cl ctest1.c
......
/out:ctest1.exe
ctest1.obj
生成された「ctest1.exe」ファイルの中身を見てみます。
C:\tmp>certutil -f -encodehex ctest1.exe tmp 11
入力長 = 95232
出力長 = 442304
CertUtil: -encodehex コマンドは正常に完了しました。
C:\tmp>type tmp
......
e590 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO
e5a0 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f PQRSTUVWXYZ[\]^_
e5b0 60 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f `ABCDEFGHIJKLMNO
e5c0 50 51 52 53 54 55 56 57 58 59 5a 7b 7c 7d 7e 7f PQRSTUVWXYZ{|}~.
......
153d0 77 78 79 7a 00 00 00 00 00 00 41 42 43 44 45 46 wxyz......ABCDEF
153e0 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 GHIJKLMNOPQRSTUV
153f0 57 58 59 5a 00 00 00 00 00 00 00 00 00 00 00 00 WXYZ............
......
15600 00 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f .ABCDEFGHIJKLMNO
15610 50 51 52 53 54 55 56 57 58 59 5a 00 00 00 00 00 PQRSTUVWXYZ.....
......
プログラムには書いていないのに、”ABCDEFG…” が 4 箇所に見つかります(exe ファイル内アドレス「0xe591」「0xe5b1」「0x153da」「0x15601」)。
ファイル内のアドレスからソースを探す
アドレス「0xe591」にある “ABCDEFG…” はどこから来た文字列なのでしょうか。
調査のため、マップファイル「ctest1.map」を生成しておきます(/Fm オプション)。
C:\tmp>cl /Fm ctest1.c
......
/out:ctest1.exe
/map:ctest1.map
ctest1.obj
また、exe ファイルのヘッダ情報を取得します。
C:\tmp>dumpbin /headers ctest1.exe
......
SECTION HEADER #1
......
400 file pointer to raw data (00000400 to 0000C3FF)
......
SECTION HEADER #2
......
C400 file pointer to raw data (0000C400 to 000151FF)
......
SECTION HEADER #3
......
15200 file pointer to raw data (00015200 to 00015BFF)
......
SECTION HEADER #4
......
15C00 file pointer to raw data (00015C00 to 000169FF)
......
SECTION HEADER #5
......
16A00 file pointer to raw data (00016A00 to 00016BFF)
......
SECTION HEADER #6
......
16C00 file pointer to raw data (00016C00 to 000173FF)
......
ヘッダ情報から、exe ファイル内のアドレス「0xe591」は、「SECTION HEADER #2」の「file pointer to raw data (0000C400 to 000151FF)」に含まれることがわかります(0xC400 <= 0xe591 <= 0x151FF)。
「セクションヘッダ #2」内でのオフセットは「0x2191」です(0xe591 – 0xC400)。
続いてマップファイル「ctest1.map」を参照し、「セクションヘッダ #2」内のオフセット「0x2191」、すなわち「0002:00002191」に何があるのか調べます。
......
0002:00001f50 __newclmap 000000014000ef50 libucrt:ctype.obj
0002:000020d0 __newcumap 000000014000f0d0 libucrt:ctype.obj
0002:00002250 ??_C@_15PJ...... 000000014000f250 libucrt:get_qualified_locale.obj
......
「__newcumap」という変数(定数)の中を指しています(0002:000020d0 <= 0002:00002191 < 0002:00002250)。行末の「libucrt:ctype.obj」から、libucrt ライブラリ(マイクロソフトの C ランタイムライブラリ)内の「ctype.obj」で定義されていることもわかります
「ctype.obj」のソース「ctype.cpp」から「__newcumap」の定義を見てみます。
(私の PC では「C:\Program Files (x86)\Windows Kits\10\Source\10.0.19041.0\ucrt\locale」内にありました。)
......
extern "C" extern unsigned char const __newcumap[384]
{
......
0x41, // 41 A
0x42, // 42 B
0x43, // 43 C
0x44, // 44 D
0x45, // 45 E
0x46, // 46 F
0x47, // 47 G
......
確かに、”ABCDEFG…” が定義されていました。
同様にヘッダ情報とマップファイルから探す
exe ファイル内のアドレス「0xe5b1」「0x153da」「0x15601」にある “ABCDEFG…” についても、同じように調査します。
exe ファイル内のアドレス「0xe5b1」は「セクションヘッダ #2」に含まれます(0000C400 to 000151FF)。
「セクションヘッダ #2」内でのオフセットは「0x21b1」です(0xe5b1 – 0xc400)。
マップファイルから「0002:000021b1」の場所を探すと、「ctype.obj」の「__newcumap」内であることがわかります(さきほどと同じ)。
0002:000020d0 __newcumap 000000014000f0d0 libucrt:ctype.obj
「__newcumap」の定義をあらためて見てみると、”ABCDEFG…” が 2 回定義されていました。
......
extern "C" extern unsigned char const __newcumap[384]
{
......
0x41, // 41 A
0x42, // 42 B
0x43, // 43 C
0x44, // 44 D
0x45, // 45 E
0x46, // 46 F
0x47, // 47 G
......
0x41, // 61 a
0x42, // 62 b
0x43, // 63 c
0x44, // 64 d
0x45, // 65 e
0x46, // 66 f
0x47, // 67 g
......
次です。
exe ファイル内のアドレス「0x153da」は「セクションヘッダ #3」に含まれます(00015200 to 00015BFF)。
「セクションヘッダ #3」内でのオフセットは「0x1da」です(0x153da – 0x15200)。
マップファイルから「0003:0000001da」の場所を探すと、「mbctype.obj」の「__acrt_initial_multibyte_data」内であることがわかります。
0003:00000060 __acrt_initial_multibyte_data 0000000140016060 libucrt:mbctype.obj
「mbctype.obj」のソース「mbctype.cpp」から「__acrt_initial_multibyte_data」の定義を見ると、確かに “ABCDEFG…”(0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47…)が定義されていました。
(私の PC では「C:\Program Files (x86)\Windows Kits\10\Source\10.0.19041.0\ucrt\mbstring」内にありました。)
......
__crt_multibyte_data __acrt_initial_multibyte_data =
{
......
0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73,
0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b,
0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00 /* rest is zero */
......
最後です。
exe ファイル内のアドレス「0x15601」も「セクションヘッダ #3」に含まれます(00015200 to 00015BFF)。
「セクションヘッダ #3」内でのオフセットは「0x401」です(0x15601 – 0x15200)。
マップファイルから「0003:00000401」の場所を探すと、「mbctype.obj」の「_mbcasemaps」内であることがわかります。
0003:000003a0 _mbcasemaps 00000001400163a0 libucrt:mbctype.obj
「mbctype.obj」のソース「mbctype.cpp」から「_mbcasemaps」の定義を見ると、確かに “ABCDEFG…”(0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47…)が定義されていました。
......
#define _MBCASEMAP_DEFAULT \
{ \
......
0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, \
0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, \
0x58, 0x59, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00 /* rest is zero */ \
}
static unsigned char _mbcasemaps[__crt_state_management::state_index_count][256] =
{
_MBCASEMAP_DEFAULT
......
“ABCDEFG…” は C ランタイムライブラリでした
予想はしていましたが、”ABCDEFG…” の実体は C ランタイムライブラリでした。
C ランタイムライブラリを exe ファイル内に抱えるのではなく、実行時に動的にリンクするよう指定すると(/MD オプション)、exe ファイル内から “ABCDEFG…” の文字が消えました。
C:\tmp>cl /MD ctest1.c
C:\tmp>certutil -f -encodehex ctest1.exe tmp 11
C:\tmp>type tmp | find "ABC"
<検索されず>
C:\tmp>type tmp | find "DEF"
<検索されず>