Сейчас на форуме: asfa, bartolomeo (+7 невидимых)

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

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

Создано: 07 июня 2012 16:15 · Поправил: Dim77
· Личное сообщение · #1

Существует две задачи.
1. Нужно добавить дополнительную строку инициализации данных в код, приведенный ниже. В этом коде в асме из той функции, куда нужно добавить строку вызываются другие функции. Учитывая, что у функций в декомпилированном ехе нет имен только адреса, то есть ли способ, как написать вызов функции по адресу в С++, который был бы эквивалентен call <address> в асме. Зачем это нужно - код гораздо понятнее и удобнее для последующих модификаций в С++ чем если писать дополнения в асме.
Т.е. нужно добавить строку типа:
Code:
  1. sub_57EDA6((int)&unk_8372C0, this, aL_human, aLrace_dbf);
по аналогии с кодом ниже. Но как правильно прописать вызов sub_57EDA6, если известен только адрес этой функции: 57EDA6?

2. В функции ниже есть ссылки на переменные - глобальные (захардкодированные) и переменные класса, которые инициализируются runtime. Глобальные переменные я заменил их значениями: т.е. вместо
Code:
  1. sub_57EDA6((int)&unk_8372C0, this, off_7AB380, off_7AB37C);
подставил:
Code:
  1. sub_57EDA6((int)&unk_8372C0, this, aL_human, aLrace_dbf);


Следующий шаг - что делать с переменными класса, под которые выделена память по адресу 8372C0 и т.д.

Идея такая - заменить адреса на произвольные (подходящие по смыслу) имена и заменить все функции, которые эти данные используют, прописав вместо unk_8372C0 - aLraceId_human, например. Т.к. это переменные класса this в этом примере, то сработает ли такой подход и возможно ли таким способом будет добавить переменную в этот класс?

Оригинальный код асма:

