перехват CreateProcessW рушит проводник windows 7

Тема в разделе "WASM.BEGINNERS", создана пользователем Postscripter, 19 май 2010.

  1. Postscripter

    Postscripter New Member

    Публикаций:
    0
    Регистрация:
    15 май 2009
    Сообщения:
    63
    Добрый день, я опять с глупыми вопросами... подскажите, отчего перехват (инжектинг) функции NTCreateFile, предложенный в статьях MS-REM'а, переделанный мной под NTCreateProcessW, нормально работает под ХР-ёй и Вистой, но на некоторых (не на всех) компьютерах с семёркой валит проводник с указанной ниже ошибкой? Семёрки у меня нет, поэтому ошибка - со слов пользователей:

    Сигнатура проблемы:
    Имя события проблемы: BEX
    Имя приложения: Explorer.EXE
    Версия приложения: 6.1.7600.16450
    Отметка времени приложения: 4aeba271
    Имя модуля с ошибкой: StackHash_0a9e
    Версия модуля с ошибкой: 0.0.0.0
    Отметка времени модуля с ошибкой: 00000000
    Смещение исключения: 07731f95
    Код исключения: c0000005
    Данные исключения: 00000008
    Версия ОС: 6.1.7600.2.0.0.256.1
    Код языка: 1049
    Дополнительные сведения 1: 0a9e
    Дополнительные сведения 2: 0a9e372d3b4ad19135b953a78882e789
    Дополнительные сведения 3: 0a9e
    Дополнительные сведения 4: 0a9e372d3b4ad19135b953a78882e789
     
  2. Postscripter

    Postscripter New Member

    Публикаций:
    0
    Регистрация:
    15 май 2009
    Сообщения:
    63
    Вот процедура входа

    Код (Text):
    1. // При старте - подгруз ко всем и захват проводника
    2. procedure DLLEntryPoint(dwReason: DWord);
    3. var
    4.   buff: PChar;
    5. begin
    6.   case dwReason of
    7.     DLL_PROCESS_ATTACH: begin
    8.                           SetGlobalHook();
    9.                           getmem(buff,250);
    10.                           CurrentAppHnd:=windows.GetModuleHandle(nil);
    11.                           GetModuleFileName(CurrentAppHnd, buff, 250);
    12.                           CurrentApp:=string(buff);
    13.                           freemem(buff);
    14.                           if pos('EXPLORER.EXE',upstring(CurrentApp))=length(CurrentApp)-11 then
    15.                            begin
    16.                             showmessage('1 этап выполнен. Библиотека загружена в адресное пространство проводника.');
    17.                             HookProc('kernel32.dll', 'CreateProcessW', @NewCreateProcessW, @TrueCreateProcessW);
    18.                             seterrormode(sem_failcriticalerrors);
    19.                             showmessage('2 этап выполнен. Перехват установлен!');
    20.                            end;
    21.                         end;
    22.     DLL_PROCESS_DETACH: if pos('EXPLORER.EXE',upstring(CurrentApp))=length(CurrentApp)-11 then
    23.                            UnhookCode(@TrueCreateProcessW);
    24.   end;
    25. end;
     
  3. Postscripter

    Postscripter New Member

    Публикаций:
    0
    Регистрация:
    15 май 2009
    Сообщения:
    63
    Вот - обработчик перехвата. Он получает управление, но где-то сбоит...

    Код (Text):
    1. function NewCreateProcessW(lpApplicationName: PWideChar; lpCommandLine: PWideChar;
    2.   lpProcessAttributes, lpThreadAttributes: PSecurityAttributes;
    3.   bInheritHandles: BOOL; dwCreationFlags: DWORD; lpEnvironment: Pointer;
    4.   lpCurrentDirectory: PWideChar; const lpStartupInfo: TStartupInfo;
    5.   var lpProcessInformation: TProcessInformation): BOOL; stdcall;
    6.  
    7. var
    8.  decision:TModalResult;   // Решение пользователя                               - это всё не важно......
    9.  ini:TRegIniFile;         // Флаги в реестре
    10.  txt:string;              // Предупреждение пользователя!
    11.  AMsgDialog: TForm;       // Форма
    12.  APrevIcon:TImage;        // Прочие контролы
    13.  fMes:TLabel;
    14.  fYes,fNo,fCancel:TButton;
    15.  
    16.  
    17.  
    18. function Launch:boolean;
    19. begin
    20.  showmessage('11 Выполнен вход в подпрограмму запуска');
    21.  result:=TrueCreateProcessW(lpApplicationName, lpCommandLine,
    22.    lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags,
    23.    lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
    24.  showmessage('12 Выполнен запуск');  
    25. end;
    26.  
    27. begin
    28.  showmessage('3 этап. Вход в процедуру выполнен.');
    29.  result:=false;
    30.  
    31.  {------ПРОВЕРКА-------}
    32.  
    33.  exec:=string(lpApplicationName);      // Пустая строка   ----- ЗАПУСК!!!
    34.  showmessage('4 этап. Выделено имя');
    35.  if length(exec)=0 then
    36.   begin
    37.    showmessage('5 этап. Сейчас произойдёт запуск пустой строки');
    38.    result:=Launch; ;
    39.    exit;
    40.   end;
    41.  
    42.  let:=exec[1];                  
    43.  if not (CheckDriveType(let) in [disk_flash, disk_noname]) then
    44.   begin
    45.    showmessage('10 этап. Сейчас произойдёт запуск программы (не с флешки)');
    46.    result:=Launch;
    47.    showmessage('13 Возврат управления');
    48.    exit;
    49.   end;      
    50.  
    51. ..................... дальше кусок кода вырезан, так как выполняется только для сменных носителей. Ошибка - где-то выше
    52.  
    53. end;
     
  4. Postscripter

    Postscripter New Member

    Публикаций:
    0
    Регистрация:
    15 май 2009
    Сообщения:
    63
    Сбой происходит в момент запуска абсолютно любой программы, но где именно - сказать не могу, семёркой не владею..... Компилировал под Delphi7, работает, как и говорил, на XP + Vista.
    Процедура CheckDriveType - вообще в одну строчку result:=GetDriveType(PChar(DriveLetter + ':\'));

    Может, ошибка в методе перехвата? Так я его не менял - всё как у товарища Рема))

    Код (Text):
    1. {
    2.   Установка перехвата функции.
    3.   TargetProc - адрес перехватываемой функции,
    4.   NewProc    - адрес функции замены,
    5.   OldProc    - здесь будет сохранен адрес моста к старой функции.
    6. }
    7. function HookCode(TargetProc, NewProc: pointer; var OldProc: pointer): boolean;
    8. var
    9.   Address: dword;
    10.   OldProtect: dword;
    11.   OldFunction: pointer;
    12.   Proc: pointer;
    13. begin
    14.   Result := False;
    15.   try
    16.     Proc := TargetProc;
    17.     //вычисляем адрес относительного (jmp near) перехода на новую функцию  
    18.     Address := dword(NewProc) - dword(Proc) - 5;
    19.     VirtualProtect(Proc, 5, PAGE_EXECUTE_READWRITE, OldProtect);
    20.     //создаем буффер для true функции
    21.     GetMem(OldFunction, 255);
    22.     //копируем первые 4 байта функции
    23.     dword(OldFunction^) := dword(Proc);
    24.     byte(pointer(dword(OldFunction) + 4)^) := SaveOldFunction(Proc, pointer(dword(OldFunction) + 5));
    25.     //byte(pointer(dword(OldFunction) + 4)^) - длина сохраненного участка
    26.     byte(Proc^) := $e9; //устанавливаем переход
    27.     dword(pointer(dword(Proc) + 1)^) := Address;
    28.     VirtualProtect(Proc, 5, OldProtect, OldProtect);
    29.     OldProc := pointer(dword(OldFunction) + 5);
    30.   except
    31.     Exit;
    32.   end;
    33.   Result := True;
    34. end;
    35.  
    36.  
    37. {
    38.  Установка перехвата функции из Dll в текущем процессе.
    39.  lpModuleName - имя модуля,
    40.  lpProcName   - имя функции,
    41.  NewProc    - адрес функции замены,
    42.  OldProc    - здесь будет сохранен адрес моста к старой функции.
    43.  В случае отсутствия модуля в текущем АП, будет сделана попытка его загрузить.
    44. }
    45. function HookProc(lpModuleName, lpProcName: PChar;
    46.                   NewProc: pointer; var OldProc: pointer): boolean;
    47. var
    48.  hModule: dword;
    49.  fnAdr: pointer;
    50. begin
    51.  Result := false;
    52.  hModule := GetModuleHandle(lpModuleName);
    53.  if hModule = 0 then hModule := LoadLibrary(lpModuleName);
    54.  if hModule = 0 then Exit;
    55.  fnAdr := GetProcAddress(hModule, lpProcName);
    56.  if fnAdr = nil then Exit;
    57.  Result := HookCode(fnAdr, NewProc, OldProc);
    58. end;
     
  5. Postscripter

    Postscripter New Member

    Публикаций:
    0
    Регистрация:
    15 май 2009
    Сообщения:
    63
    А может и не получает... Факт то что сбой - только в момент запуска любого процесса! В аттаче - либа, о каждом своём шаге она отчитывается через ShowMessage, если у кого семёрка есть, проверьте на каком этапе сбой plz? Спасибо.........
     
  6. Postscripter

    Postscripter New Member

    Публикаций:
    0
    Регистрация:
    15 май 2009
    Сообщения:
    63
    Или это из-за того что я её upx-ом сжимал? Хотя вряд ли - на висте пахает...
     
  7. PSR1257

    PSR1257 New Member

    Публикаций:
    0
    Регистрация:
    30 ноя 2008
    Сообщения:
    933
    Postscripter

    Возможно, думать почему еще рано. Нужно собирать данные. Например установить обработчег исключений (UnhandledExceptionHandler/etc) и понять в какой точке происходит сбой (крашдамп с EIP и необходимым количеством байтов по EIP чтобы локализовать сбойный код).
     
  8. Postscripter

    Postscripter New Member

    Публикаций:
    0
    Регистрация:
    15 май 2009
    Сообщения:
    63
    Но у меня нет семёрки...(( Что такого принципиально нового могло появиться в Win7 ?? И ошибка какая-то странная - StackHash... о_0 ? Она что там, контрольные суммы высчитывает??? Перед тем как процедуру вызвать... Самое интересное - что проявляется не на всех семёрках, судя по письмам, на половине машин точно
     
  9. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    StackHash_0a9e1 в студию.
     
  10. K10

    K10 New Member

    Публикаций:
    0
    Регистрация:
    3 окт 2008
    Сообщения:
    1.590
    поставить семерку и посмотреть отладчиком?
     
  11. Postscripter

    Postscripter New Member

    Публикаций:
    0
    Регистрация:
    15 май 2009
    Сообщения:
    63
    - Что именно нужно???

    Код (Text):
    1. поставить семерку и посмотреть отладчиком?
    - у меня проблемы и с тем и с другим ))))))))))))))))))))

    Прочитал, что DEP может быть причиной такого поведения... На семёрке он по умолчанию включен для всех программ.
     
  12. Sunzer

    Sunzer Member

    Публикаций:
    0
    Регистрация:
    25 май 2008
    Сообщения:
    256
    Скачайте, и поставьте на виртуалку
     
  13. Postscripter

    Postscripter New Member

    Публикаций:
    0
    Регистрация:
    15 май 2009
    Сообщения:
    63
    А много весит?? У меня 128 кбс, но попробую!

    жесть)) А ведь, говорят, так и было раньше - штырьки переставляли)))))))))))
     
  14. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Postscripter
     
  15. Postscripter

    Postscripter New Member

    Публикаций:
    0
    Регистрация:
    15 май 2009
    Сообщения:
    63
    Clerk - вот это и есть имя модуля. Виртуальный он, несуществующий.. но ошибки генерит исправно)))
     
  16. Postscripter

    Postscripter New Member

    Публикаций:
    0
    Регистрация:
    15 май 2009
    Сообщения:
    63
    Ну, в общем, я разобрался... по правилам Wasm'а надо всем рассказать как;)

    Короче всё просто, обратите внимание на эту строчку: GetMem(OldFunction, 255);
    Не вдаваясь в подробности (я в них не уверен, поэтому всё только с точки зрения логики) - где распределяется память? В сегменте данных наверное. А потом, в момент вызова "CreateProcess" по этому адресу посылают ЦП, который не дурак, а Intel, и, при включённом DEP, на аппаратном уровне предотвращает ошибки типа переполнения буфера. То есть запрещает выполнение кода из сегмента данных...

    Проблема решилась включением DEP для всех программ - теперь ошибка проявляется и на XP-е тоже)))
     
  17. Postscripter

    Postscripter New Member

    Публикаций:
    0
    Регистрация:
    15 май 2009
    Сообщения:
    63
    Решать надо, как мне кажется, выделением участка памяти в сегменте кода, например, написанием процедуры типа

    Код (Text):
    1.  asm
    2.   nop
    3.   nop
    4.   ... ... ...
    5.   nop
    6.  end;
    И потом писать новый код по адресу этой процедуры. Хотя немного сомневаюсь что компилятор делфи - умняшка - вообще включает команды типа nop в exe-файл )))
     
  18. Postscripter

    Postscripter New Member

    Публикаций:
    0
    Регистрация:
    15 май 2009
    Сообщения:
    63
    Но вот проблема - проверить не получается...
    Если вместо

    GetMem(OldFunction, 255);

    написать

    OldFunction:=@NopProc;

    то всё перестаёт работать, то есть управление коду NewCreateProcessW не передаётся...(
     
  19. Postscripter

    Postscripter New Member

    Публикаций:
    0
    Регистрация:
    15 май 2009
    Сообщения:
    63
    И в процедуре Hook code срабатывает исключение.. Может в сегмент кода писать нельзя? Надо воспользоваться VirtualProtect и открыть @процедуру для записи, да?
     
  20. Postscripter

    Postscripter New Member

    Публикаций:
    0
    Регистрация:
    15 май 2009
    Сообщения:
    63
    ЙеС!

    Всем спасибо за моральную поддерку=)

    Исправленный код:
    Код (Text):
    1. // Пустая процедура для выполнения произвольного кода
    2. Procedure NopProc;
    3. begin  {20*25}
    4.  asm
    5.   nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;
    6.   nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;
    7.   nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;
    8.   nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;
    9.   nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;
    10.   nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;
    11.   nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;
    12.   nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;
    13.   nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;
    14.   nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;
    15.   nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;
    16.   nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;
    17.   nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;
    18.   nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;
    19.   nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;
    20.   nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;
    21.   nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;
    22.   nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;
    23.   nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;
    24.   nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;
    25.  end;
    26. end;
    27.  
    28.  
    29.  
    30. function HookCode(TargetProc, NewProc: pointer; var OldProc: pointer): boolean;
    31. var
    32.   Address: dword;
    33.   OldProtect, oldprotect2: dword;
    34.   OldFunction: pointer;
    35.   Proc: pointer;
    36. begin
    37.   Result := False;
    38.   try
    39.     Proc := TargetProc;
    40.     //вычисляем адрес относительного (jmp near) перехода на новую функцию  
    41.     Address := dword(NewProc) - dword(Proc) - 5;
    42.     VirtualProtect(Proc, 5, PAGE_EXECUTE_READWRITE, OldProtect);
    43.     VirtualProtect(@NopProc, 100, PAGE_EXECUTE_READWRITE, oldprotect2);  {***********}
    44.     //создаем буффер для true функции
    45.     //GetMem(OldFunction, 255);  {***********}
    46.     OldFunction:=@NopProc;  // Выделим область в сегменте кода, дабы не раздражать DEP {***********}
    47.     //копируем первые 4 байта функции
    48.     dword(OldFunction^) := dword(Proc);
    49.     byte(pointer(dword(OldFunction) + 4)^) := SaveOldFunction(Proc, pointer(dword(OldFunction) + 5));
    50.     //byte(pointer(dword(OldFunction) + 4)^) - длина сохраненного участка
    51.     byte(Proc^) := $e9; //устанавливаем переход
    52.     dword(pointer(dword(Proc) + 1)^) := Address;
    53.     VirtualProtect(Proc, 5, OldProtect, OldProtect);
    54.     VirtualProtect(@NopProc, 5, OldProtect2, OldProtect2); {***********}
    55.     OldProc := pointer(dword(OldFunction) + 5);
    56.   except    
    57.     messagebeep(mb_iconerror);
    58.     Exit;
    59.   end;
    60.   Result := True;
    61. end;