私が気にする100の事象

気にしなければ始まらない。

12021-06-02

昨日の日記(12021年6月2日)です。 天気は曇り。 電波は悪い。

VRChat

VR感度とは?というワールドへ行きました。

f:id:skytomo:20210603082108p:plain
shinoさん(左)とYuniboshiさん(右)

f:id:skytomo:20210603082035p:plain
旗を立てるペンギンさん

ところで、ハンバーグから温かみとか匂いというのは感じられませんでした。 そういう感覚はあんまり分からないっぽいです。

f:id:skytomo:20210603081947p:plain
shinoさん(左)と秋葉原さん(右)

f:id:skytomo:20210603081925p:plain
秋葉原さん(上)とshinoさん(下)

f:id:skytomo:20210603081851p:plain
秋葉原さん(上)とshinoさん(下)

かわいいですね。

f:id:skytomo:20210603081823p:plain
ねじまきさん(左)とshinoさん(右)

ねじまきさんとは初めてお会いしました。

exeファイルを読んで見る(5日目)

前にエントリーポイントのところを逆アセンブリしましたが、

sub   rsp, 28h
call  00000A84h
add   rsp, 28h
jmp   00000528h

意味がよくわかっていませんでした。 そこで今回はGhidraを使いました。

                      **************************************************************
                      *                          FUNCTION                          *
                      **************************************************************
                      int __fastcall entry(void)
      int               EAX:4          <RETURN>
                      mainCRTStartup                                  XREF[2]:     Entry Point(*), 140000118(*)  
                      entry
1400012a4 48 83 ec 28     SUB        RSP,0x28
1400012a8 e8 d7 03        CALL       __security_init_cookie                           void __security_init_cookie(void)
          00 00
1400012ad 48 83 c4 28     ADD        RSP,0x28
1400012b1 e9 72 fe        JMP        __scrt_common_main_seh                           int __scrt_common_main_seh(void)
          ff ff
                      -- Flow Override: CALL_RETURN (CALL_TERMINATOR)

うおおお、すごい! 切り出してみましょう。

SUB        RSP,0x28
CALL       __security_init_cookie
ADD        RSP,0x28
JMP        __scrt_common_main_seh

すごい… どうして関数がわかるんでしょうか。

Ghidraくんはデコンパイルできるので、それを使ってみると…

int entry(void)

{
  int iVar1;

  __security_init_cookie();
  iVar1 = __scrt_common_main_seh();
  return iVar1;
}

おおー! すごいです。

SUB RSP,0x28int iVar1;と返り値のintに対応しています。 どういうことか説明します。 ここを参照すると、

Microsoft* x64 の呼び出し規約は、レジスター領域の拡張により、fastcall しかありません (x86 では、stdcall、thiscall、fastcall、cdecl など多数あります)。C/C++ 形式の関数を使用する場合のルールは、次のとおりです。

(略)

  • スタックは 16 バイトでアライメントされています。”call” 命令は 8 バイトの戻り値をプッシュするため、リーフでない関数はスタック領域を割り当てる際に、値を 16n+8 形式で指定してスタックを調整する必要があります。

などということが書かれています。

うーん 分かるようで分からない説明です。 細かく見てましょう。

スタックは 16 バイトでアライメントされています。

とは、 64ビット版ではスタックは16バイトごとである(読み取るデータは16の倍数のメモリアドレスにある必要がある)ということです。 こういうのを 「16バイト境界にアライン (align:整列,位置合わせ) する」 とか 「16 バイトでアライメントされている」 とか言うみたいですね。 だから16バイトの倍数でないといけないわけです。

次に、

”call” 命令は 8 バイトの戻り値をプッシュするため、リーフでない関数はスタック領域を割り当てる際に、値を 16n+8 形式で指定してスタックを調整する必要があります。

ですが、 リーフ関数とは、 直訳すると「葉っぱの関数」で、 Microsoftの文書 によると、 「非volatileレジスタを変更しない関数」と書かれていますが、 簡単に言うと、 「呼び出しスタックの一番下にのみ現れる関数」で、 もっと簡単にいうと、 「他の関数をコールしない関数」のことです。 つまり、リーフでない関数とは他の関数を呼び出す関数のことですね。

んで、 スタックは 16 バイトでアライメントされていて、 返り値のためにさらに8バイト必要なので、 16 * 2 + 8 = 40バイト、 16進数で28hになるわけです。 (どうして16バイトではなく32バイトを確保するかは後で書きます。) SUB RSP,0x28がどうして28hなのかはそういうことです。

