Сейчас на форуме: rmn, Magister Yoda, vasilevradislav, tyns777, zombi-vadim (+6 невидимых)

 eXeL@B —› Программирование —› Как программно узнать размер функции написанной на си ?
Посл.ответ Сообщение

Ранг: 271.5 (наставник), 12thx
Активность: 0.150
Статус: Участник
Packer Reseacher

Создано: 24 августа 2008 22:04 · Поправил: theCollision
· Личное сообщение · #1

Я написал ф-цию:
Code:
  1. void* xGetCoolHashe(PVOID * PData, DWORD SizeOfData)
  2. {
  3. /* много кода */
  4.   return <value>;
  5. }


вопрос, как можно узнать размер этой ф-ции для того, чтобы записать ее в файл и юзать уже в коде, который базово-независим ?

фишку вроде вроде кода после последнего оператора в ф-ции:
Code:
  1. _asm {
  2. nop
  3. nop
  4. nop
  5. nop
  6. };
с поиском значения 0x90909090 не предлагать, знаю эту фишку, ща юзаю ;)

P.S.:
Круто выглядит код в теге "код", когда прикрутили ? вроде небыло же ! ;)

-----
My love is very cool girl.





Ранг: 238.8 (наставник), 67thx
Активность: 0.20
Статус: Участник
CyberHunter

Создано: 24 августа 2008 22:23 · Поправил: Flint
· Личное сообщение · #2

что мешает это сделать так:
вначале функции вызываешь call $+5 потом pop eax и затем sub eax, 5 получишь адрес начала своей функции, потом jmp на такую же конструкцию, которая будет стоять перед ret получишь адрес конца функции потом джамп в основое тело, там получаешь разницу=размер функции в байтах.

Примерно так

Code:
  1. 00401000  CALL 00401005 
  2. 00401005  POP EAX
  3. 00401006  SUB EAX,5
  4. 00401009  MOV ECX,EAX
  5. 0040100B  JMP SHORT 0040103E
  6. 0040100D  SUB EAX,ECX ; В eax размер функции
  7. 0040100F   ; Полезный код
  8. ....
  9. 0040103C   JMP SHORT 00401049
  10. 0040103E   CALL 00401043
  11. 00401043   POP EAX
  12. 00401044   ADD EAX,6
  13. 00401047   JMP SHORT 0040100D
  14. 00401049   RETN


-----
Nulla aetas ad discendum sera




Ранг: 129.7 (ветеран), 2thx
Активность: 0.070
Статус: Участник

Создано: 24 августа 2008 23:02 · Поправил: Azur1d
· Личное сообщение · #3

Можно попробовать такую фишку:
Берешь адрес нужной функции, берешь адрес следующей, и вычисляешь разницу. Они компилятся обышно последовательно.
Но эта фишка не всегда работает.
Если юзаешь борландовский билдер, по поковыряй в сторону VMT




Ранг: 387.4 (мудрец)
Активность: 0.170
Статус: Участник
системщик

Создано: 25 августа 2008 00:05
· Личное сообщение · #4

theCollision, дело - труба, универсального решения тут нет, т.к. компилер по-разному может оптимизировать. То есть, указатели и метки это просто частные случаи.

Я бы вынес ф-цию в отдельную секцию - это будет видно в PE заголовках.



Ранг: 37.4 (посетитель)
Активность: 0.010
Статус: Участник

Создано: 25 августа 2008 04:26
· Личное сообщение · #5

Azur1d пишет:
Берешь адрес нужной функции, берешь адрес следующей, и вычисляешь разницу. Они компилятся обышно последовательно.

Пробовал такое - прокатило


Возможно, прокатит конструкция такого плана:
Code:
  1. __asm{
  2. lbl:
  3.     mov eax, lbl
  4. }




Ранг: 25.3 (посетитель)
Активность: 0.010
Статус: Участник

Создано: 25 августа 2008 09:23 · Поправил: flamer
· Личное сообщение · #6

Доброго здоровья!
Бр, а в чем беда-то?
Ну, кроме оффтопа -- кучи асма?

Правила работы с указателями в зубы и задачка решается на ура.
Без ухищрений оптимизации компиляторы не меняют порядок следования переменных и функций. Да, они могут выравнивать их на свой вкус, но порядок определяется программистом.
Вывод.
Определяем функцию ... my_func(...) {}
Ее адрес определить - элементарно - один оператор &

Определяем следующую функцию ( в примере это - main )

