Delphi Shared Library 20081014
Преди време използвах Windows 98 и си бях направил любимите "образователни" програми когато изникна гигантски проблем.
Под 9X ядрата има област от паметта между 2Gb и 3Gb която е видима от всички програми. Там се качват повечето от библиотеките като Kernel32, User32, GDI32 и т.н. Когато моята програма направи кръпка върху Kernel32 в рамките на програмата кръпката работи, но когато се друга програма направи същото извикване следва моментален забив защото моя код не се намира в тази специфична област от паметта и в адресното пространство на другата програма го няма.
Тук следваше кратко проучване и се видя само че VisualC++ може да прави т.нар. shared sections и настройка на $IMAGEBASE над 2Gb размера (0x7FFFFFFF) под Delphi не може да се направи.
Така задачите станаха 2 - да направя секциите (всичките) shared и да настроя ImageBase над 2Gb. За щастие имах програма която зареждаше модула където трябва така че всичките настройки ги направих там.
Кратко разяснение - първия коментар е ImageBase. За мое огромно съжаление НЕ РАБОТИ (затова е и закоментарен), защото всички отмествания трябва наново да се направят (т.нар. rebasing). Следва пипането на атрибутите на секциите, тук по-принцип трябва да има някакво зареждане на PE файл и пипане на секциите му, но понеже съм мързелив съм настроил отместванията както на стандартна Delphi DLL. По-интересно е последното с ReBaseImage. Ако пряко се подаде нов ImageBase пак не работи - затова се прибягва до трик - вземам адреса на Kernel32 и казвам на библиотеката да се настрои спрямо него, а DLL loader-а все някак ще се оправи.
За моя съжаление това беше само началото на проблемите ми. Следва продължение...
Под 9X ядрата има област от паметта между 2Gb и 3Gb която е видима от всички програми. Там се качват повечето от библиотеките като Kernel32, User32, GDI32 и т.н. Когато моята програма направи кръпка върху Kernel32 в рамките на програмата кръпката работи, но когато се друга програма направи същото извикване следва моментален забив защото моя код не се намира в тази специфична област от паметта и в адресното пространство на другата програма го няма.
Тук следваше кратко проучване и се видя само че VisualC++ може да прави т.нар. shared sections и настройка на $IMAGEBASE над 2Gb размера (0x7FFFFFFF) под Delphi не може да се направи.
Така задачите станаха 2 - да направя секциите (всичките) shared и да настроя ImageBase над 2Gb. За щастие имах програма която зареждаше модула където трябва така че всичките настройки ги направих там.
procedure PatchLibrary(Filename: string);
var f: file of byte;
i: byte;
a,b,c,d: cardinal;
begin
AssignFile(f, Filename);
Reset(f);
// Seek(f,$136); i:=$23; write(f,i); i:=$81; write(f,i); //imagebase $81230000
Seek(f,$1FE); i:=$72; write(f,i); i:=$83; write(f,i);
Seek(f,$21F); i:=$70; write(f,i);
Seek(f,$226); i:=$72; write(f,i); i:=$83; write(f,i);
Seek(f,$247); i:=$D0; write(f,i);
Seek(f,$24E); i:=$72; write(f,i); i:=$83; write(f,i);
Seek(f,$26F); i:=$D0; write(f,i); i:=$83; write(f,i);
Seek(f,$297); i:=$D0; write(f,i); i:=$83; write(f,i);
a:=0; b:=0; c:=0; //d:=$8123000;
d:=GetModuleHandle('kernel32.dll');
ReBaseImage(PAnsiChar(Filename),nil,true,true,false,0,a,b,c,d,0);
closefile(f);
end;
Кратко разяснение - първия коментар е ImageBase. За мое огромно съжаление НЕ РАБОТИ (затова е и закоментарен), защото всички отмествания трябва наново да се направят (т.нар. rebasing). Следва пипането на атрибутите на секциите, тук по-принцип трябва да има някакво зареждане на PE файл и пипане на секциите му, но понеже съм мързелив съм настроил отместванията както на стандартна Delphi DLL. По-интересно е последното с ReBaseImage. Ако пряко се подаде нов ImageBase пак не работи - затова се прибягва до трик - вземам адреса на Kernel32 и казвам на библиотеката да се настрои спрямо него, а DLL loader-а все някак ще се оправи.
За моя съжаление това беше само началото на проблемите ми. Следва продължение...
CreateProcessAsUser 20081013
Наложи ми се да да стартирам процес като друг потребител (който работи на същата машина) от service.
Та единствения вариaнт е CreateProcessAsUser който изисква обаче един token. Има доста начини да се вземе token, но голяма част от тях изискваха и паролата на потребителя с цел LoginUser което беше безумие.
Та лутайки се се сетих че и WinLogon някак си успява да стартира TaskMgr с акаунта на текущия потребител което е странно защото WinLogon работи на ниво System. Значи начини имаше. Стартирах набързо един WinDBG и видях как го правят.
Следва псевдо-код който прави подобна задачка:
Разяснение: Имаме стартиран процес от потребител USER. Услугата (service) ни работи на ниво System. Намираме процеса който работи под този потребител, отваряме го и му вземаме token. След което го дупликираме с важния (да се чете НАЙ-Важния) параметър и си извикваме като пичове CreateProcessAsUser без да знаем паролата на потребителя.
Всичко това естественно е прекрасно, но работи само под потребители с ранг Administrator и SYSTEM. На останалите не съм го тествал. Под обикновенни потребители НЕ РАБОТИ защото не може да се отвори процеса (още първия ред) поради ниски привилегии.
Кода който работи в WinLogon е подобен, но там го правят малко по-странно. Всичко това с tokens е подобно. Но там правят текущия thread да работи под зададения потребител (NtSetInformationThread) стартират процеса с CreateProcessAsUser, след което връщат привилегиите на зададения thread до предишните такива. За сега смисъла на тази врътка ми остава неразбран.
Та единствения вариaнт е CreateProcessAsUser който изисква обаче един token. Има доста начини да се вземе token, но голяма част от тях изискваха и паролата на потребителя с цел LoginUser което беше безумие.
Та лутайки се се сетих че и WinLogon някак си успява да стартира TaskMgr с акаунта на текущия потребител което е странно защото WinLogon работи на ниво System. Значи начини имаше. Стартирах набързо един WinDBG и видях как го правят.
Следва псевдо-код който прави подобна задачка:
OpenProcess
OpenProcessToken
DuplicateTokenEx (SecurityImpersonation) <- Най-важния параметър
CreateProcessAsUser
Разяснение: Имаме стартиран процес от потребител USER. Услугата (service) ни работи на ниво System. Намираме процеса който работи под този потребител, отваряме го и му вземаме token. След което го дупликираме с важния (да се чете НАЙ-Важния) параметър и си извикваме като пичове CreateProcessAsUser без да знаем паролата на потребителя.
Всичко това естественно е прекрасно, но работи само под потребители с ранг Administrator и SYSTEM. На останалите не съм го тествал. Под обикновенни потребители НЕ РАБОТИ защото не може да се отвори процеса (още първия ред) поради ниски привилегии.
Кода който работи в WinLogon е подобен, но там го правят малко по-странно. Всичко това с tokens е подобно. Но там правят текущия thread да работи под зададения потребител (NtSetInformationThread) стартират процеса с CreateProcessAsUser, след което връщат привилегиите на зададения thread до предишните такива. За сега смисъла на тази врътка ми остава неразбран.
CreateRemoteThread vs. CreateThread 20081013
Преди време се наложи да направя някаква форма на прехващане на основни функции на Windows с образователна цел.
Та едни от основните функции бяха CreateThread и CreateRemoteThread. В документациите функциите са описани доста добре, но реално ми направи впечатление че всичко води към NtCreateThread и в мен се породи въпроса - как тогава работят двете. След кратък размисъл и пускане на debugger истината лъсна наяве. Реално CreateThread НЯМА. Има само някавъв wrapper който извиква CreateRemoteThread, но параметъра hProcess се подава като 0xFFFFFFFF.
Та едни от основните функции бяха CreateThread и CreateRemoteThread. В документациите функциите са описани доста добре, но реално ми направи впечатление че всичко води към NtCreateThread и в мен се породи въпроса - как тогава работят двете. След кратък размисъл и пускане на debugger истината лъсна наяве. Реално CreateThread НЯМА. Има само някавъв wrapper който извиква CreateRemoteThread, но параметъра hProcess се подава като 0xFFFFFFFF.
« предишна страница
(Страница 1 от 1, общо 3 статии)
следваща страница »
