Прямой вызов / переход в ASM без использования релевантности (x86) - PullRequest
3 голосов
/ 15 февраля 2011

Я внедряю DLL-библиотеку c ++ в игру, и я хотел бы привязать функцию к своему коду. Поскольку DLL каждый раз отображается в другое место, было бы проще выполнять прямые переходы и вызовы. Кроме того, поскольку это ловушка, я не хочу менять стек или регистры, когда возвращаюсь к функции.

Я объявляю char * для хранения Asm, чтобы у меня был указатель на него (char * asm = "\ x00";) Если бы вы могли предоставить hex, это сэкономило бы мне время.

Я пытался использовать FF и EA для вызовов и прыжков, но, думаю, я просто не понимаю, как они работают. Когда я их использовал, я заметил, что теперь у меня двоеточие в операции.

JMP FAR FWORD PTR DS:[00000000]

Это не сработало и не сработало после того, как я попытался использовать указатель на место перехода.

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

01270000    50              PUSH EAX
01270001    57              PUSH EDI
01270002    E8 E9CC1BFF     CALL fwound.0042CCF0
01270007    5F              POP EDI
01270008    58              POP EAX
01270009    50              PUSH EAX                      //replacements
0127000A    8D4C24 7C       LEA ECX,DWORD PTR SS:[ESP+7C] //
0127000E  - E9 36D11BFF     JMP fwound.0042D149

Я сделал этот блок, используя Олли, поэтому он знал, какие соответствующие переходы / вызовы необходимы в то время.

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

Итак, как я могу исправить свой блок Asm, чтобы использовать прямые переходы и вызовы?

Ответы [ 2 ]

4 голосов
/ 15 февраля 2011

Вы можете кодировать его следующим образом (синтаксис сборки в стиле gcc / AT & T):

    jmp    *.Ltgtaddr
.Ltgtaddr:  .long absoluteAddrOfFunctionToCall

Собирается в десять байтов (на 32-битной x86) - ff 25 для абсолютного jmp с 32-битным операндом памятизатем четыре байта с адресом следующего слова, за которым следует содержимое, которое затем является (абсолютным) целевым адресом вашего кода.

Редактировать: я обновил раздел ниже скомпилированным и протестированнымпример.

Вы можете из исходного кода C динамически создать такой батут.Пример источника (требуется 32-битный x86, оставленный читателю в качестве упражнения для преобразования батута в 64-битный):

#include <sys/mman.h>
#include <stdio.h>

void oneWay(char *str, int arg)
{ printf("string is \"%s\", int is %d\n", str, arg); }

void otherWay(char *str, int arg)
{ printf(str, arg); printf("\n"); }

void *trampGen(void *tgtAddr)
{
    char *trampoline = mmap(NULL, 10, PROT_EXEC | PROT_WRITE | PROT_READ,
        MAP_PRIVATE | MAP_ANON, -1, 0);
    trampoline[0] = (char)0xff; trampoline[1] = (char)0x25;
    *(char**)(trampoline+2) = trampoline + 6;
    *(void**)(trampoline+6) = tgtAddr;
    return trampoline;
}

int main(int argc, char **argv)
{
    void * (*funcptr)(char*, int) = trampGen(oneWay);
    *funcptr("Test %d String", 12345);
    *(void **)(((char *)funcptr) + 6) = otherWay;
    *funcptr("Test %d String", 12345);
    munmap(funcptr, 10);
    return 0;
}

Вывод для меня:

$ ./tt
string is "Test %d String", int is 12345
Test 12345 String

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

0 голосов
/ 15 февраля 2011

Я никогда пробовал такого рода вещи,
но я думаю, что вы должны использовать смещение от известного места в памяти игры (чтобы найти с ollydbg), поэтому каждый раз, когда вы добавляете это (фиксированное) смещение к (переменному) адресу. Этот адрес может быть, например, адресом возврата, найденным в ss:ebp (поскольку ваша функция вызывается игрой), а смещение от него вычисляется с помощью ollyDBG.

...