Перейти к содержанию

Почему адрес перехода jmp разный в byte и opcode


helldrg

Рекомендуемые сообщения

Здравствуйте! Хотел записать переход по jmp даже порядок записи изменил байтов, заметил такую особенность:

                   Bytes                          Opcode  

088A0000 - E9 088A0000           - jmp 088A8A0D


В Bytes все правильно записывается 0xe9 - команда безусловного перехода и адрес перехода 088A0000. В итоге должно получится зацикливание (только сейчас заметил =)). Но в Opcode адрес перехода другой 088A8A0D. Почему так?

Ссылка на комментарий
Поделиться на другие сайты

там не прямой адрес. вот например:

Скрытый текст

.lulz:
lea eax,[.zz] ;адрес для jmp
sub eax,0x400000  даном случае база модуля
lea ecx,[.kk+5] ;адрес jmp +его размер
sub ecx,0x400000
sub eax,ecx ;получаем новый адрес для jmp
mov [.kk+1],eax ;пишем
.zz:
nop
.kk:
jmp near .lulz

 

так что у тебя должно быть 0-5=FFFFFFFB типа E9 FBFFFFFF

 

  • Плюс 1
Ссылка на комментарий
Поделиться на другие сайты

это относительных переход и рассчитывается по формуле <Адрес куда прыгаем> - <Адрес от куда прыгаем> - <Количество байт занятых под команду jmp>

то бишь    0x088A0000 - 0x088A0000 - 2  

тк это near jmp, то он будет занимать 2 байт

в итоге получаем EB FE

  • Плюс 1
Ссылка на комментарий
Поделиться на другие сайты

Воууу, почему так сложно =)

Тоесть что бы попасть с адреса на адрес  0x088A0000  нужно вписать   jmp EB FE ? там кстати если так делать четыре 0 дописывается

 

Ссылка на комментарий
Поделиться на другие сайты

Еще можно прыгать на + или - сколько-нибудь байт вперед. Типа "jmp 5" - вперед (ниже по коду) на 5 байт. CE, по-моему, даже умеет автоматически определять разницу между short jmp и far jmp. А "почему так сложно" - наоборот, просто, все переходы - статические. Код лежит всегда по одним и тем же относительным смещениям, так компилятор делает и так процессору проще в этой каше разбираться. Как результат - программы работают быстрее. 

  • Плюс 1
Ссылка на комментарий
Поделиться на другие сайты

Сложность в том состоит, что вот к примеру:

05F70000 - E9 05F70000           - jmp 05F7F70A

если писать E9  EB FE(я так понял это как раз и будет зацикливание, потому что <Адрес куда прыгаем> - <Адрес от куда прыгаем>  равняется 0, а - 2 байта тут говорят равняется EB FE), то еще появятся 00 00.
Че то я вообще не доганяю

Ссылка на комментарий
Поделиться на другие сайты

2 минуты назад, keng сказал:

Еще можно прыгать на + или - сколько-нибудь байт вперед. Типа "jmp 5" - вперед (ниже по коду) на 5 байт. CE, по-моему, даже умеет автоматически определять разницу между short jmp и far jmp. А "почему так сложно" - наоборот, просто, все переходы - статические. Код лежит всегда по одним и тем же относительным смещениям, так компилятор делает и так процессору проще в этой каше разбираться. Как результат - программы работают быстрее. 

Да конечно умеет. Но я понимаю стремление ТСа самому разобраться в этом.

 

17 минуту назад, helldrg сказал:

Воууу, почему так сложно =)

Тоесть что бы попасть с адреса на адрес  0x088A0000  нужно вписать   jmp EB FE ? там кстати если так делать четыре 0 дописывается

 

Ноу. 

EB - это и есть код команды short jmp (short\near одно и тоже)

FE - это относительное смещение , которое ты высчитал по формуле

 

11D70000 EB FE - jmp 11D70000


 

  • Плюс 1
Ссылка на комментарий
Поделиться на другие сайты

