· Начало · Статистика · WASM.RU · Noir.Ru ·

 WASM Phorum (Оффлайн - 24.11.2003) —› WASM.WIN32 —› Как заменить call [pAPIfunc] на call APIfunc?

Посл.отвђт Сообщенiе


Дата: Май 23, 2003 20:02:35

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


Дата: Май 23, 2003 21:24:08

Я не совсем тебя понял. Привязать exe к конкретной оси - bind -u filename (утилита из MS VS). Как думаешь - стоит положить? НО - эта утилита патчит IAT. Смысл же тебе понятен. Компилер генерит call xxx -> xxx: jmp [pAPIfunc] -> IAT. Для того, чтобы избавится от jmp надо указать компилеру dllspec. Но call останется все равно! А если ты хочешь call сразу_функцию_не_залезая_в_IAT, то тогда только ручками, на ассемблере. Узнаешь GetProcAddress адреса функций для твоей Windows и вперед! Ручами патчить каждый call. И молись богу, чтобы твой exe не попал на другую ОС и вдвойне молись богу, чтобы (если это dll) ее никто никуда от Preferred load address не унес. Иначе....


Дата: Май 23, 2003 22:35:10

volodya:
Вы хотите сказать, что такая последовательность приведет к проблемам:

1. hDLL = GetModuleHandle ("USER32.DLL");
2. pfn1 = GetProcAddress (hDLL, "SomeWin32API");

3. My EXE was relocated due to something...

4. hDLL = GetModuleHandle ("USER32.DLL");
5. pfn2 = GetProcAddress (hDLL, "SomeWin32API");

Теперь адрес pfn1 не будет равен адресу pfn2?


Дата: Май 23, 2003 22:57:34

Конечно, не равен. Я, конечно, возможно, выражаюсь излишне самоуверенно, надо бы проверить. Но не должен быть он равен и все тут! Я же говорил о другом. Похоже, Black_mirror хочет сразу звать call SomeWin32API; не залезая в IAT. А это значит, что функция дожна звать СРАЗУ АДРЕС SomeWin32API В ПАМЯТИ - т.е. call 77E6574 (от фонаря взял число, но смысл понятен). Такое можно закодировать, насколько я знаю, только прямо в HIEW, поправив адрес операнда call. Компилятор, по идее, такое пропустить не должен. И тут возникает вопросос. Что произойдет, если по требуемому адресу ничего не будет? Очевидно, GPF. А по поводу relocation я, кажись, погорячился. Здесь важно понимать суть. Смещения всех переменных в памяти, ессно, изменятся. Я себе слабо представляю как можно перерелокейтить exe ВО ВРЕМЯ ВЫПОЛНЕНИЯ, думаю, так просто нельзя, но то, что адреса изменяться - очевидно. Имеет смысл почитать статьи Питрека - он это подробно описывает, а также слить PEBrowseProfessional - он показывает секцию релоков. Описание секции - PE Spec.


Дата: Май 24, 2003 00:51:59

Вот, выкопал интересную статейку:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tools /tools/rebase.asp

Похоже, только DLLs могут быть 'relocated due to collision...'. Поскольку системные DLLs загружены первыми - они никогда не будут relocated. Таким образом, адреса АPI должны остаться на месте.


Дата: Май 24, 2003 17:06:38

Функция написана, только у метода есть два недостатка:
1) страница в памяти отличается от страницы на диске -> если страница кода будет удалена из памяти, то после ее загрузки из exe-файла настройку нужно выполнять заново. Для dll все понятно, если адрез загрузки отличается от базового, то после настройки релоков, винда если не хватает памяти скидыват ее в своп. А вот что может помешать винде считать страницу кода из экзешника, и заново настроить релоки? Может хук можно повесить на pagefault?
2) вполне может быть что элемент в секции reloc ссылается вовсе не на команду call, а байт 0E8h это mod/r , SIB или часть адреса(хотя последнее вряд ли).

Может вообще не смысла заменять косвенные вызовы на прямые?