Вычитаем из большего адреса меньший - получаем длинну блока, который компилятор выделил под функцию. Да, в нем может быть хлам за концом функции, но это не страшно.

Зная адрес и длинну блока памяти можешь делать с ним, что хочешь.


Code:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main(int, char**);
  4. int test (void);
  5. typedef int (*printFType) (const char *format, ... )  ;
  6. int test (void) {
  7.          printFType pprintf=&printf;
  8.          pprintf("address of pprintf = 0x%x\n", pprintf);
  9. return 0;
  10. }
  11. int main(int argc, char** argv) {
  12.          unsigned int testEnd = (unsigned int) &main,
  13.                   testStart = (unsigned int) &test;
  14.          test();
  15.          printf("address of test = 0x%x\nsize of test = 0x%x",
  16.                    (unsigned int) &test, testEnd-testStart);
  17.          return EXIT_SUCCESS;
  18. }

Ну, и небольшой оффтоп, хотя, вопрос может возникнуть.
Внутри "проблемной" функции другие функции лучше вызывать через указатели.
Т.е. вначале целевой функции создать указатели на испольуземые функции и использовать их.
В чем суть? В упрощенности отвязки кода от месторасположения. В случае, если используемые функции будут в другом месте (например системные вызовы) достаточно (на 32-битках) поменять один дворд, а не перекомпилить функцию.



Ранг: 284.8 (наставник), 6thx
Активность: 0.150
Статус: Участник

Создано: 25 августа 2008 10:03
· Личное сообщение · #7

flamer
не согласен =)

писал на VC++ 6.0:
1) во первых когда получаешь адресс функции (если на Debug ) то получишь адресс jmp на свою функцию, а не адресс ее начала.
2) почти никогда функции не располагаются друг за другом, это уже причуды компилера.

в итоге это сработает только на Release когда код будет малость оптимизирован + можно добавить атрибут static функции.




Ранг: 793.4 (! !), 568thx
Активность: 0.740
Статус: Участник
Шаман

Создано: 25 августа 2008 10:04 · Поправил: PE_Kill
· Личное сообщение · #8

s0larian пишет:
дело - труба, универсального решения тут нет, т.к. компилер по-разному может оптимизировать.

А что мешает вырубить оптимизацию для этой функции?

зы А вообще, имхо, такие вещи надо на асме делать, особенно кулхэш ;)

-----
Yann Tiersen best and do not fuck




Ранг: 25.3 (посетитель)
Активность: 0.010
Статус: Участник

Создано: 25 августа 2008 10:09 · Поправил: flamer
· Личное сообщение · #9

RSI пишет:
не согласен =)

PE_Kill пишет:
А что мешает вырубить оптимизацию для этой функции?

+1

Всё равно, раз функция должна быть переносимой, то ее использование уже не стандартно.
Ну отладь ее, да выкуси. (++ пост №6 обновил)

Flint пишет:
вначале функции вызываешь call $+5 потом pop eax и затем sub eax, 5 получишь адрес начала своей функции, потом jmp на такую же конструкцию, которая будет стоять перед ret получишь адрес конца функции потом джамп в основое тело, там получаешь разницу=размер функции в байтах


И если уж идти по пути асма, то кто мешает не геморроиться, а элементарно ипользовать лэблы?



Ранг: 271.5 (наставник), 12thx
Активность: 0.150
Статус: Участник
Packer Reseacher

Создано: 25 августа 2008 11:30
· Личное сообщение · #10

Господа,какой нафиг асм ? ;) Вопрос касательно использования на языке С и только ! Будет вопрос по асму, задам в отдельной теме, а тут задал про С ;) Так что смотрю только и только по С, а кто писал на асме, те посты пропускаю! ;)

-----
My love is very cool girl.




Ранг: 37.4 (посетитель)
Активность: 0.010
Статус: Участник

Создано: 26 августа 2008 03:22
· Личное сообщение · #11

theCollision пишет:
с поиском значения 0x90909090 не предлагать, знаю эту фишку, ща юзаю ;)

Кстати, хорошая идея - для случая, если кто-то будет исследовать программу



Ранг: 271.5 (наставник), 12thx
Активность: 0.150
Статус: Участник
Packer Reseacher

Создано: 26 августа 2008 11:47
· Личное сообщение · #12

Dian
Где ее ставить то? Перед закрывающей "}" ? Тогда компиллер эпилог поставит! Если как накед, то самому мудрить с эпилогом и прологом!

-----
My love is very cool girl.





