.486
.model flat,stdcall
option casemap:none
include windows.inc
include kernel32.inc
include user32.inc
include masm32.inc
includelib kernel32.lib
includelib user32.lib
includelib masm32.lib
.const
replaceAt dd 00403000h ; по этому адресу нужно вставить
replaceBy db "Hooked!",0 ; вот это
.data
ProcessId dd 0 ; PID
ProcessHandle dd 0 ; Открытый процесс
Lentgh dd 0 ; Длина строки для патчинга (strlen(replaceBy))
ProtectFlag dd 0 ; Тут сохраняются "права доступа" к памяти.
msgCaption db "Dll message",0 ; Заголовок MessageBox
msgErrorOpenProc1 db "Error while retrieving process id.",0 ; 1
msgErrorOpenProc2 db "Error while opening process.",0 ; 2
msgErrorMemReplace1 db "Replacing memory failed.",0 ; 3
msgErrorMemReplace2 db "Replacing memory at first Virtual Protect failed.",0 ; 4
msgErrorMemReplace3 db "Replacing memory at MemCopy failed.",0 ; 5
msgErrorMemReplace4 db "Replacing memory at second Virtual Protect failed.",0 ; 6... 1,2,3,4,5,6 это тексты MessageBox.
.code
ReplaceMem proc ReplaceAtAddr:DWORD,ReplaceByValue:DWORD,Len:DWORD ; Функция патчинга.
invoke VirtualProtect,ReplaceAtAddr,Len,PAGE_EXECUTE_READWRITE,ADDR ProtectFlag ; Выставляем права(?) на доступ к памяти.
.if eax==FALSE ; если VirtualProtect возвратила false - ошибка и завершение программы.
invoke MessageBox,NULL,ADDR msgErrorMemReplace2,ADDR msgCaption,MB_OK or MB_ICONERROR
mov eax,FALSE
ret
.endif
invoke MemCopy,ReplaceAtAddr,ADDR ReplaceByValue,Len ; Используем функцию Masm'а, MemCopy (аналог memcpy в C).
.if eax==FALSE ; если MemCopy вернула false - ошибка и завершение программы.
invoke MessageBox,NULL,ADDR msgErrorMemReplace3,ADDR msgCaption,MB_OK or MB_ICONERROR
mov eax,FALSE
ret
.endif
invoke VirtualProtect,ReplaceAtAddr,Len,ProtectFlag,NULL ; Восстанавливаем права доступа к памяти из ProtectFlag.
.if eax==FALSE ; Если VirtualProtect вернула false - ошибка и завершение программы.
invoke MessageBox,NULL,ADDR msgErrorMemReplace4,ADDR msgCaption,MB_OK or MB_ICONERROR
mov eax,FALSE
ret
.endif
mov eax,TRUE ;
ret ; возвращаем true, что успешно выполнен патчинг.
ReplaceMem endp ; конец функции патчинга
LibMain proc hInstDLL:DWORD, dwReason:DWORD, unused:DWORD ; Это будет EP дллки, здесь происходит вызов патчера.
.if dwReason==DLL_PROCESS_ATTACH
invoke GetCurrentProcessId ; получаем PID нашего процесса (той проги то запустила DLL).
mov ProcessId,eax ; кладём PID в ProcessId.
.if ProcessId==FALSE ; Если ProcessId=false - ругаемся и выходим из программы.
invoke MessageBox,NULL,ADDR msgErrorOpenProc1,ADDR msgCaption,MB_OK or MB_ICONERROR
invoke ExitProcess,0h
.endif
invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,ProcessId ; открываем процесс.
mov ProcessHandle,eax ; записываем возвращёное значение в ProcessHandle
.if ProcessHandle==FALSE ; если ProcessHandle=false - ругаемся и выходим
invoke MessageBox,NULL,ADDR msgErrorOpenProc2,ADDR msgCaption,MB_OK or MB_ICONERROR
invoke ExitProcess,0h
.endif
invoke StrLen,ADDR replaceBy ; Читаем длину строки.
add eax,1 ; добавляем 1 (вспомним что строки кончаются символом 0h).
mov Lentgh,eax ; суём длину строки в Lentgh
invoke ReplaceMem,replaceAt,ADDR replaceBy,Lentgh ; вызываем нашу функцию патчинга.
.if eax==FALSE ; если возвращён false - ругаемся и выходим.
invoke MessageBox,NULL,ADDR msgErrorMemReplace1,ADDR msgCaption,MB_OK or MB_ICONERROR
invoke ExitProcess,0h
.endif
mov eax,TRUE ;
ret ; возвращаем TRUE.
.elseif dwReason==DLL_PROCESS_DETACH
.elseif dwReason==DLL_THREAD_ATTACH
.elseif dwReason==DLL_THREAD_DETACH
.endif
ret
LibMain endp
end LibMain
Патчер памяти на MASM
Для чего мне, собственно, это нужно?
- Ну к примеру для создания патчей или трейнеров, да и просто для расширения знаний.
Почему на ассемблере?
- Нужна предельная скорость пропатчивания и маленький размер, да и просто в данный момент меня наиболее интересует изучение именно этого языка.
Суть моего вопроса конечно же заключается в том, что сам додуматься, как правильно писать в память на MASM'е - не могу, ибо я уже успел запутаться в коде... Я ассемблером начал заниматься полтора месяца назад, многое неясно, многое непонятно, но потихоньку разбираюсь и даже нахожу аналогии в алгоритме с другими языками программирования.
Этот код я попытался перегнать из C++ в MASM. (руками естественно)
Вот код после перегонки (ясный пень где-то ошибки есть, ибо я просто так тему бы не создавал), так как ошибка появляется именно при использовании АПИ функции - думаю тему я запостил там где надо, этот код компилируется в DLL:
Код:
Нужно сделать так, чтобы "Message Title" сменилось на "Hooked!"
Если лень компилировать, вот сурсы и бинарники, также там есть рабочий пример длл на C++.
Надеюсь на помощь. Или хотя-бы подсказку, где я сплоховал.
Или может есть какие-нибудь полегче способы может?
Hook.asm:
Код:
.386
.model flat, stdcall
option casemap :none
include E:\masm32\include\windows.inc
include E:\masm32\include\kernel32.inc
include E:\masm32\include\user32.inc
includelib E:\masm32\lib\kernel32.lib
includelib E:\masm32\lib\user32.lib
include E:\masm32\macros\Strings.mac
include E:\masm32\include\w2k\ntstatus.inc
include E:\masm32\include\w2k\native.inc
include E:\masm32\include\w2k\ntdll.inc
includelib E:\masm32\lib\w2k\ntdll.lib
includelib MemReplace.lib
extrn _imp__My@0:dword
My equ _imp__My@0
.data
mytext db "My good Title Of Message Box",0h
myproc db "My",0h
.code
_start proc
LOCAL han:DWORD
LOCAL memory:DWORD
LOCAL heap:DWORD
LOCAL procaddr:DWORD
;call My
invoke GetProcessHeap
mov heap,eax
invoke HeapAlloc,eax,HEAP_ZERO_MEMORY,1000h
mov memory,eax
invoke GetModuleHandle,$CTA0("MemReplace.dll")
mov han,eax
invoke GetModuleFileName,han,memory,1000h
;invoke MessageBox,0h,memory,$CTA0("Title"),MB_OK
invoke HeapFree,heap,0h,memory
invoke GetProcAddress,han,offset myproc
mov procaddr,eax
call eax
invoke MessageBox,0h,offset mytext,offset mytext,MB_OK
invoke ExitProcess,0h
_start endp
end _start
.model flat, stdcall
option casemap :none
include E:\masm32\include\windows.inc
include E:\masm32\include\kernel32.inc
include E:\masm32\include\user32.inc
includelib E:\masm32\lib\kernel32.lib
includelib E:\masm32\lib\user32.lib
include E:\masm32\macros\Strings.mac
include E:\masm32\include\w2k\ntstatus.inc
include E:\masm32\include\w2k\native.inc
include E:\masm32\include\w2k\ntdll.inc
includelib E:\masm32\lib\w2k\ntdll.lib
includelib MemReplace.lib
extrn _imp__My@0:dword
My equ _imp__My@0
.data
mytext db "My good Title Of Message Box",0h
myproc db "My",0h
.code
_start proc
LOCAL han:DWORD
LOCAL memory:DWORD
LOCAL heap:DWORD
LOCAL procaddr:DWORD
;call My
invoke GetProcessHeap
mov heap,eax
invoke HeapAlloc,eax,HEAP_ZERO_MEMORY,1000h
mov memory,eax
invoke GetModuleHandle,$CTA0("MemReplace.dll")
mov han,eax
invoke GetModuleFileName,han,memory,1000h
;invoke MessageBox,0h,memory,$CTA0("Title"),MB_OK
invoke HeapFree,heap,0h,memory
invoke GetProcAddress,han,offset myproc
mov procaddr,eax
call eax
invoke MessageBox,0h,offset mytext,offset mytext,MB_OK
invoke ExitProcess,0h
_start endp
end _start
MemReplace.asm:
Код:
.486 ; create 32 bit code
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive
include E:\masm32\include\windows.inc
include E:\masm32\include\kernel32.inc
include E:\masm32\include\user32.inc
include E:\masm32\include\masm32.inc
includelib E:\masm32\lib\kernel32.lib
includelib E:\masm32\lib\user32.lib
includelib E:\masm32\lib\masm32.lib
.const
replaceAt dd 00403000h
replaceBy db "Hooked!",0
.data
Buff db "number",0
msgCaption db "Dll message",0
msgErrorOpenProc1 db "Error while retrieving process id.",0
msgErrorOpenProc2 db "Error while opening process.",0
msgErrorMemReplace1 db "Replacing memory failed.",0
msgErrorMemReplace2 db "Replacing memory at first Virtual Protect failed.",0
msgErrorMemReplace3 db "Replacing memory at MemCopy failed.",0
msgErrorMemReplace4 db "Replacing memory at second Virtual Protect failed.",0
.data?
hInstance dd ?
ProcessId dd ?
ProcessHandle dd ?
Lentgh dd ?
ProtectFlag dd ?
ProtectFlag2 dd ?
.code
Memoryproc proc ReplaceAtAddr:DWORD,ReplaceByValue:DWORD,Len:DWORD
mov edi,ReplaceAtAddr
mov esi,ReplaceByValue
mov ecx,Len
rep movsb
ret
Memoryproc endp
ReplaceMem proc ReplaceAtAddr:DWORD,ReplaceByValue:DWORD,Len:DWORD
invoke VirtualProtect,ReplaceAtAddr,Len,PAGE_EXECUTE_READWRITE,ADDR ProtectFlag
.if eax==FALSE
invoke MessageBox,NULL,ADDR msgErrorMemReplace2,ADDR msgCaption,MB_OK or MB_ICONERROR
mov eax,FALSE
ret
.endif
;invoke MemCopy,ReplaceAtAddr,ReplaceByValue,Len
invoke Memoryproc,ReplaceAtAddr,ReplaceByValue,Len
.if eax==FALSE
invoke MessageBox,NULL,ADDR msgErrorMemReplace3,ADDR msgCaption,MB_OK or MB_ICONERROR
mov eax,FALSE
ret
.endif
invoke VirtualProtect,ReplaceAtAddr,Len,ProtectFlag,offset ProtectFlag2
.if eax==FALSE
invoke MessageBox,NULL,ADDR msgErrorMemReplace4,ADDR msgCaption,MB_OK or MB_ICONERROR
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
ReplaceMem endp
My proc
invoke MessageBox,0h,offset msgCaption,offset msgCaption,MB_OK
invoke GetCurrentProcessId
mov ProcessId,eax
.if ProcessId==FALSE
invoke MessageBox,NULL,ADDR msgErrorOpenProc1,ADDR msgCaption,MB_OK or MB_ICONERROR
invoke ExitProcess,0h
.endif
invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,ProcessId
mov ProcessHandle,eax
.if ProcessHandle==FALSE
invoke MessageBox,NULL,ADDR msgErrorOpenProc2,ADDR msgCaption,MB_OK or MB_ICONERROR
invoke ExitProcess,0h
.endif
invoke StrLen,ADDR replaceBy
add eax,1
mov Lentgh,eax
invoke ReplaceMem,replaceAt,ADDR replaceBy,Lentgh
.if eax==FALSE
invoke MessageBox,NULL,ADDR msgErrorMemReplace1,ADDR msgCaption,MB_OK or MB_ICONERROR
invoke ExitProcess,0h
.endif
mov eax,TRUE
ret
My endp
LibMain proc instance:DWORD,reason:DWORD,unused:DWORD
.if reason == DLL_PROCESS_ATTACH
push instance
pop hInstance
mov eax, TRUE
.elseif reason == DLL_PROCESS_DETACH
.elseif reason == DLL_THREAD_ATTACH
.elseif reason == DLL_THREAD_DETACH
.endif
ret
LibMain endp
end LibMain
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive
include E:\masm32\include\windows.inc
include E:\masm32\include\kernel32.inc
include E:\masm32\include\user32.inc
include E:\masm32\include\masm32.inc
includelib E:\masm32\lib\kernel32.lib
includelib E:\masm32\lib\user32.lib
includelib E:\masm32\lib\masm32.lib
.const
replaceAt dd 00403000h
replaceBy db "Hooked!",0
.data
Buff db "number",0
msgCaption db "Dll message",0
msgErrorOpenProc1 db "Error while retrieving process id.",0
msgErrorOpenProc2 db "Error while opening process.",0
msgErrorMemReplace1 db "Replacing memory failed.",0
msgErrorMemReplace2 db "Replacing memory at first Virtual Protect failed.",0
msgErrorMemReplace3 db "Replacing memory at MemCopy failed.",0
msgErrorMemReplace4 db "Replacing memory at second Virtual Protect failed.",0
.data?
hInstance dd ?
ProcessId dd ?
ProcessHandle dd ?
Lentgh dd ?
ProtectFlag dd ?
ProtectFlag2 dd ?
.code
Memoryproc proc ReplaceAtAddr:DWORD,ReplaceByValue:DWORD,Len:DWORD
mov edi,ReplaceAtAddr
mov esi,ReplaceByValue
mov ecx,Len
rep movsb
ret
Memoryproc endp
ReplaceMem proc ReplaceAtAddr:DWORD,ReplaceByValue:DWORD,Len:DWORD
invoke VirtualProtect,ReplaceAtAddr,Len,PAGE_EXECUTE_READWRITE,ADDR ProtectFlag
.if eax==FALSE
invoke MessageBox,NULL,ADDR msgErrorMemReplace2,ADDR msgCaption,MB_OK or MB_ICONERROR
mov eax,FALSE
ret
.endif
;invoke MemCopy,ReplaceAtAddr,ReplaceByValue,Len
invoke Memoryproc,ReplaceAtAddr,ReplaceByValue,Len
.if eax==FALSE
invoke MessageBox,NULL,ADDR msgErrorMemReplace3,ADDR msgCaption,MB_OK or MB_ICONERROR
mov eax,FALSE
ret
.endif
invoke VirtualProtect,ReplaceAtAddr,Len,ProtectFlag,offset ProtectFlag2
.if eax==FALSE
invoke MessageBox,NULL,ADDR msgErrorMemReplace4,ADDR msgCaption,MB_OK or MB_ICONERROR
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
ReplaceMem endp
My proc
invoke MessageBox,0h,offset msgCaption,offset msgCaption,MB_OK
invoke GetCurrentProcessId
mov ProcessId,eax
.if ProcessId==FALSE
invoke MessageBox,NULL,ADDR msgErrorOpenProc1,ADDR msgCaption,MB_OK or MB_ICONERROR
invoke ExitProcess,0h
.endif
invoke OpenProcess,PROCESS_ALL_ACCESS,FALSE,ProcessId
mov ProcessHandle,eax
.if ProcessHandle==FALSE
invoke MessageBox,NULL,ADDR msgErrorOpenProc2,ADDR msgCaption,MB_OK or MB_ICONERROR
invoke ExitProcess,0h
.endif
invoke StrLen,ADDR replaceBy
add eax,1
mov Lentgh,eax
invoke ReplaceMem,replaceAt,ADDR replaceBy,Lentgh
.if eax==FALSE
invoke MessageBox,NULL,ADDR msgErrorMemReplace1,ADDR msgCaption,MB_OK or MB_ICONERROR
invoke ExitProcess,0h
.endif
mov eax,TRUE
ret
My endp
LibMain proc instance:DWORD,reason:DWORD,unused:DWORD
.if reason == DLL_PROCESS_ATTACH
push instance
pop hInstance
mov eax, TRUE
.elseif reason == DLL_PROCESS_DETACH
.elseif reason == DLL_THREAD_ATTACH
.elseif reason == DLL_THREAD_DETACH
.endif
ret
LibMain endp
end LibMain
И ещё:
invoke VirtualProtect,ReplaceAtAddr,Len,ProtectFlag,offset ProtectFlag2
Если последний параметр равен NULL, то функция обязательно провалится!
А у тебя вот так было:
Код:
ReplaceMem proc ReplaceAtAddr:DWORD,ReplaceByValue:DWORD,Len:DWORD
invoke VirtualProtect,ReplaceAtAddr,Len,PAGE_EXECUTE_READWRITE,ADDR ProtectFlag
.if eax==FALSE
invoke MessageBox,NULL,ADDR msgErrorMemReplace2,ADDR msgCaption,MB_OK or MB_ICONERROR
mov eax,FALSE
ret
.endif
invoke MemCopy,ReplaceAtAddr,ADDR ReplaceByValue,Len
.if eax==FALSE
invoke MessageBox,NULL,ADDR msgErrorMemReplace3,ADDR msgCaption,MB_OK or MB_ICONERROR
mov eax,FALSE
ret
.endif
invoke VirtualProtect,ReplaceAtAddr,Len,ProtectFlag,NULL
.if eax==FALSE
invoke MessageBox,NULL,ADDR msgErrorMemReplace4,ADDR msgCaption,MB_OK or MB_ICONERROR
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
ReplaceMem endp
invoke VirtualProtect,ReplaceAtAddr,Len,PAGE_EXECUTE_READWRITE,ADDR ProtectFlag
.if eax==FALSE
invoke MessageBox,NULL,ADDR msgErrorMemReplace2,ADDR msgCaption,MB_OK or MB_ICONERROR
mov eax,FALSE
ret
.endif
invoke MemCopy,ReplaceAtAddr,ADDR ReplaceByValue,Len
.if eax==FALSE
invoke MessageBox,NULL,ADDR msgErrorMemReplace3,ADDR msgCaption,MB_OK or MB_ICONERROR
mov eax,FALSE
ret
.endif
invoke VirtualProtect,ReplaceAtAddr,Len,ProtectFlag,NULL
.if eax==FALSE
invoke MessageBox,NULL,ADDR msgErrorMemReplace4,ADDR msgCaption,MB_OK or MB_ICONERROR
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
ReplaceMem endp
УДАЧИ во всём!!! И с наступающим Новым Годом!!!
Большое спасибо. Есть ещё один вопрос по твоему коду.
У меня Memoryproc в открытом виде не работает. Прога не запускается. (при дебаге пишет, что ошибка чтения-записи в [00000000])
Поэтому я немного исправил код:
Код:
ReplaceMem proc ReplaceAtAddr:DWORD, ReplaceByVal:DWORD, Len:DWORD
invoke VirtualProtect, ReplaceAtAddr, Len, PAGE_EXECUTE_READWRITE, ADDR ProtectFlag
pusha
mov edi,ReplaceAtAddr
mov esi,ReplaceByVal
mov ecx,Len
rep movsb
popa
invoke VirtualProtect, ReplaceAtAddr, Len, ProtectFlag, ADDR ProtectFlag2
ret
ReplaceMem endp
invoke VirtualProtect, ReplaceAtAddr, Len, PAGE_EXECUTE_READWRITE, ADDR ProtectFlag
pusha
mov edi,ReplaceAtAddr
mov esi,ReplaceByVal
mov ecx,Len
rep movsb
popa
invoke VirtualProtect, ReplaceAtAddr, Len, ProtectFlag, ADDR ProtectFlag2
ret
ReplaceMem endp
Или я где-то ошибся, или rep movsb юзает ещё какие-то регистры кроме esi, edi, ecx. Хотя в справочнике от интела указанны только они. Кстати, спасибо за этот способ копирования. :)
Если хочешь - посмотри архивчик!