ASM - расширение функции своим кодом

assembler ASM


Примечание:
Делаю вставку собственного куска кода в функцию формирования отладочных сообщений - Msg.
Назначение моей вставки - писать отладочное сообщение(содержимое DstBuf) в файл c:\paranoid.log,
при каждом вызове функции Msg. Для вставки в dll добавляется новая секция NewSect, с размерностью == 1000,
защита отсутствует.

ПРОБЛЕМА: После компилляции программа не запускается.Помогите дописать мою вставку кода до рабочего состояния.
Подозреваю, что нужно привести стэк в, нужное состояние, как это сделать я не знаю. Было бы не плохо, если
кто-нибудь, на данном примере пояснил принципы работы со стэком: как просмотреть текущее состояние, какое
должно быть состояние на выходе из функции?

ДОПОЛНЕНИЕ: После вставки моего кода в функцию Msg, Msg, судя по псевдокоду, сменила тип void на int.

Примечание:
КУСОК КОДА ИЗ IdaPro:

.text:10018640 ; int __cdecl Msg(char *Format, char ArgList)
.text:10018640 public ?Msg@@YAXPBDZZ
.text:10018640 ?Msg@@YAXPBDZZ proc near ; CODE XREF: CTimerBase::Dump(void)+16p
.text:10018640 ; CTimer::Dump(void)+16p ...
.text:10018640
.text:10018640 DstBuf = byte ptr -400h
.text:10018640 var_1 = byte ptr -1
.text:10018640 Format = dword ptr 4
.text:10018640 ArgList = byte ptr 8
.text:10018640
.text:10018640 ; FUNCTION CHUNK AT .NewSect:10150016 SIZE 00000035 BYTES
.text:10018640
.text:10018640 sub esp, 400h
.text:10018646 mov ecx, [esp+400h+Format]
.text:1001864D lea eax, [esp+400h+ArgList]
.text:10018654 push eax ; ArgList
.text:10018655 push ecx ; Format
.text:10018656 lea edx, [esp+408h+DstBuf]
.text:1001865A push 3FFh ; MaxCount
.text:1001865F push edx ; DstBuf
.text:10018660 call ds:_vsnprintf
.text:10018666 add esp, 10h
.text:10018669 test eax, eax
.text:1001866B mov [esp+400h+var_1], 0
.text:10018673 jz short loc_10018681
.text:10018675 lea eax, [esp+400h+DstBuf]
.text:10018678 push eax
.text:10018679 jmp loc_10150016 : *РАСШИРЕНИЕ Msg НОВЫМ КУСКОМ
.text:1001867E ; ---------------------------------------------------------------------------
.text:1001867E nop
.text:1001867F nop
.text:10018680 nop
.text:10018681
.text:10018681 loc_10018681: ; CODE XREF: Msg(char const *,...)+33j
.text:10018681 ; Msg(char const *,...)+137A06j
.text:10018681 add esp, 400h
.text:10018687 retn
.text:10018687 ?Msg@@YAXPBDZZ endp ; sp-analysis failed

Примечание:
МОЯ ВСТАВКА КОДА:

.NewSect:10150000 ; char aA[2]
.NewSect:10150000 aA db 'a',0 ; DATA XREF: Msg(char const *,...)+1379E0o
.NewSect:10150002 ; char aCParanoid_log[]
.NewSect:10150002 aCParanoid_log db 'c:\paranoid.log',0 ; DATA XREF: Msg(char const *,...)+1379E5o
.NewSect:10150012 ; char aS_4[]
.NewSect:10150012 aS_4 db '%s',0Ah,0 ; DATA XREF: Msg(char const *,...)+1379F3o
.NewSect:10150016 ; ---------------------------------------------------------------------------
.NewSect:10150016 ; START OF FUNCTION CHUNK FOR ?Msg@@YAXPBDZZ
.NewSect:10150016
.NewSect:10150016 loc_10150016: ; CODE XREF: Msg(char const *,...)+39j
.NewSect:10150016 mov ebx, eax
.NewSect:10150018 call ?Log@@YAXPBD@Z ; Log(char const *) *ТО ЧТО БЫЛО ВЫРЕЗАНО ПОД jmp loc_10150016
.NewSect:1015001D add esp, 4 ; *ТО ЧТО БЫЛО ВЫРЕЗАНО ПОД jmp loc_10150016
.NewSect:10150020 push offset aA ; "a"
.NewSect:10150025 push offset aCParanoid_log ; "c:\\paranoid.log"
.NewSect:1015002A call ds:fopen
.NewSect:10150030 mov esi, eax
.NewSect:10150032 push ebx
.NewSect:10150033 push offset aS_4 ; "%s\n"
.NewSect:10150038 push esi ; File
.NewSect:10150039 call ds:fprintf
.NewSect:1015003F push esi ; File
.NewSect:10150040 call ds:fclose
.NewSect:10150046 jmp loc_10018681
.NewSect:10150046 ; END OF FUNCTION CHUNK FOR ?Msg@@YAXPBDZZ
.NewSect:10150046 ; ---------------------------------------------------------------------------
.NewSect:1015004B align 1000h

Примечание:
ПРСЕВДОКОД:

int Msg(const char *Format, ...)
{
int result; // eax@1
FILE *v2; // esi@2
char DstBuf; // [sp+0h] [bp-400h]@1
char v4; // [sp+3FFh] [bp-1h]@1
va_list va; // [sp+408h] [bp+8h]@1

va_start(va, Format);
result = vsnprintf(&DstBuf, 0x3FFu, Format, va);
v4 = 0;
if ( result )
{
Log(&DstBuf);
v2 = fopen("c:\\paranoid.log", "a"); МОЯ ВСТАВКА
fprintf(v2, "%s\n", &DstBuf); МОЯ ВСТАВКА
result = fclose(v2); МОЯ ВСТАВКА
}
return result;
}

