Windows環境(PE実行可能ファイル)で、CALLXXXXXXXXXXXXXXX命令がどのように機能するかについて明確に説明したいと思います。私はPE形式を研究してきましたが、CALL ADDRESS命令、dllからの関数のインポート、およびCALLADDRESSがDLL内のコードに到達する方法の関係についてかなり混乱しています。ASLRおよびその他のセキュリティ機能がDLL内を移動する可能性があることに加えて、実行可能ファイルはこれにどのように対処しますか?
3 に答える
それ(つまり、通常の相対呼び出しでインポートを直接呼び出す)は機能しません。そのため、これは実行されません。
インポートされた関数を呼び出すには、Import Address Table(IAT)と呼ばれるものを実行します。つまり、IATのエントリは最初に関数名を指し(つまり、インポート名テーブルのコピーとして開始されます)、これらのポインターはローダーによって実際の関数を指すように変更されます。
IATは固定アドレスにありますが、画像がリベースされている場合は再配置できるため、IATを介した呼び出しには、単一の間接参照のみが含まれます。したがって、call r/m
インポートされた関数を呼び出すために、メモリオペランド(単なる定数)とともに使用されます。例call [0x40206C]
。
2013年1月22日:(A)間違った答えが解決策として選択され、(B)私の元の答えが、OPを含む一部の読者に明らかに理解されなかったため、より簡単な具体的な例と議論を追加しました。申し訳ありませんが、meaculpa。急いで答えを投稿し、すでに手元にあるコード例を追加しました。
質問をどのように解釈するか。
あなたが尋ねる、
「私はPE形式を研究してきましたが、CALL ADDRESS命令、dllからの関数のインポート、およびCALLADDRESSがDLL内のコードに到達する方法の関係についてかなり混乱しています。」
CALL ADDRESSという用語は、C ++レベルではあまり意味がないため、アセンブリ言語またはマシンコードレベルでのCALLADDRESSを意味していると思います。
問題は、DLLが優先アドレス以外のアドレスにロードされた場合、call
命令がDLL関数にどのように接続されるかということです。
それの不足。
- マシンコードレベルでは、指定されたアドレスを持つaは、単一の命令
call
で構成される最小限の転送ルーチンを呼び出すことによって機能します。jmp
このjmp
命令は、テーブルルックアップを介してDLL関数を呼び出します。通常、DLLのインポートライブラリは、名前プレフィックス付きのDLL関数自体と、__imp__
そのような名前プレフィックスなしのラッパールーチン(例:__imp__MessageBoxA@16
および)の両方をエクスポートします_MessageBoxA@16
。
つまり、私が以下の名前を発明したことを除いて、アセンブラは通常翻訳します
call MessageBox
の中へ
call MessageBox_forwarder
;
ここに何でも
MessageBox_forwarder: jmp ds:[MessageBox_tableEntry]
DLLがロードされると、ローダーは関連するアドレスをテーブルに配置します。
アセンブリ言語レベルで
call
は、ルーチンが識別子として指定されている場合、識別子に対して宣言されたタイプに応じてcall
、フォワーダーにマップすることも、テーブルルックアップを介してDLL関数に直接マップすることもできます。call
同じDLLからのインポートの場合でも、DLL関数アドレスのテーブルが複数存在する可能性があります。ただし、一般に、これらは1つの大きなテーブルと見なされ、「インポートアドレステーブル」または略してIATと呼ばれます。IATテーブル(より正確にはテーブル)はそれぞれ画像内の固定された場所にあります。つまり、固定されたアドレスではなく、好ましくない場所にロードされると、コードとともに移動されます。
現在選択されているソリューションの回答は、次の点で正しくありません。
答えは、「それは機能しない、そしてそれがそれが行われる方法ではない理由です」と主張します。おそらく「それ」はコールアドレスを指します。ただし、アセンブリまたはマシンコードレベルでCALL ADDRESSを使用すると、DLL関数を呼び出す場合に問題なく機能します。それが正しく行われていれば。
答えは、IATが固定アドレスにあることを維持します。しかし、そうではありません。
CALLADDRESSは問題なく機能します。
アドレスが非常によく知られているDLL関数、つまり[user32.dll]DLLからのWindowsAPI関数の呼び出しである具体的なCALLADDRESS命令について考えてみましょう。MessageBoxA
call MessageBoxA
この命令を使用しても問題はありません。
以下に示すように、マシンコードレベルでは、このcall
命令自体に、呼び出しが命令を実行するようにするオフセットが含まれています。この命令jmp
は、関数ポインタのインポートアドレステーブルでDLLルーチンアドレスを検索します。これは通常、問題のDLLをロードするときのローダー。
マシンコードを検査できるようにするために、その具体的な例の命令を使用した完全な32ビットx86アセンブリ言語プログラムを次に示します。
.model flat, stdcall
option casemap :none ; Case sensitive identifiers, please.
_as32bit textequ <DWord ptr>
public start
ExitProcess proto stdcall :DWord
MessageBoxA_t typedef proto stdcall :DWord, :DWord, :DWord, :DWord
extern MessageBoxA : MessageBoxA_t
extern _imp__MessageBoxA@16 : ptr MessageBoxA_t
MB_ICONINFORMATION equ 0040h
MB_SETFOREGROUND equ 00010000h
infoBoxOptions equ MB_ICONINFORMATION or MB_SETFOREGROUND
.const
boxtitle_1 db "Just FYI 1 (of 3):", 0
boxtitle_2 db "Just FYI 2 (of 3):", 0
boxtitle_3 db "Just FYI 3 (of 3):", 0
boxtext db "There’s intelligence somewhere in the universe", 0
.code
start:
push infoBoxOptions
push offset boxtitle_1
push offset boxtext
push 0
call MessageBoxA ; Call #1 - to jmp to DLL-func.
push infoBoxOptions
push offset boxtitle_2
push offset boxtext
push 0
call ds:[_imp__MessageBoxA@16] ; Call #2 - directly to DLL-func.
push infoBoxOptions
push offset boxtitle_3
push offset boxtext
push 0
call _imp__MessageBoxA@16 ; Call #3 - same as #2, due to type of identifier.
push 0 ; Exit code, 0 indicates success.
call ExitProcess
end
Microsoftのツールチェーンを使用したアセンブルとリンク。/debug
リンカオプションは、リンカにVisualStudioデバッガで使用するPDBデバッグ情報ファイルを生成するように要求します。
[d:\ dev \ test \ call] > ml / nologo / c asm_call.asm アセンブル:asm_call.asm [d:\ dev \ test \ call] >リンク/nologoasm_call.obj kernel32.lib user32.lib / entry:start / subsystem:windows / debug [d:\ dev \ test \ call] > dir asm * / b asm_call.asm asm_call.exe asm_call.ilk asm_call.obj asm_call.pdb [d:\ dev \ test \ call] > _
これをデバッグする簡単な方法の1つは、Visual Studio([devenv.exe]プログラム)を起動し、Visual Studioで[デバッグ] → [ステップイン]をクリックするか、F11キーを押すことです。
[d:\ dev \ test \ call] > devenv asm_call.exe [d:\ dev \ test \ call] > _
上の図では、動作中のVisual Studio 2012デバッガーを示しており、左端の大きな赤い矢印は、マシンコード命令内のアドレス情報、つまり0000004E
16進数(注:最下位バイトは最下位アドレスで、最初はメモリ内)を示しています。もう1つの大きな赤い矢印は、信じられないほど、このかなり小さいマジックナンバーが_MessageBoxA@16
、デバッガーが知る限り、アドレス01161064h
16進数に存在する関数を何らかの形で示していることを示しています。
CALL ADDRESS命令のアドレスデータは、次の命令のアドレスを基準にしたオフセットであるため、DLLの配置を変更するための修正は必要ありません。
呼び出し先のアドレスには、が含まれているだけ
jmp ds:[IAT_entry_for_MessageBoxA]
です。このフォワーダーコードは、DLLからではなく、インポートライブラリから取得されるため、修正も必要ありません(ただし、DLL関数アドレスと同様に、特別な処理が行われるようです)。
2番目の呼び出し命令は、最初の命令に対して行うことを直接実行しjmp
ます。つまり、IATテーブルでDLL関数アドレスを検索します。
これで、3番目の呼び出し命令は、マシンコードレベルで2番目の呼び出し命令と同じであることがわかります。declspec( dllimport )
どうやら、アセンブリでVisualC++をエミュレートする方法はよく知られていません。上記の種類の宣言は一方向であり、おそらくテキストequと組み合わされます。
IATは固定アドレスにありません。
次のC++プログラムは、ロードされたアドレス、どのDLL関数をどのモジュールからインポートするか、およびさまざまなIATテーブルが存在する場所を報告します。
Microsoftのツールチェーンの最新バージョンで構築され、デフォルトを使用するだけの場合、通常、実行されるたびに異なるアドレスに読み込まれます。
リンカオプションを使用すると、この動作を防ぐことができます/dynamicbase:no
。
#include <assert.h> // assert
#include <stddef.h> // ptrdiff_t
#include <sstream>
using std::ostringstream;
#undef UNICODE
#define UNICODE
#include <windows.h>
template< class Result, class SomeType >
Result as( SomeType const p ) { return reinterpret_cast<Result>( p ); }
template< class Type >
class OffsetTo
{
private:
ptrdiff_t offset_;
public:
ptrdiff_t asInteger() const { return offset_; }
explicit OffsetTo( ptrdiff_t const offset ): offset_( offset ) {}
};
template< class ResultPointee, class SourcePointee >
ResultPointee* operator+(
SourcePointee* const p,
OffsetTo<ResultPointee> const offset
)
{
return as<ResultPointee*>( as<char const*>( p ) + offset.asInteger() );
}
int main()
{
auto const pImage =
as<IMAGE_DOS_HEADER const*>( ::GetModuleHandle( nullptr ) );
assert( pImage->e_magic == IMAGE_DOS_SIGNATURE );
auto const pNTHeaders =
pImage + OffsetTo<IMAGE_NT_HEADERS const>( pImage->e_lfanew );
assert( pNTHeaders->Signature == IMAGE_NT_SIGNATURE );
auto const& importDir =
pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
auto const pImportDescriptors = pImage + OffsetTo<IMAGE_IMPORT_DESCRIPTOR const>(
importDir.VirtualAddress //+ importSectionHeader.PointerToRawData
);
ostringstream stream;
stream << "I'm loaded at " << pImage << ", and I'm using...\n";
for( int i = 0; pImportDescriptors[i].Name != 0; ++i )
{
auto const pModuleName = pImage + OffsetTo<char const>( pImportDescriptors[i].Name );
DWORD const offsetNameTable = pImportDescriptors[i].OriginalFirstThunk;
DWORD const offsetAddressTable = pImportDescriptors[i].FirstThunk; // The module "IAT"
auto const pNameTable = pImage + OffsetTo<IMAGE_THUNK_DATA const>( offsetNameTable );
auto const pAddressTable = pImage + OffsetTo<IMAGE_THUNK_DATA const>( offsetAddressTable );
stream << "\n* '" << pModuleName << "'";
stream << " with IAT at " << pAddressTable << "\n";
stream << "\t";
for( int j = 0; pNameTable[j].u1.AddressOfData != 0; ++j )
{
auto const pFuncName =
pImage + OffsetTo<char const>( 2 + pNameTable[j].u1.AddressOfData );
stream << pFuncName << " ";
}
stream << "\n";
}
MessageBoxA(
0,
stream.str().c_str(),
"FYI:",
MB_ICONINFORMATION | MB_SETFOREGROUND
);
}
自己複製するWindowsマシンコードプログラム。
最後に、私の元の回答から、いくつかの問題を説明するために別の目的で作成したMicrosoftアセンブラー(MASM)プログラムがあります。これは、その性質上(アセンブルして実行すると同じソースコードを生成する出力ソースコードとして生成され、など)完全に再配置可能なコードである必要があり、通常のプログラムローダーからのほんの少しの助けが必要です。
.model flat, stdcall
option casemap :none ; Case sensitive identifiers, please.
dword_aligned textequ <4> ; Just for readability.
; Windows API functions:
extern ExitProcess@4: proc ; from [kernel32.dll]
extern GetStdHandle@4: proc ; from [kernel32.dll]
extern WriteFile@20: proc ; from [kernel32.dll]
extern wsprintfA: proc ; from [user32.dll]
STD_OUTPUT_HANDLE equ -11
; The main code.
GlobalsStruct struct dword_aligned
codeStart dword ?
outputStreamHandle dword ?
GlobalsStruct ends
globals textequ <(GlobalsStruct ptr [edi])>
.code
startup:
jmp code_start
; Trampolines to add references to these functions.
myExitProcess: jmp ExitProcess@4
myGetStdHandle: jmp GetStdHandle@4
myWriteFile: jmp WriteFile@20
mywsprintfA: jmp wsprintfA
;------------------------------------------------------------------
;
; The code below is reproduced, so it's all relative.
code_start:
jmp main
prologue:
byte ".model flat, stdcall", 13, 10
byte "option casemap :none", 13, 10
byte 13, 10
byte " extern ExitProcess@4: proc", 13, 10
byte " extern GetStdHandle@4: proc", 13, 10
byte " extern WriteFile@20: proc", 13, 10
byte " extern wsprintfA: proc", 13, 10
byte 13, 10
byte " .code", 13, 10
byte "startup:", 13, 10
byte " jmp code_start", 13, 10
byte 13, 10
byte "jmp ExitProcess@4", 13, 10
byte "jmp GetStdHandle@4", 13, 10
byte "jmp WriteFile@20", 13, 10
byte "jmp wsprintfA", 13, 10
byte 13, 10
byte "code_start:", 13, 10
prologue_nBytes equ $ - prologue
epilogue:
byte "code_end:", 13, 10
byte " end startup", 13, 10
epilogue_nBytes equ $ - epilogue
dbDirective byte 4 dup( ' ' ), "byte "
dbDirective_nBytes equ $ - dbDirective
numberFormat byte " 0%02Xh", 0
numberFormat_nBytes equ $ - numberFormat
comma byte ","
windowsNewline byte 13, 10
write:
push 0 ; space for nBytesWritten
mov ecx, esp ; &nBytesWritten
push 0 ; lpOverlapped
push ecx ; &nBytesWritten
push ebx ; nBytes
push eax ; &s[0]
push globals.outputStreamHandle
call myWriteFile
pop eax ; nBytesWritten
ret
displayMachineCode:
dmc_LocalsStruct struct dword_aligned
numberStringLen dword ?
numberString byte 16*4 DUP( ? )
fileHandle dword ?
nBytesWritten dword ?
byteIndex dword ?
dmc_LocalsStruct ends
dmc_locals textequ <[ebp - sizeof dmc_LocalsStruct].dmc_LocalsStruct>
mov ebp, esp
sub esp, sizeof dmc_LocalsStruct
; Output prologue that makes MASM happy (placing machine code data in context):
; lea eax, prologue
mov eax, globals.codeStart
add eax, prologue - code_start
mov ebx, prologue_nBytes
call write
; Output the machine code bytes.
mov dmc_locals.byteIndex, 0
dmc_lineLoop:
; loop start
; Output a db directive
;lea eax, dbDirective
mov eax, globals.codeStart
add eax, dbDirective - code_start
mov ebx, dbDirective_nBytes
call write
dmc_byteIndexingLoop:
; loop start
; Create string representation of a number
mov ecx, dmc_locals.byteIndex
mov eax, 0
;mov al, byte ptr [code_start + ecx]
mov ebx, globals.codeStart
mov al, [ebx + ecx]
push eax
;push offset numberFormat
mov eax, globals.codeStart
add eax, numberFormat - code_start
push eax
lea eax, dmc_locals.numberString
push eax
call mywsprintfA
add esp, 3*(sizeof dword)
mov dmc_locals.numberStringLen, eax
; Output string representation of number
lea eax, dmc_locals.numberString
mov ebx, dmc_locals.numberStringLen
call write
; Are we finished looping yet?
inc dmc_locals.byteIndex
mov ecx, dmc_locals.byteIndex
cmp ecx, code_end - code_start
je dmc_finalNewline
and ecx, 07h
jz dmc_after_byteIndexingLoop
; Output a comma
; lea eax, comma
mov eax, globals.codeStart
add eax, comma - code_start
mov ebx, 1
call write
jmp dmc_byteIndexingLoop
; loop end
dmc_after_byteIndexingLoop:
; New line
; lea eax, windowsNewline
mov eax, globals.codeStart
add eax, windowsNewline - code_start
mov ebx, 2
call write
jmp dmc_lineLoop;
; loop end
dmc_finalNewline:
; New line
; lea eax, windowsNewline
mov eax, globals.codeStart
add eax, windowsNewline - code_start
mov ebx, 2
call write
; Output epilogue that makes MASM happy:
; lea eax, epilogue
mov eax, globals.codeStart
add eax, epilogue - code_start
mov ebx, epilogue_nBytes
call write
mov esp, ebp
ret
main:
sub esp, sizeof GlobalsStruct
mov edi, esp
call main_knownAddress
main_knownAddress:
pop eax
sub eax, main_knownAddress - code_start
mov globals.codeStart, eax
push STD_OUTPUT_HANDLE
call myGetStdHandle
mov globals.outputStreamHandle, eax
call displayMachineCode
; Well behaved process exit:
push 0 ; Process exit code, 0 indicates success.
call myExitProcess
code_end:
end startup
そして、これが自己複製出力です:
.model flat, stdcall
option casemap :none
extern ExitProcess@4: proc
extern GetStdHandle@4: proc
extern WriteFile@20: proc
extern wsprintfA: proc
.code
startup:
jmp code_start
jmp ExitProcess@4
jmp GetStdHandle@4
jmp WriteFile@20
jmp wsprintfA
code_start:
byte 0E9h, 03Bh, 002h, 000h, 000h, 02Eh, 06Dh, 06Fh
byte 064h, 065h, 06Ch, 020h, 066h, 06Ch, 061h, 074h
byte 02Ch, 020h, 073h, 074h, 064h, 063h, 061h, 06Ch
byte 06Ch, 00Dh, 00Ah, 06Fh, 070h, 074h, 069h, 06Fh
byte 06Eh, 020h, 063h, 061h, 073h, 065h, 06Dh, 061h
byte 070h, 020h, 03Ah, 06Eh, 06Fh, 06Eh, 065h, 00Dh
byte 00Ah, 00Dh, 00Ah, 020h, 020h, 020h, 020h, 065h
byte 078h, 074h, 065h, 072h, 06Eh, 020h, 020h, 045h
byte 078h, 069h, 074h, 050h, 072h, 06Fh, 063h, 065h
byte 073h, 073h, 040h, 034h, 03Ah, 020h, 070h, 072h
byte 06Fh, 063h, 00Dh, 00Ah, 020h, 020h, 020h, 020h
byte 065h, 078h, 074h, 065h, 072h, 06Eh, 020h, 020h
byte 047h, 065h, 074h, 053h, 074h, 064h, 048h, 061h
byte 06Eh, 064h, 06Ch, 065h, 040h, 034h, 03Ah, 020h
byte 070h, 072h, 06Fh, 063h, 00Dh, 00Ah, 020h, 020h
byte 020h, 020h, 065h, 078h, 074h, 065h, 072h, 06Eh
byte 020h, 020h, 057h, 072h, 069h, 074h, 065h, 046h
byte 069h, 06Ch, 065h, 040h, 032h, 030h, 03Ah, 020h
byte 070h, 072h, 06Fh, 063h, 00Dh, 00Ah, 020h, 020h
byte 020h, 020h, 065h, 078h, 074h, 065h, 072h, 06Eh
byte 020h, 020h, 077h, 073h, 070h, 072h, 069h, 06Eh
byte 074h, 066h, 041h, 03Ah, 020h, 070h, 072h, 06Fh
byte 063h, 00Dh, 00Ah, 00Dh, 00Ah, 020h, 020h, 020h
byte 020h, 02Eh, 063h, 06Fh, 064h, 065h, 00Dh, 00Ah
byte 073h, 074h, 061h, 072h, 074h, 075h, 070h, 03Ah
byte 00Dh, 00Ah, 020h, 020h, 020h, 020h, 06Ah, 06Dh
byte 070h, 020h, 020h, 020h, 020h, 020h, 063h, 06Fh
byte 064h, 065h, 05Fh, 073h, 074h, 061h, 072h, 074h
byte 00Dh, 00Ah, 00Dh, 00Ah, 06Ah, 06Dh, 070h, 020h
byte 045h, 078h, 069h, 074h, 050h, 072h, 06Fh, 063h
byte 065h, 073h, 073h, 040h, 034h, 00Dh, 00Ah, 06Ah
byte 06Dh, 070h, 020h, 047h, 065h, 074h, 053h, 074h
byte 064h, 048h, 061h, 06Eh, 064h, 06Ch, 065h, 040h
byte 034h, 00Dh, 00Ah, 06Ah, 06Dh, 070h, 020h, 057h
byte 072h, 069h, 074h, 065h, 046h, 069h, 06Ch, 065h
byte 040h, 032h, 030h, 00Dh, 00Ah, 06Ah, 06Dh, 070h
byte 020h, 077h, 073h, 070h, 072h, 069h, 06Eh, 074h
byte 066h, 041h, 00Dh, 00Ah, 00Dh, 00Ah, 063h, 06Fh
byte 064h, 065h, 05Fh, 073h, 074h, 061h, 072h, 074h
byte 03Ah, 00Dh, 00Ah, 063h, 06Fh, 064h, 065h, 05Fh
byte 065h, 06Eh, 064h, 03Ah, 00Dh, 00Ah, 020h, 020h
byte 020h, 020h, 065h, 06Eh, 064h, 020h, 073h, 074h
byte 061h, 072h, 074h, 075h, 070h, 00Dh, 00Ah, 020h
byte 020h, 020h, 020h, 062h, 079h, 074h, 065h, 020h
byte 020h, 020h, 020h, 020h, 020h, 020h, 020h, 030h
byte 025h, 030h, 032h, 058h, 068h, 000h, 02Ch, 00Dh
byte 00Ah, 06Ah, 000h, 08Bh, 0CCh, 06Ah, 000h, 051h
byte 053h, 050h, 0FFh, 077h, 004h, 0E8h, 074h, 0FEh
byte 0FFh, 0FFh, 058h, 0C3h, 08Bh, 0ECh, 083h, 0ECh
byte 050h, 08Bh, 007h, 005h, 005h, 000h, 000h, 000h
byte 0BBh, 036h, 001h, 000h, 000h, 0E8h, 0D7h, 0FFh
byte 0FFh, 0FFh, 0C7h, 045h, 0FCh, 000h, 000h, 000h
byte 000h, 08Bh, 007h, 005h, 057h, 001h, 000h, 000h
byte 0BBh, 00Fh, 000h, 000h, 000h, 0E8h, 0BFh, 0FFh
byte 0FFh, 0FFh, 08Bh, 04Dh, 0FCh, 0B8h, 000h, 000h
byte 000h, 000h, 08Bh, 01Fh, 08Ah, 004h, 019h, 050h
byte 08Bh, 007h, 005h, 066h, 001h, 000h, 000h, 050h
byte 08Dh, 045h, 0B4h, 050h, 0E8h, 02Ah, 0FEh, 0FFh
byte 0FFh, 083h, 0C4h, 00Ch, 089h, 045h, 0B0h, 08Dh
byte 045h, 0B4h, 08Bh, 05Dh, 0B0h, 0E8h, 08Fh, 0FFh
byte 0FFh, 0FFh, 0FFh, 045h, 0FCh, 08Bh, 04Dh, 0FCh
byte 081h, 0F9h, 068h, 002h, 000h, 000h, 074h, 02Bh
byte 083h, 0E1h, 007h, 074h, 013h, 08Bh, 007h, 005h
byte 06Eh, 001h, 000h, 000h, 0BBh, 001h, 000h, 000h
byte 000h, 0E8h, 06Bh, 0FFh, 0FFh, 0FFh, 0EBh, 0AAh
byte 08Bh, 007h, 005h, 06Fh, 001h, 000h, 000h, 0BBh
byte 002h, 000h, 000h, 000h, 0E8h, 058h, 0FFh, 0FFh
byte 0FFh, 0EBh, 086h, 08Bh, 007h, 005h, 06Fh, 001h
byte 000h, 000h, 0BBh, 002h, 000h, 000h, 000h, 0E8h
byte 045h, 0FFh, 0FFh, 0FFh, 08Bh, 007h, 005h, 03Bh
byte 001h, 000h, 000h, 0BBh, 01Ch, 000h, 000h, 000h
byte 0E8h, 034h, 0FFh, 0FFh, 0FFh, 08Bh, 0E5h, 0C3h
byte 083h, 0ECh, 008h, 08Bh, 0FCh, 0E8h, 000h, 000h
byte 000h, 000h, 058h, 02Dh, 04Ah, 002h, 000h, 000h
byte 089h, 007h, 06Ah, 0F5h, 0E8h, 098h, 0FDh, 0FFh
byte 0FFh, 089h, 047h, 004h, 0E8h, 023h, 0FFh, 0FFh
byte 0FFh, 06Ah, 000h, 0E8h, 084h, 0FDh, 0FFh, 0FFh
code_end:
end startup
リンカー。実行可能ファイルがリンクされると、リンカはすべてのDLLアドレスを置き換えてベースにします。仮想メモリにより、すべてのプロセスが同じベースアドレスにロードされ、アドレス指定が容易になります。DLLはPIL(位置に依存しないコード)であるため、ローダーはアプリケーションのDLLをリベースできます。コードは、いいね!が再配置できるシンボルを参照しているため、その場所を気にする必要はありません。
編集:これのいくつかがオフになっていることに気づきました-LinuxダイナミックライブラリはPILですが、Windowsライブラリはそうではありません(そのため、リベースする必要があります)。