さて、次にCALL __security_init_cookieですが、 __security_init_cookieMicrosoftの公式ドキュメント があります。 詳しくは説明しませんが、 セキュリティ関連のことらしいですね。 ここ(またしてもMicrosoftの公式ドキュメント) とか すなのかたまり(msmaniaさんのブログ) とかでさらに詳しい説明があります。

__security_init_cookie関数をデコンパイルすると、

void __security_init_cookie(void)

{
  DWORD DVar1;
  _FILETIME local_res8;
  _FILETIME local_res10;
  uint local_res18;
  undefined4 uStackX28;

  if (__security_cookie == 0x2b992ddfa232) {
    local_res10 = (_FILETIME)0x0;
    GetSystemTimeAsFileTime((LPFILETIME)&local_res10);
    local_res8 = local_res10;
    DVar1 = GetCurrentThreadId();
    local_res8 = (_FILETIME)((ulonglong)local_res8 ^ (ulonglong)DVar1);
    DVar1 = GetCurrentProcessId();
    local_res8 = (_FILETIME)((ulonglong)local_res8 ^ (ulonglong)DVar1);
    QueryPerformanceCounter((LARGE_INTEGER *)&local_res18);
    __security_cookie =
         ((ulonglong)local_res18 << 0x20 ^ CONCAT44(uStackX28,local_res18) ^ (ulonglong)local_res8 ^
         (ulonglong)&local_res8) & 0xffffffffffff;
    if (__security_cookie == 0x2b992ddfa232) {
      __security_cookie = 0x2b992ddfa233;
    }
  }
  __security_cookie_complement = ~__security_cookie;
  return;
}

となるのですが、

  DWORD DVar1;
  _FILETIME local_res8;
  _FILETIME local_res10;
  uint local_res18;
  undefined4 uStackX28;

が対応するアセンブリが、

MOV        qword ptr [RSP + local_res20],RBX

ここなんですね。 DWORD(4バイト)+_FILETIME(8バイト)+_FILETIME(8バイト)+uint(4バイト)+undefined4(4バイト) で28バイト、 スタックのアライメントは16バイトなので、 32バイト確保する必要があるわけです。

__security_init_cookieをちゃんと読む気はないので、 飛ばします。

次に__scrt_common_main_sehを見てみましょう。

                      **************************************************************
                      *                          FUNCTION                          *
                      **************************************************************
                      int __fastcall __scrt_common_main_seh(void)
      int               EAX:4          <RETURN>
      undefined8        Stack[0x10]:8  local_res10                             XREF[2]:     14000112d(W), 
                                                                                            140001274(R)  
      undefined8        Stack[0x8]:8   local_res8                              XREF[2]:     140001128(W), 
                                                                                            14000126f(R)  
      undefined1        Stack[-0x18]:1 local_18                                XREF[2]:     14000114c(W), 
                                                                                            1400011b8(W)  
                      __scrt_common_main_seh                          XREF[1]:     entry:1400012b1(c)  
140001128 48 89 5c        MOV        qword ptr [RSP + local_res8],RBX
          24 08
14000112d 48 89 74        MOV        qword ptr [RSP + local_res10],RSI
          24 10
140001132 57              PUSH       RDI
140001133 48 83 ec 30     SUB        RSP,0x30
140001137 b9 01 00        MOV        ECX,0x1
          00 00
