Всем привет
алгоритм такой вызывается функция GetAddr и ей передается
уникальное число хеш посчитанный от имени функции которую надо вызвать
и чей адрес она должна вернуть когда в первый раз вызывается GetAddr
для конкретного хеша она парсит экспорт находит адрес запоминает
его по какой то схеме которую надо придумать и во время следующих
вызовов с этим же хешем быстро возращает адрес хеш из себя представляет
любое число от 0x00000000 — 0xfffffff надо максимально быстро отобразить
хеш на адрес функции и вернуть его тоесть по сути задача сводится
к маскимально быстрому отображению числа в диапазоне
0x00000000 — 0xfffffff на адрес функции
как тут можно реализовать есть идеи ?
скорость должна быть сравнимой с обычным вызовом функции
Здравствуйте, jyuyjiyuijyu, Вы писали:
J>как тут можно реализовать есть идеи ? J>скорость должна быть сравнимой с обычным вызовом функции
Хэш-таблици не интересуют?
Кстати, на момент компиляции этого хозяйства, все функции уже известны? А то есть много методик построения по известному набору образцов хэш-функции без коллизий, или с ограниченным сичлом коллизий...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
ну как бы есть некая адовая смесь которая при вызове обычной
winapi функции генерирует не то что ожидалось например
в исходнике мы видим например
SetWindowText(hWnd, szMsg);
разворачивается это в момент компиляции в следующее
push szMsg
push hWnd
push 0xYYYYYYYY ; это наш хеш от SetWindowText
call GetAddr ; на выхоже в eax адрес
call eax ; это наш SetWindowText
тоесть какую бы мы функцию не вызывали меняться будут только
хеши вся подстановка прозрачна для вызывающего кода он и не знает
что вызовы идут через хеши для этого специальной программой генерируется
.h файл с переопределенными макросами типа SetWindowText в реализации
которых много магии например учет сигнатуры вызываемой функции
подстановка хешей и прочее
вообщем механизм примерно такой смысл в том что хеш для каждой конкретной
функции передается всегда при каждом вызове этой функции и надо придумать
быструю систему отображения этих хешей на адреса время будет тратится только во воемя
первого вызова когда будет реальный поиск в таблице экспорта
хеши все известны ну вот представь .h файл со всеми определениями
функций нескольких системных библиотек какую я захочу оттуда функцию
вызвать одному богу известно
Здравствуйте, jyuyjiyuijyu, Вы писали:
J>тоесть какую бы мы функцию не вызывали меняться будут только J>хеши вся подстановка прозрачна для вызывающего кода он и не знает J>что вызовы идут через хеши для этого специальной программой генерируется J>.h файл с переопределенными макросами типа SetWindowText в реализации J>которых много магии например учет сигнатуры вызываемой функции J>подстановка хешей и прочее
J>хеши все известны ну вот представь .h файл со всеми определениями J>функций нескольких системных библиотек какую я захочу оттуда функцию J>вызвать одному богу известно
Что-то я не понял. Ну просто перенумеруй функции, дефайнами присвойим номера, и храни где-то статический массив, отображающий номера на адреса...
только не ясно, на кой это всё надо-то?
Смотри, шаг 1.
Вместо
call GetAddr
call eax
пишем просто call GoToAddr, а GoToAddr сама вычисляет адрес и переходит.
Но, если GoToAddr это просто
pop eax
jp MyTable[eax]
то можно просто call туда сделать без всякой GoToAddr, но, если, опять же, это просто вектор адресов, то можно просто сложить подряд jp туда и оз сюда, а call деать внутрь этого вектора. А сам вектро можно поручить линкеру прореживать, и оставлять там только нужные джампы.
Ну и, наконец, можно почитать доки к твоему линкеру, очень может быть, что он уже и сам всё это умеет...
Может расскажешь, зачем это всё надо? Тогда и совет получше получишь...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Что-то я не понял. Ну просто перенумеруй функции, дефайнами присвойим номера, и храни где-то статический массив, отображающий номера на адреса...
а можно немного кода набросать как все это будет не иогу понять ?
что значит пронумеровать по какому принципу пронумеровать
все функции из нескольких библиотек насколько большой делать массив
его что надо будет изменять для каждой программы а если нет то он просто
очень огромный будет что не подходит к тому же придется передавать хеш
и еще номер плюс аргументы или я Вас не понял
E>только не ясно, на кой это всё надо-то?
ну то что программы получаются без таблицы импорта это не надо объяснять
просто интересно сделать чтоб было хорошо и работало может пригодится
я грешным делом думал так сделать
получаем первый раз хеш парсим экспорт получаем адрес
вставляем в массив делаем qsort когда приходят новые хеши
делаем bsearch по этому массиву если нет то парсим и новый
адрес добавляем в массив делаем qsort для последующего быстрого
bsearch но во первых мы тут упираемся в фундаментальную проблему
синхронизации пока один поток ищет другой может сортировать
это не говоря уже про эффективность двочного поиска при
каждом вызове пусть в среднем 400 api в массиве
это при bsearch 8 сравнений впринципе очень быстро
но проблема синхронизации все портит
хотя нет же можно сразу вставлять в нужную позицию если использовать
binary search tree для в среднем 400-х функций что вставка что
отображение хеша на адрес будут моментальными 8 сравнений
узел можно представить парой хеш <--> адрес
сортировать дерево по значению хеша
но вот от проблемы синхронизации мы никуда не ушли
ну вот примерно так если в массиве 400 элементов что где то будет
соответствовать истине то если повторить поиск один миллиард раз
займет это менньше секунды вот для наглядности я сделалд 10
циклов по миллиарду поисков в каждом
time == 0.734000
time == 0.766000
time == 0.750000
time == 0.781000
time == 0.703000
time == 0.750000
time == 0.766000
time == 0.718000
time == 0.750000
time == 0.750000
Для продолжения нажмите любую клавишу . . .
отлично но ведь надо будет еще вставить синхронизацию
я вот о чем думаю множество потоков может искать одновремено
но когда кто то один или несколько потоков захотят вставить надо
дать им эксклюзивный доступ хорошо что операция вставки очень редкая
и время за нее можно не считать а в остальное время потоки параллельно
должны вести поиск тоесть не синхронизироватся надо придумать что то
типа модели много читающих один пишущий (много ищущих один вставляющий)
это мне кажется самое эффективное будет
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
struct CHashAddrTree
{
static CHashAddrTree Tree;
VOID Add(DWORD dwHash, PVOID pvAddr)
{
_Add(dwHash, pvAddr, &pRoot);
}
PVOID Find(DWORD dwHash)
{
return _Find(dwHash, pRoot);
}
private:
struct NODETREE;
VOID _Add(DWORD dwHash, PVOID pvAddr, NODETREE** ppRoot)
{
if (!*ppRoot)
{
if (MaxNodes == dwCurFree)
__asm int 3;
NODETREE* pNode = &aNodes[dwCurFree];
pNode->dwHash = dwHash;
pNode->pvAddr = pvAddr;
*ppRoot = pNode;
dwCurFree++;
}
else if ((*ppRoot)->dwHash > dwHash)
_Add(dwHash, pvAddr, &(*ppRoot)->pLeft);
else if ((*ppRoot)->dwHash < dwHash)
_Add(dwHash, pvAddr, &(*ppRoot)->pRight);
else
__asm int 3;
}
PVOID _Find(DWORD dwHash, NODETREE* pRoot)
{
if (!pRoot)
return 0;
if (pRoot->dwHash > dwHash)
return _Find(dwHash, pRoot->pLeft);
if (pRoot->dwHash < dwHash)
return _Find(dwHash, pRoot->pRight);
return pRoot->pvAddr;
}
struct NODETREE
{
DWORD dwHash;
PVOID pvAddr;
NODETREE* pLeft;
NODETREE* pRight;
};
enum{MaxNodes = 400};
NODETREE aNodes[MaxNodes];
NODETREE* pRoot;
DWORD dwCurFree;
};
CHashAddrTree CHashAddrTree::Tree;
#pragma message("enable -O2 -Ot for test")
#include <set>
#include <boost/timer.hpp>
int main()
{
std::set<int> v;
srand(GetTickCount());
for (size_t i = 0; i < 400; i++)
{
int val = rand();
std::pair<std::set<int>::iterator,bool> it = v.insert(val);
if (it.second)
CHashAddrTree::Tree.Add(val, 0);
else
i--;
}
for (int i = 0; i < 10; i++)
{
boost::timer tt;
int volatile yu = 67;
for (size_t ii = 0; ii < 1000000000; ii++)
CHashAddrTree::Tree.Find(yu);
printf("time == %f\n", tt.elapsed());
}
}
мои извинения на самом деле компилятор выкинул вызов функции Find
(я как чувствовал что то тут не то слишком быстро зря не посмотрел в ассемблер)
потому что я не использовал результат гад какой умный там же куча
вызовов рекурсивных и оставил такой
for (size_t ii = 0; ii < 1000000000; ii++)
004011B7 83 E8 01 sub eax,1
CHashAddrTree::Tree.Find(yu);
004011BA 8B 54 24 50 mov edx,dword ptr [esp+50h]
004011BE 75 F7 jne main+107h (4011B7h)
вот данные исправленного теста 100.000.000 (сто миллионов)
поисков делает за 2 секунды
time == 2.140000
time == 2.063000
time == 2.031000
time == 2.031000
time == 2.031000
time == 2.032000
time == 2.047000
time == 2.015000
time == 2.031000
time == 2.047000
Для продолжения нажмите любую клавишу . . .
int main()
{
std::set<int> v;
srand(GetTickCount());
for (size_t i = 0; i < 400; i++)
{
int val = rand();
std::pair<std::set<int>::iterator,bool> it = v.insert(val);
if (it.second)
CHashAddrTree::Tree.Add(val, 0);
else
i--;
}
for (int i = 0; i < 10; i++)
{
boost::timer tt;
int volatile yu = 67;
PVOID volatile gg;
for (size_t ii = 0; ii < 100000000; ii++)
{
gg = CHashAddrTree::Tree.Find(yu);
}
printf("time == %f\n", tt.elapsed());
}
}
величина название обозначение величина название обозначение
101 с декасекунда дас das 10−1 с децисекунда дс ds
102 с гектосекунда гс hs 10−2 с сантисекунда сс cs
103 с килосекунда кс ks 10−3 с миллисекунда мс ms
106 с мегасекунда Мс Ms 10−6 с микросекунда мкс µs
109 с гигасекунда Гс Gs 10−9 с наносекунда нс ns
1012 с терасекунда Тс Ts 10−12 с пикосекунда пс ps
1015 с петасекунда Пс Ps 10−15 с фемтосекунда фс fs
1018 с эксасекунда Эс Es 10−18 с аттосекунда ас as
1021 с зеттасекунда Зс Zs 10−21 с зептосекунда зс zs
1024 с йоттасекунда Ис Ys 10−24 с йоктосекунда ис ys
если одна секунда это 1.000.000.000 миллиард наносекунд
у нас в секунду делается примерно 50.000.000 миллионов поисков
один поиск выходит занимает где то 20 наносекунд
Здравствуйте, jyuyjiyuijyu, Вы писали:
E>>только не ясно, на кой это всё надо-то? J>ну то что программы получаются без таблицы импорта это не надо объяснять J>просто интересно сделать чтоб было хорошо и работало может пригодится
Почему, это, интересно, без таблицы импорта? А откуда, в конце концов, возьмутся адреса входов в системные DLL? Они на разных системах разные, вообще-то...
Если тебя устраивает работоспособность только на одной какой-то конкретной версии, то есть утилитка, которая умеет првязывать к нужной системе сразу, без хаков и глюков...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Почему, это, интересно, без таблицы импорта? А откуда, в конце концов, возьмутся адреса входов в системные DLL? Они на разных системах разные, вообще-то... E>Если тебя устраивает работоспособность только на одной какой-то конкретной версии, то есть утилитка, которая умеет првязывать к нужной системе сразу, без хаков и глюков...
как откуда а чьи хеша мы собтвенно на адреса отображать будем
именно этих системных api смотри первый раз пришедший хеш берем
берем таблицу экпорта системного модуля хешируем имя каждой
функции из экспорта сравниваем с нашим хешем если сошлись
запоминаем адрес опаределенной функции на следующие запросы
просто возвращаем адрес это может быть адрес той же
SetWindowText или какой то жругой определяется хешем а хеш
определяется в зависимости от того какую функцию мы вызываем
он неявно подставляется а сам файл с перепределенными макросами
и соответствующими хешами создается отдельной программой его потом
подключаеш и пишеш
Здравствуйте, jyuyjiyuijyu, Вы писали:
J>как откуда а чьи хеша мы собтвенно на адреса отображать будем J>именно этих системных api смотри первый раз пришедший хеш берем J>берем таблицу экпорта системного модуля хешируем имя каждой J>функции из экспорта сравниваем с нашим хешем если сошлись J>запоминаем адрес опаределенной функции на следующие запросы J>просто возвращаем адрес это может быть адрес той же J>SetWindowText или какой то жругой определяется хешем а хеш J>определяется в зависимости от того какую функцию мы вызываем J>он неявно подставляется а сам файл с перепределенными макросами J>и соответствующими хешами создается отдельной программой его потом J>подключаеш и пишеш
Я стечняюсь спросить: вы принципиально знаки препинания не употребляете?
J>плюс тут еще оверхед сам цикл дает его по идее J>тоже надо вычесть из общего времени
кстати, тут свои сообщения редактировать низзя, а вот удалять при помощи бомбочки справа сверху и писать новые, дополненные так сказать — можно
Как много веселых ребят, и все делают велосипед...
получился макет так как некоторые функции еще не написаны
и так тут разрешается параллельный поиск нескольких потоков
тоесть никакой синхронизации нет и только когда будут
получать реальные адреса будет синхронизация с блокировкой остальных
но это во первых только в начале работы программы когда первые вызовы
api будут происходить во вторых очень мало
все ли корректно в этом макете в плане параллельных запросов ?
или может добавить SwitchToThread в цикл а то если попадется
свирепствующий поток с высоким приоритетом он задавит
поток который получает адрес вот и деадлок