Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > Handle и windows 7


Автор: mayor123 27.9.2012, 01:07
доброго времени суток!
помогите решить проблему. работает по win XP, отказывается работать под Win 7. алгоритм:
1) программа получает SeDebugPrivilege
2) программа определяет PID чужого процесса - определяет корректно
3) программа определяет хэндл - вот тут ХР отрабатывает нормально, а 7-ка в режиме совместимости с вин ХР показывает один хендл, без совместимости - другой, и оба неверные. в чем беда?
hProc := OpenProcess(PROCESS_ALL_ACCESS, false, PID);

вместо PROCESS_ALL_ACCESS были испробованы всеразличные, в т.ч. PROCESS_QUERY_LIMITED_INFORMATION, PROCESS_VM_READ и прочие.

Автор: bems 27.9.2012, 03:38
каждое открытие даёт разный хендл. По числовому значению их сравнивать нельзя
как ты определяешь что хендл "неправильный"?

Автор: Delvish 27.9.2012, 08:47
у меня с ТС немного сходный вопрос - можно я паровозом встану? smile
если прога запущена в IDE - показывает один хендл (хоть 10 раз перезапускаю - он не изменяется и равен, скажем, 1944). а если из проводника запускаю - хендл совершенно другой (и тоже хоть 20 раз перезапущу - определится один и тот же, скажем, 64). но у меня WinXP. и совместимостями я не баловался.

Автор: bems 27.9.2012, 10:06
это значит что от проводника и ide процесс получает разный набор унаследованных хендлов, и нужный получает разной место в таблице хендлов процесса

Автор: Delvish 27.9.2012, 11:41
видимо, я не так выразился. или сам не так понял smile я запускаю программу 1.exe из IDE и она по PID процесса 2.exe смотрит его, 2.exe, хэндл, и получает одно значение. а когда 1.exe запущена из проводника, то она показывает что у 2.exe (который висит себе в памяти, никак не меняясь) совершенно другой хэндл. разве это нормально?
понятно что хэндл будет разный для 1.exe сколько раз я ее буду перезапускать. но почему же у другой проги хэндлы разные при разных обстоятельствах?

для ТС: попробуй "суповой набор"
OpenProcess(
 PROCESS_QUERY_INFORMATION or
 PROCESS_CREATE_THREAD or
 PROCESS_VM_OPERATION or
 PROCESS_VM_WRITE,
 FALSE, ProcID);

должно под 7й отработать нормально

Автор: mayor123 27.9.2012, 12:56
из модуля AdvAPIHook под экспихой InjectDLL работает - библиотека загружается в сторонний процесс и показывает MessageBox, а под 7й MessageBox не появляется. PID процесса верный, значит раз не появляется MessageBox, то проблема с хэндлом. тем более что программа определяет хэндл стороннего процесса в режиме совместимости и без него по разному - странно ведь

Автор: bems 27.9.2012, 13:34
Цитата(Delvish @  27.9.2012,  11:41 Найти цитируемый пост)
 но почему же у другой проги хэндлы разные при разных обстоятельствах?
у процесса стабилен только пид. он является "глобальным" идентификатором объекта в системе, и пока процесс работает этот пид не может быть выдан другому процессу. Что касается хендла, то он "локальный идентификатор". Каждая операция открытия возвращает (с высокой вероятностью) разный хендл. все эти хендлы указывают на один и тот же объект. у одного объекта может быть много хендлов. пока хендл не закрыт, он не будет выдан для другого или того же объекта (но только если открывает тот же процесс). для проверки можешь открыть один и тот же объект два раза (не закрывая первый хендл перед вторым открытием), и убедиться что хендлы разные
прочитай это и посмотри на рисунки в статье http://msdn.microsoft.com/en-us/library/windows/desktop/ms724485%28v=vs.85%29.aspx

Цитата(mayor123 @  27.9.2012,  12:56 Найти цитируемый пост)
из модуля AdvAPIHook под экспихой InjectDLL работает - библиотека загружается в сторонний процесс и показывает MessageBox, а под 7й MessageBox не появляется. PID процесса верный, значит раз не появляется MessageBox, то проблема с хэндлом. тем более что программа определяет хэндл стороннего процесса в режиме совместимости и без него по разному - странно ведь 
ничего странного. хендлы не обязаны быть одинаковыми. ты должен только проверять вернул ли OpenProcess корректный хендл (не 0). А на само значение хендла не смотри
что касается того что не работает инжект, то в семерке тому может быть много других причин. Если OpenProcess не вернула 0 значит у тебя есть валидный хендл

