Программа под отладчиком работает не так как без отладчика. Магия? - Assembler

Узнай цену своей работы

Формулировка задачи:

Ситуёвина такова, что прога правильно работает под отладчиком, но неправильно без него. Вот код:
.386
.model  flat, stdcall
option  casemap:none
 
include    \masm32\include\windows.inc
include    \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
 
GetFName proto
 
.data
fHandle  DWORD ?
stdout   DWORD ?
cWritten DWORD ?
error    BYTE  "Нет такого файла"
noname   BYTE  "Укажите имя файла"
 
.code
start:
    main proc
        invoke  GetStdHandle, STD_OUTPUT_HANDLE
        mov     stdout, eax
        invoke  GetFName
        cmp     eax, -1
        jz      empty
        invoke  CreateFile,
                eax, 
                GENERIC_READ, 
                0,
                NULL,
                OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL,
                0
        cmp eax,INVALID_HANDLE_VALUE
        jz  exit
        mov     fHandle, eax
        invoke  CloseHandle, fHandle
        invoke  ExitProcess, 0
    exit:
        invoke  WriteConsoleA, stdout, ADDR error, sizeof error, ADDR cWritten, NULL
        invoke  ExitProcess, 0
    empty:
        invoke  WriteConsoleA, stdout, ADDR noname, sizeof noname, ADDR cWritten, NULL
        invoke  ExitProcess, 0
    main endp
 
    GetFName proc
        invoke  GetCommandLine
        mov     edi, eax 
        push    edi
        mov     al, 0 
        mov     ecx,-1 
        cld
        repne   scasb ;ищем нулевой символ, чтобы определить конец командной строки
        not     ecx
        pop     edi 
        mov     al,20h 
        repne   scasb ;ищем пробел, чтобы отделить параметр, переданный в командной строке
        dec     edi               ;проверяем ..
        cmp     byte ptr [edi],0  ;.. не ноль ли мы нашли вместо пробела
        jz      empty ;.. если ноль, то параметра не было.. 
        inc     edi ;.. если не ноль, то переходим к первому символу параметра
        mov     eax,edi ;возвращаем адрес начала строки с параметром
        ret
    empty:
        mov     eax,-1 
        ret
    GetFName endp
end start
Прога запускается в консоли. Получает параметр. Если параметр не передать, то выводится "Укажите имя файла". Если параметр передан, то прога должна вывести "Нет такого файла" в том случае, если параметр не является именем существующего файла. Если же параметр является именем существующего файла, то никакого вывода не должно быть, прога просто отрабатывает и завершается. Но! Если я не передаю параметр, то всё происходит правильно, и прога выдаёт "Укажите имя файла". А вот если я передаю ей параметр, то она в любом случае выдаёт "Нет такого файла", даже если параметр является именем существующего файла. Но если запустить прогу под отладчиком и передать правильный параметр, то она завершается правильно (если проследить за поиском строки, то видно, что название параметра обрабатывается верно, и в регистре EAX действительно передаётся верный адрес.. и прога переходит на нужную ветку исполнения, и завершается верно). В качестве отладчика использую OllyDbg. Я разломал себе уже весь мозг, ибо только ещё начинаю учиться и пока не могу разбираться в таких нюансах. Надеюсь, у меня получилось понятно объяснить проблему.

Решение задачи: «Программа под отладчиком работает не так как без отладчика. Магия?»

textual
Листинг программы
GetFName proc
        invoke  GetCommandLine
        mov     edi, eax 
        xor     eax,eax;al, 0 
        or     ecx,-1         
        repne   scasb ;ищем нулевой символ, чтобы определить конец командной строки
        not     ecx
        mov     al,20h
        std 
        repne   scasb ;ищем последний пробел, чтобы отделить параметр, переданный в командной строке
        add     edi,2
        cld  
        jecxz      empty ;.. если ноль, то параметра не было.. 
        mov     eax,edi ;возвращаем адрес начала параметра
        ret
    empty:
        or     eax,-1 
        ret
    GetFName endp

Объяснение кода листинга программы

В коде представлено две процедуры: GetFName и empty.

  1. Процедура GetFName:
    • Получает адрес начала параметра, переданного в командной строке.
    • Выполняет следующие действия: 1.1. Применяет функцию GetCommandLine для получения адреса командной строки. 1.2. Сохраняет адрес командной строки в регистре edi. 1.3. Очищает регистр eax. 1.4. Использует инструкцию or для поиска последнего нулевого символа в строке (задание конца строки). 1.5. Использует инструкцию not для изменения знака регистра ecx. 1.6. Перемещает значение 20h в регистр al (используется для проверки наличия пробелов). 1.7. Использует инструкцию std для перехода к следующему байту в строке. 1.8. Использует инструкцию repne scasb для поиска последнего пробела в строке (задание начала параметра). 1.9. Добавляет 2 к значению регистра edi (переход к следующему байту после найденного пробела). 1.10. Использует инструкцию cld для перехода к следующему байту в строке. 1.11. Проверяет значение регистра ecx. Если оно равно нулю, то параметр отсутствует. 1.12. Возвращает адрес начала параметра в регистре eax.
    • Возвращает управление.
  2. Процедура empty:
    • Выполняет следующие действия: 2.1. Использует инструкцию or для поиска последнего нулевого символа в строке (задание конца строки). 2.2. Возвращает управление. Обратите внимание, что в коде используются регистры edi, eax, ecx, которые являются регистрами общего назначения и могут использоваться для хранения различных значений в процессе выполнения программы.

Оцени полезность:

14   голосов , оценка 3.929 из 5
Похожие ответы