Code:
  1. _asm {
  2.  
  3.                         MOV EAX,006AFED0        Entry point    
  4.                         CALL <JMP.&MSVCRT._EH_prolog>              //Jump to msvcrt._EH_prolog        
  5.                         PUSH ECX             
  6.                         PUSH ESI             
  7.                         MOV ESI,ECX       
  8.                         XOR EAX,EAX       
  9.                         MOV DWORD PTR SS:[EBP-10],ESI       
  10.                         MOV DWORD PTR DS:[ESI+4],EAX         
  11.                         MOV DWORD PTR DS:[ESI+8],EAX         
  12.                         MOV DWORD PTR DS:[ESI+0C],EAX       
  13.                         MOV DWORD PTR DS:[ESI+10],EAX       
  14.                         MOV DWORD PTR DS:[ESI],OFFSET 006E7234       
  15.                         PUSH DWORD PTR DS:[7AB37C]                 //Arg4 = ASCII "LRace.dbf"         
  16.                         MOV DWORD PTR SS:[EBP-4],EAX                       
  17.                         PUSH DWORD PTR SS:[EBP+8]                          //Arg3 => [ARG.EBP+8]
  18.                         PUSH DWORD PTR SS:[EBP+0C]                         //Arg2 => [ARG.EBP+0C]
  19.                         PUSH ESI                                           //Arg1
  20.                         CALL 0057ED2E                              //Discipl2.0057ED2E       
  21.                         PUSH DWORD PTR DS:[7AB37C]                 //Arg4 = ASCII "LRace.dbf"         
  22.                         PUSH DWORD PTR DS:[7AB380]                         //Arg3 = ASCII "L_HUMAN"
  23.                         PUSH ESI                                           //Arg2
  24.                         PUSH OFFSET 008372C0                               //Arg1 = Discipl2.8372C0
  25.                         CALL 0057EDA6                              //Discipl2.0057EDA6       
  26.                         PUSH DWORD PTR DS:[7AB37C]                // /Arg4 = ASCII "LRace.dbf"        
  27.                         PUSH DWORD PTR DS:[7AB384]                         //Arg3 = ASCII "L_DWARF"
  28.                         PUSH ESI                                           //Arg2
  29.                         PUSH OFFSET 008372E0                               //Arg1 = Discipl2.8372E0
  30.                         CALL 0057EDA6                             // \Discipl2.0057EDA6      
  31.                         PUSH DWORD PTR DS:[7AB37C]                 ///Arg4 = ASCII "LRace.dbf"        
  32.                         PUSH DWORD PTR DS:[7AB388]                 //      Arg3 = ASCII "L_HERETIC"
  33.                         PUSH ESI                                  //       Arg2
  34.                         PUSH OFFSET 008372D0                       //      Arg1 = Discipl2.8372D0
  35.                         CALL 0057EDA6                             // \Discipl2.0057EDA6      
  36.                         PUSH DWORD PTR DS:[7AB37C]                 ///Arg4 = ASCII "LRace.dbf"        
  37.                         PUSH DWORD PTR DS:[7AB38C]                 //      Arg3 = ASCII "L_UNDEAD"
  38.                         PUSH ESI                                   //      Arg2
  39.                         PUSH OFFSET 00837290                      //       Arg1 = Discipl2.837290
  40.                         CALL 0057EDA6                             // \Discipl2.0057EDA6      
  41.                         PUSH DWORD PTR DS:[7AB37C]                // /Arg4 = ASCII "LRace.dbf"        
  42.                         PUSH DWORD PTR DS:[7AB390]                //       Arg3 = ASCII "L_NEUTRAL"
  43.                         PUSH ESI                                  //       Arg2
  44.                         PUSH OFFSET 008372B0                      //       Arg1 = Discipl2.8372B0
  45.                         CALL 0057EDA6                             // \Discipl2.0057EDA6      
  46.                         PUSH DWORD PTR DS:[7AB37C]                // /Arg4 = ASCII "LRace.dbf"        
  47.                         PUSH DWORD PTR DS:[7AB394]                //       Arg3 = ASCII "L_ELF"
  48.                         PUSH ESI                                  //       Arg2
  49.                         PUSH OFFSET 008372A0                       //      Arg1 = Discipl2.8372A0
  50.                         CALL 0057EDA6                              //\Discipl2.0057EDA6      
  51.                         MOV ECX,ESI       
  52.                         CALL 0057ECE9   
  53.                         MOV ECX,DWORD PTR SS:[EBP-0C]       
  54.                         MOV EAX,ESI       
  55.                         MOV DWORD PTR FS:[0],ECX                 
  56.                         POP ESI               
  57.                         LEAVE          
  58.                         RETN 8
  59. }


Код, сгенеренный HRay (можно и самому, но так удобнее для начала):

Code:
  1. int __thiscall sub_57EB99(int this, char *Dir, int a3)
  2. {
  3.   int v3; // esi@1
  4.  
  5.   v3 = this;
  6.   *(_DWORD *)(this + 4) = 0;
  7.   *(_DWORD *)(this + 8) = 0;
  8.   *(_DWORD *)(this + 12) = 0;
  9.   *(_DWORD *)(this + 16) = 0;
  10.   *(_DWORD *)this = &off_6E7234;
  11.   sub_57ED2E(this, a3, Dir, (char *)off_7AB37C);
  12.   sub_57EDA6((int)&unk_8372C0, v3, off_7AB380, off_7AB37C);
  13.   sub_57EDA6((int)&unk_8372E0, v3, off_7AB384, off_7AB37C);
  14.   sub_57EDA6((int)&unk_8372D0, v3, off_7AB388, off_7AB37C);
  15.   sub_57EDA6((int)&unk_837290, v3, off_7AB38C, off_7AB37C);
  16.   sub_57EDA6((int)&unk_8372B0, v3, off_7AB390, off_7AB37C);
  17.   sub_57EDA6((int)&unk_8372A0, v3, off_7AB394, off_7AB37C);
  18.   sub_57ECE9(v3);
  19.   return v3;
  20. }