Автор: mayor123 27.9.2012, 13:42
спасибо за ответ. OpenProcess возвращает не ноль - 100 без режима совместимости (сколько раз ни запускал) и около 250 в режиме совместимости. понять бы теперь что за причины отсутствия инжекта в 7й... если есть идея - расскажите, пожалуйста. у меня пока что ничего путного в голове не появляется

Автор: Delvish 27.9.2012, 13:44
Цитата(bems @  27.9.2012,  14:34 Найти цитируемый пост)
у процесса стабилен только пид. он является "глобальным" идентификатором объекта в системе, и пока процесс работает этот пид не может быть выдан другому процессу. Что касается хендла, то он "локальный идентификатор". Каждая операция открытия возвращает (с высокой вероятностью) разный хендл. все эти хендлы указывают на один и тот же объект. у одного объекта может быть много хендлов. пока хендл не закрыт, он не будет выдан для другого или того же объекта (но только если открывает тот же процесс). для проверки можешь открыть один и тот же объект два раза (не закрывая первый хендл перед вторым открытием), и убедиться что хендлы разныепрочитай это и посмотри на рисунки в статье http://msdn.microsoft.com/en-us/library/wi...v=vs.85%29.aspx


хммм... я считал что хэндл при открытии процесса является "глобальным", сродни PID'у, и должен быть постоянным для запущенного приложения, сколько бы раз к нему не обратились. спасибо за просвещение!

Автор: bems 27.9.2012, 13:54
Цитата(mayor123 @  27.9.2012,  13:42 Найти цитируемый пост)
понять бы теперь что за причины отсутствия инжекта в 7й... если есть идея - расскажите, пожалуйста. у меня пока что ничего путного в голове не появляется 
выложи тестовый проект вместе с AdvAPIHook

Автор: mayor123 27.9.2012, 14:16
с библиотекой все просто - один лишь MessageBox(0, 'It is a work!', 'Inject', mb_OK);

код программки:
используемые функции из AdvAPIHook:

взятие ID процесса
Код

function GetProcessId(pName: PChar): dword;
var
 Snap: dword;
 Process: TPROCESSENTRY32;
begin
  Result := 0;
  Snap := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if Snap <> INVALID_HANDLE_VALUE then
     begin
      Process.dwSize := SizeOf(TPROCESSENTRY32);
      if Process32First(Snap, Process) then
         repeat
          if lstrcmpi(Process.szExeFile, pName) = 0 then
             begin
              Result := Process.th32ProcessID;
              CloseHandle(Snap);
              Exit;
             end;
         until not Process32Next(Snap, Process);
      Result := 0;
      CloseHandle(Snap);
     end;
end;


включение Debug-привилегий (вроде без них в 7й никак)
Код

function EnablePrivilegeEx(Process: dword; lpPrivilegeName: PChar):Boolean;
var
  hToken: dword;
  NameValue: Int64;
  tkp: TOKEN_PRIVILEGES;
  ReturnLength: dword;
begin
  Result:=false;
  OpenProcessToken(Process, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken);
  if not LookupPrivilegeValue(nil, lpPrivilegeName, NameValue) then
    begin
     CloseHandle(hToken);
     exit;
    end;
  tkp.PrivilegeCount := 1;
  tkp.Privileges[0].Luid := NameValue;
  tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
  AdjustTokenPrivileges(hToken, false, tkp, SizeOf(TOKEN_PRIVILEGES), tkp, ReturnLength);
  if GetLastError() <> ERROR_SUCCESS then
     begin
      CloseHandle(hToken);
      exit;
     end;
  Result:=true;
  CloseHandle(hToken);
end;


инъекция
Код

Function InjectDll(Process: dword; ModulePath: PChar): boolean;
var
  Memory:pointer;
  Code: dword;
  BytesWritten: dword;
  ThreadId: dword;
  hThread: dword;
  hKernel32: dword;
  Inject: packed record
           PushCommand:byte;
           PushArgument:DWORD;
           CallCommand:WORD;
           CallAddr:DWORD;
           PushExitThread:byte;
           ExitThreadArg:dword;
           CallExitThread:word;
           CallExitThreadAddr:DWord;
           AddrLoadLibrary:pointer;
           AddrExitThread:pointer;
           LibraryName:array[0..MAX_PATH] of char;
          end;
