Call / Ret в сборке x86, встроенной в C ++ - PullRequest
1 голос
/ 16 мая 2010

Это, вероятно, тривиально, но по какой-то причине я не могу это сработать. Предполагается, что это простая функция, которая изменяет последний байт слова на «AA» (10101010), но ничего не происходит, когда я вызываю функцию. Он просто возвращает мой оригинальный меч.

__declspec(naked) long
    function(unsigned long inputDWord, unsigned long *outputDWord)
    {
      _asm{
        mov ebx, dword ptr[esp+4]

  push ebx
  call SET_AA
  pop ebx

  mov eax, dword ptr[esp+8]
  mov dword ptr[eax], ebx
       }
}

__declspec(naked) unsigned long 

SET_AA( unsigned long inputDWord )

{

       __asm{
          mov eax, [esp+4]
                mov al, 0xAA //10101010 didn't work either 
                ret
             }
}

Ответы [ 6 ]

4 голосов
/ 16 мая 2010

Вы, похоже, путаете возврат значения и наличие переменной out.

Здесь:

push ebx
call SET_AA
pop ebx

вы действуете так, как будто ebx является переменной out.

и здесь:

mov eax, [esp+4]
mov al, 0xAA //10101010 didn't work either 
ret

вы просто записываете материал в eax дважды (один раз с параметром, затем вы перезаписываете его своим 0xAA). eax традиционно является регистром возвращаемого значения. Вам нужно выбрать тот, который вы хотите использовать.

Если вы хотите, чтобы это была переменная out, вам нужно сделать что-то вроде этого:

__declspec(naked) long function(unsigned long inputDWord, unsigned long *outputDWord) {
    _asm{
        mov ebx, dword ptr[esp+4]

        push ebx
        call SET_AA
        pop ebx

        mov eax, dword ptr[esp+8]
        mov dword ptr[eax], ebx
    }
}

__declspec(naked) void SET_AA( unsigned long inputDWord ) {
    __asm{
        mov [esp+4], 0xAA // put 0xAA into the variable passed on the stack
        ret
    }
}

Если вы хотите получить возвращаемое значение, вы можете сделать что-то вроде этого:

__declspec(naked) long function(unsigned long inputDWord, unsigned long *outputDWord) {
    _asm{
        mov ebx, dword ptr[esp+4]

        call SET_AA
        mov ebx, eax

        mov eax, dword ptr[esp+8]
        mov dword ptr[eax], ebx
    }
}

__declspec(naked) unsigned long SET_AA(/* input param not needed, we are just returning a value */) {
    __asm{
        mov eax, 0xAA // return 0xAA via the eax register
        ret
    }
}
2 голосов
/ 16 мая 2010

Я думаю, это больше, чем вы имели в виду.Одна важная вещь: как говорит MSDN ,

Голые функции должны обеспечивать собственный пролог ... и эпилог

Ваш SET_AA() в порядке,Оставляет результат в eax.(Вы можете обойтись без пролога / эпилога, потому что вы вызываете его с _asm, а не с C.)

__declspec(naked) unsigned long 
SET_AA(unsigned long inputDWord )
{
    __asm
    {
        mov eax, [esp+4]
        mov al, 0xAA
        ret               // final value is in eax
    }
}

function() должен вернуть void, поскольку вы хотите получить результат в *outputDWord.Также вы можете использовать inputDWord вместо [esp + 4]:

__declspec(naked) void
function(unsigned long inputDWord, unsigned long *outputDWord)
{
    _asm
    {
    // you need a prolog/epilog to make C happy
    // here's the prolog:
    push ebp
    mov ebp, esp

    mov ebx, inputDWord    // the value you're going to change
    mov ecx, outputDWord   // address of where to put the result

    push ebx
    call SET_AA // puts the result in eax
    pop ebx

    // copy the result to the thing ecx points to (*outputDWord)
    mov [ecx], eax

    // epilog to keep C happy
    pop ebp
    ret
    }
}
0 голосов
/ 16 мая 2010

Почему бы просто не написать функцию на C ++? Он с радостью предоставляет битовые операции.

0 голосов
/ 16 мая 2010

, если вы не используете __cdecl в качестве соглашения о вызовах, в обеих ваших функциях отсутствует очистка стека, это вызовет проблемы, когда возвращаемые значения раскручивают кадры стека, а также тот факт, что регистры не сохраняются правильно. *

используя что-то более структурированное, ясное и лаконичное:

__declspec(naked) unsigned long __stdcall SET_AA(unsigned long inputDWord )
{
    __asm
    {
        mov eax, [esp+4]
        mov al, 0xAA
        retn 4
    }
}

__declspec(naked) void __fastcall function(unsigned long inputDWord, unsigned long *outputDWord)
{
    _asm
    {
    push ecx //push inputDWord
    call SET_AA // puts the result in eax

    // copy the result to the thing ecx points to (*outputDWord)
    mov [edx], eax
    retn//fastcall has no cleaup for the first 2 args
    }
}
0 голосов
/ 16 мая 2010

Я согласен с тем, что сказали другие пользователи.

  1. SET_AA сохраняет возвращаемое значение в регистре EAX. Однако вместо его возврата вы возвращаете переданный им параметр (EBX).
  2. Ваш function не имеет инструкции RET в конце. Также вы не можете вручную реализовать код, возвращающий вызывающей стороне.

Кроме того, хотелось бы отметить, что в function вы перезаписываете значение регистра EBX, не сохраняя его (в стеке) и не восстанавливая в конце.

Вы не указываете, какое соглашение о вызовах вы принимаете для своего function. (Поскольку вы даже не используете инструкцию RET или RET(8), я не могу угадать, что это было). Однако согласно большинству соглашений о вызовах, которые я знаю, незаконно перезаписывать регистр EBX без его восстановления в конце.

Регистры, доступные для использования по функции (в большинстве соглашений): EAX, ECX, EDX. Все остальные регистры также могут использоваться по желанию, однако они должны быть восстановлены.

0 голосов
/ 16 мая 2010

Ваша функция SET_AA изменяет значение в EAX (и только в регистре), но после call SET_AA вы перемещаете другое значение в EAX в своей первой функции, перезаписывая результат из SET_AA звонок. Поэтому изменение использования регистров таким образом, чтобы не перезаписывать EAX (как указано в вашем ответе), решает вашу проблему.

...