format PE GUI
entry start

include 'include\kernel.inc'
include 'include\macro\stdcall.inc'

macro pusharg [arg]
{ reverse
push arg
}

macro directcall proc,[arg]
{ common
if ~ arg eq
pusharg arg
end if
db 0e8h ; код команды call
dd proc ; смемещение где будет находится реальный адрес вызова
}

section '.data' data readable writeable

time rd 32

section '.code' code readable executable

directcallinit:
call $+5 ;ищем imagebase
pop ebx
and ebx,0ffff0000h
add ebx,10000h
.l1:
sub ebx,10000h
cmp word [ebx],'MZ'
jnz .l0
.l0:
movzx edi,word [ebx+3ch]
add edi,ebx
cmp dword [edi],'PE'
jnz .l1
mov eax,[edi+80h]
add eax,ebx
push ebx ;imagebase [esp+12]
push eax ;import start [esp+8]
add eax,[edi+84h]
push eax ;import end [esp+4]
mov eax,[edi+0a4h]
push eax ;reloc size [esp]
mov esi,[edi+0a0h]
add esi,ebx ;esi - relocbase
.l2:
cmp dword [esp],0 ;пока не обработаем всю секцию reloc
jle .l5
mov ebx,[esi] ;смещение страницы
add ebx,[esp+12] ;ebx - адрес страницы
mov edi,[esi+4] ;длина релоков для данной страницы
add esi,8
sub edi,8
sub dword [esp],8
.l4:
cmp edi,0 ;пока не обработаем все релоки для данной страницы
jle .l2
mov eax,[esi] ;смещение релока от начала страницы
add esi,2
sub edi,2
sub dword [esp],2
and eax,0fffh
add eax,ebx ;адрес потенциальной комманды call
cmp byte [eax-1],0E8h ;если это не call то идем дальше
jnz .l4
mov edx,[eax] ;смещение адреса вызова
cmp edx,[esp+4] ;проверяем попадает ли он в секцию импорта
jae .l4
cmp edx,[esp+8]
jb .l4
mov edx,[edx] ;берем из таблицы адрес вызова
sub edx,eax
sub edx,4
push edx
mov edx,esp
invoke WriteProcessMemory,-1,eax,edx,4,edx;правим call
pop eax
jmp .l4
.l5:
add esp,16
ret

start:
call directcallinit
mov [time],time
directcall GetSystemTime,[time]
directcall SetSystemTime,time
directcall ExitProcess,0

section '.idata' import readable writeable

include 'include\macro\import.inc'

library kernel,'KERNEL32.DLL'

kernel:
import ExitProcess,'ExitProcess',\
GetSystemTime,'GetSystemTime',\
SetSystemTime,'SetSystemTime',\
WriteProcessMemory,'WriteProcessMemory'

section '.reloc' fixups data readable discardable


Дата: Май 24, 2003 21:00:16

to AsmGuru62
Вероятно, я неправильно понял вопрос. Естественно и абсолютно понятно, что базовый адрес загрузки dll может быть и будет изменен при необходимости, что же касательно системных dll - то здесь уже все интересно и ситуация разительным образом отличается от таковой в 9x. Для 9x копии dll (kernel, user, gdi) были ОБЩИМИ, в NT - они ЧАСТНЫЕ. А это, знаете ли... А может, расскажете, почему у kernel32.dll и всех остальных есть секция .reloc?
to BlackMirror
Ой, бля... Кто ж это будет все читать? Ну ладно, потом разберусь. По поводу релоков лучше не гадать, а сразу проверить по докам. И все. По идее, reloc должен показывать на секцию операнда, какой смысл патчить E8?

если страница кода будет удалена из памяти, то после ее загрузки из exe-файла настройку нужно выполнять заново

Чего? Это что-то новое! У меня такое ощущение, что у меня поехала крыша. Никому даром не нужна такая ОСь, которая будет производить fixup релоков при сбросе в своп! Файл настраивается только один раз - при загрузке! Откуда такая информация?


