информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
Атака на InternetПортрет посетителяВсе любят мед
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Три миллиона электронных замков... 
 Doom на газонокосилках 
 Умер Никлаус Вирт 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
ФОРУМ
если вы видите этот текст, отключите в настройках форума использование JavaScript
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
  • Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
  • Новичкам также крайне полезно ознакомиться с данным документом.
ну блин 05.05.06 14:04  Число просмотров: 3335
Автор: z0 <z0> Статус: Member
<"чистая" ссылка>
> Не производит. И lsass.exe и rpc-серверы (в svchost.exe с
> соответствующими dll-ками) запускаются как сервисы. А любой
> сервис в своей ServiceMain должен проинициализировать
> таблицу SERVICE_TABLE_ENTRY-ей и вызвать
> StartServiceCtrlDispatcher (эта функция кстати не
> возвращается пока не завершатся все сервисы,
> контроллируемые данным процессом).
> Это тоже так, мысли вслух

это тебя великий и могучий МСДН так учит что и как надо делать в ServiceMain
а сами вот как пишут - цитата из lsass.exe (windows 2003 std gold)

.text:01001418 _main proc near ; CODE XREF: mainNoCRTStartup()+33p
.text:01001418
.text:01001418 var_1C = dword ptr -1Ch
.text:01001418 var_4 = dword ptr -4
.text:01001418
.text:01001418 push ebp
.text:01001419 mov ebp, esp
.text:0100141B push ecx
.text:0100141C push esi
.text:0100141D push 1 ; uMode
.text:0100141F call ds:__imp__SetErrorMode@4 ; SetErrorMode(x)
.text:01001425 push offset _LsaTopLevelExceptionHandler@4 ; lpTopLevelExceptionFilter
.text:0100142A call ds:__imp__SetUnhandledExceptionFilter@4 ; SetUnhandledExceptionFilter(x)
.text:01001430 push 1
.text:01001432 push 0
.text:01001434 push 1
.text:01001436 call ds:__imp__RtlSetProcessIsCritical
.text:0100143C add esp, 0Ch
.text:0100143F push 4
.text:01001441 lea eax, [ebp+var_4]
.text:01001444 push eax
.text:01001445 push 5
.text:01001447 push 0FFFFFFFFh
.text:01001449 mov [ebp+var_4], 9
.text:01001450 call ds:__imp__NtSetInformationProcess@16 ; NtSetInformationProcess(x,x,x,x)
.text:01001456 mov esi, eax
.text:01001458 test esi, esi
.text:0100145A jl short loc_10014B7
.text:0100145C call _LsapCheckBootMode@0 ; LsapCheckBootMode()
.text:01001461 mov esi, eax
.text:01001463 test esi, esi
.text:01001465 jl short loc_10014B7
.text:01001467 call _ServiceInit@0 ; ServiceInit()
.text:0100146C mov esi, eax
.text:0100146E test esi, esi
.text:01001470 jl short loc_10014B7
.text:01001472 call _LsapInitLsa@0 ; LsapInitLsa()
.text:01001477 mov esi, eax
.text:01001479 test esi, esi
.text:0100147B jl short loc_10014B7
.text:0100147D call _SamIInitialize@0 ; SamIInitialize()
.text:01001482 mov esi, eax
.text:01001484 test esi, esi
.text:01001486 jl short loc_10014B7
.text:01001488 call _LsapDsInitializePromoteInterface@0 ; LsapDsInitializePromoteInterface()
.text:0100148D mov esi, eax
.text:0100148F test esi, esi
.text:01001491 jl short loc_10014B7
.text:01001493 push 1
.text:01001495 call _LsapAuOpenSam@4 ; LsapAuOpenSam(x)
.text:0100149A mov esi, eax
.text:0100149C test esi, esi
.text:0100149E jl short loc_10014B7
.text:010014A0 call _SampUsingDsData@0 ; SampUsingDsData()
.text:010014A5 xor ecx, ecx
.text:010014A7 test al, al
.text:010014A9 setnz cl
.text:010014AC inc ecx
.text:010014AD mov eax, ecx
.text:010014AF push eax
.text:010014B0 call _LsapDsInitializeDsStateInfo@4 ; LsapDsInitializeDsStateInfo(x)
.text:010014B5 mov esi, eax
.text:010014B7
.text:010014B7 loc_10014B7: ; CODE XREF: _main+42j
.text:010014B7 ; _main+4Dj ...
.text:010014B7 push esi
.text:010014B8 call _LsapNotifyInitializationFinish@4 ; LsapNotifyInitializationFinish(x)
.text:010014BD push esi ; dwExitCode
.text:010014BE call ds:__imp__ExitThread@4 ; ExitThread(x)
.text:010014C4 int 3 ; Trap to Debugger
.text:010014C5