Ранг: 126.7 (ветеран)
Активность: 0.140
Статус: Участник
#CCh

Создано: 26 августа 2008 13:05
· Личное сообщение · #13

А если value для return передавать какое-нибудь особенное. Повторений избежать не сложно. Ищем сигну от начала функции и все.

-----
invoke OpenFire




Ранг: 135.2 (ветеран)
Активность: 0.070
Статус: Участник

Создано: 26 августа 2008 14:01 · Поправил: alexey_k
· Личное сообщение · #14

пример на борландовском компилере (робит только в Release-билде, на дебаге не прокатит )

Code:
  1. int myfunc(int i);
  2. int main(int argc, char* argv[])
  3. {
  4.          return myfunc(0);
  5. }
  6. int myfunc(int i)
  7. {
  8. // тут какой-нить код
  9.          return 0; // напр. так
  10. __asm db 'whatermark',0
  11. }


далее просто получаем указатель на эту функу (это будед начало), затем ищем строку "whatermark", вычитаем её длинну и получаем адрес конца функи.

из иды:
Code:
  1. .text:00401170 ; int __cdecl main(int argc,const char **argv,const char *envp)
  2. .text:00401170 _main           proc near               ; DATA XREF: .data:0040204Co
  3. .text:00401170
  4. .text:00401170 argc            = dword ptr  8
  5. .text:00401170 argv            = dword ptr  0Ch
  6. .text:00401170 envp            = dword ptr  10h
  7. .text:00401170
  8. .text:00401170                 push    ebp
  9. .text:00401171                 mov     ebp, esp
  10. .text:00401173                 push    0
  11. .text:00401175                 call    @jpeg@_16402    ; jpeg::_16402
  12. .text:0040117A                 pop     ecx
  13. .text:0040117B                 pop     ebp
  14. .text:0040117C                 retn
  15. .text:0040117C _main           endp
  16. ; вот хз почему моя функа стала называться jpeg =)
  17. .text:00401180 @jpeg@_16402    proc near               ; CODE XREF: _main+5p
  18. .text:00401180                 push    ebp
  19. .text:00401181                 mov     ebp, esp
  20. .text:00401183                 xor     eax, eax
  21. .text:00401185                 pop     ebp
  22. .text:00401186                 retn
  23. .text:00401186 @jpeg@_16402    endp
  24. .text:00401186
  25. .text:00401186 ; ---------------------------------------------------------------------- -----
  26. .text:00401187 aWhatermark     db 'whatermark',0
  27. .text:00401192 ; ---------------------------------------------------------------------- -----
  28. .text:00401192                 pop     ebp ; правда это
  29. .text:00401193                 retn ; и это тоже непонятно зачем тут =(


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




Ранг: 126.7 (ветеран)
Активность: 0.140
Статус: Участник
#CCh

Создано: 26 августа 2008 14:14
· Личное сообщение · #15

alexey_k пишет:
правда это
.text:00401193 retn ; и это тоже непонятно зачем тут =(

стандартная хрень на дельфи

return(0x90909090) компилится, как нистранно в mov EAX,90909090, после сигны ищем первый 0xC3 дизасмом длин это и есть последний retn. В функцию передаем указатель на выходной буфер и все. Я бы так и сделал и не одной строчки на асме, как ты и хотел)

-----
invoke OpenFire




Ранг: 37.4 (посетитель)
Активность: 0.010
Статус: Участник

Создано: 27 августа 2008 09:38
· Личное сообщение · #16

theCollision, размер эпилога нужно счесть константой и просто прибавить

Где-то на форуме мне попадался "дизассемблер длин функций" - очень сильная штука



Ранг: 284.8 (наставник), 6thx
Активность: 0.150
Статус: Участник

Создано: 27 августа 2008 10:10
· Личное сообщение · #17

theCollision
если уж сильно хочешь загнаться, то можешь посмотреть как работают проты ( в частности ExeCryptor и Themida ) когда юзаются маркеры ( т.е. маркер это опять таки забитая цепочка байт ( сигна ) по которой прот находит начало и конец, а дальше опеределяет что с этим сделать).



Ранг: 271.5 (наставник), 12thx
Активность: 0.150
Статус: Участник
Packer Reseacher

Создано: 27 августа 2008 20:26 · Поправил: theCollision
· Личное сообщение · #18

Ice-T
Логично ! ;) Думаю даже дизасм-длин не нужен, просто поиск 0xC3 )

