-1

このプログラムには、もともと標準化されていない規則を使用していた cdecl 呼び出し規則を実装する必要がありました。私が知る限り、それは正しいように見えますが、「アクセス違反の書き込み場所0x00000066。プログラムが「バイトptr [eax]ではありません」という行に到達したときにヒットするようです」という未処理の例外エラーが発生します。矢印はプログラムを中断した後のポイントです。

私のプログラムの何が問題なのか、どうすれば修正できるのか、誰か教えてもらえますか? ありがとうございました。

void encrypt_chars (int length, char EKey)
{   char temp_char;                     

for (int i = 0; i < length; i++)    
{
    temp_char = OChars [i];         
    __asm {
            push   eax
            movzx  eax, temp_char
            push   eax
            lea    eax, EKey
            push   eax
            call   encrypt
            mov    temp_char, al

            pop    eax
    }
    EChars[i] = temp_char;          
return;


// Inputs: register EAX = 32-bit address of Ekey,
//                  ECX = the character to be encrypted (in the low 8-bit field, CL).
// Output: register EAX = the encrypted value of the source character (in the low 8-bit field, AL).

__asm {          

encrypt:

        push ebp
        mov ebp, esp
        mov ecx, 8[ebp] 
        mov eax, 12[ebp]
        push edi                  
        push ecx                  
        not byte ptr[eax]         
        add byte ptr[eax], 0x04   
        movzx edi, byte ptr[eax]  
        pop eax                   
        xor eax, edi              
        pop edi                   
        rol al, 1                 
        rol al, 1                 
        add al, 0x04              
        mov esp, ebp
        pop ebp
        ret                       
}
4

1 に答える 1

3

調べてみると、暗号化機能に関するコメントは間違っています。覚えておいてください: スタックは下に成長するので、引数がスタックにプッシュされると、最初にプッシュされたものはより高いアドレスを持つため、スタック フレームのベース ポインターからのオフセットが高くなります。

へのコメントにencryptは次のように書かれています。

// Inputs: register EAX = 32-bit address of Ekey,
//                  ECX = the character to be encrypted

ただし、呼び出しシーケンスは次のとおりです。

movzx  eax, temp_char    ; push the char to encrypt FIRST
push   eax
lea    eax, EKey         ; push the encryption key SECOND
push   eax
call   encrypt

したがって、文字は最初にプッシュされます。したがって、暗号化する文字encryptは次のようにロードされます。

; On function entry, the old Instruction Pointer (4 bytes) is pushed onto the stack
; so now the EKey is +4 bytes from the stack pointer
; and the character is +8 bytes from the stack pointer
;

push ebp
mov ebp, esp

; We just pushed another 4 bytes onto the stack (the esp register)
; and THEN we put the stack pointer (esp) into ebp as base pointer
; to the stack frame.
;
; That means EKey is now +8 bytes off of the base pointer
; and the char to encrypt is +12 off of the base pointer
;
mov ecx, 8[ebp]            ; This loads EKey pointer to ECX
mov eax, 12[ebp]           ; This loads char-to-encrypt to EAX

次に、コードはEAXポインターとして参照しようとします (EKeyこれは であると見なされるため)。ポインターとして参照しようとする最初のときに暗号化するのはあなたのキャラクターであるため、アクセス違反が発生しますEAX。これは次のとおりです。

not byte ptr[eax]

だからあなたのデバッガポインタは正しかった! :)

これらの 2 つのレジスタを交換するだけで修正できます。

mov eax, 8[ebp]            ; This loads EKey pointer to EAX
mov ecx, 12[ebp]           ; This loads char-to-encrypt to ECX

最後に、encrypt の呼び出しは、完了時にスタック ポインターをクリーンアップしません。を呼び出す前に 8 バイトのデータをスタックにプッシュしencrypt、スタックのクリーンアップなしencryptで標準retを実行するため、呼び出し後にクリーンアップする必要があります。

...
call   encrypt
add    esp, 8
...
于 2015-03-19T15:53:58.153 に答える