Мой код переделанной функции (в процессе, еще не решил, что делать с *(_DWORD *)this = &off_6E7234; - не смотрел еще что по адресу 6E7234 находится и sub_57ED2E(this, a3, Dir, (char *)aLrace_dbf); еще не изучал):

Code:
  1.  
  2. #define aL_green "L_Green" // новая глобальная переменная
  3.  
  4. int __thiscall sub_57EB99(int *this, char *Dir, int a3)
  5. {
  6.  
  7. int aLraceId_human = 0;
  8. int aLraceId_dwarf = 0;
  9. int aLraceId_heretic = 0;
  10. int aLraceId_undead =0;
  11. int aLraceId_neutral =0;
  12. int aLraceId_elf =0;
  13.  
  14. aLraceId_green =0; // добавленная переменная
  15.  
  16.   *(_DWORD *)this = &off_6E7234;
  17.  
  18.   sub_57ED2E(this, a3, Dir, (char *)aLrace_dbf);
  19.   sub_57EDA6( aLraceId_human, this, aL_human, aLrace_dbf);
  20.   sub_57EDA6( aLraceId_dwarf, this, aL_dwarf, aLrace_dbf);
  21.   sub_57EDA6(aLraceId_heretic, this, aL_heretic, aLrace_dbf);
  22.   sub_57EDA6(aLraceId_undead, this, aL_undead, aLrace_dbf);
  23.   sub_57EDA6(aLraceId_neutral, this, aL_neutral, aLrace_dbf);
  24.   sub_57EDA6(aLraceId_elf, this, aL_elf, aLrace_dbf);
  25.  sub_57EDA6(aLraceId_green, this, aL_green, aLrace_dbf); // добавленная строка.
  26.  
  27.   sub_57ECE9(*this);
  28.   return *this;
  29. }





Ранг: 1053.6 (!!!!), 1078thx
Активность: 1.060.81
Статус: Участник

Создано: 07 июня 2012 16:45 · Поправил: reversecode
· Личное сообщение · #2

this всегда ходит первым параметром
или через стек, если это gcc
или через ecx если это ms$

так что правильно все для начала поразбирай
и четко формулируй вопросы, а то в рассуждениях теряется мысль



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

Создано: 07 июня 2012 23:08
· Личное сообщение · #3

reversecode пишет:
this всегда ходит первым параметром

Хмм, в случае с sub_57EDA6 видно, что он второй. По комментам к аргументам в асме это то же видно.

Code:
  1.                PUSH DWORD PTR DS:[7AB37C]                // /Arg4 = ASCII "LRace.dbf"        
  2.                         PUSH DWORD PTR DS:[7AB394]                //       Arg3 = ASCII "L_ELF"
  3.                         PUSH ESI                                                //       Arg2
  4.                         PUSH OFFSET 008372A0                       //      Arg1 = Discipl2.8372A0
  5.                         CALL 0057EDA6                              //\Discipl2.0057EDA6


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

reversecode пишет:
и четко формулируй вопросы, а то в рассуждениях теряется мысль


1. Какой эквивалент в С++ вызову функции по адресу: call 57EDA6? Имени функции нет, только адрес 57EDA6. Вместо sub_57EDA6 что в С++ писать?

2. Сработает ли переименование адресов переменных (int)&unk_8372C0 в поименованные переменные типа aLraceId_human, если такая замена будет произведена во всех функциях, которые использовали адреса (int)&unk_8372C0?

3. Можно ли расширять класс, добавляя ему переменную при помощи строки:
Code:
  1. sub_57EDA6(aLraceId_green, this, aL_green, aLrace_dbf);


Где aLraceId_green - новая переменная.

ЗЫ По идее, должно сработать, ибо функция sub_57EDA6 выделяет под эту переменную память и записывает туда ее значение. Но я не уверен, как в асме происходит инициализация класса, и достаточно ли того, что я выше написал, чтобы вставить туда дополнительную переменную.




Ранг: 331.1 (мудрец), 561thx
Активность: 0.190.06
Статус: Участник

Создано: 07 июня 2012 23:49 · Поправил: Vamit
· Личное сообщение · #4

