Исследование функции

Тема в разделе "WASM.RESEARCH", создана пользователем Killbrum, 9 ноя 2009.

  1. Killbrum

    Killbrum New Member

    Публикаций:
    0
    Регистрация:
    7 май 2009
    Сообщения:
    25
    Всем доброго времени суток!
    Ребята. Я изучаю только С++ и в Асм я не такой знаток... так что очень прошу вашей помощи. Работаю с онлайн ММОРПГ MuOnline ( http://www.muonline.co.kr/ ). Собственно дело вот в чем. Доступа к коду у меня нету, поетому хукаю длл и работаю напрямую. Есть ф-ция для перерасчета характеристик персонажа, определена она так :
    Код (Text):
    1. #define gObjCalCharacter ((void(*)(int))0x004C2650)
    Ну собственно вызов таков:
    gObjCalCharacter(ID игрока);
    То есть она принимает ID игрока и по этому ID делает перерасчет характеристик персонажа. Мне нужно было сделать некоторые корективы данной ф-ции и в конец данной ф-ции хукнул свою, чтобы всякий раз при вызове данной ф-ции исполнялся нужный мне код (как я уже говорил прямого доступа к коду нет, и сервер вызывает данную ф-цию не только когда я это хочу (привел пример выше) но и еще когда он это щитает нужным). Проблема заключается в том что мне надо узнать для какого ID игрока была вызвана данная ф-ция. С чем собственно справится не могу. И очень прошу вашей помощи.

    Прикрепил ф-цию.
     
  2. takerZ

    takerZ New Member

    Публикаций:
    0
    Регистрация:
    6 апр 2008
    Сообщения:
    18
    Если вам известен адрес данной функции, вы знаете, что конвенция вызова cdecl, знаете список формальных параметров и вам нужно получить фактический аргумент, так почему вы не сделаете стандартный хук сплайсингом и не решите проблему? Прошу пощения, что отвечаю вопросом на вопрос и, нет, я не еврей.
     
  3. Killbrum

    Killbrum New Member

    Публикаций:
    0
    Регистрация:
    7 май 2009
    Сообщения:
    25
    Чесно говоря не знал про сплайсинг. Почитал... цитирую
    "Splicing в переводе с английского - склеивание, сращивание. Суть этого метода перехвата функций заключается в замене первых байт функции на переход в функцию-перехватчик, которая сделает некоторые действия и вернет управление в программу."
    То есть при вызове пойдет вызов главной ф-ции сразу передается управление нашей ф-ции, после её завершения управление передается главной. Но тут маленькая проблемка выходит. Мне надо всё с точностью до наоборот. Чтобы сначала отработала главная ф-ция, а уже следом за ней моя. Надо именно так и увы иначе просто нельзя(в плане том что мне иначе не подойдет). Вызов своей хукнули очень просто - подвинули в главной ф-ции RETN и дописали вызов ф-ции из дллки. Просто вся моя проблема в том что к OllyDbg отношусь на Вы, и каких то крупных познаний в С++\АСМ пока что не имею :dntknw:
    Появилась конечно идея... хукнуть сплайсингом,считать параметр, вернутся в главную ф-цию. Но тут уже будет проблема в том что главная потеряет входящий параметр.
    Очень надеюсь на Вашу помощь!
     
  4. crypto

    crypto Active Member

    Публикаций:
    0
    Регистрация:
    13 дек 2005
    Сообщения:
    2.533
    Killbrum
    Попробуйте превратить эту процедуру в функцию:
    начальный фрагмент
    переделываем вот так:
    MOV EAX,DWORD PTR SS:[EBP+8]
    PUSH EAX
    PUSH ESI
    PUSH EDI

    а в конце вместо
    будет
    004C4DCB |. 5F POP EDI
    004C4DCC |. 5E POP ESI
    004C4DCD |. 5B POP EAX
    004C4DCE |. 8BE5 MOV ESP,EBP
    004C4DD0 |. 5D POP EBP
    004C4DD1 \. C3 RETN

    и на выходе функции получите искомое значение аргумента.
    ЗЫ
    Это будет работать при условии, что регистр EBX может быть изменен после выхода, если нет, то посмотрите, может быть такой фокус пройдет с регистром ESI или EDI.
     
  5. takerZ

    takerZ New Member

    Публикаций:
    0
    Регистрация:
    6 апр 2008
    Сообщения:
    18
    Если вы скопируете его, ничего она не потеряет.
    to crypto
    Есть некоторая ненулевая вероятность, что из-за несохраненного регистра ebx, esi или edi программа упадет.
     
  6. crypto

    crypto Active Member

    Публикаций:
    0
    Регистрация:
    13 дек 2005
    Сообщения:
    2.533
    takerZ
    Существует, конечно, поэтому нужно посмотреть все вызовы данной сабрутины.
     
  7. crypto

    crypto Active Member

    Публикаций:
    0
    Регистрация:
    13 дек 2005
    Сообщения:
    2.533
    Можно еще попробовать сэкономить байт, изменив инструкцию умножения.
     
  8. Killbrum

    Killbrum New Member

    Публикаций:
    0
    Регистрация:
    7 май 2009
    Сообщения:
    25
    Невышло :dntknw: ребята а может можно как то записать в ячейку памяти? И оттуда считать ?
     
  9. crypto

    crypto Active Member

    Публикаций:
    0
    Регистрация:
    13 дек 2005
    Сообщения:
    2.533
    Killbrum
    Что конкретно не вышло? Вы не пробовали проанализировать вызовы сабрутины на предмет использования регистров ebx, esi, edi?
     
  10. Killbrum

    Killbrum New Member

    Публикаций:
    0
    Регистрация:
    7 май 2009
    Сообщения:
    25
    Не вышло вот что... сделали как Вы говорили... извините если что, мой уровень С++ не на столько хорош, если я не ошибаюсь если в ф-ции я указываю входящий аргумент то оно считывает его из стека? Верно? Вообщем было там число -2 милиарда. Это явно не то. Значения должны быть от 6400 до 7400. Только в этом диапазоне значений идут ID игроков (так задумано разработчиками, не знаю зачем).
    Не знаю может быть я в чем то не прав, очень надеюсь что вы меня поправите, просто как уже не раз замечал мои знания С++ и принципа работы С++ (то есть как оно всё внутри работает) не такие уж и хорошие.
    Сделал что Вы говорили.
    В дллке написал так:
    Код (Text):
    1. extern "C" _declspec(dllexport) void CalChar(int aIndex)
    2. {
    3. }
    Но результат не тот.
    EBX, EDI свободны, то есть не используются. Но это именно в этой ф-ции. Программа писана на Visual C++ 6.0 поетому думаю нет смысла проверять внутренние call.
    По своей памяти когда работал с АСМ на MCS - 51 я мог записать в ячейку памяти. Если бы тут так можно было то я думаю всё намного бы упростилось.
    А что если сразу после
    Код (Text):
    1. MOV EAX,DWORD PTR SS:[EBP+8]
    влепить
    Код (Text):
    1. PUSH EAX
    Если меня не подводит память то он будет висеть в стеке пока его от туда не заберут, но по принципу FILO (First Input Last Output), если не ошибаюсь здесь так, то учитывая это это число будет висеть в стеке пока его от туда не заберут, а заберу я его перед концом процедуры вызовом своей ф-ции.
    Вызываем свою функцию вот так:
    Код (Text):
    1. 004C4DCB   . 5F             POP EDI
    2. 004C4DCC   . 5E             POP ESI
    3. 004C4DCD   . 58             POP EAX
    4. 004C4DCE   . 8BE5           MOV ESP,EBP
    5. 004C4DD0   . 5D             POP EBP
    6. 004C4DD1   . 68 C08E5D00    PUSH GameServ.005D8EC0                           ; /FileName = "Addon.dll"
    7. 004C4DD6   . FF15 F4BC8C0C  CALL DWORD PTR DS:[<&KERNEL32.LoadLibraryA>]     ; \LoadLibraryA
    8. 004C4DDC   . 09C0           OR EAX,EAX
    9. 004C4DDE   . 0F84 B1610D00  JE GameServ.0059AF95
    10. 004C4DE4   . 68 F58E5D00    PUSH GameServ.005D8EF5                           ; /ProcNameOrOrdinal = "CalChar"
    11. 004C4DE9   . 50             PUSH EAX                                         ; |hModule
    12. 004C4DEA   . FF15 F0BC8C0C  CALL DWORD PTR DS:[<&KERNEL32.GetProcAddress>]   ; \GetProcAddress
    13. 004C4DF0   . FFD0           CALL EAX
    14. 004C4DF2   . C3             RETN
    Это дописал в конце ф-ции. Извиняюсь если что то не так...
     
  11. crypto

    crypto Active Member

    Публикаций:
    0
    Регистрация:
    13 дек 2005
    Сообщения:
    2.533
    Killbrum
    Насчет влепить: именно это я и советовал сделать, уж не знаю, как Вы это реализовали. Объясняю еще раз. Начало сабрутины:
    Код (Text):
    1. 004C2650 >/> 55             PUSH EBP
    2. 004C2651  |. 8BEC           MOV EBP,ESP
    3. 004C2653  |. 81EC 0C010000  SUB ESP,10C
    4. 004C2659  |. 53             PUSH EBX
    5. 004C265A  |. 56             PUSH ESI
    6. 004C265B  |. 57             PUSH EDI
    7. 004C265C  |. 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8]
    8. 004C265F  |. 69C0 68190000  IMUL EAX,EAX,1968
    Переделываем его в hex-редакторе:
    Код (Text):
    1. 004C2650 >/> 55             PUSH EBP
    2. 004C2651  |. 8BEC           MOV EBP,ESP
    3. 004C2653  |. 81EC 0C010000  SUB ESP,10C
    4. 004C2659  |. 8B45 08        MOV EAX,DWORD PTR SS:[EBP+8]
    5. 004C265C  |. 53             PUSH EAX
    6. 004C265D  |. 56             PUSH ESI
    7. 004C265E  |. 57             PUSH EDI
    8. 004C265F  |. 69C0 68190000  IMUL EAX,EAX,1968
    Конец сабрутины:
    Код (Text):
    1. 004C4DCB  |. 5F             POP EDI
    2. 004C4DCC  |. 5E             POP ESI
    3. 004C4DCD  |. 5B             POP EBX
    4. 004C4DCE  |. 8BE5           MOV ESP,EBP
    5. 004C4DD0  |. 5D             POP EBP
    6. 004C4DD1  \. C3             RETN
    Переделываем его в hex-редакторе:
    Код (Text):
    1. 004C4DCB  |. 5F             POP EDI
    2. 004C4DCC  |. 5E             POP ESI
    3. 004C4DCD  |. 58             POP EAX
    4. 004C4DCE  |. 8BE5           MOV ESP,EBP
    5. 004C4DD0  |. 5D             POP EBP
    6. 004C4DD1  \. C3             RETN
    А в приведенном Вами фрагменте
    Код (Text):
    1. 004C4DCB   . 5F             POP EDI
    2. 004C4DCC   . 5E             POP ESI
    3. 004C4DCD   . 58             POP EAX
    4. 004C4DCE   . 8BE5           MOV ESP,EBP
    5. 004C4DD0   . 5D             POP EBP
    6. 004C4DD1   . 68 C08E5D00    PUSH GameServ.005D8EC0                           ; /FileName = "Addon.dll"
    7. 004C4DD6   . FF15 F4BC8C0C  CALL DWORD PTR DS:[<&KERNEL32.LoadLibraryA>]     ; \LoadLibraryA
    8. 004C4DDC   . 09C0           OR EAX,EAX
    9. 004C4DDE   . 0F84 B1610D00  JE GameServ.0059AF95
    10. 004C4DE4   . 68 F58E5D00    PUSH GameServ.005D8EF5                           ; /ProcNameOrOrdinal = "CalChar"
    11. 004C4DE9   . 50             PUSH EAX                                         ; |hModule
    12. 004C4DEA   . FF15 F0BC8C0C  CALL DWORD PTR DS:[<&KERNEL32.GetProcAddress>]   ; \GetProcAddress
    13. 004C4DF0   . FFD0           CALL EAX
    14. 004C4DF2   . C3             RETN
    непонятно, где используется значение регистра EAX (искомый аргумент), который Вы успешно восстановили.
     
  12. Killbrum

    Killbrum New Member

    Публикаций:
    0
    Регистрация:
    7 май 2009
    Сообщения:
    25
    В приведенном коде что я использовал я загружаю из дллки свою ф-цию.
    Код (Text):
    1. extern "C" _declspec(dllexport) void CalChar(int aIndex)
    2. {
    3. }
    Входящим аргументом там идет
    int aIndex
    Чуствую что ошибаюсь... но мне казалось что int aIndex будет считан из стека. Видимо я не так понимал представление кода С++ в АСМе. Как тогда передать значение из EAX в вызываемую ф-цию?

    Изивиняюсь за мои знания... знаю они скудные...
     
  13. crypto

    crypto Active Member

    Публикаций:
    0
    Регистрация:
    13 дек 2005
    Сообщения:
    2.533
    Killbrum
    Тогда по адресу 004C4DD1 (сразу после pop ebp) нужно вставить инструкцию push eax, содержимое регистра будет аргументом для Вашей функции. А проверять лучше в дебуггере, по-крайней мере сразу увидите, что передается.
     
  14. crypto

    crypto Active Member

    Публикаций:
    0
    Регистрация:
    13 дек 2005
    Сообщения:
    2.533
    Killbrum
    Да, и еще нужно будет аккуратно оформить выход из сабрутины в случае ошибки фукнции LoadLibrary (снять лишний dword из стека - то самое значение, о котором мы тут толкуем).
     
  15. Killbrum

    Killbrum New Member

    Публикаций:
    0
    Регистрация:
    7 май 2009
    Сообщения:
    25
    Спасибо большое! Немножко потанцевали с бубном но теперь всё работает на УРА! Ещё раз очень и очень благодарю!
     
  16. crypto

    crypto Active Member

    Публикаций:
    0
    Регистрация:
    13 дек 2005
    Сообщения:
    2.533
    Killbrum
    И как же была решена проблема? Вот мало кто пишет об этом!
     
  17. Killbrum

    Killbrum New Member

    Публикаций:
    0
    Регистрация:
    7 май 2009
    Сообщения:
    25
    Сделали так как Вы и сказали а в самом конце доставили pop ebi =)
     
  18. crypto

    crypto Active Member

    Публикаций:
    0
    Регистрация:
    13 дек 2005
    Сообщения:
    2.533
    Killbrum
    pop ebi - это круто звучит по-русски! Ну, успехов.
     
  19. Killbrum

    Killbrum New Member

    Публикаций:
    0
    Регистрация:
    7 май 2009
    Сообщения:
    25
    crypto
    ^_^ Да в принципе всё то что Вы написали оно и работает. Просто pop ebi поставили т.к. там надо было убрать одно значение из стека :).

    Вот пожалуйста :)
    http://rapidshare.com/files/307965306/GameServer.rar.html