Тогда теперь ситуация такая, в конце ф-ции я же могу возвращать нетолько хреновый результат а-ля return(-1) но и зашибись типа return(0) или другой какой важный проге! Если поставлю после последнего ретурна :
Code:
  1. __asm {
  2.  nop 
  3.  nop
  4.  nop 
  5.  nop
  6. }
т.е. вероятность что компиллер подумает это нах ненадо и выкинет! ;))) Как принудительно директивами это задать , в стиле:
Code:
  1. __asm {
  2. __отимизиатор_вЫключить
  3.  nop 
  4.  nop
  5.  nop 
  6.  nop
  7. __отимизиатор
_включить
}

я бы задал это в макросе и в конце нужных мне ф-ций его вставлял бы! А потом бы написал ф-цию поиска 0x90909090 и потом 0xC3 и копировал бы в файлом без учета B8 90 90 90 90 , а вставлял бы 0xC3

Вот примерно то что я хочу, осталось заставить компиллер MS Visual Studio 2005(8) Team Stuidio это захавать ))

Code:
  1. #define FUNC_FINISH               
  2.         __asm {                   
  3.         #pragma optimize("", off) 
  4.           nop                     
  5.           nop                     \  
  6.           nop                     
  7.           nop                     
  8.         #pragma optimize("", on)  
  9.         }

пока пришел к:
Code:
  1. #define FUNC_FINISH __asm _emit 0x90 __asm  _emit 0x90 __asm _emit 0x90 __asm  _emit 0x90
но как в этот же макросвставить отключение оптимизации и дальнейшее включение. Чтобы вставив один единственный FUNC_FINISH у меня генерировлось эта 90909090 и оптимизатор чтобы не выкидывал ее из кода!

-----
My love is very cool girl.




Ранг: 271.5 (наставник), 12thx
Активность: 0.150
Статус: Участник
Packer Reseacher

Создано: 27 августа 2008 22:26
· Личное сообщение · #19

На данном этапе у меня:
Code:
  1. #define FUNC_FINISH __asm { __asm _emit 0x90 __asm  _emit 0x90 __asm _emit 0x90 __asm  _emit 0x90 }
  2. /* много дури */
  3. #pragma optimize("", off)
  4. DWORD xMyFunc()
  5. {
  6. /* много кода */
  7.   } /* for i */
  8.   return(-1);
  9.   FUNC_FINISH
  10. }
  11. #pragma optimize("", on)

и получаю:
Code:
  1. ; 94 : return(-1);
  2.   000d5  83 c8 ff   or        eax, -1
  3.   000d8  eb 04          jmp         SHORT $LN9@xMyFunc
  4. ; 95 : FUNC_FINISH
  5.   000da  90                DB    -112               ; ffffff90H
  6.   000db  90                DB    -112               ; ffffff90H
  7.   000dc  90                DB    -112               ; ffffff90H
  8.   000dd  90                DB    -112               ; ffffff90H
  9. $LN9@xMyFunc:


Но вставляется тело ф-ции без оптимизации! А мне бы хотелось убрать только и только эти самые 0x90...

-----
My love is very cool girl.





Ранг: 126.7 (ветеран)
Активность: 0.140
Статус: Участник
#CCh

Создано: 28 августа 2008 06:34
· Личное сообщение · #20

Вычисляй размер функции в конце самой функции и пусть return его возвращает

-----
invoke OpenFire




Ранг: 271.5 (наставник), 12thx
Активность: 0.150
Статус: Участник
Packer Reseacher

Создано: 28 августа 2008 11:09
· Личное сообщение · #21

Ice-T Дааа, еще чего предложишь ? )

-----
My love is very cool girl.




Ранг: 253.9 (наставник)
Активность: 0.130
Статус: Участник

Создано: 28 августа 2008 14:07
· Личное сообщение · #22

какая-то странная затея это все. столько уже всего предложили, а что еще нужно?
"программно узнать размер функции на си" - мы говорим о функции, в которой нет ни одного CALL или JMP вне функции? Если функция своя-самописаная, к чему это все? Можно перевести в опкод и не морочиться. Если хочется все так оптимизировать, тогда искать по RETN или по сигнатуре. Ведь проект компилится одним компилем, так под него и подгонять!
Странная тема вообще

-----
MicroSoft? Is it some kind of a toilet paper?




Ранг: 271.5 (наставник), 12thx
Активность: 0.150
Статус: Участник
Packer Reseacher

Создано: 28 августа 2008 14:40
· Личное сообщение · #23