Дата: Май 25, 2003 14:13:29

E8 я и не патчу а проверяю, чтоб чего-нибудь лишнего не по пропатчить. Хотя такая вероятность все равно остается.

В программе вместо call [pAPIfunc] записано:
db 0E8h
patchhere dd pAPIfunc
после загрузки процедура directcallinit вместо pAPIfunc записывает APIfunc-patchhere-4 (используя данные из секции reloc), то есть получается call APIfunc.

если страница кода будет удалена из памяти, то после ее загрузки из exe-файла настройку нужно выполнять заново

Я не совсем точно выразился. Я имел ввиду следующее:
Так как страницы секции кода только для чтения, то их можно не сбрасывать в своп, а просто удалить. А когда они потребуется то заново загрузить из exe-файла, и настроить релоки.

В секции reloc, для каждой страницы, где нужно что либо настраивать, присутствует следующая структура:

pageoffset (относительно imagebase): dword
structsize (включая длину массива): dword
relocoffset (относительно pagebase): array of word (в старших четырех битах тип, нужно будет потом их учесть, а то программа уж слишком глючной получилась, но работает!)
(pagebase=imagebase+pageoffset)

Очень похоже что так было сделано для возможности подгрузки страниц из exe-файла. Хотя может быть такое возможно только в других системах. А если релоки настраиваются только при загрузке, то задача почти решена, осталось только разобраться: что нужно патчить, а что нет.


Дата: Май 25, 2003 18:06:25

[ Black_mirror: Так как страницы секции кода только для чтения, то их можно не сбрасывать в своп, а просто удалить. ]

Только в том случае, если на этой странице нет адресов подвергнутых релоку.
В противном случае, в свопе выделяется место куда будет сброшена эта страница.

[ Black_mirror: А когда они потребуется то заново загрузить из exe-файла, и настроить релоки. ]

Опять же, только в том случае, если на этой странице нет адресов подвергнутых релоку.
В противном случае, эта страница подгружается из свопа.

[ Black_mirror: А если релоки настраиваются только при загрузке,... ]

Если речь о системе, то именно так и происходит.

[ Black_mirror: ...то задача почти решена, осталось только разобраться: что нужно патчить, а что нет. ]

И еще неплохо было бы разобраться, а зачем это вообще нужно - делать релок екзешнику вручную? Екзешник всегда грузится первым. Там куда он грузится всегда есть место. Зачем релок? Для длл система сама все сделает что нужно. Зачем делать это вручную?


Дата: Май 25, 2003 23:36:26

Спасибо что разъяснили когда страницы сбрасываются в своп, а когда из экзешника подгружаются.

Релоки вручную я настраивать и не хочу.
Мне нужно чтоб в программе вместо call [pAPIfunc] было написано call APIfunc.
А для поиска где нужно пропатчить я использую секцию reloc.
Плюс данного метода проявляется в td: при отладке он пишет имя модуля и вызываемой функции, а не call [0043D3F4] например.
Есть еще небольшой плюсик - таблица адресов импотрируемых функций не засоряет кэш.


Дата: Май 26, 2003 13:21:04

[ Black_mirror: Плюс данного метода проявляется в td: при отладке он пишет имя модуля и вызываемой функции, а не call [0043D3F4] например. ]

А не проще ли использовать более продвинутый дебагер?


Дата: Май 26, 2003 15:21:44

TD мне кажется удобнее остальных. К тому же у него есть одна полезная возможность, отсутствующая у дебаггеров с графическим интерфейсом: можно отлаживать программу на участке PrimarySurface.Lock()/Unlock().
Вот если научусь пользоваться софтайсом может на него перейду.


Дата: Май 26, 2003 20:42:47

[ Black_mirror: Вот если научусь пользоваться софтайсом может на него перейду. ]

Могу только посоветовать сделать это как можно быстрее, т.к. при использовании этого замечательного инструмента появляется возможность отлаживать что угодно, где угодно и как угодно ;-)


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