Вместо sub_57EDA6 что в С++ писать?
Что за странный вопрос - реверсом что-ли не занимался? Если не можешь придумать имя функции по смыслу её действия, то так и пиши - sub_57EDA6(ля..., ля..., ля...), по крайней мере будет соответствовать Иде - не заблудишься, а переименовать в любое время можно, только делай это одновременно в отреверсенном коде и в Иде.

sub_57EDA6(aLraceId_green, this, aL_green, aLrace_dbf);
а вот это уже почти бред, так никто не пишет, причем учти, что компиляторы VisualStudio не ниже 2008 this могуть передать в любую функцию как любым аргументом, так и любым регистром, поэтому, если распознал, что это действительно this, то делай функцию членом класса, а не тыкай this в аргументы.

Но по вашей логике - рано вам ещё заниматься реверсом...

-----
Everything is relative...





Ранг: 1053.6 (!!!!), 1078thx
Активность: 1.060.81
Статус: Участник

Создано: 08 июня 2012 00:06 · Поправил: reversecode
· Личное сообщение · #5

Dim77 пишет:
Хмм, в случае с sub_57EDA6 видно, что он второй. По комментам к аргументам в асме это то же видно.

значит это не this, либо ты нетак его разобрал
this в MSVC ходит прямо через ecx минуя стек
бывают конечно исключения, но они исключительные
большинство же прог скомпилены стандартно, this-ecx

углубись вообщем во все дерево функций которые идет вниз после перых функций что ты привел


Code:
  1.  *(_DWORD *)this = &off_6E7234;

vtbl класса там




Ранг: 527.7 (!), 381thx
Активность: 0.160.09
Статус: Участник
Победитель турнира 2010

Создано: 08 июня 2012 01:21
· Личное сообщение · #6

--> Reversing C++ <-- для чтения на досуге.

-----
127.0.0.1, sweet 127.0.0.1


| Сообщение посчитали полезным: Dim77, plutos, mak, _ruzmaz_

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

Создано: 08 июня 2012 01:32 · Поправил: Dim77
· Личное сообщение · #7

Vamit пишет:
Если не можешь придумать имя функции по смыслу её действия, то так и пиши - sub_57EDA6(ля..., ля..., ля...)

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

Т.е. попробую еще раз: я изменяю функцию sub_57EB99. Ее я либо так оставлю, либо переименую. Тут все понятно.

Из функции sub_57EB99 происходит вызов sub_57EDA6. sub_57EDA6 я переписывать не хочу. Хочу оставить ее такой, какая она есть в уже скомпиленном ехе. О sub_57EDA6 мне известен ее статический адрес в ехе, который естесственно: 0057EDA6

Вопрос: Как мне по этому адресу вызвать функцию в С++? sub_57EDA6 как мы все понимаем не прокатит, т.к. такой функции нет, если я ее не определю сам. Можно ли обратиться к функции только по ее адресу?

ЗЫ можно было бы, конечно, в своей длл прописать функцию sub_57EDA6 ничего там не меняя, просто взять и вставить туда асм из ехе с адреса 57EDA6. Тогда вызов sub_57EDA6 замечательно бы сработал. Но таким образом моя длл превратится в копию ехе с большей частью асма скопированного из ехе в длл. Вопрос собственно был в том, чтобы такого не делать, по возможности.

reversecode пишет:
большинство же прог скомпилены стандартно, this-ecx

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



Ранг: 11.9 (новичок), 22thx
Активность: 0.010
Статус: Участник

Создано: 08 июня 2012 05:56 · Поправил: TOM_RUS
· Личное сообщение · #8

Dim77 пишет:
Вопрос: Как мне по этому адресу вызвать функцию в С++? sub_57EDA6 как мы все понимаем не прокатит, т.к. такой функции нет, если я ее не определю сам. Можно ли обратиться к функции только по ее адресу?


Про function pointers слышали? Помоему это то что Вы ищите...

http://paste2.org/p/2048284

| Сообщение посчитали полезным: Dim77

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

