5

Windows環境(PE実行可能ファイル)で、CALLXXXXXXXXXXXXXXX命令がどのように機能するかについて明確に説明したいと思います。私はPE形式を研究してきましたが、CALL ADDRESS命令、dllからの関数のインポート、およびCALLADDRESSがDLL内のコードに到達する方法の関係についてかなり混乱しています。ASLRおよびその他のセキュリティ機能がDLL内を移動する可能性があることに加えて、実行可能ファイルはこれにどのように対処しますか?

4

3 に答える 3

10

それ(つまり、通常の相対呼び出しでインポートを直接呼び出す)は機能しません。そのため、これは実行されません。

インポートされた関数を呼び出すには、Import Address Table(IAT)と呼ばれるものを実行します。つまり、IATのエントリは最初に関数名を指し(つまり、インポート名テーブルのコピーとして開始されます)、これらのポインターはローダーによって実際の関数を指すように変更されます。

IATは固定アドレスにありますが、画像がリベースされている場合は再配置できるため、IATを介した呼び出しには、単一の間接参照のみが含まれます。したがって、call r/mインポートされた関数を呼び出すために、メモリオペランド(単なる定数)とともに使用されます。例call [0x40206C]

于 2013-01-19T16:41:24.887 に答える
4

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デバッガーを示しており、左端の大きな赤い矢印は、マシンコード命令内のアドレス情報、つまり0000004E16進数(注:最下位バイトは最下位アドレスで、最初はメモリ内)を示しています。もう1つの大きな赤い矢印は、信じられないほど、このかなり小さいマジックナンバーが_MessageBoxA@16、デバッガーが知る限り、アドレス01161064h16進数に存在する関数を何らかの形で示していることを示しています。

  • 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
于 2013-01-19T17:54:31.150 に答える
0

リンカー。実行可能ファイルがリンクされると、リンカはすべてのDLLアドレスを置き換えてベースにします。仮想メモリにより、すべてのプロセスが同じベースアドレスにロードされ、アドレス指定が容易になります。DLLはPIL(位置に依存しないコード)であるため、ローダーはアプリケーションのDLLをリベースできます。コードは、いいね!が再配置できるシンボルを参照しているため、その場所を気にする必要はありません。

編集:これのいくつかがオフになっていることに気づきました-LinuxダイナミックライブラリはPILですが、Windowsライブラリはそうではありません(そのため、リベースする必要があります)。

于 2013-01-19T16:22:28.790 に答える