begin
  Result := false;
  Memory := VirtualAllocEx(Process, nil, sizeof(Inject),
                           MEM_COMMIT, PAGE_EXECUTE_READWRITE);
  if Memory = nil then Exit;

  Code := dword(Memory);
  Inject.PushCommand    := $68;
  inject.PushArgument   := code + $1E;
  inject.CallCommand    := $15FF;
  inject.CallAddr       := code + $16;
  inject.PushExitThread := $68;
  inject.ExitThreadArg  := 0;
  inject.CallExitThread := $15FF;
  inject.CallExitThreadAddr := code + $1A;
  hKernel32 := GetModuleHandle('kernel32.dll');
  inject.AddrLoadLibrary := GetProcAddress(hKernel32, 'LoadLibraryA');
  inject.AddrExitThread  := GetProcAddress(hKernel32, 'ExitThread');
  lstrcpy(@inject.LibraryName, ModulePath);
  WriteProcessMemory(Process, Memory, @inject, sizeof(inject), BytesWritten);
  hThread := CreateRemoteThread(Process, nil, 0, Memory, nil, 0, ThreadId);
  if hThread = 0 then Exit;
  CloseHandle(hThread);
  Result := True;
end;


и сам код программочки:
Код

var hFile : Cardinal;
    PID : DWORD;

...

PID := GetProcessId('calc.exe');
EnablePrivilegeEx(INVALID_HANDLE_VALUE, 'SeDebugPrivilege');
hFile := OpenProcess(PROCESS_ALL_ACCESS, False, PID);
InjectDll(hFile, 'test.dll');


Автор: bems 27.9.2012, 14:46
в InjectDll есть молчаливые выходы
 if Memory = nil then Exit;
 if hThread = 0 then Exit;
и не проверяется что возвращает WriteProcessMemory
посмотри не наворачивается ли где-то там

также базовые адреса системных дллок в семерке уже не обязаны совпадать во всех процессах (чтобы совпадали оба процесса должны работать в режиме совместимости с хр)

Добавлено через 51 секунду
еще этот код не будет работать на юникодных делфях и х64-виндах

Автор: mayor123 27.9.2012, 14:53
винда 32 бита, использую Delphi 7. чуть позже попробую с выводом промежуточных результатов в лог по каждому сомнительному моменту, о результатах отпишу. спасибо за идеи

Автор: Illusion Dolphin 27.9.2012, 23:13
Цитата

для ТС: попробуй "суповой набор"
OpenProcess(
 PROCESS_QUERY_INFORMATION or
 PROCESS_CREATE_THREAD or
 PROCESS_VM_OPERATION or
 PROCESS_VM_WRITE,
 FALSE, ProcID);


MSDN:
Код

//A handle to the process in which the thread is to be created. The handle must have the PROCESS_CREATE_THREAD, PROCESS_QUERY_INFORMATION, PROCESS_VM_OPERATION, PROCESS_VM_WRITE, and PROCESS_VM_READ access rights, and may fail without these rights on certain platforms.


Цитата

EnablePrivilegeEx(INVALID_HANDLE_VALUE, 'SeDebugPrivilege');

Не работает под гостем.

Цитата

с библиотекой все просто - один лишь MessageBox(0, 'It is a work!', 'Inject', mb_OK);

Вы ведь в курсе что в DLL_PROCESS_ATTACH нельзя вызывать подобные функции?

Автор: Delvish 28.9.2012, 01:05
Цитата(Illusion Dolphin @  28.9.2012,  00:13 Найти цитируемый пост)
с библиотекой все просто - один лишь MessageBox(0, 'It is a work!', 'Inject', mb_OK);

Вы ведь в курсе что в DLL_PROCESS_ATTACH нельзя вызывать подобные функции?


так тут у него вроде не виртуальная dll с отображением в памяти чужого процесса с измененной таблицей импорта и прочим. разве загруженная таким образом библиотека лишается части функций?

Автор: bems 28.9.2012, 02:06
в DllMain нельзя вызывать ничего кроме kernel32.dll
но обычно user32.dll работает хоть это и запрещено. сама делфи нарушает этот запрет и в основном всё работает
думаю мессейджбокс не при чем

Автор: mayor123 28.9.2012, 14:57
удалось добиться появления MessageBox, но следующая задача - добавить в программу, куда происходит инжект, права на бэкап реестра (SeBackupPrivilege) видимо не получается, т.к. программа не может прочитать некоторые ветки. а если в другой программе задействовать тот же алгоритм - права на бэкап добавляются.

Автор: Dik0n 28.9.2012, 22:17
Программа должна быть запущена обязательно с правами "админа", и не забываем про манифест, что-бы не возникало проблем с UAC.

Код

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="requireAdministrator" uiAccess="false"></requestedExecutionLevel>
      </requestedPrivileges>
    </security>
  </trustInfo>
</assembly>

Автор: mayor123 1.10.2012, 00:10
Всем спасибо. Помогло.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)