StartServiceCtrlDispatcher вызывается из отдельного треда, созданного внутри samsrv!ServiceInit()
чтобы не ждать пока она действительно не возвращается
он там спокойно не спеша полазит по реестру, инициализирует все свои RPC-шки
а основной поток lsass сразу на старте как хорошо видно выходит по ExitThread
спорим на поллитра?
<programming>
[Win32] Не создается поток 30.04.06 14:58   [Killer{R}]
Автор: makeworld Статус: Member
<"чистая" ссылка>
есть такой код. CreateThread() отрабатывает нормально, но признаков работы потока нет. использую VC++ 2005. не могу понять, в чем дело..

#include <windows.h>
#include <stdio.h>

void func();
DWORD WINAPI ThreadProc(LPVOID lParam);

int main() {
	func();
	return 0;
}

void func() {
	unsigned int tid;
	char test[30]={0};
	
	memset(&test[0], 'A', 29);
	printf("%s\n", test);


	HANDLE hT1 = CreateThread(NULL, 0, ThreadProc, &test[0], 0, (LPDWORD)&tid);
	HANDLE hT2 = CreateThread(NULL, 0, ThreadProc, &test[0], 0, (LPDWORD)&tid);
	HANDLE hT3 = CreateThread(NULL, 0, ThreadProc, &test[0], 0, (LPDWORD)&tid);

	if ((hT1 == INVALID_HANDLE_VALUE)|		(hT2 == INVALID_HANDLE_VALUE)|		(hT3 == INVALID_HANDLE_VALUE))
		printf("failed\n");

	int lastErr = GetLastError();
	if (lastErr)
		printf("last error = %d\n", lastErr);

}


DWORD WINAPI ThreadProc(LPVOID lParam) {
	char *p = (char *)lParam;

//	Sleep(100);

	printf("i'm thread %d\n", GetCurrentThreadId());
	printf("%s\n", p);

	MessageBox(NULL, TEXT("test"), TEXT("test"), MB_OK);

	return 0;
}

---
я бы использовал _beginthreadex. 03.05.06 05:09  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка>
я бы использовал _beginthreadex.
Со слипами я бы разобрался. Может не нады они? Регулировать переключение слипами не стал бы. Не угадаешь. Если уж надо чего-то ждать - используйте события.
а чем _beginthreadex реально лучше? вроде же это обертка над... 03.05.06 16:34  
Автор: makeworld Статус: Member
<"чистая" ссылка>
> я бы использовал _beginthreadex.
> Со слипами я бы разобрался. Может не нады они? Регулировать
> переключение слипами не стал бы. Не угадаешь. Если уж надо
> чего-то ждать - используйте события.

а чем _beginthreadex реально лучше? вроде же это обертка над API функцией CreateThread

про синхронизацию это само собой

я просто не знал о том, что потоки завершаются автоматом при завершении главного потока
Это не ко мне. Это к Рихтеру. 04.05.06 05:24  
Автор: void <Grebnev Valery> Статус: Elderman
<"чистая" ссылка>
В который раз замечаю, что меня не замечают (sic!) 03.05.06 17:24  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
- Доктор, меня игнорируют.
- Следующий

> я просто не знал о том, что потоки завершаются автоматом
> при завершении главного потока

