Форум АНТИЧАТ

Форум АНТИЧАТ (https://forum.antichat.xyz/index.php)
-   С/С++, C#, Delphi, .NET, Asm (https://forum.antichat.xyz/forumdisplay.php?f=24)
-   -   Проблема с выделением памяти в заинжекченом процессе (https://forum.antichat.xyz/showthread.php?t=53946)

razzzar 19.11.2007 21:10

Проблема с выделением памяти в заинжекченом процессе
 
Есть программа, которая инжектирует свой код в svchost.exe
Выполняет в нем какой-то код, а потом выполняет действия наподобии этих:
Код:

char * szData = (char *) malloc(GetFileSize(hFile, NULL));
...
free(szData);

Так вот работает все отлично, но как только доходит до выделения памяти выкидует сообщение о ошибке и просьбе отослать отчет в Microsoft. Кто знает с чем связано?

ZaCo 19.11.2007 23:01

>>Есть программа, которая инжектирует свой код в svchost.exe

ну да, код может и инжекцируется, но вы уверенны, что хэндл hFile имеет место быть в процессе svchost? если нет, то malloc'у передастся -1. не хочется разбираться почему, но malloc возвращает не NULL на -1, однако очевидно, что память такого размера выделиться не может и первые четыре байта до возвращаемого указателя совсем не размер содержат...

KEZ 19.11.2007 23:17

Гыыы) Дело в CRT-шных malloc'ах и free'хах))

Код:

void *new_malloc(size_t size)
{
  return HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size);
}

void new_free(void *p)
{
  HeapFree(GetProcessHeap(),0,p);
}

при инжекте в процесс многие ф-ие CRT использовать не получится

а вообще, автор, отладчики ведь придумали не просто так

PS
HeapAlloc, HeapFree - это в NT на самом деле экспорт-форвардинг на ntdll.RtlAllocateHeap и соотв. ntdll.RtlFreeHeap.
как и getlasterror=RtlGetLastWin32Error

ZaCo 19.11.2007 23:39

2KEZ а что в реализации этих crt-функций такого?)

_Great_ 19.11.2007 23:41

Цитата:

Сообщение от kez
а вообще, автор, отладчики ведь придумали не просто так

Да, и очень жаль, что люди, подобные ТС, не умеют ими пользоваться.

DWORD 19.11.2007 23:52

Цитата:

Сообщение от ZaCo
2KEZ а что в реализации этих crt-функций такого?)

Их нет как я понимаю, хотя я в отладчик не заглядывал.

razzzar 20.11.2007 00:43

спасибо за ответ )

KEZ 20.11.2007 01:06

Цитата:

2KEZ а что в реализации этих crt-функций такого?)
Зако тоже не любит отладченки походу.
Для чего нужна инициализация CRT? Вот оно инициализивалась, особенно куча тек. процесса получилась, и тут вдруг кусок кода идет в совсем другой процесс со своей кучей. Подробнее - см. дизасм malloc() и free().
Это примерно тоже, что получить хендлы, справедливые только в текущем процессе (открытые объекты "файл", к примеру) и инжектнуть код, с ними работающий, в другой процесс, удивляясь, почему не работает.
А в crt как бы нет ориентировки на то, что её будут хакеры использовать в целях инжекта в бедный svchost

ZaCo 20.11.2007 03:01

2KEZ ну это ясно. только не понятно зачем ты щас конретизируешь кучу, ведь изначально ошибко кроется в том, что нельзя инжектить код, который использует "родные" адреса для вызова дальних jmp или call. ну в общем-то да, вот только тогда не понятно как автор решил инжектить код со своими адресами.. ахх, если бы винду собирали с crt автору при удачном стечении обстоятельств было бы попроще:)

KEZ 20.11.2007 12:58

Цитата:

ведь изначально ошибко кроется в том, что нельзя инжектить код, который использует "родные" адреса для вызова дальних jmp или call.
Все адреса при инжекте остались родными) В svchost выделили нужные адреса, скопировали туда свой образ целиком (автор, я телепат??) и запустили нужную ф-ию.
Проблема не в jmp или call. С джампами и колами - это другая проблема, их надо релочить. А тут - косяк чисто в CRT. Достаточно посмотреть шаги работы malloc().
Помниться, когда я только узнал про инжект в процесс, у меня была точно такая же проблема.

