Deem |
Отправлено: 28.04.2005, 17:44 |
|
Мастер участка
Группа: Участник
Сообщений: 327
|
Я как-то получил-таки такой указатель и преобразовывал его к void* для дальнейшей работы. Сйчас надо, а нет того файла.
Кто подскажет, кто знает?
Если просто функция или метод статик — так нет проблем.
А если просто метод ? Помню, тогда я порадовался за борланд, т.к. получилось благодаря какому-то его расширению языка. Может это был модификатор _closure (?), но с таким указателем потом ничего не слепишь: только присваивать или запускать функцию через него.
Есть в си штука: указывать класс, к которому принадлежит метод
TForm1::MyMethod, но указатель получается неконвертируемый какой-то.
А надо бы нормальный доступ в память.
А может я опять что-то перепутал
|
|
Rius |
Отправлено: 28.04.2005, 18:58 |
|
Мастер участка
Группа: Участник
Сообщений: 321
|
тип функции
typedef HANDLE (__cdecl *tdefCloseDevice) (HANDLE fHandle);
указатель на функцию
tdefCloseDevice dCloseDevice;
получение указателя из DLL
dCloseDevice = (tdefCloseDevice) GetProcAddress(DLL.Handle, "_dCloseDevice");
обращение к функции
HANDLE h = dCloseDevice(Handle);
метод есть функция без результата, сработать должно аналогично
Отредактировано Rius — 28/04/2005, 21:59
|
|
xim |
Отправлено: 28.04.2005, 20:47 |
|
Станционный диспетчер
Группа: Участник
Сообщений: 143
|
Указатель на метод ничего не даст (если он не static конечно) без соответствующего экземпляра класса. Первым параметром при объявлении метода всегда является указатель на представитель класса. Понятно почему таким образом можно получить указатель на static метод — вместо 1 параметра можно указать NULL. Для published методов можно сделать так:
CODE |
#include <vcl.h>
class TMyClass : public TObject{
public:
__fastcall TMyClass();
virtual __fastcall ~TMyClass();
__published:
void method1();
};
__fastcall TMyClass::TMyClass()
{
}
__fastcall TMyClass::~TMyClass()
{
}
void TMyClass::method1()
{
ShowMessage("method1");
}
typedef void (*PMethod1)(TMyClass *);
int main()
{
TMyClass *cl=new TMyClass();
PMethod1 meth=(PMethod1)TMyClass::MethodAddress(__classid(TMyClass),"method1");
if(meth)meth(cl);
delete cl;
return 0;
}
| |
|
olegenty |
Отправлено: 29.04.2005, 07:01 |
|
Ветеран
Группа: Модератор
Сообщений: 2412
|
ну а с closure я работаю так (собственно, это интерфейсная часть exe, с которой работают все dll):
Callback.h
CODE |
#ifndef CCallbackH
#define CCallbackH
#include <Forms.hpp>
#include <ADODB.hpp>
enum TUserRole {urRead, urWrite, urCheck};
typedef TForm* __stdcall (__closure *PCommon )(const AnsiString);
typedef TADOConnection* __stdcall (__closure *PConn )();
typedef HWND __stdcall (__closure *PFMHandle)();
typedef TDateTime __stdcall (__closure *PDate )();
typedef TUserRole __stdcall (__closure *PUserRole)(const HWND);
typedef void __stdcall (__closure *PShowWait)();
typedef void __stdcall (__closure *PHideWait)();
class CCallback
{
private:
PCommon m_pCommon ;
PConn m_pConn ;
PFMHandle m_pHandle ;
PDate m_pDate ;
PUserRole m_pUserRole;
PShowWait m_pShowWait;
PHideWait m_pHideWait;
public:
__fastcall CCallback(PCommon Common ,
PConn Conn ,
PFMHandle FMHandle,
PDate Date ,
PUserRole UserRole,
PShowWait ShowWait,
PHideWait HideWait);
TForm* __stdcall Common(const AnsiString Name);
TADOConnection* __stdcall Conn();
HWND __stdcall Handle();
TDateTime __stdcall Date();
TUserRole __stdcall UserRole(const HWND Handle);
void __stdcall ShowWait();
void __stdcall HideWait();
};
#endif
|
Callback.cpp
CODE |
#pragma hdrstop
#include "CCallback.h"
#pragma package(smart_init)
__fastcall CCallback::CCallback(PCommon Common ,
PConn Conn ,
PFMHandle FMHandle,
PDate Date ,
PUserRole UserRole,
PShowWait ShowWait,
PHideWait HideWait)
{
m_pCommon = Common ;
m_pConn = Conn ;
m_pHandle = FMHandle;
m_pDate = Date ;
m_pUserRole = UserRole;
m_pShowWait = ShowWait;
m_pHideWait = HideWait;
}
TForm* __stdcall CCallback::Common(const AnsiString Name)
{
return m_pCommon(Name);
}
TADOConnection* __stdcall CCallback::Conn()
{
return m_pConn();
}
HWND __stdcall CCallback::Handle()
{
return m_pHandle();
}
TDateTime __stdcall CCallback::Date()
{
return m_pDate();
}
TUserRole __stdcall CCallback::UserRole(const HWND Handle)
{
return m_pUserRole(Handle);
}
void __stdcall CCallback::ShowWait()
{
m_pShowWait();
}
void __stdcall CCallback::HideWait()
{
m_pHideWait();
}
|
ну а в главной форме экземпляр класса CCallback создаётся для последующей передачи в DLL (и инициируется указателями на методы главной формы) так:
CODE |
Callback = new CCallback(&Common,
&Conn,
&FormHandle,
&Date,
&UserRole,
&ShowWait,
&HideWait);
|
|
|
AVC |
Отправлено: 29.04.2005, 08:57 |
|
Ветеран
Группа: Модератор
Сообщений: 1583
|
2xim
QUOTE |
Указатель на метод ничего не даст (если он не static конечно) без соответствующего экземпляра класса.
|
Даст, если он хочет его шифровать (мне алгоритм очень не нравится)
А еще его можно "грамотно" применять. Пример:
CODE |
Как добраться до protected свойства.
class a {protected int prot;}
Задача добраться до a:prot
делаем описание (можно прямо перед функцией)
class b : public a
{private privb;
public int GetProta (void);
};
b::GetProt(int) { return a::prot; }; // у меня обязательно не inline
Использование
.....
b *bpoi = (b*)(указатель на экземпляр класса a);
prot = bpoi->GetProta();
|
Обратите внимание, что экземпляр класса b не создается и, что естественно, bpoi->privb содержит "мусор" если его можно так назвать. А вот метод вернет реальное значение.
Преобразования методов vcl к нативным функциям и использование
CODE |
//описание указателей на методы
typedef void __fastcall (__closure *TAxTimerCallBack_vcl)(TTinyOnePrompt*);
typedef void __fastcall ( *TAxTimerCallBack_nat)(void*, TTinyOnePrompt*);
// постфих _vcl — метод класса, _nat "просто" функция
// использование
// получаю как метод объекта _vcl сохраняю как указатели
int __fastcall TDM::TimerQue_Add
(TDateTime pWhen
,TAxTimerCallBack_vcl cbfun
,TForm *pForm
)
{
...
TMethod Method = *(TMethod*)&cbfun;
TTinyOnePrompt *tp = FTimer_Queue->Add(tque_code, name);
tp->Code1 = int(Method.Code);
tp->Code2 = int(pForm);
...
}
// вызов _nat
void __fastcall TDM::TimerQue_Dispatch (void) // Выполнить все наступившие
{
TTinyPrompt *plist = FTimer_Queue;
TTinyOnePrompt *itm;
TAxTimerCallBack_nat fun;
TForm *frm;
...
for (int i=0; i < plist->Count; i++)
{ itm = plist->Items[i];
....
fun = NULL;
frm = NULL;
if (itm->Code1 != 0) fun = TAxTimerCallBack_nat (itm->Code1);
if (itm->Code2 != 0) frm = (TForm*) (itm->Code2);
if (!fun) continue;
....
if (frm) fun(frm, itm);
else fun(Application, itm);
| |
|
Deem |
Отправлено: 29.04.2005, 13:09 |
|
Мастер участка
Группа: Участник
Сообщений: 327
|
Ойой! Закидали. Однако, про прямой доступ к "телу" метода (если не пропустил ничего) у вас нету. Получить указатель для последующего запуска через него можно от чего угодно.
А метод, даже если он не статик, гже-то же валяется и память занимает. Надо было до этой самой памяти доступ получить. DLL ваще не рассматриваю. Все в эхешнике одном.
Ну ладно, видимо нет такого варианта. А указатели, получаемые при помощи указания экземпляра класса (а может и __closure, не смотрел) занимают аж 12 байт! Понятно, что к void* никто не захочет приводить.
А MethodAddress, как я понял, только с __pablushed (?) — методами работает.
|
|
Георгий |
Отправлено: 29.04.2005, 20:52 |
|
Почетный железнодорожник
Группа: Модератор
Сообщений: 874
|
у борланда _closure, но это не стандартно.
а есть ещё библиотека http://www.boost.org/ с неплохими классами для работы с указателями на методы (см boost::bind) причём работает она с ANSI C++ без всяких нестандартных расширений
указатель на метод действительно 12 байт занимает
развлекался с виртуальными методами. для них:
первые 4 = указатель на функцию-заглушку вызывающую нужный метод по таблице виртуальных функций
вторые 4 = индекс в таблице. значения отличный от 0 не видел
третьи 4 = смещение. так же значений отличных от нуля не видел.
подозеваю, что для статических и обычных методов поля те же, но вместо функции заглушки находится сам метод.
можно ещё по указателю на метод reinterpret_cast проехаться — он то точно к void* сможет преобразовать, но что из этого выйдет даже не догадываюсь
PS. если это всё затеяно, что бы защититься от отладчиково вроде SoftIce, то ничего не выйдет — он работает в 1 или 0 кольце защиты, а ты в 3м. Обманет он тебя — сам сможет писать в твой сегмент кода, а тебе не позволит. лучше купить защиту вроде ключей alladin — их разработчики как обещают защиту от крякеров.
Отредактировано Георгий — 29/04/2005, 23:55 |
|
Asher |
Отправлено: 04.05.2005, 08:12 |
|
Мастер участка
Группа: Модератор
Сообщений: 550
|
Привет.
QUOTE | вторые 4 = индекс в таблице. значения отличный от 0 не видел
третьи 4 = смещение. так же значений отличных от нуля не видел. |
А при множественном наследовании смотрел?
|
|
Георгий |
Отправлено: 04.05.2005, 08:28 |
|
Почетный железнодорожник
Группа: Модератор
Сообщений: 874
|
QUOTE (Asher @ 04/05/2005, 08:12) | А при множественном наследовании смотрел? |
на брилиантике смотрел:CODE | class root{virtual void method();};
class child1:public root{virtual void method();};
class child2:public root{virtual void method();};
class multi:public child1, public child2{virtual void method();} | всё равно нули. только поле адрес метода имеет другое значение и функция заглушка передеёт управление по этому значение, проводя какие то непонятные вычисление с использованием других полей (хоть они и нулевые, но всё равно что-то с их использованием вычисляется).
а вот явный вызов методаэти дополнительный поля вообще не используются.
PS. что самое интересное код генерируемый Wactom C10.6 (1996 год выпуска) и BCB6 (куда более свежий компилятор) практически совпадает при работе с виртуальными методами |
|
Asher |
Отправлено: 04.05.2005, 09:10 |
|
Мастер участка
Группа: Модератор
Сообщений: 550
|
По идее объект полученный в результате множественного наследования от полиморфных классов будет содержать несколько “унаследованных” указателей на vtbl.
Может у тебя виртуального деструктора нехватает, и поэтому компилятор, прикинув невозможность нормального преобразования указателя на производный класс в указатель на любой из базовых, отоптимизировал таблицу vtlb.
Я в вопросе плотно не разбирался, поэтому все это чисто домыслы и умозрения.
|
|
Deem |
Отправлено: 04.05.2005, 09:30 |
|
Мастер участка
Группа: Участник
Сообщений: 327
|
Посмотрю библиотечку. А с дебугерами все просто: ты сам можешь писать в тот блок памяти, в котором сейчас стоит брякпоинт дебугера. А в других запись невозможна (если сам не заказал доступ). Вот так-то. Короче, можно так сделать: при входе в каждую функцию пробовать писать в себя же: если можно — тута где-то валяется бркпоинт, и дебугер шастает поблизости, соответственно.
Не знаю, как это хлопотно, но догадываюсь.
Сам так не собираюсь делать, хотя, кто знает. А самомодифицирующийся код — пока что самый крутой и действенный метод зпщиты. Как минимум, дизассемблер ехешник просто так не расковыряет. Пока что я использовал VirtualProtect, что меня смущает, т.к. именно его (я думаю) можно отследить. А если отследить, значит и поковырять все остальное. Хотя можно ставить разрешение на запись для очень большого куска кода, а не коткретной функции. Тогда хакер долго будет искать, что модифицировалось.
Ну пока я только обощаю теорию, первые шаги. После них будут вторые и третьи. А брать готовую не советую никому. Крякеры уже знают и ковыряют ее.
А хардкей тоже не поможет: ломается, да и хлопотно с ним.
Защита должна быть у каждого своя.
А ваще БГ сволочь: защита должна реализовываться на уровне операционки. Правда, он и сам не в силах защититься.
|
|
|