私はあなたへの答えを見つけようとしましたが、失敗しました。私が実際に成功したのは、疑わしいコードを単純化することだけです。
void f1( )
{
}
int main( )
{
*(char*) f1 = *(char*) f1;
return( 0 );
}
はい、セグメンテーション違反(gcc)またはメモリアクセス違反(MS VC)で失敗します。
編集:
実は私はあなたがやりたいことをすることに成功しました
(Basile Starynkevitchの回答に基づく)。ただし、x86のみ、gccのみ、および特定の例のみ。以下はいくつかのコード例です。
最初に-簡略化された例。
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
void f1( )
{
}
int main( )
{
int rc;
int pagesize;
char *p;
f1( );
pagesize = sysconf( _SC_PAGE_SIZE );
printf( "pagesize=%d (0x%08X).\n", pagesize, pagesize );
if( pagesize == -1 )
return( 2 );
p = (char*) f1;
printf( "p=0x%08X.\n", p );
p = (char*) ((size_t) p & ~(pagesize - 1));
printf( "p=0x%08X.\n", p );
rc = mprotect( p, pagesize, PROT_READ | PROT_WRITE | PROT_EXEC );
printf( "rc=%d.\n", rc );
if( rc != 0 )
return( 2 );
printf( "'mprotect()' succeeded.\n" );
*(char*) f1 = *(char*) f1;
printf( "Write succeeded.\n" );
f1( );
printf( "Call succeeded.\n" );
return( 0 );
}
これをコンパイルして一度起動します。失敗しますが、ページサイズはわかります。たとえば、4096です。次に、この例を次のようにコンパイルします。
gcc a1.c -falign-functions=4096
そしてそれはうまくいくはずです。
出力:
pagesize=4096 (0x00001000).
p=0x00402000.
p=0x00402000.
rc=0.
'mprotect()' succeeded.
Write succeeded.
Call succeeded.
高度な例:
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
//extern void f1( void ) __attribute__(( aligned( 4096 ) ));
__asm__( ".text" );
__asm__( ".align 4096" );
void f1( void )
{
printf( "%d\n", 123 );
}
void f2( void )
{
printf( "%d\n", 124 );
}
int main( void )
{
int rc;
int pagesize;
char *p;
int i;
printf( "f1=0x%08X.\n", f1 );
printf( "f2=0x%08X.\n", f2 );
f1( );
f2( );
pagesize = sysconf( _SC_PAGE_SIZE );
printf( "pagesize=%d (0x%08X).\n", pagesize, pagesize );
if( pagesize == -1 )
return( 2 );
p = (char*) f1;
printf( "p=0x%08X.\n", p );
p = (char*) ((size_t) p & ~(pagesize - 1));
printf( "p=0x%08X.\n", p );
rc = mprotect( p, pagesize, PROT_READ | PROT_WRITE | PROT_EXEC );
printf( "rc=%d.\n", rc );
if( rc != 0 )
return( 2 );
printf( "'mprotect()' succeeded.\n" );
for( i = 0; i < (size_t) f2 - (size_t) f1; i++ ) {
if( ((char*) f2)[ i ] == 124 ) {
printf( "i=%d.\n", i );
((char*) f1)[ i ] = ((char*) f2)[ i ];
}
}
//memcpy( f1, f2, (size_t) f2 - (size_t) f1 );
printf( "Write succeeded.\n" );
f1( );
f2( );
printf( "Call succeeded.\n" );
return( 0 );
}
「 f1()」および「f2()」内の「printf() 」の呼び出しは絶対的ではなく相対的であるため、ここでは「 memcpy() 」を使用できません(コメント付き)。そして、それらを絶対にする方法を見つけることができませんでした(「-fPIC」も「-fno-PIC」も私の場合は機能しませんでした)。「 f1()」と「f2() 」に相対関数呼び出しがない場合は、 「 memcpy() 」を使用できると思います(ただし、試しませんでした)。
また、「f1() 」をページサイズに合わせる必要があります(「 f1() 」が開始する前に十分なコードがあることが確実な場合を除く)。gcc 4.3以降を使用している場合は、属性を使用できます(gcc v4.1.2を使用しているため、コメントが付けられています)。そうでない場合は、その醜くて信頼できない " _asm_ "を使用できます。
出力:
f1=0x00402000.
f2=0x0040201E.
123
124
pagesize=4096 (0x00001000).
p=0x00402000.
p=0x00402000.
rc=0.
'mprotect()' succeeded.
i=12.
Write succeeded.
124
124
Call succeeded.
そしてもちろん、その恐ろしい「if(((char *)f2)[i] == 124)」。これは、何を置き換える必要があるか(印刷された番号)と何を置き換えるべきでないか(相対参照)を区別するのに役立ちます。明らかに、これは非常に単純化されたアルゴリズムです。あなたはあなたの仕事に適したあなた自身を実装しなければならないでしょう。