-1

これは、x86 インライン アセンブリを使用した C++ [Intel 構文] です。

関数:

     DWORD *Call ( size_t lArgs, ... ){

    DWORD *_ret = new DWORD[lArgs];

    __asm {
        xor edx, edx
        xor esi, esi
        xor edi, edi
        inc edx
start:
        cmp edx, lArgs
        je end
        push eax
        push edx
        push esi
        mov esi, 0x04
        imul esi, edx
        mov ecx, esi
        add ecx, _ret
        push ecx
        call dword ptr[ebp+esi] //Doesn't return to the next instruction, returns to the caller of the parent function.
        pop ecx
        mov [ecx], eax
        pop eax
        pop edx
        pop esi
        inc edx
        jmp start
end:
        mov eax, _ret
        ret
    }
}

この関数の目的は、複数の関数/アドレスを個別に呼び出さずに呼び出すことです。

なぜデバッグしてもらうのですか?その日は学校を始めなければならず、夕方までに終わらせる必要があります。

どうもありがとう、iDomo

4

2 に答える 2

3

完全なコンパイル可能な例をありがとう、それは問題を解決することをはるかに簡単にします。

関数のシグネチャによるとCall、スタックフレームが設定されると、lArgsはでebp+8、ポインタはで始まりebp+Cます。そして、他にもいくつか問題があります。これは、MSVC 2010(16.00.40219.01)でテストされた、プッシュ/ポップの最適化とクリーンアップを含む修正バージョンです。

DWORD *Call ( size_t lArgs, ... ) {

    DWORD *_ret = new DWORD[lArgs];

    __asm {
        xor edx, edx
        xor esi, esi
        xor edi, edi
        inc edx
        push esi
start:
        cmp edx, lArgs
        ; since you started counting at 1 instead of 0
        ; you need to stop *after* reaching lArgs
        ja end
        push edx
        ; you're trying to call [ebp+0xC+edx*4-4]
        ; a simpler way of expressing that - 4*edx + 8
        ; (4*edx is the same as edx << 2)
        mov esi, edx
        shl esi, 2
        add esi, 0x8
        call dword ptr[ebp+esi]
        ; and here you want to write the return value
        ; (which, btw, your printfs don't produce, so you'll get garbage)
        ; into _ret[edx*4-4] , which equals ret[esi - 0xC]
        add esi, _ret
        sub esi, 0xC
        mov [esi], eax
        pop edx
        inc edx
        jmp start
end:
        pop esi
        mov eax, _ret
        ; ret ; let the compiler clean up, because it created a stack frame and allocated space for the _ret pointer
    }
}

delete[]そして、あなたが終わった後にこの関数から返されるメモリを忘れないでください。

于 2012-04-13T14:13:22.557 に答える
1

呼び出す前に、EAX、EDX、ESI、ECX を (順番に) プッシュしますが、戻った後に逆の順序でポップしないことに気付きました。最初の CALL が適切に返されるが、後続の CALL が返されない場合、それが問題である可能性があります。

于 2012-04-13T12:59:53.353 に答える