Цитата:

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

ZaCo 20.11.2007 14:07

>>В svchost выделили нужные адреса

>>Так вот работает все отлично, но как только доходит до выделения памяти выкидует
>>сообщение о ошибке и просьбе отослать отчет в Microsoft.

не знаю, имхо код был просто скопирован :o

razzzar 20.11.2007 19:03

Цитата:

Сообщение от ZaCo
>>В svchost выделили нужные адреса

>>Так вот работает все отлично, но как только доходит до выделения памяти выкидует
>>сообщение о ошибке и просьбе отослать отчет в Microsoft.

не знаю, имхо код был просто скопирован :o

ничего там скопированого не было. все писал я.

2КЕЗ, да, вы телепат )

ZaCo 20.11.2007 19:59

>>ничего там скопированого не было. все писал я.
я про код процесса, а не программы на C)

KEZ 20.11.2007 21:20

> не знаю, имхо код был просто скопирован

При инжекте у ТС с текущего процесса в адресное пространство другого по _одинаковым_ адресам копируется какой-либо код/+данные/+етц
иначе все слетело бы ещё задолго до вызова malloc()
о чем тут спорить можно ? : DDD

DWORD 20.11.2007 21:36

Цитата:

Сообщение от KEZ
> не знаю, имхо код был просто скопирован

При инжекте у ТС с текущего процесса в адресное пространство другого по _одинаковым_ адресам копируется какой-либо код/+данные/+етц
иначе все слетело бы ещё задолго до вызова malloc()
о чем тут спорить можно ? : DDD

Почему, есть инструкция call, адресующая функцию относительно текущего EIP, она кстати и используется, данные все можно формировать на стеке, api функции подключать в ходе выполнения...

KEZ 20.11.2007 22:13

Не от EIP, а от своего месторасположения.

Цитата:

она кстати и используется, данные все можно формировать на стеке, api функции подключать в ходе выполнения...
что тут написано и как это относится к бедному razzzar, которому уже все давно объяснили - я пока ещё не понял

есть большой кусок кода, сгенерированый компилятором, который при перемещении в другой процесс надо либо релочить, либо перемещать на тот же VA, где он и должен быть в процессе, либо записывать его VA-независимым, например, вместо call [addr] делать mov eax,[addr]\call eax.
тут, вроде как, неочем спорить больше.

DWORD 20.11.2007 22:25

Цитата:

Сообщение от KEZ
Не от EIP, а от своего месторасположения.

"от своего месторасположения" это как? 0xE8 опкод инструкции вызова функции, адрес функции вычисляется как EIP + операнд.


Цитата:

Сообщение от KEZ
что тут написано и как это относится к бедному razzzar, которому уже все давно объяснили - я пока ещё не понял

есть большой кусок кода, сгенерированый компилятором, который при перемещении в другой процесс надо либо релочить, либо перемещать на тот же VA, где он и должен быть в процессе, либо записывать его VA-независимым, например, вместо call [addr] делать mov eax,[addr]\call eax.
тут, вроде как, неочем спорить больше.

Ну а почему именно такие варианты? Что мешает не использовать абсолютных адресов, формируя все данные на стеке (а глобальные переменные вынося в динамиечкую память, выделяемую уже в контексте "проинжектинного" процесса, подгружая все системные функции на лету и прыгая с функции на функцию 0xE8 call'ами (или вообще не прыгая, а делать все в __inline)

KEZ 21.11.2007 03:17

Цитата:

"от своего месторасположения" это как? 0xE8 опкод инструкции вызова функции, адрес функции вычисляется как EIP + операнд.
Это так, что можно вычислять как EIP+операнд в момент выполнения CALL, а можно - в общем случае - адрес инструкции CALL + её операнд. Так как заранее известно, каким будет EIP в момент выполнения инструкции (когда она где-то расположена в виртуальной памяти) - думаю, уж можно сказать, что адрес процедуры будет равен адресу инструкции CALL + её операнду. Да, процессору все равно что и где там расположено, но с точки зрения чисто-человеческой логики, можно сказать про адрес инструкции call, а не про EIP в момент её выполнения, который, по сути, является тем же самым. Ладно, ок, от EIP зависит - это правильно.

Цитата:

прыгая с функции на функцию 0xE8 call'ами
ну и?)) e8 call то должен быть расположен либо там, где и был, либо его надо корректировать. это и есть "использование абсолютных адресов"