14000113c e8 2f 03        CALL       __scrt_initialize_crt                            bool __scrt_initialize_crt(__scr
          00 00
140001141 84 c0           TEST       AL,AL
140001143 0f 84 36        JZ         LAB_14000127f
          01 00 00
140001149 40 32 f6        XOR        SIL,SIL
14000114c 40 88 74        MOV        byte ptr [RSP + local_18],SIL
          24 20
140001151 e8 de 02        CALL       __scrt_acquire_startup_lock                      bool __scrt_acquire_startup_lock
          00 00
140001156 8a d8           MOV        BL,AL
140001158 8b 0d 52        MOV        ECX,dword ptr [__scrt_current_native_startup_s   = ??
          24 00 00
14000115e 83 f9 01        CMP        ECX,0x1
140001161 0f 84 23        JZ         LAB_14000128a
          01 00 00
140001167 85 c9           TEST       ECX,ECX
140001169 75 4a           JNZ        LAB_1400011b5
14000116b c7 05 3b        MOV        dword ptr [__scrt_current_native_startup_state   = ??
          24 00 00 
          01 00 00 00
140001175 48 8d 15        LEA        RDX,[__xi_z]                                     = 
          64 10 00 00
14000117c 48 8d 0d        LEA        RCX,[__xi_a]                                     = 
          45 10 00 00
140001183 e8 aa 0a        CALL       _initterm_e                                      undefined _initterm_e()
          00 00
140001188 85 c0           TEST       EAX,EAX
14000118a 74 0a           JZ         LAB_140001196
14000118c b8 ff 00        MOV        EAX,0xff
          00 00
140001191 e9 d9 00        JMP        LAB_14000126f
          00 00
                      LAB_140001196                                   XREF[1]:     14000118a(j)  
140001196 48 8d 15        LEA        RDX,[__xc_z]                                     = 
          23 10 00 00
14000119d 48 8d 0d        LEA        RCX,[__xc_a]                                     = 
          0c 10 00 00
1400011a4 e8 83 0a        CALL       _initterm                                        undefined _initterm()
          00 00
1400011a9 c7 05 fd        MOV        dword ptr [__scrt_current_native_startup_state   = ??
          23 00 00 
          02 00 00 00
1400011b3 eb 08           JMP        LAB_1400011bd
                      LAB_1400011b5                                   XREF[1]:     140001169(j)  
1400011b5 40 b6 01        MOV        SIL,0x1
1400011b8 40 88 74        MOV        byte ptr [RSP + local_18],SIL
          24 20
                      LAB_1400011bd                                   XREF[1]:     1400011b3(j)  
1400011bd 8a cb           MOV        CL,BL
1400011bf e8 1c 04        CALL       __scrt_release_startup_lock                      void __scrt_release_startup_lock
          00 00
1400011c4 e8 cb 05        CALL       __scrt_get_dyn_tls_init_callback                 _func__cdecl_void_void_ptr_ulong
          00 00
1400011c9 48 8b d8        MOV        RBX,RAX
1400011cc 48 83 38 00     CMP        qword ptr [RAX],0x0
1400011d0 74 1e           JZ         LAB_1400011f0
1400011d2 48 8b c8        MOV        RCX,RAX
1400011d5 e8 6e 03        CALL       __scrt_is_nonwritable_in_current_image           bool __scrt_is_nonwritable_in_cu
          00 00
1400011da 84 c0           TEST       AL,AL
1400011dc 74 12           JZ         LAB_1400011f0
1400011de 45 33 c0        XOR        R8D,R8D
1400011e1 41 8d 50 02     LEA        EDX,[R8 + 0x2]
1400011e5 33 c9           XOR        ECX,ECX
1400011e7 48 8b 03        MOV        RAX,qword ptr [RBX]
1400011ea ff 15 a8        CALL       qword ptr [->_guard_dispatch_icall]
          0f 00 00
                      LAB_1400011f0                                   XREF[2]:     1400011d0(j), 1400011dc(j)  
1400011f0 e8 a7 05        CALL       __scrt_get_dyn_tls_dtor_callback                 _func__cdecl_void_void_ptr_ulong
          00 00
1400011f5 48 8b d8        MOV        RBX,RAX
1400011f8 48 83 38 00     CMP        qword ptr [RAX],0x0
1400011fc 74 14           JZ         LAB_140001212
1400011fe 48 8b c8        MOV        RCX,RAX
140001201 e8 42 03        CALL       __scrt_is_nonwritable_in_current_image           bool __scrt_is_nonwritable_in_cu
          00 00
140001206 84 c0           TEST       AL,AL
140001208 74 08           JZ         LAB_140001212
14000120a 48 8b 0b        MOV        RCX,qword ptr [RBX]
14000120d e8 50 0a        CALL       _register_thread_local_exe_atexit_callback       undefined _register_thread_local
          00 00
                      LAB_140001212                                   XREF[2]:     1400011fc(j), 140001208(j)  
140001212 e8 0f 0a        CALL       _get_initial_narrow_environment                  undefined _get_initial_narrow_en
          00 00
140001217 48 8b f8        MOV        RDI,RAX
14000121a e8 31 0a        CALL       __p___argv                                       undefined __p___argv()
          00 00
14000121f 48 8b 18        MOV        RBX,qword ptr [RAX]
140001222 e8 23 0a        CALL       __p___argc                                       undefined __p___argc()
          00 00
140001227 4c 8b c7        MOV        R8,RDI
14000122a 48 8b d3        MOV        RDX,RBX
14000122d 8b 08           MOV        ECX,dword ptr [RAX]
14000122f e8 cc fd        CALL       main                                             int main(int _Argc, char * * _Ar
          ff ff
140001234 8b d8           MOV        EBX,EAX
140001236 e8 c5 06        CALL       __scrt_is_managed_app                            bool __scrt_is_managed_app(void)
          00 00
14000123b 84 c0           TEST       AL,AL
14000123d 74 55           JZ         LAB_140001294
14000123f 40 84 f6        TEST       SIL,SIL
140001242 75 05           JNZ        LAB_140001249
140001244 e8 0d 0a        CALL       _cexit                                           void _cexit(void)
          00 00
                      LAB_140001249                                   XREF[1]:     140001242(j)  
140001249 33 d2           XOR        EDX,EDX
14000124b b1 01           MOV        CL,0x1
14000124d e8 b2 03        CALL       __scrt_uninitialize_crt                          bool __scrt_uninitialize_crt(boo
          00 00
140001252 8b c3           MOV        EAX,EBX
140001254 eb 19           JMP        LAB_14000126f

うーん、 main関数に到達するまでの下準備が色々あるんですね。

何はともあれ、 entry関数から実行が始まり、 entry関数が__scrt_common_main_seh関数を呼び出し、 __scrt_common_main_seh関数がmain関数を呼び出していることが分かりました。

最後に__scrt_common_main_seh関数のデコンパイル結果を貼って終わりにしたいと思います。

int __scrt_common_main_seh(void)

{
  bool bVar1;
  bool bVar2;
  int iVar3;
  _func__cdecl_void_void_ptr_ulong_void_ptr **pp_Var4;
  char **_Env;
  char **ppcVar5;
  int *piVar6;
  uint unaff_EBX;
  undefined8 in_R9;
  undefined uVar7;

  bVar1 = __scrt_initialize_crt(exe);
  if (bVar1 == false) {
    __scrt_fastfail(7);
  }
  else {
    bVar1 = false;
    uVar7 = 0;
    bVar2 = __scrt_acquire_startup_lock();
    unaff_EBX = unaff_EBX & 0xffffff00 | (uint)bVar2;
    if (__scrt_current_native_startup_state != initializing) {
      if (__scrt_current_native_startup_state == uninitialized) {
        __scrt_current_native_startup_state = initializing;
        iVar3 = _initterm_e(__xi_a,__xi_z);
        if (iVar3 != 0) {
          return 0xff;
        }
        _initterm(__xc_a,__xc_z);
        __scrt_current_native_startup_state = initialized;
      }
      else {
        bVar1 = true;
        uVar7 = 1;
      }
      __scrt_release_startup_lock(bVar2);
      pp_Var4 = __scrt_get_dyn_tls_init_callback();
      if ((*pp_Var4 != (_func__cdecl_void_void_ptr_ulong_void_ptr *)0x0) &&
         (bVar2 = __scrt_is_nonwritable_in_current_image(pp_Var4), bVar2 != false)) {
        (*(code *)&_guard_dispatch_icall)(0,2,0,in_R9,uVar7);
      }
      pp_Var4 = __scrt_get_dyn_tls_dtor_callback();
      if ((*pp_Var4 != (_func__cdecl_void_void_ptr_ulong_void_ptr *)0x0) &&
         (bVar2 = __scrt_is_nonwritable_in_current_image(pp_Var4), bVar2 != false)) {
        _register_thread_local_exe_atexit_callback();
      }
      _Env = (char **)_get_initial_narrow_environment();
      ppcVar5 = (char **)__p___argv();
      ppcVar5 = (char **)*ppcVar5;
      piVar6 = (int *)__p___argc();
      unaff_EBX = main(*piVar6,ppcVar5,_Env);
      bVar2 = __scrt_is_managed_app();
      if (bVar2 != false) {
        if (!bVar1) {
          _cexit();
        }
        __scrt_uninitialize_crt(true,false);
        return (int)unaff_EBX;
      }
      goto LAB_140001294;
    }
  }
  __scrt_fastfail(7);
LAB_140001294:
                    /* WARNING: Subroutine does not return */
  exit(unaff_EBX);
}