К винде это не имеет никакого отношения. Просто в C программа завершается при выходе из функции main. При его разработке никто не закладывался на многопоточность. Вот и приходится при выходе из main прибивать все "лишние" потоки. Если ты поставишь в настройках линкера точку входа, отличную от xxxCRTStartup (вместо xxx - всякие main, wmain, WinMain и wWinMain), то процесс у тебя не завершится (естественно большинством рантаймовых функций ты пользоваться не сможешь и аргументы argv/argc не получшь)

dl уже даже протестил:
http://bugtraq.ru/cgi-bin/forum.mcgi?type=sb&b=2&m=134498
а вообще этим могла бы заниматься и система 03.05.06 19:46  
Автор: dl <Dmitry Leonov>
<"чистая" ссылка>
Хэндл главного потока ей по крайней мере при создании процесса известен, могла бы и запомнить, после чего обработать так же, как рантайм.
Могла бы, но незачем 03.05.06 21:15  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
> Хэндл главного потока ей по крайней мере при создании
> процесса известен, могла бы и запомнить, после чего
> обработать так же, как рантайм.

Не вводи сущностей сверх необходимости и прочее.
А вообще красивый и управляемый код чаще всего имеет высокую степень обобщенности и симметрии. В том смысле, что если нет ОБЯЗАТЕЛЬНЫХ причин выделять какой либо один поток, то лучше не делать этого из эстетических соображений.

А рантайм занимается этим насколько я понимаю именно из за того, что стандарт C напрямую указывает завершать программу (независимо от того, в каком виде она представлена) при выходе из main. Насколько я помню в posix-е и потоков то нету. Один процесс - один поток исполнения (другое дело, что они могут разделять память, хендлы и пр.., но у каждого свой PID и такое прочее).
эстетика дело такое 03.05.06 21:41  
Автор: dl <Dmitry Leonov>
<"чистая" ссылка>
зато не нужно было бы таскать из программы в программу один и тот же код :)
пост читал 03.05.06 17:31  
Автор: makeworld Статус: Member
<"чистая" ссылка>
> К винде это не имеет никакого отношения. Просто в C
> программа завершается при выходе из функции main. При его
> разработке никто не закладывался на многопоточность. Вот и
> приходится при выходе из main прибивать все "лишние"
> потоки. Если ты поставишь в настройках линкера точку входа,
> отличную от xxxCRTStartup (вместо xxx - всякие main, wmain,
> WinMain и wWinMain), то процесс у тебя не завершится
> (естественно большинством рантаймовых функций ты
> пользоваться не сможешь и аргументы argv/argc не получшь)
>
> dl уже даже протестил:
> http://bugtraq.ru/cgi-bin/forum.mcgi?type=sb&b=2&m=
> 134498

пост читал
теперь понятно, что дело в CRT, хотя в принципе, если создавать обычное приложение без изменения точки входа, откючения CRT и т.д., не важно на уровне CRT или на уровне ОС происходит принудительное завершение потоков, результат один и тот же.
[UPD]как сказать 03.05.06 17:36  
Автор: Killer{R} <Dmitry> Статус: Elderman
Отредактировано 03.05.06 17:46  Количество правок: 2
<"чистая" ссылка>
> пост читал
> теперь понятно, что дело в CRT, хотя в принципе, если
> создавать обычное приложение без изменения точки входа,
> откючения CRT и т.д., не важно на уровне CRT или на уровне
> ОС происходит принудительное завершение потоков, результат
> один и тот же.
как сказать


#include "windows.h"

DWORD CALLBACK trd(void *)
{
for(;;)Sleep(1000);
}
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // command line
int nCmdShow // show state
)
{
CreateThread(NULL,0,trd,NULL,0,NULL);
ExitThread(0);
return 0;
}

[UPD]
BTW у меня есть сильное подозрение что когда у процесса заканчиваюцца потоки умирает он тоже не по собственному желанию а по приказу csrss.exe
Нет. Процесс убивается в ядре 03.05.06 17:59  
Автор: amirul <Serge> Статус: The Elderman
<"чистая" ссылка>
> BTW у меня есть сильное подозрение что когда у процесса
> заканчиваюцца потоки умирает он тоже не по собственному
> желанию а по приказу csrss.exe

