Полноценный вызов функций по указателю

Разговоры на любые темы: вы можете обсудить здесь какой-либо сайт, найти единомышленников или просто пообщаться...
gaidar
System Debugger
System Debugger
 
Сообщения: 3152
Зарегистрирован: 23.12.2001 (Вс) 13:22

Сообщение gaidar » 12.09.2004 (Вс) 16:59

GSerg писал(а):А чё, мы ничё, мы по мелочи :D
VB8 напишем и успокоимся :)


Поздно уже, есть VS8 :)
Давайте сразу 10 :), а то Майкрософт быстро работает.

А вообще, если без шуток, то жду от вас всех статей на эту тему. Может быть и правда, когда-нибудь пригодится кому-нибудь еще, кроме вас :) :lol:
The difficult I’ll do right now. The impossible will take a little while. (c) US engineers in WWII
I don't always know what I'm talking about, but I know I'm right. (c) Muhammad Ali

Approximator
Постоялец
Постоялец
 
Сообщения: 572
Зарегистрирован: 26.06.2004 (Сб) 3:10

Сообщение Approximator » 13.09.2004 (Пн) 1:13

GSerg писал(а):Писать? Напишем :) Моё мыло видишь? Видишь :)

О'к.
С уважением, Approximator.

Approximator
Постоялец
Постоялец
 
Сообщения: 572
Зарегистрирован: 26.06.2004 (Сб) 3:10

Сообщение Approximator » 13.09.2004 (Пн) 1:15

gaidar писал(а):ВОт читаю топик и думаю, куда это все приведет :)

:) А это смотря, что понимать под ЭТИМ ВСЕМ. :)
С уважением, Approximator.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 20.11.2004 (Сб) 11:17

Вернёмся к этой теме :)

Approximator, объясни мне, почему не работает следующее.
Код: Выделить всё
Option Explicit

Private Declare Function FreeLibrary Lib "kernel32.dll" (ByVal hLibModule As Long) As Long
Private Declare Function GetProcAddress Lib "kernel32.dll" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Declare Function LoadLibrary Lib "kernel32.dll" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long

Private Declare Function PutMem4 Lib "msvbvm60" (ByVal pDst As Long, ByVal NewValue As Long) As Long

Private user As Long
Private Wrapper1Address As Long

Private Sub Command1_Click()
  MsgBox Wrapper1(Me.hWnd)
End Sub

Private Sub Form_Load()
  user = LoadLibrary("user32.dll")
  Wrapper1Address = GetProcAddress(user, "IsWindow")
End Sub

Private Function Wrapper1(ByVal hWnd As Long) As Long
  Redirect Wrapper1Address
End Function

Private Sub Redirect(ByVal Addr As Long)
  PutMem4 VarPtr(Addr) - 4, Addr
End Sub

Private Sub Form_Unload(Cancel As Integer)
  FreeLibrary user
End Sub


Msgbox вызывает Wrapper1. Wrapper1 вызывает Redirect. Redirect изменяет свой адрес возврата и возвращается по этому изменённому адресу. При этом в стеке остаётся то, что там было в начале вызова Wrapper1, а именно параметр hWnd и адрес возврата в msgbox. Его получает функция IsWindow. Она же его удаляет из стека, возвращаясь в msgbox.
Почему всегда 0?
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 20.11.2004 (Сб) 12:36

Всё ещё юзаешь пару LoadLibrary/FreeLibrary вместо одного GetModuleHandle? :-D

Кстати, если вместо GetProcAddress подставить адрес обственной процедуры, то в неё тоже не заходит.
Да и вообще, ты затираешь не адрес возврата, а Me... Адрес возврата в VarPtr(Addr) - 8 ;-)
Изображение

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 20.11.2004 (Сб) 14:06

Ну попробуй, попробуй :)
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 20.11.2004 (Сб) 14:11

GSerg писал(а):Ну попробуй, попробуй :)
Дык среда падает ;-)
Изображение

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 20.11.2004 (Сб) 14:13

Да ну? :)
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 20.11.2004 (Сб) 14:36

А у тебя как? :-)
(btw, у меня SP3).
Изображение

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 20.11.2004 (Сб) 15:29

Ирония не прошла :)

Имей совесть, я тут сонный сижу, а ты мне не помогаешь. Давай, думай, в чём фишка :)
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 20.11.2004 (Сб) 16:37

У меня у самого подобная запара, мне бы кто помог...

Щас тогда тебе мою запару намылю. Она ба-а-ашая и страшная :twisted: И погляжу пока на твою...
Изображение

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 20.11.2004 (Сб) 16:52

