Arcane
January 13th, 2009, 15:17
HI.
ever wantet to unload a .dll from memory which was imported via the Import Table ? no , well i have , and turns out that windows prevents you from doing this , for security obiviously , as it would be pretty bad to unload a .dll by accident you'd later need
, but none the less i did some research and found out its more then possible if you preform a little magic , so here are the steps described which are required to do this.
1) Unpinning dll's
when windows Loads a .dll into your process space , the .dll is added to the PEB to be more exact in the PEB->LoaderData this Double linked list contains all the Modules Loaded into our image space , lets take a look what it looks like.
typedef struct _PEB_LDR_DATA
{
ULONG Length;
BOOLEAN Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
}
PEB_LDR_DATA, *PPEB_LDR_DATA;
now you see it contains multiple things , for this article the only ones we are interestet in are the 3 LIST_ENTRY's , these 3 are pointers to double linked lists , each entry in the double linked lists contains 1
typedef struct _LDR_MODULE {
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID BaseAddress; PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
SHORT LoadCount; SHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE
now all this , is various info about our .dll , but lets go back to when Windows Loads a .dll , Everytime you call LoadLibraryA("mydll.dll"
windows will add a entry ( if it doesent excist already) and increase the LoadCount by 1 , now what happens when it loads a .dll via our ImportTable ?
well more or less the same except it sets LoadCount to -1 , which means the .dll is pinned , and if this is the case windows will refuse to unload the .dll from memory.
So how do we change this ? well take a look at this code:
bool Mem_Manager::UnPinnAlldlls() {
OutputDebugStringA("UnPinning All Dll's"
;
DWORD PebAddr = 0;
__asm
{
mov eax,DWORD PTR FS:[0x18]
mov eax,DWORD PTR DS:[eax+0x30]
mov PebAddr,eax
}
PPEB Peb = (PPEB)PebAddr;
_LDR_MODULE *peb_ldr_module;
peb_ldr_module = (_LDR_MODULE*)Peb->Ldr->InLoadOrderModuleList.Flink;
// Go through each modules one by one in their load order. DWORD First = 0; while((DWORD)peb_ldr_module != First)
{
if(First == 0)
{
First = (DWORD)peb_ldr_module;
}
peb_ldr_module->LoadCount = 1;
peb_ldr_module = (_LDR_MODULE*)peb_ldr_module->InLoadOrderModuleList.Flink;
}
return true;
}
what happens is:
1. Gets Addr of PEB via __asm{} block
2. Access PEB->PEB_LDR_DATA
3. Get First Loaded Module via : Peb->Ldr->InLoadOrderModuleList.Flink
4. Log Address of First Entry ( as its a Recursive Double linked list , so we stop once we been all the way round)
5. Set RefCount of LoadedModule to 1 , so we can unload it with FreeLibrary
6. Get Next LoadedModule Via: peb_ldr_module->InLoadOrderModuleList.Flink
so once , these steps have been preformed , you can unload any .dll with a simpel call to FreeLibrary("dllName.dll"
and it will be free'd from memory
hope somebody found this interesting , else oh well
ever wantet to unload a .dll from memory which was imported via the Import Table ? no , well i have , and turns out that windows prevents you from doing this , for security obiviously , as it would be pretty bad to unload a .dll by accident you'd later need

1) Unpinning dll's
when windows Loads a .dll into your process space , the .dll is added to the PEB to be more exact in the PEB->LoaderData this Double linked list contains all the Modules Loaded into our image space , lets take a look what it looks like.
typedef struct _PEB_LDR_DATA
{
ULONG Length;
BOOLEAN Initialized;
PVOID SsHandle;
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
}
PEB_LDR_DATA, *PPEB_LDR_DATA;
now you see it contains multiple things , for this article the only ones we are interestet in are the 3 LIST_ENTRY's , these 3 are pointers to double linked lists , each entry in the double linked lists contains 1
typedef struct _LDR_MODULE {
LIST_ENTRY InLoadOrderModuleList;
LIST_ENTRY InMemoryOrderModuleList;
LIST_ENTRY InInitializationOrderModuleList;
PVOID BaseAddress; PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
SHORT LoadCount; SHORT TlsIndex;
LIST_ENTRY HashTableEntry;
ULONG TimeDateStamp;
} LDR_MODULE, *PLDR_MODULE
now all this , is various info about our .dll , but lets go back to when Windows Loads a .dll , Everytime you call LoadLibraryA("mydll.dll"

well more or less the same except it sets LoadCount to -1 , which means the .dll is pinned , and if this is the case windows will refuse to unload the .dll from memory.
So how do we change this ? well take a look at this code:
bool Mem_Manager::UnPinnAlldlls() {
OutputDebugStringA("UnPinning All Dll's"

DWORD PebAddr = 0;
__asm
{
mov eax,DWORD PTR FS:[0x18]
mov eax,DWORD PTR DS:[eax+0x30]
mov PebAddr,eax
}
PPEB Peb = (PPEB)PebAddr;
_LDR_MODULE *peb_ldr_module;
peb_ldr_module = (_LDR_MODULE*)Peb->Ldr->InLoadOrderModuleList.Flink;
// Go through each modules one by one in their load order. DWORD First = 0; while((DWORD)peb_ldr_module != First)
{
if(First == 0)
{
First = (DWORD)peb_ldr_module;
}
peb_ldr_module->LoadCount = 1;
peb_ldr_module = (_LDR_MODULE*)peb_ldr_module->InLoadOrderModuleList.Flink;
}
return true;
}
what happens is:
1. Gets Addr of PEB via __asm{} block
2. Access PEB->PEB_LDR_DATA
3. Get First Loaded Module via : Peb->Ldr->InLoadOrderModuleList.Flink
4. Log Address of First Entry ( as its a Recursive Double linked list , so we stop once we been all the way round)
5. Set RefCount of LoadedModule to 1 , so we can unload it with FreeLibrary
6. Get Next LoadedModule Via: peb_ldr_module->InLoadOrderModuleList.Flink
so once , these steps have been preformed , you can unload any .dll with a simpel call to FreeLibrary("dllName.dll"

hope somebody found this interesting , else oh well