2017-01-01 17 views
0

double(...)の関数をx64シェルコードとしてコンパイルしたいと思います。私はすでにa + b/aのような単純な数学演算のためのエンコードされたアセンブリを生成する作業プログラムを持っています。ここではabdoubleです。シェルコード内で関数を呼び出す

生成されたコードは実行可能なmmapバッファにロードされ、後で呼び出すことができます。

私は次のような問題があります。私は生成されたシェルコードの中に、expなどのようにmath.hの機能を呼びたいと思います。すべてのcallオペコードは32ビットのアドレスまたは相対ジャンプを使用するため、これらの命令を簡単に使用することはできません。したがって、私は自分のcall -instructionをこのように実装してみました:

lea rax, [rip+0x0] ;load instruction pointer into rax 
add rax, <offset-to-return-to> 
push rax 

moveabs rax, <adress-of-function> ;load the function pointer to rax 
jmp rax 

これは、これらの命令を生成するために私のコードです:残念ながら

//lea rax, [rip+0x0] 
insertAll(code,std::list<uint8_t>{ 0x48, 0x8D, 0x05, 0x00, 0x00, 0x00, 0x00 }); 
//add rax, <offset-to-return-to> 
insertAll(code,std::list<uint8_t>{ 0x48, 0x83, 0xC0, <offset-to-return-to>}); 

//push rax 
code.push_back(0x50); 

//moveabs rax, address-of-function 
uint8_t reg = 0; //rax 
uint8_t rexWPrefix = 0x48 + (reg > 8); 
uint8_t opCode = 0xB8 + (reg % 8); 
insertAll(code,std::list<uint8_t>{ rexWPrefix, opCode }); 
code.insert(code.end(),reinterpret_cast<uint8_t*>(&fabs),reinterpret_cast<uint8_t*>(&fabs) + 8); 

//jmp rax 
insertAll(code,std::list<uint8_t>{ 0xFF, 0xE0 }); 

、この方法が機能しない関数を呼び出すと、プログラムはでクラッシュa SIGSEGVエラー。私のアセンブリコードや命令のエンコーディングに何か問題がありますか?機能が正しい位置に戻るようにするには、どの値を<offset-to-return-to>にする必要がありますか?

免責事項:私は、これがコードの動的生成を処理する最良の方法ではないことを知っています...ダイナミックライブラリをコンパイルし、dlsymでロードできます。これは、アセンブリ/シェルコードについて学ぶためのちょうど楽しい方法です。あまり深刻ではありません。

+2

一見理にかなって見るためにデバッガを使用どこで、なぜそれが失敗するのか。 PS:あなたはもちろん、 'lex 'に' add rax'をマージすることができます。正しいオフセットを使用してください。 – Jester

+2

「x64シェルコード」とは何ですか? CとC++は異なる言語です。タグをスパムしないでください。 – Olaf

+0

@Olaf:私はコードにx86-64命令を使用していると言いたいと思います。これは、アドレスのサイズが64ビットであるため、jmp命令では重要です。 – tly

答えて

1

3つのエラーが見つかりました。 jmp命令は絶対ではありませんが、afaik RIP-relativeです。 retは、スタック上にある絶対アドレスにジャンプするため、代わりにpush + retを使用しました。

さらに、呼び出し元がスタック上に4 * 8バイトのシャドウスペースを確保することが必須であることはわかりませんでした。詳細はhereです。

最後に、関数ポインタを命令コードに挿入するコードが間違っていました。これは完成した作業コードで

code.insert(code.end(),reinterpret_cast<uint8_t*>(&fabs),reinterpret_cast<uint8_t*>(&fabs) + 8); 

:私が誤って機能コードの代わりにポインタの値の最初の8つのバイトを挿入

//add rsp,0x20 --> shadow space of 4*8 bytes 
insertAll(code,std::list<uint8_t>{ 0x48, 0x83, 0xC4, 0x20 }); 
//lea rax, [rip+0x0] 
insertAll(code,std::list<uint8_t>{ 0x48, 0x8D, 0x05, 0x00, 0x00, 0x00, 0x00 }); 
//add rax, 18 
insertAll(code,std::list<uint8_t>{ 0x48, 0x83, 0xC0, 18 }); 
//push rax 
code.push_back(0x50); 

//moveabs rax, address-of-function 
uint8_t reg = 0; //rax 
uint8_t rexWPrefix = 0x48 + (reg > 8); 
uint8_t opCode = 0xB8 + (reg % 8); 
insertAll(code,std::list<uint8_t>{ rexWPrefix, opCode }); 
void* address = reinterpret_cast<void*>(&my_abs); 
code.insert(code.end(),reinterpret_cast<uint8_t*>(&address),reinterpret_cast<uint8_t*>(&address) + sizeof(address)); 

//push rax 
code.push_back(0x50); 
//retq 
code.push_back(0xC3); 
//sub rsp,0x20 --> shadow space of 4*8 bytes 
insertAll(code,std::list<uint8_t>{ 0x48, 0x83, 0xEC, 0x20 }); 
関連する問題