DECLSPEC_NORETURN
VOID
PspExitThread(
    IN NTSTATUS ExitStatus
    )
{
// [skipped]
    Thread = PsGetCurrentThread();
    Process = THREAD_TO_PROCESS(Thread);
// [skipped]
    if ( (Process->ThreadListHead.Flink == Process->ThreadListHead.Blink)
         && (Process->ThreadListHead.Flink == &Thread->ThreadListEntry) ) {
        LastThread = TRUE;
        if ( ExitStatus == STATUS_THREAD_IS_TERMINATING ) {
            if ( Process->ExitStatus == STATUS_PENDING ) {
                Process->ExitStatus = Process->LastThreadExitStatus;
            }
        } else {
            Process->ExitStatus = ExitStatus;
        }

        DbgkExitProcess(ExitStatus);
    }
// [skipped]
    if ( LastThread && Process->Win32Process ) {
        (PspW32ProcessCallout)(Process,FALSE); // Вот тут он разрегистрируется в csrss-е
        }
// [skipped]
    //
    // If this is the last thread in the process, then clean the address space
    //

    if ( LastThread ) {
        if (!(ExChangeHandle(PspCidTable,Process->UniqueProcessId, PspMarkCidInvalid, PSP_INVALID_ID))) {
            KeBugCheck(CID_HANDLE_DELETION);
        }
        KeQuerySystemTime(&Process->ExitTime);
        PspExitProcess(TRUE,Process);
    }
// [skipped]
}

---

Такие дела.
Да, все функции убивания потока заканчиваются в этой самой PspExitThread. Если TerminateThread вызван для текущего потока, то напрямую, а если для другого - через special APC
ну я имел ввиду относительно моего примера 03.05.06 17:49  
Автор: makeworld Статус: Member
Отредактировано 03.05.06 17:53  Количество правок: 4
<"чистая" ссылка>
> #include "windows.h"
>
> DWORD CALLBACK trd(void *)
> {
> for(;;)Sleep(1000);
> }
> int WINAPI WinMain(
> HINSTANCE hInstance, // handle to current instance
> HINSTANCE hPrevInstance, // handle to previous instance
> LPSTR lpCmdLine, // command line
> int nCmdShow // show state
> )
> {
> CreateThread(NULL,0,trd,NULL,0,NULL);
> ExitThread(0);
> return 0;
> }

ну я имел ввиду относительно моего примера. А так вообще конечно надежней было бы, если бы этим ОС занималась. Тут вообще конфликт получается. С одной стороны есть CRT, а с другой вполне легальная функция ExitThread(), которой до CRT и ее функций, вызываюшихся после выхода из main/WinMain и т.д., дела нет.
именно тем что это обертка над... 03.05.06 16:54  
Автор: Killer{R} <Dmitry> Статус: Elderman
<"чистая" ссылка>
Она дает знать CRT о том что тред запускается/завершается. Если ты не юзаешь CRT'шные функции в треде (что маловероятно), то можно и CreateThread заюзать.
т.е. CRT-шные функции, используемые в потоке, будут работать... 03.05.06 17:26  
Автор: makeworld Статус: Member
<"чистая" ссылка>
> Она дает знать CRT о том что тред запускается/завершается.

т.е. CRT-шные функции, используемые в потоке, будут работать учитывая то, что выполняются внутри потока??

можно простой пример пользы от примения _beginthreadex
примерно так 03.05.06 19:43  
Автор: dl <Dmitry Leonov>
<"чистая" ссылка>
Точнее, для глобальных данных, используемых этими функциями, будет сделана обертка, привязанная к конкретному потоку, так чтобы их совместное использование из разных потоков не привело к глюкам.

Хотя на самом деле все не так страшно и может даже проскочить:

"Ой, вместо _beginthreadex я по ошибке вызвал CreateThread