Примечание:
@ none7

> loc_10150016: ; CODE XREF: Msg(char const *,...)+39j
> call ?Log@@YAXPBD@Z ; Log(char const *)
> push eax
> push offset aA ; "a"
> push offset aCParanoid_log ; "c:\\paranoid.log"
> call ds:fopen
> push dword ptr ss:[esp+12]
> push offset aS_4 ; "%s\n"
> push eax ; File
> call ds:fprintf
> call ds:fclose
> mov eax, [esp+20]
> add esp, 28
> jmp loc_10018681

СПАСИБО за помощь, но что-то не хочет работать.
Псевдокод после компиляции и декомпиляции какой-то неправильный получается:

int Msg(const char *Format, ...)
{
int result; // eax@1
int v2; // eax@2
int v3; // ST14_4@2
FILE *v4; // eax@2
int v5; // ST18_4@2
FILE *v6; // ST00_4@2
char DstBuf; // [sp+8h] [bp-400h]@1
char v8; // [sp+407h] [bp-1h]@1
va_list va; // [sp+410h] [bp+8h]@1

va_start(va, Format);
result = vsnprintf(&DstBuf, 0x3FFu, Format, va);
v8 = 0;
if ( result )
{
Log(&DstBuf);
v3 = v2;
v4 = fopen("c:\\paranoid.log", "a");
fprintf(v4, "%s\n", v5);
fclose(v6);
result = v3;
}
return result;
}

Примечание:
@ none7

> Так не работает или псевдокод странный.

Не работает, но последний вариант кода даёт более логичный псевдокод:

int Msg(const char *Format, ...)
{
int result; // eax@1
int v2; // eax@2
int v3; // edi@2
FILE *v4; // esi@2
char DstBuf; // [sp+0h] [bp-400h]@1
char v6; // [sp+3FFh] [bp-1h]@1
va_list va; // [sp+408h] [bp+8h]@1

va_start(va, Format);
result = vsnprintf(&DstBuf, 0x3FFu, Format, va);
v6 = 0;
if ( result )
{
Log(&DstBuf);
v3 = v2;
v4 = fopen("c:\\paranoid.log", "a");
fprintf(v4, "%s\n", &DstBuf);
fclose(v4);
result = v3;
}
return result;
}

Непонятно почему функция опять меняет тип void на int?
Если ?Log@@YAXPBD@Z так же имеет тип void, то в eax что-то пишется?
А ещё, почему add esp, 28? Так как pop edi pop esi pop ebx?

Примечание:
@ 7none

> Проблема точно в коде? Будет ли работать, если заменить на:
> call ?Log@@YAXPBD@Z
> add esp, 4
> jmp loc_10018681

Проблема точно в коде, как указано выше работает, т.е этот кусок переносится в новую секцию в dll - всё компилится и работает. Так же удалял call ?Log@@YAXPBD@Z - тоже работает, родной лог естественно перестаёт выводиться..

Примечание:
Естественно пустой файл paranoid.log лежит в корне диска C:\

Примечание:
Кажется локализовал проблемный кусок кода. Если убрать часть с fopen fprintf fclose, то дллка компилится и приложение запускается:

loc_10150016: ; CODE XREF: Msg(char const *,...)+39j
pop eax
push ebx
push esi
push edi
mov ebx, eax
push eax ; char *
call ?Log@@YAXPBD@Z ; Log(char const *)
mov edi, eax
add esp, 4
mov eax, edi
pop edi
pop esi
pop ebx
jmp loc_10018681

Если только добавить fopen - после компиляции длл, приложение уже не запускается:

loc_10150016: ; CODE XREF: Msg(char const *,...)+39j
pop eax
push ebx
push esi
push edi
mov ebx, eax
push eax ; char *
call ?Log@@YAXPBD@Z ; Log(char const *)
mov edi, eax
push offset aA ; "a"
push offset aCParanoid_log ; "c:\\paranoid.log"
call ds:fopen
add esp, 0Ch
mov eax, edi
pop edi
pop esi
pop ebx
jmp loc_10018681

Наверное всё-таки дело в компиляции, хотя в других проектах проблем с ней не возникало.
Есть ли какие соображения из-за чего это может происходить?
Хотя и так СПАСИБО за помощь: поставил Лучший Ответ.
Ответы:
Ты запихнул в стек 6 параметров, Сишные функции(с __cdecl) не выталкивают эти параметры, об восстановлении стека должна заботится вызывающая функция, соответственно перед возвращением в оригинальную функцию необходимо выполнить инструкцию add esp, 24; 6*4. Но это не всё, Сишная функция должна вернуть регистры ebx, esi, edi, ebp, в состояние в котором они находились при входе в функцию. Оригинальная функция не сохраняет и не восстанавливает регистры ebx и esi, а твоя вставка меняет их значения, в итоге вызывающая функция получит в этих регистрах мусор.
Да и весьма желательно, чтобы eax на выходе из твоей вставки соответствовал значению eax полученному от ?Log@@YAXPBD@Z.


13 лет назад

RPI.su - самая большая русскоязычная база вопросов и ответов. Наш проект был реализован как продолжение популярного сервиса otvety.google.ru, который был закрыт и удален 30 апреля 2015 года. Мы решили воскресить полезный сервис Ответы Гугл, чтобы любой человек смог публично узнать ответ на свой вопрос у интернет сообщества.

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

Чтобы связаться с нами по любому вопросу О САЙТЕ (реклама, сотрудничество, отзыв о сервисе), пишите на почту [email protected]. Только все общие вопросы размещайте на сайте, на них ответ по почте не предоставляется.