0

このコードに出くわしたとき、起動時にそれをアンパックするセクションを実行可能ファイルに書き込む単純な実行可能パッカーのコードを調べていました。

void setDistance( unsigned long size )
{
    char* set = (((char *)I)+pUnpacker->VirtualAddress);
    union
    {
        short sh[2];
        long  l;
    } conv;
    conv.l      = size;
    conv.sh[0]  = 0;

    unpacker_set(set, (char *)(&conv.l), 4, TEXT_DISTANCE);
}

サイズは、メモリ内のアンパッカー コードから、アンパックされるセクションの先頭までの距離です。ローダー コードでは、unsigned long として定義されています。一方、 unpacker_set には次のコードがあります。

void inline unpacker_set( char* at, char* what, size_t size, unsigned long sig )
{
    DWORD oldprotect;
    unsigned char *set  = (unsigned char *)at;

    while(*((unsigned long*)(set)) != sig)
        set++;

    if(VirtualProtect(set, size, PAGE_READWRITE, &oldprotect) == TRUE)
        for(unsigned i=0; i<size; i++)
            *(set+i) = *(what+i);
}

2番目のルーチンがアンパッカーコードの値を置き換えることは理解していますが、なぜユニオンで面倒なことが行われるのか知りたいです。どんな助けでも大歓迎です。

4

1 に答える 1

1

おそらく、コードを理解するための最良の方法は、非常に最小限のテスト ケースを作成し、その動作を確認することです。

#include <iostream>

void f()
{
  union 
  {
    short sh[2];
    long l ;
  } conv ;
   conv.l = 100000000 ;

   std::cout << std::hex << conv.l << std::endl ;

  conv.sh[0] = 0 ;

  std::cout << std::hex << conv.l << std::endl ;
}

int main()
{
  f() ;
}

これに対する出力は次のとおりです。

5f5e100
5f50000

したがって、コードの意図は、サイズの上位ビットをマスクしようとしているように見えますが、これは非常に見苦しく、移植性は低いです。

David が指摘したように、厳密なエイリアシングに注意する必要があります。この記事Type-punning and strict-aliasingは、s を使用した現実世界の問題の確かな例をいくつか示しているため、さらに優れていますunion。したがって、このコードが想定どおりに機能することを保証するgccclangは、次のコマンド ライン引数を渡す必要があります-fno-strict-aliasing

于 2013-04-01T12:57:11.163 に答える