· Начало · Отвђтить · Статистика · Поиск · FAQ · Правила · Установки · Язык · Выход · WASM.RU · Noir.Ru ·

 WASM Phorum —› WASM.WIN32 —› Как определить оконачние распаковки процесса?

. 1 . 2 . >>

Посл.отвђт Сообщен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: Теперь предстоит самое Дзенное занятие из всех Дзенных занятий - переписать все это дело с Ассемблера на Дельфи :)

. 1 . 2 . >>


Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.262