简单加密汇编程序 - 写入内存位置的访问冲突

时间:2015-03-19 14:58:44

标签: c++ assembly encryption cdecl

我必须在这个程序中实现一个cdecl调用约定,该程序最初使用非标准化约定。据我所知它看起来正确,但我得到一个未处理的异常错误说“Accress违规写入位置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                       
}

1 个答案:

答案 0 :(得分:3)

通过检查,对加密功能的评论是错误的。请记住:堆栈增长 down ,因此当参数被推入堆栈时,首先推送的参数具有更高的地址,因此,与堆栈帧中的基本指针的偏移量更高。

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]

所以你的调试器指针是正确的! :)

您可以通过交换这两个寄存器来修复它:

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

最后,您的加密调用在完成后不会清理堆栈指针。由于您在调用encrypt之前将8个字节的数据压入堆栈,并且由于encrypt执行标准ret而没有堆栈清理,因此您需要在调用后清理:< / p>

...
call   encrypt
add    esp, 8
...