А вторая ошибка здесь:
GSerg писал(а):При этом в стеке остаётся то, что там было в начале вызова Wrapper1, а именно параметр hWnd и адрес возврата в msgbox. Его получает функция IsWindow. Она же его удаляет из стека, возвращаясь в msgbox.

У Wrapper1 два параметра.
Первый из них - Me - и передаётся в IsWindow, и она справедливо отвечает, что это не окно. :-D


Если твой код вынести в модуль, тогда он будет работать именно так, как тебе нужно. А из формы так можно вызывать только те API, где первым параметром идёт IDispatch* :lol:
Изображение

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 21.11.2004 (Вс) 8:09

Я ж говорю - сонный я был :)
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 21.11.2004 (Вс) 10:40

Так, чё за фигня :)
Если в модуль вынести и скомпилировать - работает. Во всяком случае, похоже на то.
Под IDE либо не пашет (если пишем по -4), либо рушится (если пишем по -8 ).

Ну дык и почему? :?
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 21.11.2004 (Вс) 13:45

Ну, вставь заглушку под IDE вместо Redirect...
Получится быстрее, чем ты будешь отладчиком всю IDE со своим запущенным проектом расковыривать.


Чё про намыленную запару-то ничего не ответил? :-)
Изображение

Approximator
Постоялец
Постоялец
 
Сообщения: 572
Зарегистрирован: 26.06.2004 (Сб) 3:10

Сообщение Approximator » 22.11.2004 (Пн) 3:54

GSerg писал(а):Так, чё за фигня :)
Если в модуль вынести и скомпилировать - работает. Во всяком случае, похоже на то.


Даже, если это так, то это случайность. Вообще говоря, не должно работать.

GSerg писал(а):Так, чё за фигня :)
Под IDE либо не пашет (если пишем по -4), либо рушится (если пишем по -8 ).

Ну дык и почему? :?


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

В форме:
Код: Выделить всё
Option Explicit

Private Declare Function FreeLibrary Lib "kernel32.dll" (ByVal hLibModule As Long) As Long
Private Declare Function GetProcAddress Lib "kernel32.dll" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Declare Function LoadLibrary Lib "kernel32.dll" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long

Private user As Long

Private Sub Form_Click()
  MsgBox Wrapper1(Me.hWnd)
End Sub

Private Sub Form_Load()
  user = LoadLibrary("user32.dll")
  Wrapper1Address = GetProcAddress(user, "IsWindow")
  InitS
End Sub

Private Sub Form_Unload(Cancel As Integer)
  FreeLibrary user
End Sub


В модуле:
Код: Выделить всё
Option Explicit

Private Declare Function PutMem4 Lib "msvbvm60" (ByVal pDst As Long, ByVal NewValue As Long) As Long
Private Declare Sub CopyMem Lib "kernel32" Alias "RtlMoveMemory" _
(ByVal pDst As Long, ByVal pSrc As Long, ByVal ByteLen As Long)

Public Wrapper1Address As Long
Private vESP As Long, pOC As Long, pRet As Long, pMP As Long
Private OC() As Byte, MP() As Byte

Public Sub InitS()
  ReDim OC(1 To 20)
  ReDim MP(1 To 20)
 
  'для проверки
  'Wrapper1Address = GetPA(AddressOf Test1)

  pOC = VarPtr(OC(1))
  'push imm32=hWnd
  OC(1) = &H68: PutMem4 VarPtr(OC(2)), 0&
  'push imm32=<адрес возврата>
  OC(6) = &H68: PutMem4 VarPtr(OC(7)), 0&
  'jmp   dword ptr ds:[imm32=VarPtr(Wrapper1Address)]
  OC(11) = &HFF: OC(12) = &H25: PutMem4 VarPtr(OC(13)), VarPtr(Wrapper1Address)

  'sub   esp,imm8=20
  MP(1) = &H83: MP(2) = &HEC: MP(3) = 4
  'push  imm32=<адрес возврата>
  MP(4) = &H68: PutMem4 VarPtr(MP(5)), 0&
  'jmp   dword ptr ds:[VarPtr(Wrapper1Address)]
  MP(9) = &HFF: MP(10) = &H25: PutMem4 VarPtr(MP(11)), VarPtr(Wrapper1Address)

End Sub