Создано: 08 июня 2012 13:27
· Личное сообщение · #9

TOM_RUS пишет:
Помоему это то что Вы ищите...

Да, это оно Спасибо.




Ранг: 1053.6 (!!!!), 1078thx
Активность: 1.060.81
Статус: Участник

Создано: 08 июня 2012 14:03 · Поправил: reversecode
· Личное сообщение · #10

Dim77 ты же здесь
http://exelab.ru/f/action=vthread&forum=5&topic=19932&page=0#12
тоже самое делал, указатель на фукцию
там знал, а здесь забыл?



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

Создано: 09 июня 2012 01:23
· Личное сообщение · #11

reversecode пишет:
там знал, а здесь забыл?
Просто замкнуло... Меня на sub_<address> зациклило. В голове почему-то только вариант с копированием асма вертелся.



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

Создано: 10 июня 2012 16:50 · Поправил: Dim77
· Личное сообщение · #12

reversecode пишет:
большинство же прог скомпилены стандартно, this-ecx

В ecx - адрес, по этому адресу
Code:
  1. *(_DWORD *)this = &off_6E7234;
записывает значение. Затем это значение передается 2-м параметром в
Code:
  1.  sub_57EDA6( aLraceId_dwarf, this, aL_dwarf, aLrace_dbf);


Т.е., если принять, что это vtbl, то таким образом он и передается функции sub_57EDA6, что в общем-то логично.

Как, кстати, прописать в С передачу параметра через ecx? Или нужно вызывающую функцию поменять, чтобы можно было вызываемую функцию задекларировать как thiscall c последующей передачей this как первого параметра?
По типу:
Code:
  1.     typedef void (__thiscall *t)(ClassObjPtr*, int);
  2.     t f = (t)0x809200;
  3.     f(this, arg2);




Ранг: 481.4 (мудрец), 109thx
Активность: 0.180
Статус: Участник
Тот самый :)

Создано: 12 июня 2012 19:25 · Поправил: Hexxx
· Личное сообщение · #13

Dim77 пишет:
Как, кстати, прописать в С передачу параметра через ecx?

thiscall - это псевдо конвенция о которой знает только IDA. По-хорошему нужно класс объявить с виртуальным методом и перегрузить. Ну или __fastcall юзать если это MSVC. Сишный фасткол - это будет ecx, edx, стек. Так что придется поддельный аргумент в edx запихивать.

-----
Реверсивная инженерия - написание кода идентичного натуральному




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

Создано: 13 июня 2012 16:21
· Личное сообщение · #14

Hexxx пишет:
По-хорошему нужно класс объявить с виртуальным методом и перегрузить.

Т.е. нужно переписать существующий класс. Было бы, конечно, здорово, хотя и не тривиально, учитывая, что в реверсинге я такого еще не делал...

Hexxx пишет:
Сишный фасткол - это будет ecx, edx, стек
Тут понятно. Попробую.



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

Создано: 27 июня 2012 01:14 · Поправил: Dim77
· Личное сообщение · #15

Hexxx пишет:
Ну или __fastcall юзать если это MSVC. Сишный фасткол - это будет ecx, edx, стек.

Короче говоря, написал, используя fastcall.

Почти работает, но почти как известно не считается. Ниже кусок кода до вызова первой функции. В эту функцию VtblPtr_proc (0057ED2E) аргументы передаются такими, какими они должны быть, только стек отличается от оригинального. Внутри этой функции все идет нормально до тех пор пока не вызывается функция, которая использует первый аргумент. На этом месте по адресу первого аргумента со смещением записывается какая-то ерунда вместо того, чтобы собственно использовать сам адрес.

Подозрения три -
1. я что-то накосячил с первым аргументом 0057ED2E
2. Порушился стек каким-то образом
3. Тип функции 0057ED2E должен быть другим (в Иде она stdcall)