Dino
Спасибо большое еще раз! Я вроде как разобрался, теперь использую E9 - это наверно far jmp =)

Скрытый текст

BYTE *bytes = new BYTE[20];
            DWORD jmpAddress = allocAddress - (baseAddress + offsetAddress[2]) - 5;
            BYTE *b = new BYTE[4];
            memcpy((void*)b, &jmpAddress, 4);
            bytes[0] = '\xe9';
            bytes[1] = b[0];
            bytes[2] = b[1];
            bytes[3] = b[2];
            bytes[4] = b[3];
            bytes[5] = '\x90';
            bytes[6] = '\x90';
            if (Process.WriteMemory(baseAddress + offsetAddress[2], (LPVOID)bytes, 7) == FALSE)
                wsprintf(buffer, "Ошибка!");
            jmpAddress = (baseAddress + offsetAddress[2]) - allocAddress - 19 + 7;
            memcpy((void*)b, &jmpAddress, 4);
            bytes[0] = '\xc7';
            bytes[1] = '\x46';
            bytes[2] = '\xc8';
            bytes[3] = '\x00';
            bytes[4] = '\x00';
            bytes[5] = '\x16';
            bytes[6] = '\x44';
            bytes[7] = '\xd9';
            bytes[8] = '\x46';
            bytes[9] = '\xc8';
            bytes[10] = '\x8a';
            bytes[11] = '\x5c';
            bytes[12] = '\x24';
            bytes[13] = '\x17';
            bytes[14] = '\xe9';
            bytes[15] = b[0];
            bytes[16] = b[1];
            bytes[17] = b[2];
            bytes[18] = b[3];
            if (Process.WriteMemory(allocAddress, (LPVOID)bytes, 19) == FALSE)
                wsprintf(buffer, "Ошибка!");

 

Вот такое чудовище получилось, но оно работает :DD Спасибо за терпение к моей не образованности!!! Спасибо kengу за замечательные уроки!!!

Изменено пользователем helldrg
  • Плюс 1
Ссылка на комментарий
Поделиться на другие сайты

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

Ссылка на комментарий
Поделиться на другие сайты

4 hours ago, Xipho said:

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

Изменяет, т.к. это зависит только от размера. Near - это +-127 байт от EIP. Верхняя же планка, по-моему, стоит в 4 Гб.

Ссылка на комментарий
Поделиться на другие сайты

1 hour ago, Xipho said:

Может, я по старой памяти путаю near и short.

Short - это динозавр, который позволяет прыгать только на 8 бит (???). Near - +-127 байт, т.е. 8, 16 или 32 бита. Far - дальше или в другой сегмент. У меня тут возник вопрос - какой будет опкод, если прыгать надо недалеко (до 127), но в соседний сегмент? Far?

Ссылка на комментарий
Поделиться на другие сайты

Far, разумеется. Вообще, сколько я копался в современных приложениях, везде та же олька ставит jmp short (или near, не помню, надо будет посмотреть), поскольку память в винде уже с лохматых времен плоская. Это в досе и вин до 95 память была сегментированной. И, если мне не изменяет память, в ДОСе размер сегмента не мог превышать 64 килобайта. А командные интерпретаторы типа command.com по каким-то ограничениям обязаны были состоять из одного сегмента, и потому их размер ну никак не мог превышать те самые 64 килобайта.

 

Добавлено:

Собственно. 

near - в одном сегменте. 

far - за пределы сегмента

http://x86.renejeschke.de/html/file_module_x86_id_147.html

Ссылка на комментарий
Поделиться на другие сайты

Плоская память - это про виртуальную. Сам бинарник мапится на физическую память согласно секциям, которые не могут быть больше 4Гб. Вот как раз при расчете адреса для прыжка между секциями (или между модулями бинарника, если это надо) и будет short или far. Плоская память позволяет адресануться гигов за 10 и винда не подавится, иначе бы пришлось пересчитывать все смещения.

Ссылка на комментарий
Поделиться на другие сайты

×
×
  • Создать...

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.