Public Function Wrapper1(ByVal hWnd As Long) As Long
  Dim pRet As Long, vT As Long
  'адрес (условный) "начала стека"
  vESP = VarPtr(hWnd) - 4
  'получаем адрес возврата
  CopyMem VarPtr(pRet), vESP, 4
  'смотрим каким было обращение
  CopyMem VarPtr(vT), pRet - 5, 4
  If vT = &HE8 Then
    PutMem4 VarPtr(MP(5)), pRet
    PutMem4 VarPtr(hWnd) - 4, pMP
  Else
    vESP = vESP - 4
    CopyMem VarPtr(pRet), vESP, 4
    PutMem4 VarPtr(OC(2)), hWnd
    PutMem4 VarPtr(OC(7)), pRet
    PutMem4 VarPtr(hWnd) - 8, pOC
  End If
End Function

Private Function Redirect(ByVal Addr As Long) As Long
  PutMem4 VarPtr(Addr) - 8, VarPtr(OC(1)) 'AddressOf Test1 'Addr
End Function

Private Function Test1(ByVal vVal As Long) As Long
  MsgBox vVal, vbOKOnly, "Test1"
  Test1 = vVal
End Function

Private Function GetPA(ByVal vPA As Long) As Long
GetPA = vPA
End Function


Если чё непонятно - спрашивай хоть построчно - поясню.
С уважением, Approximator.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 22.11.2004 (Пн) 5:01

Не, ты мне объясни, почему не работает в скомпилированном виде...

Я ж хотел извратиться на предмет вызова по указателю без асмовых переходников. С ними-то я вызову :)
Ну почему не работает прямая перезапись адреса возврата в exe, ведь buffer overrun основан именно на этом...
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 22.11.2004 (Пн) 5:20

Approximator писал(а):
GSerg писал(а):Так, чё за фигня :)
Если в модуль вынести и скомпилировать - работает. Во всяком случае, похоже на то.

Даже, если это так, то это случайность. Вообще говоря, не должно работать.

В скомпилированном - не должно работать? Почему? :-?
Изображение

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 22.11.2004 (Пн) 5:22

GSerg писал(а):Не, ты мне объясни, почему не работает в скомпилированном виде...

В смысле, твой старый код?
Я думал, я тебе объяснил - потому что а) перезаписывается не адрес возврата, а Me; б) если это исправить, то в IsWindow передаётся не hWnd, а Me.
Изображение

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 22.11.2004 (Пн) 5:28

Ну разумеется, мой старый код, перемещённый в модуль!
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 22.11.2004 (Пн) 6:10

GSerg писал(а):Ну разумеется, мой старый код, перемещённый в модуль!
А он разве не работает в скомпилированном виде?
Ты писал, работает; и у меня работал...
Изображение

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 22.11.2004 (Пн) 10:01

gettickcount идёт правильно...
А та же iswindow возвращает некую странную длинную цифирь, хотя известно, что должна быть единица.
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

Approximator
Постоялец
Постоялец
 
Сообщения: 572
Зарегистрирован: 26.06.2004 (Сб) 3:10

Сообщение Approximator » 23.11.2004 (Вт) 2:27

GSerg писал(а):Не, ты мне объясни, почему не работает в скомпилированном виде...

Я ж хотел извратиться на предмет вызова по указателю без асмовых переходников. С ними-то я вызову :)
Ну почему не работает прямая перезапись адреса возврата в exe, ведь buffer overrun основан именно на этом...


Ты меня не понял. Не работает не перезапись адреса возврата - это работает всегда. Может не работать заполнение стека подобным образом.
Смотри, ты используешь связку <Wrapper1+Rdirect>. Redirect выполняет функции переключателя, по умолчанию тобой предполагается, что после выхода из Redirect esp установлен в то же положение, что и в момент прихода в Wrapper1, но вся штука в том, что это не обязательно (хотя бывает) так.
Во всяком случае я бы посмотрел, как именно Wrapper1 откомпилирован. Если действительно до вызова Redirect во Wrapper1 esp не меняется, то обязано работать.
С уважением, Approximator.

Approximator
Постоялец
Постоялец
 
Сообщения: 572
Зарегистрирован: 26.06.2004 (Сб) 3:10

Сообщение Approximator » 23.11.2004 (Вт) 2:31

Кстати
GSerg писал(а):gettickcount идёт правильно...
А та же iswindow возвращает некую странную длинную цифирь, хотя известно, что должна быть единица.

Это как раз и говорит о том, что траблы именно с правильной передачей данных стека Wrapper1. Функция GetTickCount не имеет аргументов, потому работает правильно, а IsWindow аргументы имеет. Всё же, похоже, что Wrapper1 откомпилирован так, что в нём до вызова Redirect изменяется значение esp.
С уважением, Approximator.

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 23.11.2004 (Вт) 20:52

Approximator, при чём здесь передача аргументов, если "iswindow возвращает некую странную длинную цифирь"? IsWindow при любых аргументах должна возвращать 1 либо 0; значит, вызывается не она ;-)