Цитата:

Что мешает не использовать абсолютных адресов, формируя все данные на стеке
Компилятор мешает. Я уже сказал, что можно использовать базонезависимый код - ты как раз и говоришь про такой. Который будет где угодно выполняться. Да, да, это формирование в стеке, глобальные данные в куче, может быть замена call mem на mov reg,mem\call reg и т.п. неудобства.
Как видно по первому посту в топике - компилятор c/cpp.
Вот он, к примеру, очень часто будет ставить свои __CRT_CheckESP и тому подобное.
И ещё много чего делать будет. Про __inline - без комментариев, это явно тут "ни приштопай ни пришей".
А так, если самому писать код - да без проблем, можно полно всего придумать.

DWORD 21.11.2007 09:52

Цитата:

ну и?)) e8 call то должен быть расположен либо там, где и был, либо его надо корректировать. это и есть "использование абсолютных адресов"
Этого я так и не понял, почему? В непосредственном операнде стоит только смещение и ему глубоко фиолетово какой там EIP, если код весь копировать монолитно, что видимо является единственно-адекватным решением, все будет работать по любым адресам.

Кстати, чтобы call'ы имели такой вид, на сколько я понял, извращаться ненужно, я, например, смог получить call по абсолютному адресу только для 0xFF call'а при вызове функции через функциональную переменную (Borland C++), но что-то мне подсказывает что на MSVS тоже самое.

KEZ 21.11.2007 19:00

> Этого я так и не понял, почему?

А релоки в длл придумали просто так?
Проблема в том, что каким-то инструкциям нужна VA, а каким-то - смещение, относительно EIP. Поэтому - либо релочишь колы и джампы, либо mov'ы и все остальное.
Как у тебя CRT инициализируется с таким кодом:

Цитата:

Сообщение от mainCRTStartup
00413D12 . 56 PUSH ESI ; /pVersionInformation
00413D13 . FF15 4CD24200 CALL DWORD PTR DS:[<&KERNEL32.GetVersion>; \GetVersionExA
00413D19 . 8B4E 10 MOV ECX,DWORD PTR DS:[ESI+10]
00413D1C . 890D 20AF4200 MOV DWORD PTR DS:[_osplatform],ECX
00413D22 . 8B46 04 MOV EAX,DWORD PTR DS:[ESI+4]
00413D25 . A3 2CAF4200 MOV DWORD PTR DS:[_winmajor],EAX
00413D2A . 8B56 08 MOV EDX,DWORD PTR DS:[ESI+8]
00413D2D . 8915 30AF4200 MOV DWORD PTR DS:[_winminor],EDX

?

где _osplatform == 0x42AF20

перенесешь код - будет уже совсем неправильный адрес.

DWORD 21.11.2007 19:09

Цитата:

Сообщение от KEZ
> Этого я так и не понял, почему?

А релоки в длл придумали просто так?
Проблема в том, что каким-то инструкциям нужна VA, а каким-то - смещение, относительно EIP. Поэтому - либо релочишь колы и джампы, либо mov'ы и все остальное.
Как у тебя CRT инициализируется с таким кодом:



?

где _osplatform == 0x42AF20

перенесешь код - будет уже совсем неправильный адрес.

Хех, ну а причем тут CRT? Ни о каком CRT речи не идет. Следовательно не будет таких инструкций, которые бы обращались по зашитым в них адресам, все обращения по абсолютным адресам сведутся к вызовам winapi, адреса которых получены в ходе выполнения программы. Я никогда на самом деле этими вещами не занимался, но ошибок в рассуждениях своих не вижу.

KEZ 21.11.2007 19:29

Цитата:

Хех, ну а причем тут CRT? Ни о каком CRT речи не идет.
first post:
http://forum.antichat.ru/showpost.php?p=508892&postcount=1

Цитата:

Сообщение от razzzar
char * szData = (char *) malloc(GetFileSize(hFile, NULL));
...
free(szData);

...

Цитата:

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

DWORD 21.11.2007 19:35

Цитата:

Сообщение от KEZ
first post:
http://forum.antichat.ru/showpost.php?p=508892&postcount=1



...



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

Ну про первый пост мы уже не говорим, тема немножко другая. Я не буду конечно этим заниматься, что ты говоришь - лень, но интерес остался. Где-нибудь, это где - контрпример приведи. Как известно для доказательства теоремы надо ее получить, опираясь на аксиомы, а для опровержения теории достаточно привести контрпример, не клеющийся с рассуждениями этой теории и известный из постулатов или доказанных ранее теорем, ну и где он? Я специально посмотрел сейчас в отладчике код с множеством циклов, условий, свичей, даже с goto - все переходы относительные..

KEZ 21.11.2007 23:36

Пример надо приводить, когда точно известно, что предполагается делать - копировать образ бинарника в другой процесс полностью, или копировать туда 1 ф-ю/какой-нибудь кусок кода неизвестно какого размера.
В первом случае - придется специально переносить каждую секцию на другой адрес. Вообще смысла в этом никакого не вижу, разве что для проверки: "а все-таки можно ли вот так сделать"? Во втором случае сказать конкретно ничего нельзя - никто не знает что будешь копировать ... Есть факт - пока jmp'ы (и тп) будут указывать в кусок кода, который двигается вместе с ними - все будет нормально. Соотв, если убрать инструкции, требующие абсолютный адрес (все остальные, грубо говоря) - работать будет. Но тогда надо будет не использовать глобальные переменные или как-то передавать их адреса в выделеной куче. И вообще извращаться. Неужели не проще скопировать все туда же, где оно и было до этого? Это универсально по крайней мере.

panda gorl 28.11.2007 17:29

Цитата:

Сообщение от razzzar
Есть программа, которая инжектирует свой код в svchost.exe
Выполняет в нем какой-то код, а потом выполняет действия наподобии этих:
Код:

char * szData = (char *) malloc(GetFileSize(hFile, NULL));
...
free(szData);

Так вот работает все отлично, но как только доходит до выделения памяти выкидует сообщение о ошибке и просьбе отослать отчет в Microsoft. Кто знает с чем связано?

ZaCo - ламо, KEZ прав абсолютно, ибо дело в тупом CRT. Я для того чтобы обойти баг просто тупо переопределил все маллоки и операторы нью\делит:

Код:

void* __cdecl malloc(size_t n)
{
    void* pv = HeapAlloc(GetProcessHeap(), 0, n);
    return pv;
}
void* __cdecl calloc(size_t n, size_t s)
{
    return malloc(n*s);
}
void* __cdecl realloc(void* p, size_t n)
{
    if (p == NULL) return malloc(n);
    return HeapReAlloc(GetProcessHeap(), 0, p, n);
}
void __cdecl free(void* p)
{
    if (p == NULL) return;
    HeapFree(GetProcessHeap(), 0, p);
}

void* __cdecl operator new(size_t n)
{
    return malloc(n);
}
void __cdecl operator delete(void* p)
{
    free(p);
}

Ты инжектишь сразу весь образ своего приложения или только его кусок?

ZaCo 28.11.2007 18:59

2panda gorl зачем ты обзываешься? мог бы сказать хотя бы перед этим где я в этом топике не прав :(

panda gorl 28.11.2007 19:23

Цитата:

Сообщение от ZaCo
2panda gorl зачем ты обзываешься? мог бы сказать хотя бы перед этим где я в этом топике не прав :(

не обижайся ;)

ZaCo 28.11.2007 19:33

ну и не говори :p

sn0w 29.11.2007 18:14

DuplicateHandle


Время: 15:58