Code:
  1.  
  2. typedef void(* LraceSetInitPtr)(DWORD, DWORD *, char*, char*);
  3. typedef void(__stdcall * VtblPtrPtr )(DWORD*, int*, char*, char*);
  4.  
  5. VtblPtrPtr VtblPtr_proc = (VtblPtrPtr)(0x0057ED2E);
  6. DWORD off_6E7234 = (DWORD)(0x006E7234);
  7.  
  8.  
  9. extern "C" __declspec(dllexport) int __fastcall LraceIDInit_proc(DWORD *Lrace_vtbl, DWORD *a1, char *Dir, int *some_address)
  10. {
  11.  
  12. int aLraceId_human = 0;
  13. int aLraceId_dwarf = 0;
  14. int aLraceId_heretic = 0;
  15. int aLraceId_undead =0;
  16. int aLraceId_neutral =0;
  17. int aLraceId_elf =0;
  18. int aLraceId_green =0; // добавленная переменная
  19.  
  20.  
  21.  
  22.   *(DWORD *)Lrace_vtbl = off_6E7234;
  23.   
  24.   VtblPtr_proc(Lrace_vtbl, some_address, Dir, "LRace.dbf");

Это по идее должно было заменой коду:
Code:
  1. MOV EAX,006AFED0        Entry point    
  2.                         CALL <JMP.&MSVCRT._EH_prolog>              //Jump to msvcrt._EH_prolog        
  3.                         PUSH ECX             
  4.                         PUSH ESI             
  5.                         MOV ESI,ECX       
  6.                         XOR EAX,EAX       
  7.                         MOV DWORD PTR SS:[EBP-10],ESI       
  8.                         MOV DWORD PTR DS:[ESI+4],EAX         
  9.                         MOV DWORD PTR DS:[ESI+8],EAX         
  10.                         MOV DWORD PTR DS:[ESI+0C],EAX       
  11.                         MOV DWORD PTR DS:[ESI+10],EAX       
  12.                         MOV DWORD PTR DS:[ESI],OFFSET 006E7234       
  13.                         PUSH DWORD PTR DS:[7AB37C]                 //Arg4 = ASCII "LRace.dbf"         
  14.                         MOV DWORD PTR SS:[EBP-4],EAX                       
  15.                         PUSH DWORD PTR SS:[EBP+8]                          //Arg3 => [ARG.EBP+8]
  16.                         PUSH DWORD PTR SS:[EBP+0C]                         //Arg2 => [ARG.EBP+0C]
  17.                         PUSH ESI                                           //Arg1
  18.                         CALL 0057ED2E                              //Discipl2.0057ED2E




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

Создано: 27 июня 2012 01:30
· Личное сообщение · #16

пользуйся вкладкой Править а не плоди посты)



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

Создано: 10 июля 2012 00:30 · Поправил: Dim77
· Личное сообщение · #17

CTPaHHuk пишет:
пользуйся вкладкой Править а не плоди посты)
Хотелось отделить предыдущие изыскания от так сказать результатов долгого последующего труда... =)

В общем, дальнейшие прогоны с разными вариантами функции показывают, что здесь: *(DWORD *)Lrace_vtbl = off_6E7234; записывается какая-то хрень. Т.е. в базовой функции вроде бы это указатель на нужный объект, а в вызываемой по адресу Lrace_vtbl записывается левое значение. Откуда он там берется - неясно (пока что). Был бы благодарен за подсказку как подправить С++ код, чтобы указатель Lrace_vtbl нормально работал. Код функции выше.

Удалось реализовать функцию при помощи нового класса. В решении ниже vtbl записывается в thisptr->vtbl, что очевидно не то же самое, что *(DWORD *) Lrace_vtbl = off_6E7234; в решении с fastcall. Плюс еще пришлось привести thiscall к stdcall. Осталась одна деталь. Последняя функция: sub_57ECE9(thisptr) является thiscall и выпадает по исключению.

Решение было найдено. Функция успешно реверсирована. Тему закрываю.


 eXeL@B —› Вопросы новичков —› Как вызывать функции по адресу?
Эта тема закрыта. Ответы больше не принимаются.
   Для печати Для печати