Ещё раз, в скомпилированном виде и в отдельном модуле у меня всё работает просто прекрасно, возвращается 1. Что за траблы у GSerg-а - не знаю. Попробуй, как у тебя?

И ещё, поясни мне, какое значение имеет положение esp. Если у Wrapper1 и вызываемой функции (IsWindow) поровну параметров, то VB вообще никак не может заметить подвоха...
Изображение

Approximator
Постоялец
Постоялец
 
Сообщения: 572
Зарегистрирован: 26.06.2004 (Сб) 3:10

Сообщение Approximator » 24.11.2004 (Ср) 3:39

tyomitch писал(а):Approximator, при чём здесь передача аргументов, если "iswindow возвращает некую странную длинную цифирь"? IsWindow при любых аргументах должна возвращать 1 либо 0; значит, вызывается не она ;-)


Нет, не так. Может быть и так, что она вызывается (в этом сомнений быть не может), но возврат из неё происходит не совсем туда. Ниже я буду пояснять про стек и подробнее объясню, что имею ввиду.

tyomitch писал(а):Ещё раз, в скомпилированном виде и в отдельном модуле у меня всё работает просто прекрасно, возвращается 1. Что за траблы у GSerg-а - не знаю. Попробуй, как у тебя?


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

tyomitch писал(а):И ещё, поясни мне, какое значение имеет положение esp. Если у Wrapper1 и вызываемой функции (IsWindow) поровну параметров, то VB вообще никак не может заметить подвоха...

Как это какое значение? Дело-то не в VB, а в вызываемой функции. Заметь из Redirect мы в любом случае попадаем в ту процедуру, адрес которой указан. Так что попасть не туда мы не можем в принципе. Однако, чтобы вернуться в то место из которого был вызван Wrapper1 необходимо, чтобы стек содержал, как минимум, адрес возврата (верхнее значение в стеке), как максимум, + все аргументы. На стек указывает значение esp. Достаточно, чтобы до вызова Redirect внутри Wrapper1 значение esp изменялось (к примеру, в некоторых случаях обычным является сохранение значения ebp в стеке), чтобы происходила какая-то белиберда.

Кстати, я же предложил способ проверки. Вызывайте не IsWindow, а свою модульную функцию. Пусть она показывает адрес стека (должен быть такой же, как и во Wrapper1) и его содержимое (всё - от аргументов, до адреса возврата). Это снимет все споры.
С уважением, Approximator.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 24.11.2004 (Ср) 5:11

Точно...
Меня терзают смутные сомненья на предмет того, что если у функции есть параметры, то первые две её команды -
Код: Выделить всё
push ebp
mov ebp, esp

Причём это выполняется до любого юзерского кода. Так что в верхушке стека оказывается ebp. Да его, к тому же, и выпихнуть надо перед возвратом.
Хреново... Без переходников-таки не обойтись...
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

Approximator
Постоялец
Постоялец
 
Сообщения: 572
Зарегистрирован: 26.06.2004 (Сб) 3:10

Сообщение Approximator » 24.11.2004 (Ср) 5:25

GSerg писал(а):Точно...
Меня терзают смутные сомненья на предмет того, что если у функции есть параметры, то первые две её команды -
Код: Выделить всё
push ebp
mov ebp, esp

Причём это выполняется до любого юзерского кода. Так что в верхушке стека оказывается ebp. Да его, к тому же, и выпихнуть надо перед возвратом.
Хреново... Без переходников-таки не обойтись...


Кажется. Есть решение этой проблемы. Если ты точно знаешь насколько изменилось содержимое стека перед обращением к Redirect, то можно было бы предложить следующее решение:
Код: Выделить всё
Private Sub Redirect(ByVal Addr As Long)
  PutMem4 VarPtr(Addr) - 4, AddressOf RDPlus
  PutMem4 VarPtr(Addr) + 4, Addr
End Sub

Private Sub RDPlus() ' может содержать аргументы, если необходимо изменить состояние esp более чем на 4
  'должно быть пусто
End Sub
С уважением, Approximator.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 24.11.2004 (Ср) 5:45

Раз ты тут, пойду дизасм помучаю. Скоро выложу, далеко не уходи :)
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

Approximator
Постоялец
Постоялец
 
Сообщения: 572
Зарегистрирован: 26.06.2004 (Сб) 3:10

Сообщение Approximator » 24.11.2004 (Ср) 5:52

GSerg писал(а):Раз ты тут, пойду дизасм помучаю. Скоро выложу, далеко не уходи :)

О'к.
С уважением, Approximator.

Пред.След.

Вернуться в Народный треп

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 28

    TopList