Текущий архив: 2002.11.11;
Скачать: CL | DM;
ВнизСканирование списков модулей, загруженных в АП тек.процесса Найти похожие ветки
← →
Digitman (2002-09-03 12:34) [0]К сожалению, информация о нижеследующем слишком разрозненна, неполна и противоречива.
Исх.данные :
Вот структуры для доступа к неким спискам, ассоциированным с процессом :
PListEntry = ^TListEntry;
TListEntry = packed record
FLink: PListEntry;
BLink: PListEntry;
end;
PModuleHeader = ^TModuleHeader;
TModuleHeader = packed record
dw00: DWord;
dw04: DWord;
list1,
list2,
list3: TListEntry;
end;
PProcessModuleInfo = ^TProcessModuleInfo;
TProcessModuleInfo = packed record
RecordSize: DWord;
ModuleHeader: TModuleHeader;
end;
PProcessEnvironmentBlock = ^TProcessEnvironmentBlock;
TProcessEnvironmentBlock = packed record
.....
ProcessHinstance: THandle;
ModuleInfo: PProcessModuleInfo;
Unknown2: DWord;
DefaultHeap: THandle;
.....
end;
Здесь TListEntry - управляющий заголовок элемента некоего двунаправленного списка.
Собственно элемент списка, видимо, следует сразу за заголовком (?) и формат его может быть произвольным, в зависимости от контекста.
Вопрос :
1. Назначение списков TModuleHeader.list1(,2,3)
2. Полная структура элемента списка (какого конкретно из 3-х ?), перечисляющего модули, загруженные в АП процесса, PEB которого рассматривается. В дан.случае интересен лишь handle (image base) каждого модуля.
← →
Игорь Шевченко (2002-09-03 12:59) [1]День добрый, Digitman ©,
Если для NT-систем, то, может и могу чем-то помочь, если задача будет более подробна.
С уважением,
← →
Digitman (2002-09-03 13:30) [2]<Игорь Шевченко>
Добрый день !
Да , пока интересна только NT-платформа.
Задача проста :
получить хэндлы всех PE-модулей, загруженных в АП тек.процесса, для некоторой последующей модификации таблицы импорта каждого из них.
toolhelp32 snapshot отпадает - работает не в динамике.
адрес ProcessEnvironmentBlock вычисляется элементарно, равно как и ProcessModuleInfo вместе с ModuleHeader.
в рез-те вынужденной трассировки NtGetModuleFileName() на данный момент мне известно следующее :
- список модулей ведется системой в TListEntry.List1.
- по смещению $18 от начала заголовка элемента списка якобы находится искомое значение хэндла
- блокировка/разблокировка работы сист.загрузчика на момент сканирования списка достигается управлением крит.секцией, ссылка на хэндл которой находится по смещению $A0 (поле TProcessEnvironmentBlock.LoaderLock типа PCriticalSection)
Хотелось бы таки поиметь наиболее правдоподобное и детальное описание структур элементов каждого из вышеупомянутых списков : Коберниченко и Шрайбер либо врут безбожно либо очепяток - море. Да и описание интересующих меня структур отсутствует у обоих авторов напрочь. Нет их, к сожалению, и на http://Sysinternals.com
← →
Игорь Шевченко (2002-09-03 14:18) [3]Гэри Неббет, справочник по базовым функциям NT/Windows 2000 (Native API reference)
RtlQueryProcessDebugInformation с параметром PDI_MODULES
С уважением,
← →
Digitman (2002-09-03 14:31) [4]Нет у меня, к сож., этого букваря под рукой сейчас.
И - опять же - imho, не в динамике работать будет эта ф-ция. Вернет мне статический снимок списка на момент запроса. А при модификации список может измениться. Можно, конечно, блокировать загрузчик перед вызовом ф-ции и после модификации модулей из полученного списка, но это тоже через зад получится ...
← →
Игорь Шевченко (2002-09-03 14:45) [5]Эти смещения не меняются в зависимости от версии ОС ? :-)
Кстати, минуту, ntdll гляну :-)))
← →
paul_shmakov (2002-09-03 15:24) [6]могу такой вариант предложить - мне он нравится больше всего
#include <windows.h>
#include <tchar.h>
#include <iostream>
#ifdef UNICODE
#define _tcout std::wcout
#else
#define _tcout std::cout
#endif
int main(void)
{
TCHAR szModuleName[MAX_PATH];
HMODULE hMod = NULL;
PBYTE pb = NULL;
MEMORY_BASIC_INFORMATION mbi;
while(VirtualQuery(pb, &mbi, sizeof(mbi)) == sizeof(mbi))
{
if(mbi.State == MEM_FREE)
mbi.AllocationBase = mbi.BaseAddress;
if((mbi.AllocationBase == mbi.BaseAddress) && (NULL != mbi.AllocationBase))
{
hMod = static_cast<HMODULE>(mbi.AllocationBase);
if(GetModuleFileName(hMod, szModuleName,
sizeof(szModuleName) / sizeof(szModuleName[0])) > 0)
{
_tcout << hMod << _T(" ") << szModuleName << _T("\n");
}
}
pb += mbi.RegionSize;
}
return 0;
}
← →
Digitman (2002-09-03 16:06) [7]>paul_shmakov
Тогда уж так :
var
hModule: THandle;
mbi: TMemoryBasicInformation;
pRegion: PChar;
begin
pRegion := nil;
while VirtualQuery(pRegion, mbi, sizeof(mbi)) = sizeof(mbi) do
begin
if mbi.State = MEM_FREE then
mbi.AllocationBase := mbi.BaseAddress;
if (mbi.AllocationBase = mbi.BaseAddress) and Assigned(mbi.AllocationBase) then
begin
hModule := THandle(mbi.AllocationBase);
if mbi.Type_9 = MEM_IMAGE then
showmessage(inttohex(hModule, 8));
end;
Inc(pRegion, mbi.RegionSize);
end;
Только вот в момент перечисления системный загрузчик никак не блокирован( .. и состояние AП в части загруженных PE-образов вполне может измениться
← →
Digitman (2002-09-03 16:32) [8]Два варианта для сравнения :
1. От <paul_shmakov>
var
hModule: THandle;
mbi: TMemoryBasicInformation;
pRegion: PChar;
cName: array[0..256] of char;
...
pRegion := nil;
while VirtualQuery(pRegion, mbi, sizeof(mbi)) = sizeof(mbi) do
begin
if mbi.State = MEM_FREE then
mbi.AllocationBase := mbi.BaseAddress;
if (mbi.AllocationBase = mbi.BaseAddress) and Assigned(mbi.AllocationBase) then
begin
hModule := THandle(mbi.AllocationBase);
if mbi.Type_9 = MEM_IMAGE then
begin
GetModuleFileName(hModule, @cName, 255);
ShowMessage(inttohex(hModule, 8) + " : " + string(cName));
end;
end;
Inc(pRegion, mbi.RegionSize);
end;
2. От <Digitman> (быстрее работающий, но - "корявый" без нормальных деклараций структур)
var
pNextModuleInfo: PListEntry;
peb: PPeb;
mh: PModuleHeader;
pmi: PProcessModuleInfo;
hModule: THandle;
...
asm
mov eax, fs:[$18]
mov eax, [eax + $30]
mov [peb], eax
end;
pmi := peb.ModuleInfo;
mh := @pmi.ModuleHeader;
pNextModuleInfo := mh.LoadedModuleList.FLink;
while pNextModuleInfo <> @pmi.ModuleHeader.LoadedModuleList do
begin
hModule:= PInteger(DWord(pNextModuleInfo) + $18)^;
showmessage(inttohex(hModule, 8));
pNextModuleInfo := pNextModuleInfo.FLink;
end;
Ни один вариант не учитывает то, что в момент енумерации системный загрузчик продолжает работать ! И его оч.желательно блокировать. И желательно - с использованием PEB.LoaderLock- поля. Что, в принципе, не вызывает проблем при наличии деклараций PEB-структуры для нескольких платформ ...
Какие еще будут варианты ?
← →
Digitman (2002-09-03 17:01) [9]минимально необходимые фрагменты деклараций к варианту 2 :
PListEntry = ^TListEntry;
TListEntry = packed record
FLink: PListEntry;
BLink: PListEntry;
end;
PModuleHeader = ^TModuleHeader;
TModuleHeader = packed record
dw00: Pointer;
dw04: Pointer;
LoadedModuleList, list2, list3: TListEntry; // что за списки 2 и 3 ? пока неясно
end;
PProcessModuleInfo = ^TProcessModuleInfo;
TProcessModuleInfo = packed record
Size: DWord;
ModuleHeader: TModuleHeader;
end;
PPeb = ^TPeb;
TPeb = packed record
AllocSize: Pointer;
Unknown1: Pointer;
ProcessHinstance: Pointer;
ModuleInfo: PProcessModuleInfo;
Unknown2: Pointer;
DefaultHeap: Pointer;
end;
← →
paul_shmakov (2002-09-03 17:29) [10]2 Digitman:
"Ни один вариант не учитывает то, что в момент енумерации системный загрузчик продолжает работать ! И его оч.желательно блокировать."
если не секрет - зачем блокировать загрузчик? хотя в вашем варианте данные в peb действительно могут измениться, что вызовет av. кто знает..
в моем блокировать ничего не надо.
← →
paul_shmakov (2002-09-03 17:34) [11]2 Digitman:
кстати, вы добавили "if mbi.Type_9 = MEM_IMAGE then" к моему коду. изначально этой проверки не было, т.к., если я не ошибаюсь, win9x/me не поддерживают этот флаг в MEMORY_BASIC_INFORMATION.
поэтому без этой проверки код должен работать везде, а с ней - только на nt/2k/xp.
← →
Digitman (2002-09-03 18:23) [12]>paul_shmakov
> зачем блокировать загрузчик?
Блокировка нужна для исключения ситуации, когда в момент работы с таблицей импорта очередного модуля из получаемого списка этот модуль будет выгружен другим потоком. Исключение, видимо, можно сделать только для ситуации работы енумератора в контексте исполнения DLLProc любого из модулей процесса (имеется ввиду - библиотечные модули) - DLLProc исполняется в крит.секции и загрузчик будет ждать ее освобождения.
> в моем блокировать ничего не надо
А толку-то собственно от енумератора ? Мне ж не просто перечислить хэндлы модулей требуется - для каждого полученного хэндла возможно потребуется модификация таблицы импорта. А в момент модификации незаблокированная система загрузки/выгрузки запросто может выгрузить модуль в другом кодовом потоке или список претертип изменения из-за загрузки нового модуля (и я его упущу из рассмотрения)
MEM_IMAGE меня вполне устраивает, т.к. речь идет в первую очередь об NT-платформах. Другой вопрос, что енумератор должен работать предельно быстро (вместе с подразумеваемым кодом сканирования и возможной модификации import table очер.модуля), В твоем же варианте - как он ни красив на первый взгляд - будет масса "холостых" циклов из-за фильтрации модулей вызовом GetModuleFileName(), каждый из которых "лезет" в PEB и занимается символьным копированием, и далеко не каждый из которых вернет достоверный факт того, что очередной регион есть очередной искомый мной PE-образ.
Собственно, в теле GetModuleFileName() и работает то, что я пытаюсь представить своим вариантом, так что получается не очень хорошо и эффективно, imho.. Так что пока вот теряюсь я в выборе решения..
← →
paul_shmakov (2002-09-03 20:43) [13]"Блокировка нужна для исключения ситуации, когда в момент работы с таблицей импорта очередного модуля из получаемого списка этот модуль будет выгружен другим потоком. Исключение, видимо, можно сделать только для ситуации работы енумератора в контексте исполнения DLLProc любого из модулей процесса (имеется ввиду - библиотечные модули) - DLLProc исполняется в крит.секции и загрузчик будет ждать ее освобождения."
как вариант можно увеличивать счетчик пользователей модуля тем или иным способом на время работы, а потом уменьшать. например, если это dll:
LoadLibrary()
try
// работаем с импортом модуля
finally
FreeLibrary();
end;
что-то вроде этого.
"В твоем же варианте - как он ни красив на первый взгляд - будет масса "холостых" циклов из-за фильтрации модулей вызовом GetModuleFileName(), каждый из которых "лезет" в PEB и занимается символьным копированием, и далеко не каждый из которых вернет достоверный факт того, что очередной регион есть очередной искомый мной PE-образ."
все верно - вариант тормозной. но я его использую по причине его работы везде - мне win9x тоже важны :(
поэтому приходится жертвовать производительностью.
если только nt, то конечно стоит поискать более производительные варианты.
но копать имхо нужно именно в сторону инкремента/декремена reference count модулей на время работы с ними.
← →
Digitman (2002-09-04 08:12) [14]>paul_shmakov
Благодарю за идею. Буду взвешивать все "за" и "против"
← →
Игорь Шевченко (2002-09-04 09:55) [15]Пример только для NT. Проверялся на WinNT 4.0, WinXP Pro
Часть 1:
unit main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls, NtPEB;
type
TfMain = class(TForm)
ListView: TListView;
CloseButton: TButton;
procedure FormCreate(Sender: TObject);
procedure CloseButtonClick(Sender: TObject);
private
FLoaderLock : Pointer;
FCurrentPeb : PPEB;
procedure BuildModulesList;
procedure DisplayModule (ModuleEntry : PLDR_DATA_TABLE_ENTRY);
procedure LockLoader();
procedure UnlockLoader();
end;
var
fMain: TfMain;
implementation
uses
NTDll, HSNtUtils;
{$R *.dfm}
procedure TfMain.BuildModulesList;
var
LdrData : PPEB_LDR_DATA;
pModule : PLDR_DATA_TABLE_ENTRY;
pLoadOrderList : PPLIST_ENTRY;
begin
LockLoader();
try
LdrData := FCurrentPEB^.Ldr;
pLoadOrderList := @(LdrData^.InLoadOrderModuleList);
pModule := PLDR_DATA_TABLE_ENTRY(pLoadOrderList^);
while (PPLIST_ENTRY(pModule) <> pLoadOrderList) do begin
DisplayModule(pModule);
pModule := PLDR_DATA_TABLE_ENTRY(pModule^.InLoadOrderLinks.Flink);
end;
finally
UnlockLoader();
end;
end;
procedure TfMain.DisplayModule (ModuleEntry : PLDR_DATA_TABLE_ENTRY);
var
LI : TListItem;
begin
LI := ListView.Items.Add();
LI.Caption := Format("%.8x", [Integer(ModuleEntry^.DllBase)]);
LI.SubItems.Add(Format("%.8x", [ModuleEntry^.SizeOfImage]));
LI.SubItems.Add(HSUnicodeStringToAnsiString(ModuleEntry^.FullDllName));
end;
procedure TfMain.LockLoader();
begin
// if HSCanLockLoader() then
// NTDLL.LdrLockLoaderLock(1, 0, @LoaderLock)
// else
// NTDLL.RtlEnterCriticalSection(CurrentPEB.LoaderLock);
end;
procedure TfMain.UnlockLoader();
begin
// if HSCanLockLoader() then
// NTDLL.LdrUnlockLoaderLock(1, LoaderLock)
// else
// NTDLL.RtlLeaveCriticalSection(CurrentPEB.LoaderLock);
end;
procedure TfMain.FormCreate(Sender: TObject);
begin
FCurrentPEB := PPEB(NTDLL.RtlGetCurrentPEB());
BuildModulesList();
end;
procedure TfMain.CloseButtonClick(Sender: TObject);
begin
Close();
end;
end.
← →
Игорь Шевченко (2002-09-04 09:56) [16]Часть 2:
unit NtPEB;
interface
uses
Windows, NtDll; { для типа Unicode_string }
type
Uint4B = Cardinal;
Uint2B = Word;
UChar = Byte;
Ptr32 = Pointer;
PLIST_ENTRY = ^TLIST_ENTRY;
TLIST_ENTRY = packed record
Flink : PLIST_ENTRY;
Blink : PLIST_ENTRY;
end;
PPLIST_ENTRY = ^PLIST_ENTRY;
TPEB_LDR_DATA = packed record
Length : Uint4B;
Initialized : UChar;
AlignmentBytes : array[1..3] of Byte;
SsHandle : Ptr32;
{ Список элементов TLDR_DATA_TABLE_ENTRY }
InLoadOrderModuleList : PLIST_ENTRY;
InMemoryOrderModuleList : PLIST_ENTRY; { Неизвестный список }
InInitializationOrderModuleList : PLIST_ENTRY; { Неизвестный список }
EntryInProgress : Ptr32;
end;
PPEB_LDR_DATA = ^TPEB_LDR_DATA;
TLDR_DATA_TABLE_ENTRY = packed record
InLoadOrderLinks : TLIST_ENTRY;
InMemoryOrderLinks : TLIST_ENTRY;
InInitializationOrderLinks : TLIST_ENTRY;
DllBase : Ptr32;
EntryPoint : Ptr32;
SizeOfImage : Uint4B;
FullDllName : TUNICODE_STRING;
BaseDllName : TUNICODE_STRING;
Flags : Uint4B;
LoadCount : Uint2B;
TlsIndex : Uint2B;
HashLinks : TLIST_ENTRY;
SectionPointer : Ptr32;
CheckSum : Uint4B;
TimeDateStamp : Uint4B;
LoadedImports : Ptr32;
EntryPointActivationContext : Ptr32; { Может, только в XP }
end;
PLDR_DATA_TABLE_ENTRY = ^TLDR_DATA_TABLE_ENTRY;
{ Текущий каталог }
type
TCURDIR = packed record
DosPath : TUNICODE_STRING;
Handle : Ptr32;
end;
{ User Process Parameters - пользовательские параметры процесса }
type
TRTL_USER_PROCESS_PARAMETERS = packed record
MaximumLength : Uint4B;
Length : Uint4B;
Flags : Uint4B;
DebugFlags : Uint4B;
ConsoleHandle : Ptr32;
ConsoleFlags : Uint4B;
StandardInput : Ptr32;
StandardOutput : Ptr32;
StandardError : Ptr32;
CurrentDirectory : TCURDIR;
DllPath : TUNICODE_STRING;
ImagePathName : TUNICODE_STRING;
CommandLine : TUNICODE_STRING;
Environment : Ptr32;
StartingX : Uint4B;
StartingY : Uint4B;
CountX : Uint4B;
CountY : Uint4B;
CountCharsX : Uint4B;
CountCharsY : Uint4B;
FillAttribute : Uint4B;
WindowFlags : Uint4B;
ShowWindowFlags : Uint4B;
WindowTitle : TUNICODE_STRING;
DesktopInfo : TUNICODE_STRING;
ShellInfo : TUNICODE_STRING;
RuntimeData : TUNICODE_STRING;
// +0x090 CurrentDirectores : [32] _RTL_DRIVE_LETTER_CURDIR
end;
PRTL_USER_PROCESS_PARAMETERS = ^TRTL_USER_PROCESS_PARAMETERS;
{ Process Environment Block - блок окружения процесса }
type
TPEB = packed record
InheritedAddressSpace : UChar;
ReadImageFileExecOptions : UChar;
BeingDebugged : UChar;
SpareBool : UChar;
Mutant : Ptr32;
ImageBaseAddress : Ptr32;
Ldr : PPEB_LDR_DATA; { Данные загрузчика }
ProcessParameters : PRTL_USER_PROCESS_PARAMETERS { _RTL_USER_PROCESS_PARAMETERS };
SubSystemData : Ptr32;
ProcessHeap : Ptr32;
FastPebLock : Ptr32; { _RTL_CRITICAL_SECTION }
FastPebLockRoutine : Ptr32;
FastPebUnlockRoutine : Ptr32;
EnvironmentUpdateCount : Uint4B;
KernelCallbackTable : Ptr32;
SystemReserved : Uint4B;
ExecuteOptions : Uint4B; {Pos 0, 2 Bits, SpareBits : Pos 2, 30 Bits }
FreeList : Ptr32; { _PEB_FREE_BLOCK }
TlsExpansionCounter : Uint4B;
TlsBitmap : Ptr32;
TlsBitmapBits : array[0..1] of Uint4B;
ReadOnlySharedMemoryBase : Ptr32;
ReadOnlySharedMemoryHeap : Ptr32;
ReadOnlyStaticServerData : Ptr32;
AnsiCodePageData : Ptr32;
OemCodePageData : Ptr32;
UnicodeCaseTableData : Ptr32;
NumberOfProcessors : Uint4B;
NtGlobalFlag : Uint4B;
CriticalSectionTimeout : TLARGEINTEGER;
HeapSegmentReserve : Uint4B;
HeapSegmentCommit : Uint4B;
HeapDeCommitTotalFreeThreshold : Uint4B;
HeapDeCommitFreeBlockThreshold : Uint4B;
NumberOfHeaps : Uint4B;
MaximumNumberOfHeaps : Uint4B;
ProcessHeaps : Ptr32;
GdiSharedHandleTable : Ptr32;
ProcessStarterHelper : Ptr32;
GdiDCAttributeList : Uint4B;
LoaderLock : Ptr32;
OSMajorVersion : Uint4B;
OSMinorVersion : Uint4B;
OSBuildNumber : Uint2B;
OSCSDVersion : Uint2B;
OSPlatformId : Uint4B;
ImageSubsystem : Uint4B;
ImageSubsystemMajorVersion : Uint4B;
ImageSubsystemMinorVersion : Uint4B;
ImageProcessAffinityMask : Uint4B;
{ Остальные данные опущены }
end;
PPEB = ^TPEB;
implementation
end.
← →
Игорь Шевченко (2002-09-04 09:58) [17]Часть 3:
unit HsNtUtils;
interface
uses
NtDll;
function HSUnicodeStringToAnsiString (usString : TUNICODE_STRING) : AnsiString;
implementation
function HSUnicodeStringToAnsiString (usString : TUNICODE_STRING) : AnsiString;
begin
Result := WideCharLenToString(usString.Buffer,
usString.Length DIV SizeOf(WideChar));
end;
end.
В дополнение:
Закомментрированные части в unit"е main показаны, как идея и не реализованы.
Функция HSCanLockLoader должна проверять, есть ли в NTDLL.DLL фукнции с именами LdrLockLoaderLock и LdrUnlockLoaderLock.
С уважением,
← →
Digitman (2002-09-04 11:13) [18]>paul_shmakov
>Игорь Шевченко
Благодарю за помощь. Все встало на свои места.
P.S.
Проверка показала, что приведенные декларации структур актуальны и для W2k . По кр.мере , в части полей, которые используются механизмом загрузки/выгрузки/блокировки.
← →
Игорь Шевченко (2002-09-04 11:23) [19]Digitman © (04.09.02 11:13)
Я знаю, что в WinXP и в WinNT4 блокировка осуществляется по-разному. В NT через RtlEnterCriticalSection (@PEB^.LoaderLock),
а в WinXP через вызов функции LdrLockLoaderLock.
С уважением,
← →
Digitman (2002-09-04 11:51) [20]>Игорь Шевченко
Не могу, к сож., проверить это - нет под рукой XP.
А ты можешь у себя посмотреть значение поля PEB.LoaderLock в XP ?
Если там таки что-то похожее на хэндл крит.секции, думаю, можно предположить, что LdrLockLoaderLock() просто инкапсулирует функц-ть той же [Rtl]EnterCriticalSection() и в конечном итоге все же использует это поле
← →
paul_shmakov (2002-09-04 13:56) [21]
TPEB
...
FastPebLock : Ptr32; { _RTL_CRITICAL_SECTION }
FastPebLockRoutine : Ptr32;
FastPebUnlockRoutine : Ptr32;
...
интересно, это не то самое?
← →
paul_shmakov (2002-09-04 14:38) [22]у меня (w2k) эти поля указывают на RtlEnterCriticalSection и RtlLeaveCriticalSection, а FastPebLock - критическая секция.
вот программа для определения на других операционках (чтобы руками не проверять):
// locktest.dpr
program locktest;
{$APPTYPE CONSOLE}
uses Windows, SysUtils;
type
PPeb = ^TPeb;
TPeb = packed record
AllocSize: Pointer;
Unknown1: Pointer;
ProcessHinstance: Pointer;
ModuleInfo: Pointer;
ProcessParameters: Pointer;
SubSystemData: Pointer;
ProcessHeap: Pointer;
FastPebLock: Pointer;
FastPebLockRoutine: Pointer;
FastPebUnlockRoutine: Pointer;
end;
procedure PrintPointer(const Text: string; P: Pointer);
begin
WriteLn(Text + " " + IntToHex(Integer(P), 8));
end;
var
Peb: PPeb;
RtlEnterCriticalSection: Pointer;
RtlLeaveCriticalSection: Pointer;
begin
asm
mov eax, fs:[$30]
mov [Peb], eax
end;
RtlEnterCriticalSection := Pointer(GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlEnterCriticalSection"));
RtlLeaveCriticalSection := Pointer(GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlLeaveCriticalSection"));
PrintPointer("Peb.FastPebLockRoutine:", Peb.FastPebLockRoutine);
PrintPointer("RtlEnterCriticalSection:", RtlEnterCriticalSection);
PrintPointer("Peb.FastPebUnlockRoutine:", Peb.FastPebUnlockRoutine);
PrintPointer("RtlLeaveCriticalSection:", RtlLeaveCriticalSection);
end.
← →
paul_shmakov (2002-09-04 14:56) [23]да, еще добавьте к предыдущей программе следующий код для проверки, что Peb.FastPebLock является TTRLCriticalSection;
TPEB
...
ProcessHeap: Pointer;
FastPebLock: PRTLCriticalSection;
FastPebLockRoutine: Pointer;
...
// а это в самый конец
PrintPointer("Peb.FastPebLock.DebugInfo:", Pointer(Peb.FastPebLock.DebugInfo));
PrintPointer("Peb.FastPebLock.LockCount:", Pointer(Peb.FastPebLock.LockCount));
PrintPointer("Peb.FastPebLock.RecursionCount:", Pointer(Peb.FastPebLock.RecursionCount));
PrintPointer("Peb.FastPebLock.OwningThread:", Pointer(Peb.FastPebLock.OwningThread));
PrintPointer("Peb.FastPebLock.LockSemaphore:", Pointer(Peb.FastPebLock.LockSemaphore));
end.
у меня выдает:
Peb.FastPebLockRoutine: 77F81B42
RtlEnterCriticalSection: 77F81B42
Peb.FastPebUnlockRoutine: 77F81B73
RtlLeaveCriticalSection: 77F81B73
Peb.FastPebLock.DebugInfo: 77FCEA80
Peb.FastPebLock.LockCount: FFFFFFFF
Peb.FastPebLock.RecursionCount: 00000000
Peb.FastPebLock.OwningThread: 00000000
Peb.FastPebLock.LockSemaphore: 00000000
из значений полей Peb.FastPebLock видно, что Peb.FastPebLock - это действительно critical section.
поэтому можно попробовать в примере Игоря:
procedure TfMain.LockLoader();
begin
CurrentPEB.FastPebLockRoutine(CurrentPEB.FastPebLock);
end;
procedure TfMain.UnlockLoader();
begin
CurrentPEB.FastPebUnlockRoutine(CurrentPEB.FastPebLock);
end;
← →
Ученик (2002-09-04 15:03) [24]Windows XP
Peb.FastPebLockRoutine: 77F7E21F
RtlEnterCriticalSection: 77F7E21F
Peb.FastPebUnlockRoutine: 77F7E300
RtlLeaveCriticalSection: 77F7E300
Peb.FastPebLock.DebugInfo: 77FC52A0
Peb.FastPebLock.LockCount: FFFFFFFF
Peb.FastPebLock.RecursionCount: 00000000
Peb.FastPebLock.OwningThread: 00000000
Peb.FastPebLock.LockSemaphore: 00000000
← →
Ученик (2002-09-04 15:09) [25]NT 4.0
Peb.FastPebLockRoutine: 77F67500
RtlEnterCriticalSection: 77F67500
Peb.FastPebUnlockRoutine: 77F675D0
RtlLeaveCriticalSection: 77F675D0
Peb.FastPebLock.DebugInfo: 77FA7620
Peb.FastPebLock.LockCount: FFFFFFFF
Peb.FastPebLock.RecursionCount: 00000000
Peb.FastPebLock.OwningThread: 00000000
Peb.FastPebLock.LockSemaphore: 00000000
← →
Игорь Шевченко (2002-09-04 15:22) [26]paul_shmakov © (04.09.02 14:56)
Ученик © (04.09.02 15:09)
Это разные локи. PebLock блокирует доступ к PEB,
а LoaderLock блокирует доступ к PEB^.Ldr.
В разных ОС реализовано по-разному
← →
paul_shmakov (2002-09-04 16:12) [27]2 Игорь Шевченко:
"Это разные локи. PebLock блокирует доступ к PEB,
а LoaderLock блокирует доступ к PEB^.Ldr.
В разных ОС реализовано по-разному"
обидно, если так. а то все очень красиво получается.
а это точно? может все же PebLock блокирует все, включая PEB^.Ldr?
2 Ученик:
спасибо за проверку!
← →
Digitman (2002-09-04 16:19) [28]думаю, что и PEB.LoaderLock - тоже крит.секция
← →
Ученик (2002-09-04 16:22) [29]>paul_shmakov © (04.09.02 16:12)
Не, это не просто так :-)
Нужна помощь, есть идентификатор Thread-а, в принципе есть TEB,
необходимо выяснить откуда этот Thread (не процесс, а модуль -EXE, DLL), киньте название какой-нибудь структуры или функции, дальше, наверно, сам найду.
← →
Игорь Шевченко (2002-09-04 16:38) [30]Ученик © (04.09.02 16:22)
Все модули - это свойство процесса, а не потока. Так что модуль, загруженный одним потоком не должен ничем отличаться от модуля, загруженного другим потоком (IMHO).
Для определения EXE по процессу есть пример в кладовке EnumFunctions - функция HSGetWindowCommandLine - имя EXE"шника, создавшего процесс.
С уважением,
← →
Ученик (2002-09-04 16:51) [31]>>Игорь Шевченко © (04.09.02 16:38)
Мне нужна информация именно о модуле (скорее DLL), так как название EXE я уже получил через информацию о процессе, задача о Hook-ах установленных в системе.
← →
Digitman (2002-09-04 17:11) [32]>Ученик
Для текущего процесса :
- берешь любой адрес из диапазона адресов, занимаемых телом ThreadFunc;
- выполняешь для него FindHInstance() - получаешь хэндл PE-модуля в АП процесса;
- по хэндлу ищешь любым удобным способом (тот же GetModuleFileName) имя файла модуля
← →
Ученик (2002-09-04 19:18) [33]>Digitman © (04.09.02 17:11)
Спасибо, попробую
← →
Игорь Шевченко (2002-09-05 13:07) [34]В дополнение.
В unit"е NtPEB (Игорь Шевченко © (04.09.02 09:56))
в описание структуры TPEB после поля
NtGlobalFlag : Uint4B;
должно быть добавлено поле
Reserved : Uint4B;
← →
Digitman (2002-09-05 13:46) [35]Вот теперь все сходится !)
RtlEnterCriticalSection/RtlLeaveCriticalSection успешно работают и с полем LoaderLock и с полем FastPebLock.
По кр.мере - W2k, NT, XP
← →
Ученик (2002-09-05 17:45) [36]>Digitman © (04.09.02 17:11)
Спасибо, все работает, только хотелось бы избавиться от использования PSAPI (GetModuleFileNameEx), не подскажете на какую структуру мы получаем адрес после FindHInstance ?
← →
Digitman (2002-09-05 18:09) [37]>Ученик
FindhInstance() возвращает хэндл модуля, являющийся по сути базовым линейным адресом начала образа PE-модуля, загруженного в ВАП процесса.
Образ PE-модуля начинается с DOS-заголовка :
PImageDosHeader = ^TImageDosHeader;
{EXTERNALSYM _IMAGE_DOS_HEADER}
_IMAGE_DOS_HEADER = packed record { DOS .EXE header }
e_magic: Word; { Magic number }
e_cblp: Word; { Bytes on last page of file }
e_cp: Word; { Pages in file }
e_crlc: Word; { Relocations }
e_cparhdr: Word; { Size of header in paragraphs }
e_minalloc: Word; { Minimum extra paragraphs needed }
e_maxalloc: Word; { Maximum extra paragraphs needed }
e_ss: Word; { Initial (relative) SS value }
e_sp: Word; { Initial SP value }
e_csum: Word; { Checksum }
e_ip: Word; { Initial IP value }
e_cs: Word; { Initial (relative) CS value }
e_lfarlc: Word; { File address of relocation table }
e_ovno: Word; { Overlay number }
e_res: array [0..3] of Word; { Reserved words }
e_oemid: Word; { OEM identifier (for e_oeminfo) }
e_oeminfo: Word; { OEM information; e_oemid specific}
e_res2: array [0..9] of Word; { Reserved words }
_lfanew: LongInt; { File address of new exe header }
end;
TImageDosHeader = _IMAGE_DOS_HEADER;
{$EXTERNALSYM IMAGE_DOS_HEADER}
IMAGE_DOS_HEADER = _IMAGE_DOS_HEADER;
взято из Windows.pas
← →
Ученик (2002-09-06 08:54) [38]>Digitman © (05.09.02 18:09)
Спасибо, но это к сожалению, не помогло, остановился на GetModuleFileNameEx, другие варианты оказались слишком громоздкими (тоже самое делает GetModuleFileNameEx)
>All
Небольшие добавления (исправления)
_PEB_LDR_DATA = packed record
Length : Cardinal;
Initialized : LongBool;
SsHandle : THandle;
InLoadOrderModuleList : TListEntry;
InMemoryOrderModuleList : TListEntry;
InInitializationOrderModuleList: TListEntry;
end;
TPebLdrData = _PEB_LDR_DATA;
Не знаю как описано в оригинале, но это вроде элементы списка InitializationOrderModuleList
TModuleEntry = packed record
ListEntry : TListEntry;
DllBase : Ptr32;
EntryPoint : Ptr32;
SizeOfImage: Ptr32;
ImageName : TUNICODE_STRING;
end;
PModuleEntry = ^TModuleEntry;
InMemoryOrderModuleList указывает на элементы TLDR_DATA_TABLE_ENTRY
← →
Digitman (2002-09-06 09:09) [39]>Ученик
Я что-то не совсем понял твою задачу.
Еще раз объясни толково - как она пересекается с той, что я описал при инициации ветки ?
← →
Ученик (2002-09-06 09:17) [40]>Digitman © (06.09.02 09:09)
Когда я влез в эту ветку, она честно говоря не пересекалась, потом выяснилось, что они пересекается на реализации GetModuleFileNameEx, там идет сканирование модулей загруженных в процесс и сравнение HInstance с TLDR_DATA_TABLE_ENTRY.DllBase
← →
Digitman (2002-09-06 09:40) [41]>Ученик
Все ясно. Ну, насколько я понял, ты уже определился на сей момент)
← →
Игорь Шевченко (2002-09-06 09:53) [42]Ученик © (06.09.02 08:54)
Откуда информация по дополнениям/исправлениям ? Ссылочку не подскажете ?
← →
Ученик (2002-09-06 10:10) [43]>Игорь Шевченко © (06.09.02 09:53)
Исправления из разных мест, поиск по PEB_LDR_DATA, добавление, (возможно структура не полная) - маленькое исследование для текущего процесса.
← →
Digitman (2002-09-06 10:37) [44]>Ученик
Наверно таки ты ошибаешься - не может такого быть, чтобы элементы TModuleEntry (включающие линк-заголовок), фигурирующие в трех разных списках, имели различные (в части линк-заголовков) структуры.
Проверь еще раз :
_PEB_LDR_DATA = packed record
Length : Cardinal;
Initialized : LongBool;
SsHandle : THandle;
InLoadOrderModuleList : PListEntry; //не сама линк-структура, а указатель на нее
InMemoryOrderModuleList : PListEntry; //тоже самое
InInitializationOrderModuleList: PListEntry; //тоже самое
end;
TPebLdrData = _PEB_LDR_DATA;
TModuleEntry = packed record
//Один и тот же TModuleEntry включен в 3 различные двунаправленные списки с помощью следующих 3-х связующих структур :
InLoadOrderLinks : TLIST_ENTRY; // данный элемент описывает модуль в порядке загрузки модулей в ВАП процесса
InMemoryOrderLinks : TLIST_ENTRY; // в порядке возрастания адресов загруженных модулей размещения в ВАП процесса
InInitializationOrderLinks : TLIST_ENTRY; // в порядке инициализации модулей
DllBase : Ptr32;
EntryPoint : Ptr32;
SizeOfImage: Ptr32;
ImageName : TUNICODE_STRING;
end;
PModuleEntry = ^TModuleEntry;
← →
Ученик (2002-09-06 11:14) [45]>Digitman © (06.09.02 10:37)
Попробуйте пройтись по InInitializationOrderModuleList с использованием PPEB_LDR_DATA
← →
Digitman (2002-09-06 11:45) [46]>Ученик
Тут вот что получается :
Для каждого непоследнего элемента InInitializationOrderModuleList - списка
его ListEntry.FLink указывает вот сюда :
TLDR_DATA_TABLE_ENTRY = packed record
InLoadOrderLinks : TLIST_ENTRY; //оно есть ! никуда не делось !
ListEntry.FLink -->>> InMemoryOrderLinks : TLIST_ENTRY;
InInitializationOrderLinks : TLIST_ENTRY;
DllBase : Ptr32;
EntryPoint : Ptr32;
SizeOfImage : Uint4B;
FullDllName : TUNICODE_STRING;
BaseDllName : TUNICODE_STRING;
.....
end;
← →
Ученик (2002-09-06 11:55) [47]>Digitman © (06.09.02 11:45)
Тут, наверно, можно долго спорить, попробуйте пройтись по всем трем спискам с использованием одной структуры элементов (TLDR_DATA_TABLE_ENTRY), так как если использованы PListEntry, то когда берется PEB_LDR_DATA.InInitializationOrderModuleList, реально мы берем PEB_LDR_DATA.InMemoryOrderModuleList.FLink
← →
Игорь Шевченко (2002-09-06 12:07) [48]Ученик © (06.09.02 11:55)
Кроме загрузчика на этот вопрос вряд ли кто-то сможет достоверно ответить. Я могу сказать, что экперимент по обходу списка
InMemoryOrderModuleList со ссылками TLDR_DATA_TABLE_ENTRY.InMemoryOrderLinks закончился Access Violation. Из чего я сделал вывод, что структуры там могут быть другие.
С уважением,
← →
Ученик (2002-09-06 12:13) [49]http://www.faqsen.de/delphi/faq.jsp?ID=505448494850494849545250
http://person.okey.net/~webcrazy/module.htm
По всем трем спискам при использовании TListEntry в _PEB_LDR_DATA гуляем без проблем
← →
Игорь Шевченко (2002-09-06 12:40) [50]Ученик © (06.09.02 12:13)
Если внимательно проанализировать последний пример( http://person.okey.net/~webcrazy/module.htm), то видно, что смещения там совсем другие, чем в TLDR_DATA_TABLE_ENTRY
> По всем трем спискам при использовании TListEntry в _PEB_LDR_DATA
> гуляем без проблем
Если у вас есть код, который это делает, не трудно в форум положить ?
С уважением,
← →
Ученик (2002-09-06 12:45) [51]Структуры обрезал (пока не уверен, в дальнейших полях)
TLDR_DATA_TABLE_ENTRY_1 = packed record
InLoadOrderModuleList : TListEntry;
InMemoryOrderModuleList : TListEntry;
InInitializationOrderModuleList: TListEntry;
DllBase : DWord;
EntryPoint : DWord;
SizeOfImage : DWord;
FullDllName : TNtUnicodeString;
BaseDllName : TNtUnicodeString;
Flags : DWord;
end;
PLDR_DATA_TABLE_ENTRY_1 = ^TLDR_DATA_TABLE_ENTRY_1;
TLDR_DATA_TABLE_ENTRY_2 = packed record
ListEntry : TListEntry;
dwUnknown1 : DWord;
dwUnknown2 : DWord;
DllBase : DWord;
EntryPoint : DWord;
SizeOfImage : DWord;
FullDllName : TNtUnicodeString;
BaseDllName : TNtUnicodeString;
Flags : DWord;
end;
PLDR_DATA_TABLE_ENTRY_2 = ^TLDR_DATA_TABLE_ENTRY_2;
TLDR_DATA_TABLE_ENTRY_3 = packed record
ListEntry : TListEntry;
DllBase : DWord;
EntryPoint : DWord;
SizeOfImage: DWord;
ImageName : TNtUnicodeString;
BaseName : TNtUnicodeString;
Flags : DWord;
end;
PLDR_DATA_TABLE_ENTRY_3 = ^TLDR_DATA_TABLE_ENTRY_3;
procedure TForm1.BuildModulesList1;
var
pModule : PLDR_DATA_TABLE_ENTRY_1;
LdrData : PPebLdrData;
begin
ListView.Clear;
LdrData := GetCurrentPeb.Ldr;
pModule := PLDR_DATA_TABLE_ENTRY_1(LdrData.InLoadOrderModuleList.FLink);
repeat
DisplayModule1(pModule);
pModule := PLDR_DATA_TABLE_ENTRY_1(pModule.InLoadOrderModuleList.Flink);
until pModule = @LdrData.InLoadOrderModuleList;
end;
procedure TForm1.BuildModulesList2;
var
pModule : PLDR_DATA_TABLE_ENTRY_2;
LdrData : PPebLdrData;
begin
ListView.Clear;
LdrData := GetCurrentPeb.Ldr;
pModule := PLDR_DATA_TABLE_ENTRY_2(LdrData.InMemoryOrderModuleList.FLink);
repeat
DisplayModule2(pModule);
pModule := PLDR_DATA_TABLE_ENTRY_2(pModule.ListEntry.Flink);
until pModule = @LdrData.InMemoryOrderModuleList;
end;
procedure TForm1.BuildModulesList3;
var
pModule : PLDR_DATA_TABLE_ENTRY_3;
LdrData : PPebLdrData;
begin
ListView.Clear;
LdrData := GetCurrentPeb.Ldr;
pModule := PLDR_DATA_TABLE_ENTRY_3(LdrData.InInitializationOrderModuleList.FLink);
repeat
DisplayModule3(pModule);
pModule := PLDR_DATA_TABLE_ENTRY_3(pModule.ListEntry.Flink);
until pModule = @LdrData.InInitializationOrderModuleList;
end;
← →
Игорь Шевченко (2002-09-06 13:07) [52]Ученик © (06.09.02 12:45)
Спасибо, теперь все ясно. Это одна и та же структура (TLDR_DATA_TABLE_ENTRY) просто из разных списков она видна с разными смещениями, так, чтобы нужный ListEntry был всегда в начале.
То есть, в InMemoryOrderModuleList находятся адреса InMemoryOrderLinks и так далее.
← →
Digitman (2002-09-06 13:10) [53]>Игорь Шевченко (06.09.02 13:07)
Вот и я о том же)
← →
Ученик (2002-09-06 13:20) [54]Одна и та же структура в памяти, но при обращении они все-таки разные
← →
Digitman (2002-09-06 13:50) [55]>Ученик
Просто дополнительная декларация нужна. С учетом смещения на пропускаемый линк. Ее и использовать для такого случая
← →
Ученик (2002-09-06 13:55) [56]>Digitman © (06.09.02 13:50)
Это как "С учетом смещения на пропускаемый линк" ?
← →
Digitman (2002-09-06 14:07) [57]Ну вот же - Digitman © (06.09.02 11:45)
← →
Ученик (2002-09-06 14:16) [58]>Digitman © (06.09.02 14:07)
Не понял, как будет выглядеть проход по второму или третьему списку ?
← →
Игорь Шевченко (2002-09-06 14:50) [59]Ученик © (06.09.02 14:16)
Для того, чтобы получить адрес PLDR_DATA_TABLE_ENTRY из указателя FLink списка, отличающегося от InLoadOrderModuleList, нужно от этого указателя отнять смещение соответствующей структуры TLIST_ENTRY относительно начала TLDR_DATA_TABLE_ENTRY.
← →
Ученик (2002-09-06 15:01) [60]Как получить я понимаю, но нормальный способ это описание разных структур, единственное что можно сделать, это упростить - вложить одну в другую.
← →
Digitman (2002-09-06 16:45) [61]>Ученик
А кто ж запрещает ? Вкладывай)
← →
Ученик (2002-09-09 09:36) [62]Изменения в TLDR_DATA_TABLE_ENTRY
typedef struct _LDR_MODULE
{
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList; // not used
LIST_ENTRY InInitializationOrderModuleList; // not used
PVOID BaseAddress;
ULONG EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
SHORT LoadCount;
SHORT TlsIndex;
HANDLE SectionHandle;
ULONG CheckSum;
ULONG TimeDateStamp;
#ifdef KDBG
IMAGE_SYMBOL_INFO SymbolInfo;
#endif /* KDBG */
} LDR_MODULE, *PLDR_MODULE;
http://prdownloads.sourceforge.net/reactos/0020_source.zip?download
Страницы: 1 2 вся ветка
Текущий архив: 2002.11.11;
Скачать: CL | DM;
Память: 0.66 MB
Время: 0.009 c