#26 23-09-2011 10:32

VintProg_Pro
Registered: 17-06-2010
Posts: 153

Re: DLL Loader

но я не знаю, как найденный код перенести на C++ (сложность в том, чтобы обозначить границы действительно нужного ассемблерного кода).

http://sannybuilder.com/forums/viewtopic.php?id=1363

есть функция void FUNCTION (int, float). я точно уверен, что важны два параметра и могу определить их в отладчике, однако в коде зачем-то в стек пихается больше значений, чем два

Возможно это не данной функций передается не нужные параметры...

как приложение понимает, что функция, вызываемая как FUNCTION (10, 234.55) на самом деле принимает только 2 параметра и как мне описать такую FUNCTION, если я наткнусь на непонятные "лишние" параметры в стеке?

IDA pro показывает arg_ сколько их столько и параметров у функции...

предположим, я хочу повторить функцию лечения игрока

Делается элементарно, просто меняешь значение в структуре игрока...

Last edited by VintProg_Pro (23-09-2011 10:34)

Offline

#27 24-09-2011 21:11

BritishColonist
Registered: 30-09-2009
Posts: 72

Re: DLL Loader

>Делается элементарно, просто меняешь значение в структуре игрока...

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

так или иначе, я уже потихоньку начал разбираться и с выполнением своего кода в пространстве других приложений и с созданием функций (инжект кусков кода).

Offline

#28 25-09-2011 20:09

listener
From: Vice City
Registered: 09-11-2006
Posts: 616
Website

Re: DLL Loader

BritishColonist wrote:

есть где-нибудь годный гайд с примерами на тему инжекта кода?
хочу повторить код, который есть в стандартном exe (естественно вызывать его в нужное мне время и с нужными мне параметрами), но я не знаю, как найденный код перенести на C++ (сложность в том, чтобы обозначить границы действительно нужного ассемблерного кода).
...
если нет гайдов, не мог бы кто-нибудь привести пример описания у себя функции с параметрами (здесь уже речь об описании прототипа функции, без использования ассемблерных вставок)?

Гайда нет. Все, что могу предложить - посмотреть, как я это делаю в gta_sa_dll или в openRage.


BritishColonist wrote:

и ещё. когда копаю эти функции, нередко натыкаюсь на "ненужные" параметры перед собственно вызовом функции по адресу (наряду с важными для функции значениями (передаваемыми параметрами) в стек пихаются какие-нибудь нули или единицы (независимо от параметров)). как у себя описывать такие функции (тут уже не куски кода, а описание функции на C++ с указанием её адреса в пространстве)? в смысле, есть функция void FUNCTION (int, float). я точно уверен, что важны два параметра и могу определить их в отладчике, однако в коде зачем-то в стек пихается больше значений, чем два. в общем, я даже не знаю как сформулировать вопрос grin как приложение понимает, что функция, вызываемая как FUNCTION (10, 234.55) на самом деле принимает только 2 параметра и как мне описать такую FUNCTION, если я наткнусь на непонятные "лишние" параметры в стеке?

http://sannybuilder.com/forums/viewtopic.php?id=159 - здесь есть все, кроме, собственно, примеров.

В дополнение к этому, стоит сказать, что для __cdecl функций можно описывать параметры произвольно.  Для __stdcall и __thiscall, важно, чтобы совпадал общий размер параметров. Тип незадействованных параметров - не критичен.

BritishColonist wrote:

ещё. предположим, я хочу повторить функцию лечения игрока (например, ту, которая срабатывает при покупке газировки). вот я нашёл, какая операция меняет собственно значение здоровья игрока. где-то выше этого кода стопроцентно всегда идёт нужный для работы функции код. как понять, где этот нужный код начинается? неужели нужен весь код до первого встречного выше ret?

Можно, конечно. заменить только несколько команд через __declspec(naked). На практике, это делать очень сильно не рекомендуется. Подавляющее большинство функций в отреверсенном виде занимает меньше ста строк. Разводить ради этого возню с ассемблером и регистрами - непродуктивно.

Впрочем, из этого правила есть исключение. новые компиляторы могут не соблюдать calling convention для внутренних функций и передавать параметры в произвольных регистрах. В этом случае, корректный реверсин требует переписывания всех "неправильных" функций, и общий объем получаться вполне ощутимым. В этом случае, naked функции оправданы.

Offline

#29 19-10-2011 03:00

BritishColonist
Registered: 30-09-2009
Posts: 72

Re: DLL Loader

во многом, кажется, разобрался. основной инструментарий - отладчик, много-много времени и нудный просмотр дизасма : D
насчёт расчёта адреса для JMP - до сих пор не понимаю, что за чудоарифметика, но это и впрямь работает (адрес получается нужным).
так вот, для CALL арифметика выходит другая, хотелось бы узнать, какая именно.
кстати, где можно почитать про байткоды операций? конкретная ссылка была бы не лишней.

ещё нужен совет, как быть в ситуации:
перехватываю управление из функции (которая лежит в DLL) и передаю его своей функции (которая лежит в другой DLL), где добавляю пару операций, затем повторяю оригинальный (заменённый на переход к моей функции) код и возвращаю управление туда, откуда его перехватил.
состояние регистров до и после перехвата должно быть идентичным, но как тогда сделать джамп к оригинальному коду, если адрес этого кода нестатичен (находится в DLL)?
было много идей, все они оказывались провальными:

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

DWORD dwAddrToGo = (DWORD)GetModuleHandle("neededLib.dll")+0x100500;
__asm
{
    push dwAddrToGo
    ret
}

этот код подошёл бы, но портит регистр:

DWORD dwAddrToGo = (DWORD)GetModuleHandle("neededLib.dll")+0x100500;
__asm
{
    mov edx, dwAddrToGo
    jump edx
}

и действительно, обратно этот регистр уже не вернуть.

был и такой вариант:

DWORD dwAddrToGo = (DWORD)GetModuleHandle("neededLib.dll")+0x100500;
__asm
{
    xchg eax, dwAddrToGo
    push eax
    xchg eax, dwAddrToGo
    ret
}

но чувствую, что тут вновь проблема в использовании переменной (подозреваю, что xchg пашет только с регистрами).

ещё была идея перед перехватом управления поместить в стек EIP, но с этим регистром вообще ничего нельзя сделать напрямую.
также была идея пихать туда не EIP, а <адрес заменяемой функции+оффсет к нужной точке возврата>; реализовывать пока не пробовал, но думаю, что придётся опять шаманить с сохранением регистров.
сейчас пришёл к выводу, что самым халявным способом будет сделать не JMP на свою функцию, а CALL (а в конце функции будет просто ret). вот в связи с этим и интересуюсь формированием байткода команды типа "CALL 00123458".

кстати, пока танцевал с бубном, раскусил-таки фишку __declsped(naked): если приписать это перед названием функции, содержать она будет (в ассемблерном виде) строго то, что мы записывали при кодинге, а если оставить всё, как есть, поместив в функцию код (лучше всего на ассемблере), то можно заметить в отладчике, что функция выполняет какие-то там дополнительные операции с регистрами (в частности с EBP), а только потом написанный при разработке код.

Offline

Board footer

Powered by FluxBB