Üye
Eğer bir manual mapper yazdıysanız LoadLibrary veya benzer bir yöntem yoluyla loadlandığında, /Windows/Winsxs'de rastgele bir klasöre uzun bir path olan bir DLL dependencye rastladığınıza eminim.
SxS (side by side assembly) kısaca, kodun DLL kaosunu çözmek için kütüphanelerin belirli sürümlerinden kütüphaneleri kullanmasına izin verir. Örneğin, bir DLL'in V5'ini kullandığınızı ve Microsoft geliştiricilerinin devam etmeye ve aynı DLL'de bazı dahili değişiklikler yapmaya karar verdiğini ve V6'nın artık kodunuzla çalışmadığını düşünelim. Compilerınıza DLL'in 5. Sürümünü kullanmanız gerektiğini ve DLL'in en son sürümüne varsayılan olarak gitmek yerine, Windows yükleyicisi bunun yerine devam edecek ve DLL'in 5. Sürümünü sizin için yükleyecektir.
Bir PE dosyasının import dizini ayrıştırılırken belirli bir DLL'in SxS altında importlandığını hemen bilemeyeceksiniz. Devam edin ve IMAGE_RESOURCE_DİRECTORY resourcelarına bakın RT_MANİFEST adlı bir resource aramalısınız. Eğer resource dizinde yoksa, kullanılmadığı için SxS'yi umursamayabilirsiniz. RT_MANİFEST adlı bir resource bulursanız, devam etmeniz ve bu resourcenin verilerini okumanız gerekir. RT_MANİFEST'İN verileri, ayrıştırılması oldukça kolay olan basit bir XML'DİR.
Notepad'den bir örnek
Önemsememiz gereken tek şey <dependency> taglarındaki bilgilerdir, bu örnekte SxS kullanılarak importlanan bir DLL olduğunu ve hangi DLL'in XML'de mevcut olduğunu için gereken bilgilerin olduğunu görebiliriz.
Aradığımız DLLiİ içeren Windows/Winsxs'deki klasör aşağıdaki gibidir
Wow64 için amd64'ü x86 ile değiştirmemiz gerektiğini unutmayın
Ayrıca, sürümün build numarasına bağlı olarak değiştiğini ve sisteminizin build revizyonunu güncellediğini bilmemiz gerekir. Bu örnekte durum şöyle olurdu
18362 ve 836 olan makinemde mevcut build numarasını ve UBR kullanacağım (her ikisine de regeditten ulaşabilirsiniz)
Bu yüzden hepsini bir araya getirerek, şimdi RT_MANİFEST'TEN gelen bilgileri kullanarak bu dependency için DLL'i tutan klasörü oluşturabiliriz
Windows/WinSxS'ye gidip klasörü açtığımızda comctl32.dll'i görürüz
Şimdi yapmamız gereken tek şey, import dizininden ayrıştırdığımız import listesine geri dönmek, comctl32 adlı dependency'i bulmak ve
comctl32.dll yolunu kullanmak yerine (WOW64'teyse SysWOW64) yukarıdaki yolu kullanın.
Bu, dependency'nin doğru sürümünün uygulama için yüklendiğini doğrular, bu da manual mapimizin çok daha iyi olduğunu gösterir.
Driver yardımıyla SxS Resolve
Bu, bağımlılığın doğru sürümünün uygulama için yüklendiğini garanti eder, bu da manuel haritalamanızın çok daha kararlı olduğu anlamına gelir.
SxS (side by side assembly) kısaca, kodun DLL kaosunu çözmek için kütüphanelerin belirli sürümlerinden kütüphaneleri kullanmasına izin verir. Örneğin, bir DLL'in V5'ini kullandığınızı ve Microsoft geliştiricilerinin devam etmeye ve aynı DLL'de bazı dahili değişiklikler yapmaya karar verdiğini ve V6'nın artık kodunuzla çalışmadığını düşünelim. Compilerınıza DLL'in 5. Sürümünü kullanmanız gerektiğini ve DLL'in en son sürümüne varsayılan olarak gitmek yerine, Windows yükleyicisi bunun yerine devam edecek ve DLL'in 5. Sürümünü sizin için yükleyecektir.
Bir PE dosyasının import dizini ayrıştırılırken belirli bir DLL'in SxS altında importlandığını hemen bilemeyeceksiniz. Devam edin ve IMAGE_RESOURCE_DİRECTORY resourcelarına bakın RT_MANİFEST adlı bir resource aramalısınız. Eğer resource dizinde yoksa, kullanılmadığı için SxS'yi umursamayabilirsiniz. RT_MANİFEST adlı bir resource bulursanız, devam etmeniz ve bu resourcenin verilerini okumanız gerekir. RT_MANİFEST'İN verileri, ayrıştırılması oldukça kolay olan basit bir XML'DİR.
Notepad'den bir örnek
XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Copyright (c) Microsoft Corporation -->
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
name="Microsoft.Windows.Shell.notepad"
processorArchitecture="x86"
version="5.1.0.0"
type="win32"/>
<description>Windows Shell</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
<ws2:dpiAwareness>PerMonitorV2</ws2:dpiAwareness>
</windowsSettings>
</application>
</assembly>
Önemsememiz gereken tek şey <dependency> taglarındaki bilgilerdir, bu örnekte SxS kullanılarak importlanan bir DLL olduğunu ve hangi DLL'in XML'de mevcut olduğunu için gereken bilgilerin olduğunu görebiliriz.
Aradığımız DLLiİ içeren Windows/Winsxs'deki klasör aşağıdaki gibidir
Kod:
amd64_name_publicKeyToken_version_language_irrelevantTokenr
Wow64 için amd64'ü x86 ile değiştirmemiz gerektiğini unutmayın
Ayrıca, sürümün build numarasına bağlı olarak değiştiğini ve sisteminizin build revizyonunu güncellediğini bilmemiz gerekir. Bu örnekte durum şöyle olurdu
Kod:
6.0.buildNumber.updateBuildRevision
18362 ve 836 olan makinemde mevcut build numarasını ve UBR kullanacağım (her ikisine de regeditten ulaşabilirsiniz)
Bu yüzden hepsini bir araya getirerek, şimdi RT_MANİFEST'TEN gelen bilgileri kullanarak bu dependency için DLL'i tutan klasörü oluşturabiliriz
Kod:
amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.18362.836_none_e6c3b34713100821
Windows/WinSxS'ye gidip klasörü açtığımızda comctl32.dll'i görürüz
Şimdi yapmamız gereken tek şey, import dizininden ayrıştırdığımız import listesine geri dönmek, comctl32 adlı dependency'i bulmak ve
comctl32.dll yolunu kullanmak yerine (WOW64'teyse SysWOW64) yukarıdaki yolu kullanın.
Bu, dependency'nin doğru sürümünün uygulama için yüklendiğini doğrular, bu da manual mapimizin çok daha iyi olduğunu gösterir.
Driver yardımıyla SxS Resolve
C:
NTSTATUS ResolveSxS(
IN PMMAP_CONTEXT pContext,
IN PUNICODE_STRING name,
OUT PUNICODE_STRING resolved
)
{
NTSTATUS status = STATUS_NOT_FOUND;
UNICODE_STRING ustrNtdll = { 0 };
BOOLEAN wow64 = PsGetProcessWow64Process( pContext->pProcess ) != NULL;
typedef struct _STRIBG_BUF
{
union
{
UNICODE_STRING name1;
UNICODE_STRING32 name132;
};
union
{
UNICODE_STRING name2;
UNICODE_STRING32 name232;
};
union
{
UNICODE_STRING origName;
UNICODE_STRING32 origName32;
};
union
{
PUNICODE_STRING pResolved;
ULONG pResolved32;
};
wchar_t origBuf[0x100];
wchar_t staticBuf[0x200];
} STRIBG_BUF, *PSTRIBG_BUF;
PSTRIBG_BUF pStringBuf = (PSTRIBG_BUF)pContext->userMem->buffer;
RtlUnicodeStringInit( &ustrNtdll, L"ntdll.dll" );
PVOID hNtdll = GetUserModule( pContext->pProcess, &ustrNtdll, wow64 );
PVOID pQueryName = GetModuleExport( hNtdll, "RtlDosApplyFileIsolationRedirection_Ustr", pContext->pProcess, NULL );
if (pQueryName == NULL)
{
return STATUS_NOT_FOUND;
}
RtlZeroMemory( pStringBuf->origBuf, sizeof( pStringBuf->origBuf ) );
RtlZeroMemory( pStringBuf->staticBuf, sizeof( pStringBuf->staticBuf ) );
memcpy( pStringBuf->origBuf, name->Buffer, name->Length );
if (wow64)
{
pStringBuf->origName32.Buffer = (ULONG)(ULONG_PTR)pStringBuf->origBuf;
pStringBuf->origName32.MaximumLength = sizeof( pStringBuf->origBuf );
pStringBuf->origName32.Length = name->Length;
pStringBuf->name132.Buffer = (ULONG)(ULONG_PTR)pStringBuf->staticBuf;
pStringBuf->name132.MaximumLength = sizeof( pStringBuf->staticBuf );
pStringBuf->name132.Length = 0;
pStringBuf->name232.Buffer = 0;
pStringBuf->name232.Length = pStringBuf->name232.MaximumLength = 0;
}
else
{
RtlInitUnicodeString( &pStringBuf->origName, pStringBuf->origBuf );
RtlInitEmptyUnicodeString( &pStringBuf->name1, pStringBuf->staticBuf, sizeof( pStringBuf->staticBuf ) );
RtlInitEmptyUnicodeString( &pStringBuf->name2, NULL, 0 );
}
__try
{
status = CallRoutine(
FALSE, pContext, pQueryName, 9,
(PVOID)TRUE, &pStringBuf->origName, NULL,
&pStringBuf->name1, &pStringBuf->name2, &pStringBuf->pResolved,
NULL, NULL, NULL
);
if (NT_SUCCESS( status ) && NT_SUCCESS( pContext->userMem->status ))
{
if (wow64)
{
ULONG tmp = ((PUNICODE_STRING32)pStringBuf->pResolved32)->Buffer;
pStringBuf->pResolved = &pStringBuf->name1;
pStringBuf->pResolved->Buffer = (PWCH)tmp;
}
RtlDowncaseUnicodeString( resolved, pStringBuf->pResolved, TRUE );
}
return NT_SUCCESS( status ) ? pContext->userMem->status : status;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return STATUS_UNHANDLED_EXCEPTION;
}
}
Bu, bağımlılığın doğru sürümünün uygulama için yüklendiğini garanti eder, bu da manuel haritalamanızın çok daha kararlı olduğu anlamına gelir.