Tim
А подумать ? Для чего еще нужно писать ф-цию написанную на си и в файл ? Да и спрашивать не где нить на форуме по базам данных, а на реверсинге, где большинство тем это крипторы, пакеры, проты и всякая подобная лабудень !!! Видно же что пишется криптор или пакер! Совсем народ думать разучился!

>>столько уже всего предложили, а что еще нужно?
А чего конкертно-то предложили ? ты вот возьми напиши xGetProcAddress положи ее в peimage.cpp и ни где в проекте ее не используй!!! Т.е. не пиши строк вида: xGetProcAddress(hDll, DllFunc);
У меня лично компиллер при построении проекта в exe-шник не ложит то что не используется!!! Т.е. он оптимизирует и думает, раз не юзается,значит нафиг не надо!!! Почему мне это должно нравится ?
Вот и возникает вопрос как сделать так чтобы и сохранить оптимизацию ф-ции и чтобы размер можно было получить! Пока пришел к методу, что написал в посте #19. Но тут отключается оптимизация вообще, было бы идеально заставить компиллер не выкидывать ф-цию и оптимизировать, при этом вставляя в конец 0x90909090, но как это сделать ?

-----
My love is very cool girl.




Ранг: 253.9 (наставник)
Активность: 0.130
Статус: Участник

Создано: 28 августа 2008 19:31
· Личное сообщение · #24

theCollision
да это понятно, что пишется прот или пакер
просто мне интересно, почему нельзя перевести функу в опкоды и юзать так
ведь эта функция же будет писаться в защищаемый файл и там использоваться?!

ведь как-то писались и пишутся сотни протов и пакеров...

-----
MicroSoft? Is it some kind of a toilet paper?




Ранг: 271.5 (наставник), 12thx
Активность: 0.150
Статус: Участник
Packer Reseacher

Создано: 28 августа 2008 20:46
· Личное сообщение · #25

Tim
А если я багу в ф-ции допущу ? Поправлю и че опять перекомпилять, опять в бин вид, а потом в виде си ! Это не есть автоматизация процесса, куда правильней задать порядок ф-ций, что я ща и делаю ;)))

Есть опция в MS Visual Studio 2005 Team Suite, с названием "/ODER" ему надо дать на вход файлик порядка ф-ций, токо пока не пойму че и как делать ! Если порядок ф-ций будет таким каким я укажу, то логично что можно получить размер по Func2 - Func1

-----
My love is very cool girl.




Ранг: 271.5 (наставник), 12thx
Активность: 0.150
Статус: Участник
Packer Reseacher

Создано: 28 августа 2008 21:03 · Поправил: theCollision
· Личное сообщение · #26

Все, вроде как победил )))

Опишу действия, которые касаются MS Visual Studio 2005 Team Suite:
0. Делаем пробную компиляцию и ищем obj main.obj файл и юзая dumpbin /symbols получаем имена ф-ций, которые записываем в файл func_order.cfg в том порядке каком хотим!
1. В опциях проекта, для обеих версий и дебаг и релиз ищем Linker->Optimization->Funcion Order в него прописываем наш файл @func_order.cfg, также не удаляем COMDATs тамже ключик по выше!
>>COMDAT record запись в формате COFF , содержащая инициализируемый общий блок данных и делающая упакованные функции видимыми для компоновщика
3. В хидере cryptor.h к примеру пишем макрос:
Code:
  1. #define SIZE_OF_xFunc1 (DWORD)((BYTE*)Func2 - (BYTE*)Func1)

4. Пишем еще одну ф-цию:
Code:
  1. DWORD SizeOfFunction(IN BYTE* Func, IN DWORD SizeOfFunc)
  2. {
  3.   for (;SizeOfFunc > 0 && Func[SizeOfFunc-1] == 0xCC; )
  4.     SizeOfFunc--;
  5.   return SizeOfFunc;
  6. }

5. Дожидаемся полнолуния
6. Компилем, результат храним в надежной от затирания файла !

-----
My love is very cool girl.



 eXeL@B —› Программирование —› Как программно узнать размер функции написанной на си ?
:: Ваш ответ
Жирный  Курсив  Подчеркнутый  Перечеркнутый  {mpf5}  Код  Вставить ссылку 
:s1: :s2: :s3: :s4: :s5: :s6: :s7: :s8: :s9: :s10: :s11: :s12: :s13: :s14: :s15: :s16:


Максимальный размер аттача: 500KB.
Ваш логин: german1505 » Выход » ЛС
   Для печати Для печати