Есть вот такой код: Код (Text): WriteToFile proc uses ebx lpAppendData: PTR ANSI_STRING LOCAL oa :OBJECT_ATTRIBUTES LOCAL sb :IO_STATUS_BLOCK LOCAL hFile :DWORD LOCAL dataLen :DWORD InitializeObjectAttributes addr oa, addr szFileName, OBJ_CASE_INSENSITIVE or OBJ_KERNEL_HANDLE, NULL, NULL invoke ZwOpenFile, addr hFile, FILE_APPEND_DATA or SYNCHRONIZE, addr oa, addr sb, FILE_SHARE_READ, FILE_SYNCHRONOUS_IO_NONALERT .if (eax == STATUS_SUCCESS) mov ebx, lpAppendData add ebx,4 mov ebx,[ebx] invoke strlen,ebx mov dataLen,eax invoke ZwWriteFile, hFile, NULL, NULL, NULL, addr sb, ebx, dataLen, NULL, NULL .if (eax == STATUS_SUCCESS) invoke DbgPrint, $CTA0("Success") .else invoke DbgPrint, $CTA0("Fail") .endif invoke ZwClose, hFile .else invoke DbgPrint, $CTA0("Error: %08X\n"), eax .endif invoke DbgPrint, $CTA0("End of write") ret WriteToFile endp ;-------- Notify Callback ------------ invoke WriteToFile, addr a_string Callback получает сообщение о создании процесса. Из него вызывается процедура записи в файл. Если процессы запускать и завершать до запуска другого процесса, все работает (в файл пишется). Если запустить процесс, и не закрывая его, запустить какой-нибудь другой процесс (т.е. предыдущий процесс ещё не закрыт), система уходит в перезагрузку. Путем комментирования определил, что перезагрузку вызывает ZwWriteFile. Какая разница, завершился предыдущий процесс или нет? Если вместо ZwWriteFile выводить строку через DbgPrint - никаких проблем. Предыдущий вызов WriteToFile завершается успешно, строки Success и End of write выводятся. Т.е. с синхронностью проблем нет. В чем может быть дело? Спасибо.
Лучше зделай хендл файла глобальним , чтоб каждый раз не открывать/закрывать .... Работу с лог файлом я делаю так: HANDLE hFileHandle; IO_STATUS_BLOCK iostatus; void InitLogFile(IN PCWSTR strLogFile) { NTSTATUS Status; OBJECT_ATTRIBUTES ObjAttr; UNICODE_STRING strFileName; hFileHandle = NULL; DPRINT("Initializing log file..."); RtlInitUnicodeString(&strFileName,strLogFile); InitializeObjectAttributes(&ObjAttr,&strFileName,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,NULL,NULL); Status = ZwCreateFile(&hFileHandle,GENERIC_WRITE | SYNCHRONIZE,&ObjAttr,&iostatus,0,FILE_ATTRIBUTE_NORMAL,FILE_SHARE_WRITE,FILE_OPEN_IF,FILE_SYNCHRONOUS_IO_NONALERT,NULL,0); if (NT_SUCCESS(Status))DPRINT("ok\n"); else DPRINT("failed\n"); } void CloseLogFile() { DPRINT("Closing log file\n"); if (!hFileHandle) return; ZwClose(hFileHandle); } void WriteLog(IN char* Buff) { NTSTATUS Status; FILE_STANDARD_INFORMATION fileInfo; if (!hFileHandle) return; Status = ZwQueryInformationFile(hFileHandle,&iostatus,&fileInfo,sizeof(FILE_STANDARD_INFORMATION),FileStandardInformation); if (NT_SUCCESS(Status)) { LARGE_INTEGER ByteOffset = fileInfo.EndOfFile; Status = ZwWriteFile(hFileHandle,NULL,NULL,NULL,&iostatus,Buff,strlen(Buff),&ByteOffset,NULL); } } [add] Ты вообще под дебагом проганял этот код при запуске второго процесса ?
Держать глобально открытый - тоже пробовал - там вообще даже одновременно один процесс запустить редко удается. Например запуск notepad - 100% перезагрузка. Может дело в том, что callback вызывается в контексте запускаемого процесса?
Уже начинаю с бубном плясать - обрамил код вызова ZwWriteFile такими вот рюшечками от Four-F: Код (Text): _try invoke ZwWriteFile, hLogFile, NULL, NULL, NULL, addr sb, ebx, dataLen, NULL, NULL .if (eax == STATUS_SUCCESS) invoke DbgPrint, $CTA0("%s"), ebx .else invoke DbgPrint, $CTA0("Can't append data: %08X\n"), eax .endif _finally Бесполезно. Перегружается по-прежнему.
Вроде нашёл: RtlUnicodeStringToAnsiString,...,...,TRUE выделяет буфер и транслирует в него юникод-строку. Если к этому буферу делать strcat, то ZwWriteFile этот буфер переварить не может. В то же время DbgPrint спокойно выводит этот буфер (что и ввело в заблуждение). Поэтому содержимое буфера от RtlUnicodeStringToAnsiString надо сначала скопировать в промежуточный буфер достаточной длины, и затем только strcat и ZwWriteFile с этим промежуточным буфером
Весь смысл ANSI_STRING/UNICODE_STRING в том, что они всегда несут длину строки и всего буфера в себе. Зачем strlen? <font color="gray][ cresta</font><!--color--><font color="gray]: Если к этому буферу делать strcat, то ZwWriteFile этот буфер переварить не может. ]</font><!--color--> А ты обновил ANSI_STRING.Length и не вышла ли длина строки за пределы ANSI_STRING.MaximumLength? strlen, strcat и тому подобную CRT хрень лучше вообще в ядре не юзать. Для аппенда есть RtlAppendStringToString. ЗЫ: И с моими рюшечками поаккурантее. Они кривенькие http://www.wasm.ru/forum/index.php?action=vthread&forum=4&topic=11025
В этом и была ошибка:MaximumLength оставался прежним. А strlen нужен потому, что к строке может добавляться другая стока произвольной длины (что вкупе с неизменением MaximumLength и приводило к ошибке), заранее неизвестно, сколько будет результирующая длина. За ссылку спасибо.
cresta а ты не пробовал запустить рядом системный ядерный поток и пусть он за тебя сам пишет, или рабочие потоки создать и пусть они за тебя там в файл пишут, зачем тратить драгоценное время на все дела непосредственно в контексте процедуры нотификации ?
вопрос в другом мне кажется, твоя процедура нотификации, вызываясь повторно, снова использует твой уникодстринг, который был до этого уже инициализирован прежним вызовом. и ты пытаешься повторно использовать её. Пересмотри алгоритм
CARDINAL В смысле ZwCreateThread? Если о нем речь, то я после отладки уберу всю работу с файлом в отдельный поток. Буфер для юникода выделяется через ExAllocatePool, затем invoke RtlUnicodeStringToAnsiString, addr as, addr us, FALSE, и затем ExFreePool. Все освобождается. А для анси - буфер на стеке, освобождать не надо.