|
|
| Посл.отвђт | Сообщенiе |
|
|
Дата: Мар 6, 2004 11:45:51 · Поправил: Gloomy Цель такова: имеется программа, сжатая упаковщиком. Нужно запустить ее, дождаться пока она полностью распакуется и записать ей определенные данные по определенному адресу. С неупакованной программой нет никаких проблем - создаем процесс с флагом CREATE_SUSPENDED, пишем в память что хотим и продолжаем выполнение программы. А как быть в данном случае? Как определить что программа уже распакована? И как подсчитать адрес в памяти куда нужно писать или он останется прежним? Теоретически можно подобрать подходящую задержку, но все компы разные по мощности - нужно более универсальное решение. Подскажите пожалуйста что лучше всего придумать? Начал копать в сторону DebugApi но чувствую что это меня не спасет и не поможет :( З.Ы. Готовые патчеры памяти не предлагать - это собственная одноразовая разработка для своей программы, а не кряк - в случае кряка я бы воспользовался готовыми патчерами. З.З.Ы. Сорри за опечатки в названии темы - хотел поправить но не смог :( |
|
|
Дата: Мар 6, 2004 11:50:33 Подождать пока распакуется можно с помощью WaitForInputIdle :-) |
|
|
Дата: Мар 6, 2004 11:51:59 · Поправил: Asterix Кстати, где-то в топике валяется мой лоадер на fasm'е, он конечно не совершенный, возможно имеется пару недочётов, не помню точно ;-), но принцип понять поможет. |
|
|
Дата: Мар 6, 2004 13:46:53 С WaitForInputIdle не получается - программа просто висит в памяти и ничего не делает :( >> лоадер на fasm'е Поискал по форуму - ничего похожего не нашел, искал поиском и вручную просмотром всех тем. Или исходник выложен в разделе исходников? |
|
|
Дата: Мар 6, 2004 14:45:52 Ищи по форуму по ключевому слову 'Loader PE example' |
|
|
Дата: Мар 6, 2004 14:46:51 > С WaitForInputIdle не получается - программа просто висит в памяти и ничего не делает Странно, это ты что-то не то делаешь ;-) |
|
|
Дата: Мар 6, 2004 15:04:32 · Поправил: Asterix Короче я тут запустил тот пример, исходник которого валяется в форуме и обнаружил что под win98 он не пашет ;-) Вот тебе новый, уже не помню для чего он делался, кажется под ASPack :-)
; Loader PE example
format PE GUI 4.0
entry start
include '%fasminc%\win32a.inc'
BaseOfImage = 000400000h
SizeOfImage = 000210000h
section '.data' data readable writeable
OldProtect dd 0
szFileName db "target.exe",0
hMemory dd 0
pMemory dd 0
AddressToWrite dd 0
BytesToWrite db 0EBh, 0FEh
BytesToUnpatch db 06Ah, 000h
StartupInfo STARTUPINFO
ProcessInfo PROCESSINFO
Buff rb 002h
; 1 2 3 4 5 6 7 8 9 10
align 4
Signature db 0C1h, 0F9h, 002h, 0F3h, 0A5h, 08Bh, 0C8h, 083h, 0E1h, 003h
db 0F3h, 0A4h, 05Eh, 068h, 000h, 080h, 000h, 000h, 06Ah, 000h
db 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h, 000h
db 000h, 000h, 083h, 0C6h, 008h, 083h, 03Eh, 000h, 00Fh, 085h
db 000h, 000h, 000h, 000h, 068h, 000h, 080h, 000h, 000h, 06Ah
section '.code' code readable executable
include 'ParseBuffer.inc'
start:
mov [StartupInfo.cb], STARTUPINFO
invoke CreateProcess, szFileName, NULL, NULL, NULL, FALSE, CREATE_SUSPENDED,\
NULL, NULL, StartupInfo, ProcessInfo
test eax, eax
jz @exit
;--------------------------------------------------------------------- ------------
;--------------------------------- parse image -----------------------------------
invoke GlobalAlloc, GMEM_MOVEABLE or GMEM_ZEROINIT, SizeOfImage
test eax, eax
jz @error
mov [hMemory], eax
invoke GlobalLock, eax
test eax, eax
jz @free
mov [pMemory], eax
invoke ReadProcessMemory, [ProcessInfo.hProcess], BaseOfImage,\
eax, SizeOfImage, NULL
test eax, eax
jz @unlock
stdcall ParseBuffer, Signature, 50, [pMemory], SizeOfImage
test eax, eax
jz @unlock
add eax, BaseOfImage
add eax, 031h
mov [AddressToWrite], eax
invoke GlobalUnlock, [pMemory]
invoke GlobalFree, [hMemory]
;------------------------------- parse image end ---------------------------------
;--------------------------------------------------------------------- ------------
invoke ReadProcessMemory, [ProcessInfo.hProcess], [AddressToWrite], Buff, 002h, NULL
test eax, eax
jz @error
cmp WORD [Buff], 0006Ah
jne @error
invoke VirtualProtectEx, [ProcessInfo.hProcess], [AddressToWrite], 002h,\
PAGE_EXECUTE_READWRITE, OldProtect
invoke WriteProcessMemory, [ProcessInfo.hProcess], [AddressToWrite], BytesToWrite, 002h, NULL
test eax, eax
jz @error
invoke VirtualProtectEx, [ProcessInfo.hProcess], [AddressToWrite], 002h,\
[OldProtect], OldProtect
invoke ResumeThread, [ProcessInfo.hThread]
invoke WaitForInputIdle, [ProcessInfo.hProcess], 00100h
invoke SuspendThread, [ProcessInfo.hThread]
invoke VirtualProtectEx, [ProcessInfo.hProcess], [AddressToWrite], 002h,\
PAGE_EXECUTE_READWRITE, OldProtect
invoke WriteProcessMemory, [ProcessInfo.hProcess], [AddressToWrite], BytesToUnpatch, 002h, NULL
test eax, eax
jz @error
invoke VirtualProtectEx, [ProcessInfo.hProcess], [AddressToWrite], 002h,\
[OldProtect], OldProtect
;--------------------------------------------------------------------- ------------
;---------------------------------- patch here -----------------------------------
; здесь можешь вписать свой патч
;----------------------------------- end patch -----------------------------------
;--------------------------------------------------------------------- ------------
invoke ResumeThread, [ProcessInfo.hThread]
@close:
invoke CloseHandle, [ProcessInfo.hThread]
invoke CloseHandle, [ProcessInfo.hProcess]
@exit:
invoke ExitProcess, 0
@error:
invoke TerminateProcess, [ProcessInfo.hProcess], 0
jmp @close
@unlock:
invoke GlobalUnlock, [pMemory]
@free:
invoke GlobalFree, [hMemory]
jmp @error
section '.idata' import data readable writeable
library kernel, 'KERNEL32.DLL',\
user, 'USER32.DLL'
import kernel,\
CreateProcess, 'CreateProcessA',\
VirtualProtectEx, 'VirtualProtectEx',\
WriteProcessMemory, 'WriteProcessMemory',\
ReadProcessMemory, 'ReadProcessMemory',\
SuspendThread, 'SuspendThread',\
ResumeThread, 'ResumeThread',\
TerminateProcess, 'TerminateProcess',\
CloseHandle, 'CloseHandle',\
ExitProcess, 'ExitProcess',\
GlobalAlloc, 'GlobalAlloc',\
GlobalLock, 'GlobalLock',\
GlobalUnlock, 'GlobalUnlock',\
GlobalFree, 'GlobalFree'
import user,\
WaitForInputIdle, 'WaitForInputIdle'
section '.rsrc' resource data readable
; resource directory
directory RT_ICON, icons,\
RT_GROUP_ICON, group_icons
; resource subdirectories
resource icons,\
1, LANG_NEUTRAL, icon_data
resource group_icons,\
17, LANG_NEUTRAL, main_icon
icon main_icon, icon_data, 'target.ico' |
|
|
Дата: Мар 6, 2004 17:59:36 Попробовал все варианты загрузчиков, остановился на варианте с бесконечным циклом в котором проверяется правильность места для записи байт (т.е. 4 байта читаются в буфер, сравниваются с тем что должно быть. Если равно то пишем в память, иначе продолжаем выполнение процесса). Возникла совершенно неожиданная проблема: процесс не успевает вовремя остановится, залетает туда где вместо нормального кода написан всякий мусор и вываливается с ошибкой. Добавил код который делает дамп памяти предположительно в том месте где выдается сообщение об ошибке - теория подтверждается - дамп только наполовину заполнен нужными байтами, все остальное нули из запускаемой программы. Кратко о том что я вообще такое пишу (может быть это поможет определиться с проблемой): пишу на Дельфи программу, которую потом нужно будет как-то защитить. Для защиты придумал такой способ: в НЕХ-редакторе забираю с ОЕР 1 Кб кода, вставляю на его место мусор - программа, ясен пень, после этого не запускается. Теперь стоит задача написать загрузчик который читал бы файл со спертыми байтами, запускал "обокраденную" программу, писал ей в память нужные байты в ОЕР и отпускал работать дальше. При неупакованной UPXом программе загрузчик работает замечательно, стабильно. Как только упаковываю UPXом начинаются глюки - загрузчик отлавливает момент когда программа уже распакована, но отлавливает его слишком поздно когда упаковщик уже передал управление программой и напоролся на мусор вместо кода. Как сделать опознавание окончания распаковки более точным? З.Ы. Купить и поставить i8080 чтобы программа работала медленее не предлагать! :) |
|
|
Дата: Мар 6, 2004 18:31:36 Твоя проблема решается элементарно! Для простых пакеров UPX/ASPack и др. вот этот лоадер рулит, ты обратил внимание на принцип его работы?? Он запускает процесс с флагом CREATE_SUSPENDED, потом парсит имадж, в поиске нужного места, потом читает два байта по найденному месту и пишет туда байты 0xEBh,0xFEh, что они делают думаю объяснять не надо, далее ждёт пока распакуется процесс, патчит байты на место, патчит если нужно программу(здесь нету) и запускает процесс дальше на выполнение. Ничего более точного тебе не придумать, использовать здесь Debug API - неверное решение. |
|
|
Дата: Мар 6, 2004 21:41:23 · Поправил: Gloomy А можно тогда еще файл "ParseBuffer.inc" а то вообще непонятно как и что делает эта функция, а без нее далеко не уйдешь. А массив Signature универсален (подходит для любых программ) или уникален (создан специально для конкретной программы)? Если не затруднит пришли пожалуйста исходник на мыло tinysoft@nm.ru. Или сюда можно выложить - вдруг еще кому-нибудь понадобится? ;) |
|
|
Дата: Мар 7, 2004 01:51:46 Массив должен быть универсален для ASPack'ов 2.12, т.е. подходит под любую запакованную этим упаковщиком прогу. stdcall ParseBuffer, Signature, 50, [pMemory], SizeOfImage - принимает на вход указатель на сигну, её длину, поинтер на область памяти куда бы считан image, размер image, далее парсит в поисках сигнатуры и возвращает в eax найденный адрес или 0 в случае неудачи. Так что можешь написать сам или если не можешь ищи по форуму, где-то она тут присутствует, но на masm'е ;-) |
|
|
Дата: Мар 7, 2004 10:01:57 · Поправил: Gloomy Функцию нашел, переписал на FASMе. Несколько вопросов: 1) что такое SizeOfImage? Это размер упакованного файла? 2) где (а точнее с какого смещения) взять сигнатуру для UPX? Посмотрел откуда она берется в данном случае - так и не понял почему именно оттуда? 3) add eax, 031h ; 31h это тоже только для ASPack? Тренируюсь на Блокноте (запакованном ASPack 2.12), отлаживаю патчер - после первого вызова ReadProcessMemory функция возвращает 0, отладчик выдает ошибку ERROR_PARTIAL_COPY. Почитал справку, добавил флаг PROCESS_VM_READ - не помогло. Почему возникает ошибка? |
|
|
Дата: Мар 7, 2004 11:19:37 · Поправил: Gloomy Ошибку с ReadProccessMemory исправил, записав в SizeOfImage размер файла. Возникла новая проблема - не работает функция ParseBuffer - возвращает 0. Переписал ее так:
proc ParseBuffer,lpScanString,ScanStringLength,lpBuffer,BufferLength
enter
push ebx edx ecx edi esi
mov edi,[lpScanString]
mov esi,[lpBuffer]
mov ecx,[ScanStringLength]
mov ebx, ecx
mov edx, esi
add edx,[BufferLength]
sub edx,[ScanStringLength]
inc edx
@loop:
cmp esi, edx
je @not_found
jecxz @found
mov al, BYTE [edi]
test al, al
jz @00h_found
cmp BYTE [esi], al
je @parse
sub edi, ebx
add edi, ecx
sub esi, ebx
add esi, ecx
inc esi
mov ecx, ebx
jmp @loop
@00h_found:
@parse:
inc edi
inc esi
dec ecx
jmp @loop
@found:
mov eax, esi
sub eax, ebx
pop esi edi ecx edx ebx
return
@not_found:
xor eax, eax
pop esi edi ecx edx ebx
return
Может быть это неправильно? |
|
|
Дата: Мар 7, 2004 12:24:39 SizeOfImage - это размер image, можно в PETools глянуть для твоего конкретного файла ;-) > где (а точнее с какого смещения) взять сигнатуру для UPX? Посмотрел откуда она берется в данном случае - так и не понял почему именно оттуда? Таков уж формат распаковщика ASPack'а что это самое удобное место для его остановки, поэтому собственно и сигнатура такая.. Для UPX'а ищи место где удобнее его остановить, можно перед самым прыжком на OEP, составляй сигну, высчитывай место для 0xEBh,0xFEh > add eax, 031h ; 31h это тоже только для ASPack? Ясное дело что процедура возвращает адрес начала найденной сигнатуры, поэтому нужно посчитать место для патча, вот это и делает такой незамысловатый код ;-) > после первого вызова ReadProcessMemory функция возвращает 0, отладчик выдает ошибку ERROR_PARTIAL_COPY Это ты чего-то напутал :-) Слепил тебе пример, за неимением заАСПаченного файла настроил на totalcmd.exe, в исходнике только имя сменил и SizeOfImage. Гы, надеюсь TotalCommander ты юзаешь ;-), проверено на версии 5.50. P.S. Процедуру ты перевёл не правильно или когда постил что-то напутал :-))) можешь кильнуть её из топика ;-) align 4 proc ParseBuffer, lpScanString, ScanStringLength, lpBuffer, BufferLength enter push ebx edx ecx edi esi mov edi, [lpScanString] mov esi, [lpBuffer] mov ecx, [ScanStringLength] mov ebx, ecx mov edx, esi add edx, [BufferLength] sub edx, [ScanStringLength] inc edx align 4 @loop: cmp esi, edx je @not_found test ecx, ecx jz @found mov al, BYTE [edi] test al, al jz @00h_found cmp BYTE [esi], al je @parse sub edi, ebx add edi, ecx sub esi, ebx add esi, ecx inc esi mov ecx, ebx jmp @loop align 4 @parse: inc edi inc esi dec ecx jmp @loop align 4 @00h_found: inc edi inc esi dec ecx jmp @loop @found: mov eax, esi sub eax, ebx sub eax, [lpBuffer] pop esi edi ecx edx ebx return @not_found: xor eax, eax pop esi edi ecx edx ebx return 1651420022__TotalLoader.rar |
|
|
Дата: Мар 7, 2004 15:39:43 Спасибо большое за помощь! Уже переделал пример под UPX 1.24 - все отлично работает. Off: Теперь предстоит самое Дзенное занятие из всех Дзенных занятий - переписать все это дело с Ассемблера на Дельфи :) |
|
Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.262 |