Вас, наверное, интересует, что случится, если создать поток не библиотечной функ цией _begintbreadex, а Windows-функцией CreateThread Когда этот поток вызовет какую-нибудь библиотечную функцию, которая манипулирует со структурой tiddata, произойдет следующее. (Большинство библиотечных функций реентерабсльно и не требует этой структуры ) Сначала эта функция попытается выяснить адрес блока дан ных потока (вызовом TleGetValue). Получив NULL вместо адреса tiddata, она узнает, что вызывающий поток не сопоставлен с таким блоком. Тогда библиотечная функция тут

же создаст и инициализирует блок tiddata для вызывающего потока. Далее этот блок будет сопоставлен с потоком (через TlsSetValue) и останется при нем до тех пор, пока выполнение потока нс прекратится, С этого моменга данная функция (как, впрочем, и любая другая из библиотеки С/С++) сможет пользоваться блоком tiddata потока.

Как это ни фантасгично, но Ваш поток будет работать почти без глюков. Хотя некоторые проблемы все же появятся. Во-первых, если этот поток воспользуется биб лиотечной функцией signal, весь процесс завершится, так как SEH-фрейм не подго товлен. Во-вторых, если поток завершится, не вызвав endtbreadex, его блокданных не высвободится и произойдет утечка памяти. (Да и кто, интересно, вызовет end threadex иэ потока, созданного с помощью CreateTbread?)".
ясно, спасибо. 03.05.06 20:03  
Автор: makeworld Статус: Member
<"чистая" ссылка>
ясно, спасибо.

хотя signal не самая часто используемая функция, повод для использования именно CRT-обертки создания потока существенный
есть такие понятия как documentation и implementation 03.05.06 20:33  
Автор: Killer{R} <Dmitry> Статус: Elderman
<"чистая" ссылка>
так вот если в документации написано чтотоНАДОделать так, а на практике известно что в принципе работает и по другому писать надо все равно именноТАКкак написано. Тк имплементация данной функции может поменяться как угодно любым хотфиксом, функция будет работать так как написано в документации, но не так как работала в прошлой версии CRT. В результате - юзера ругают программистов, пишут в техсуппорт, техсуппорт отправляет это дело манагерам, манагеры - ковыряют кто написал код который только делает вид что работает и увольняют его. Вот это основная причина почему надо юзать _beginthreadex вместо CreateThread, а не особенность поведения signal в внештатной ситуации в конкретной имплементации CRT.
Есть такое слово 03.05.06 17:31  
Автор: Killer{R} <Dmitry> Статус: Elderman
Отредактировано 03.05.06 17:33  Количество правок: 1
<"чистая" ссылка>
надо
Что и как там работает - тебя вообще в данном случае не должно интересовать, и если в конкретной версии CRT и твоих исходников CreateThread работает нормально это не значит что всегда так будет.

http://www.flounder.com/badprogram.htm
Кстати, в VC 2005 нет single-threaded libraries, есть только... 03.05.06 19:56  
Автор: makeworld Статус: Member
<"чистая" ссылка>
> надо
> Что и как там работает - тебя вообще в данном случае не
> должно интересовать, и если в конкретной версии CRT и твоих
> исходников CreateThread работает нормально это не значит
> что всегда так будет.

Кстати, в VC 2005 нет single-threaded libraries, есть только multi-threaded, и по дефолту для Debug-сборки стоит Multi-threaded Debug DLL, а для Release - Multi-threaded DLL. Т.е. главные довод, приведенный в линке, отбрасывается.

Хотя в принципе, ради избежания гемора с CRT функциями в потоках в будущем, лучше наверное использовать _beginthreadex.

CreateThread in a C program
и будет тебе счастье :) 30.04.06 16:10  
Автор: ggg <ggg> Статус: Elderman
<"чистая" ссылка>
и будет тебе счастье :)

>
> int main() {
> func();
!!!!!!!!! Sleep(5000);
> return 0;
> }
>

правда счастье будет длиться 5 секунд :)
1  |  2 >>  »  




Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2024 Dmitry Leonov   Page build time: 0 s   Design: Vadim Derkach