Раскрутка стека вызовов в MU online: бэктрейс процедурных вызовов, рассказываем, как это делать | MU

Автор 7mm, 2010 Дек. 06, 22:55

« назад - далее »

0 Пользователи и 2 гостей просматривают эту тему.

Ключевые слова [SEO] mu onlineраскрутка стека вызововбэктрейспроцедур

7mm

Иногда бывает полезно знать последовательность вызовов процедур, результатом которой явился запуск целевой функции. Эту информацию можно узнать, используя раскрутку стековых фреймов в том случае, если в стеке были сформированы стандартные EBP-based стековые фреймы. Следующий код осуществляет данное действие:

debug.h
typedef struct tagSTACK_FRAME
{
ULONG Ebp;
ULONG Eip;
} STACK_FRAME, *PSTACK_FRAME;

#define GET_REG_VALUE(x,reg)    __asm mov x, reg

VOID DbgPrintCallTrace(PCHAR pStrName)

debug.c
VOID DbgPrintCallTrace(PCHAR pStrName)
{
PSTACK_FRAME pStackFrame;

GET_REG_VALUE(pStackFrame, ebp);

DWORD dwStackBase, dwStackLimit;

GetStackLimits(&dwStackBase, &dwStackLimit);

DbgPrint("CALL TRACE (%s)n",
pStrName ? pStrName : "NULL");

DbgPrint(" Stack:%p-%p, Thread:%dn",
dwStackLimit, dwStackBase, GetCurrentThreadId());

pStackFrame = (PSTACK_FRAME)pStackFrame->Ebp;
while ((DWORD)pStackFrame >= dwStackLimit && (DWORD)pStackFrame < dwStackBase) {
DbgPrint("  <ebp>=%p, <eip>=%pn", pStackFrame, pStackFrame->Eip);
pStackFrame = (PSTACK_FRAME)pStackFrame->Ebp;
}
}

И код GetStackLimits:
void GetStackLimits(LPDWORD pStackBase, LPDWORD pStackLimit)
{
__asm {
mov eax, fs:0x04
mov ecx, pStackBase
mov [ecx], eax
mov eax, fs:0x08
mov ecx, pStackLimit
mov [ecx], eax
}
}

В качестве примера, продемонстрирую следующее применение. В клиенте в одном единственном месте используется импортируемая функция TextOutA:

.text:0042B3A0 sub_42B3A0      proc near
.text:0042B3B6                ...
.text:0042B3B7                call    ds:TextOutA
.text:0042B3BD                ...
.text:0042B3BE sub_42B3A0      endp

.text:0041F163 sub_41F163      proc near
.text:0041F4B2                ...
.text:0041F4B3                call  sub_42B3A0
.text:0041F4B8                ...
.text:0041F5CB sub_41F163      endp

.rdata:008DFF9C                ...
.rdata:008DFFA0                dd offset sub_41F163
.rdata:008DFFA4                ...


Если в IDA проследить откуда происходит её вызов, то получается следующее:
sub_41F163 -> sub_42B3A0 -> TextOutA

При этом, sub_41F163, являясь методом класса, явно ни откуда не вызывается:
.rdata:008DFF9C                ...
.rdata:008DFFA0                dd offset sub_41F163
.rdata:008DFFA4                ...

Предложенный подход позволяет получить информацию, о местах вызова функции sub_42B3A0 и, соответственно, вызывающей её функций sub_41F163.

Для этого, достаточно перехватить вызов функции sub_42B3A0:
DECLARE_HOOK(SUB_42B3A0, HDC hdc, int x, int y, LPCSTR lpString, int c)
{
DbgPrintCallTrace(__FUNCTION__);

return RealSUB_42B3A0(hdc, x, y, lpString, c);
}

В результате, на консоль будет выведена информация подобного рода:
CALL TRACE (SUB_42B3A0)
Stack:0010D000-00130000, Thread:556
<ebp>=0012D1C8, <eip>=0041EB69
<ebp>=0012D2F0, <eip>=00403137
<ebp>=0012D234, <eip>=00499926
<ebp>=0012D248, <eip>=00414FB2
<ebp>=0012D258, <eip>=004998CF
<ebp>=0012D264, <eip>=00476318
<ebp>=0012D278, <eip>=00626643

Это трейс одного из вариантов вызовов метода класса. По адресу 0041EB69 (loc_41EB69) будет косвенный вызов интересующего нас метода:
.text:0041EB66                call    dword ptr [eax+2Ch] ; sub_41F163
.text:0041EB69
.text:0041EB69 loc_41EB69:
.text:0041EB69                mov    esp, ebp

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

user_MU


7mm

Цитата: user_MU от 2010 Дек. 07, 20:36  При неявном вызове пользую retn.
Но все равно спасибо.

Ну в общем-то данный метод может быть полезен при осуществлении реверсинга программ, написанных на ЯВУ. А что вы в своём коде делаете - это ваши проблемы ;)

Похожие темы (5)

Сообщений: 37
Просмотров: 22934

Сообщений: 127
Просмотров: 40408

Сообщений: 32
Просмотров: 13877