Самоизменяющиеся алгоритмы с задачами Virtualprotect - PullRequest
2 голосов
/ 30 января 2011

У меня проблемы с API-интерфейсом Virtualprotect () для Windows. Я получил задание из школы, мой учитель сказал нам, что в прошлом, когда память была скудной и дорогой. Программисты должны были создавать продвинутые алгоритмы, которые изменяли бы себя на лету для экономии памяти Итак, у вас это есть, теперь мы должны написать такой алгоритм, он не должен быть эффективным, но он должен изменить себя.

Так что я решил сделать именно это, и я думаю, что сделал это довольно далеко, прежде чем просить о помощи.

Моя программа работает так:

У меня есть функция и цикл со встроенным переполнением стека. Стек переполняется адресом ячейки памяти, в которой находится код, созданный во время цикла. Управление передается коду в памяти. Код загружает dll и затем выходит, но прежде чем выйти, он должен восстановить цикл. Это одно из условий нашего назначения, все измененное в исходном цикле должно быть восстановлено.

Проблема в том, что у меня нет доступа на запись в цикл, только READ_EXECUTE, поэтому, как мне показалось, для изменения доступа я использую virtualprotect. Но эта функция вернула ошибку:

ERROR_NOACCESS, документация по этой ошибке очень тонкая, Windows только говорит: Неверный доступ к адресу памяти. Какие цифры, так как я хотел изменить доступ в первую очередь. Так что не так? Вот код, созданный в памяти: Названия всех данных в моем коде немного расплывчаты, поэтому я предоставил несколько комментариев

Size1: 
TrapData proc

jmp pLocals
LocalDllName db 100 dup(?)         ; name of the dll to be called ebx-82h
RestoreBuffer db 5 dup(?)          ; previous bytes at the overflow location
LoadAddress dd 0h    ; ebx - 19h   ; address to kernel32.loadlibrary
RestoreAddress dd 0h ; ebx - 15h   ; address to restore (with the restore buffer)
AddressToRestoreBuffer dd 0h ; ebx - 11h ; obsolete, I don't use this one
AddressToLea dd 0h  ; ebx - 0Dh          Changed, address to kernel32.virutalprotect
AddressToReturnTo dd 0h ; ebx - 9h       address to return execution to(the same as RestoreAddress
pLocals: 


call Refpnt
Refpnt: pop ebx    ; get current address in ebx

push ebx
mov eax, ebx

sub ebx, 82h
push ebx     ; dll name

sub eax, 19h          ; load lib address
mov eax, [eax]
call eax       


pop ebx         ; Current address
push ebx


;BOOL WINAPI VirtualProtect(
;  __in   LPVOID lpAddress,
;  __in   SIZE_T dwSize,
;  __in   DWORD flNewProtect,
;  __out  PDWORD lpflOldProtect
;);

mov eax, ebx
mov esi, ebx

sub eax, 82h
push eax            ; overwrite the buffer containing the dll name, we don't need it anymore
push PAGE_EXECUTE_READWRITE
push 5h
sub esi, 15h
mov esi, [esi]
push esi
sub ebx, 0Dh
mov ebx, [ebx]
call ebx        ; Returns error 998 ERROR_NOACCESS (to what?)

pop ebx
push ebx


sub ebx, 1Eh
mov eax, ebx    ; restore address buffer pointer

pop ebx
push ebx

sub ebx, 15h    ; Restore Address
mov ebx, [ebx]
xor esi, esi    ; counter to 0

@0:

push eax

mov al, byte ptr[eax+esi] 
mov byte ptr[ebx+esi], al

pop eax

inc esi
cmp esi, 5
    jne @0

pop ebx
sub ebx, 9h
mov ebx, [ebx]
push ebx    ; address to return to
ret

Size2: 

Так что не так? Ребята, вы можете мне помочь?

РЕДАКТИРОВАТЬ, рабочий код:

Size1: 


jmp pLocals
LocalDllName db 100 dup(?)
RestoreBuffer db 5 dup(?)
LoadAddress dd 0h    ; ebx - 19h
RestoreAddress dd 0h ; ebx - 15h
AddressToRestoreBuffer dd 0h ; ebx - 11h
AddressToLea dd 0h  ; ebx - 0Dh
AddressToReturnTo dd 0h ; ebx - 9h
pLocals: 


call Refpnt
Refpnt: pop ebx    ; get current address in ebx

push ebx
mov eax, ebx

sub ebx, 82h
push ebx     ; dll name

sub eax, 19h          ; load lib address
mov eax, [eax]
call eax       


pop ebx         ; Current address
push ebx


;BOOL WINAPI VirtualProtect(
;  __in   LPVOID lpAddress,
;  __in   SIZE_T dwSize,
;  __in   DWORD flNewProtect,
;  __out  PDWORD lpflOldProtect
;);

mov esi, ebx

push 0
push esp
push PAGE_EXECUTE_READWRITE
push 5h
sub esi, 15h
mov esi, [esi]
push esi
sub ebx, 0Dh
mov ebx, [ebx]
call ebx

pop ebx
pop ebx
push ebx


sub ebx, 1Eh
mov eax, ebx    ; restore address buffer pointer

pop ebx
push ebx

sub ebx, 15h    ; Restore Address
mov ebx, [ebx]
xor esi, esi    ; counter to 0

@0:

push eax

mov al, byte ptr[eax+esi] 
mov byte ptr[ebx+esi], al

pop eax

inc esi
cmp esi, 5
    jne @0

pop ebx
sub ebx, 9h
mov ebx, [ebx]
push ebx    ; address to return to
ret


Size2: 

Может быть, немного небрежно, но я это не имеет значения;)

Ответы [ 2 ]

3 голосов
/ 30 января 2011

Вы пытаетесь заставить VirtualProtect записать lpflOldProtect в область памяти, доступную только для чтения, т. Е. В текущую секцию кода, которую вы пытаетесь сначала снять с защиты!Я думаю, это то, что дает вам ERROR_NO_ACCESS.Так как вы все равно используете стек, пусть он записывает lpflOldProtect в расположение стека.

0 голосов
/ 30 января 2011

Это не так просто, как в старые времена;доступ на чтение, используемый для подразумеваемого доступа к выполнению, и много отображений памяти были сопоставлены с возможностью записи.

В наши дни я был бы удивлен, если бы было много (каких-либо?) отображений памяти, которыекак для записи , так и исполняемый файл.(А современных процессоров с поддержкой PAE достаточно даже для того, чтобы даже 32-разрядные ядра обеспечивали неисполняемые, но пока не читаемые отображения.)

Прежде всего, я бы сказал, найдите более старую систему Windows, Win2k илираньше затем начинали пытаться решить эту проблему.:)

РЕДАКТИРОВАТЬ : О!Я думал, что загрузка DLL не удалась.Хорошая работа.:)

Что вы подразумеваете под «восстановить цикл»?Так как вы разбили стек, чтобы перейти к своему коду, вы не действительно уничтожили текстовый сегмент цикла, вы только набросали в стеке.Вы можете вставить другую функцию перед вашим циклом, а затем вернуться из вашей dll к функции, которая вызвала ваш цикл.(Вы «вернулись» в свой введенный код из цикла, поэтому вы не можете вернуться в цикл, не создав для него фальшивый фрейм стека; возврат к предыдущей функции кажется более простым, чем создание фальшивого фрейма стека.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...