Modules are the libraries (dlls) that are already loaded on a process.
If Our payload needs to connect via internet, it’s a good technique to inject into a process that already has the appropiate dlls loaded. So we need to find which modules are loaded on the procceses. An example of a target dll is WS2_32.dll
CreateToolhelp32Snapshot (Classic technique) (WinAPI)
Takes a snapshot of the specified processes, as well as the heaps, modules, and threads used by these processes.
If the function succeeds, it returns an open handle to the specified snapshot.
HANDLE CreateToolhelp32Snapshot(
[in] DWORD dwFlags,
[in] DWORD th32ProcessID
);
dwFlags=TH32CS_SNAPMODULE
-> Includes all modules of the process specified in th32ProcessID in the snapshot. To enumerate the modules, see Module32First
and Module32Next
. If the function fails with ERROR_BAD_LENGTH
, retry the function until it succeeds.
Final code:
#include <Windows.h>
#include <stdio.h>
#include <tlhelp32.h>
int ListModules(int pid){
HANDLE hSnapshot;
MODULEENTRY32 lpme;
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
if(INVALID_HANDLE_VALUE == hSnapshot){
return -1;
}
lpme.dwSize = sizeof(MODULEENTRY32);
// Snapshot done!
if(!Module32First(hSnapshot, &lpme)){
CloseHandle(hSnapshot);
return -1;
}
printf("%#25s\t\t\t%#10s\t\t%#10s\n", "Module", "Base Address", "Size");
printf("------------------------------------------------------------------------------------------------\n");
do{
printf("%#25s\t\t0x%#10p\t\t%#10d\n", lpme.szModule,lpme.modBaseAddr, lpme.modBaseSize);
} while(Module32Next(hSnapshot, &lpme));
CloseHandle(hSnapshot);
return 1;
}
int main(int argc, char ** argv) {
int pid = 3584;
ListModules(pid);
return 0;
}
Here we can see the output of targeting notepad.exe
.
EnumProcessModulesEx (WinAPI)
EnumProcessModulesEx
retrieves a handle for each module in the specified process that meets the specified filter criteria.
BOOL EnumProcessModulesEx(
[in] HANDLE hProcess,
[out] HMODULE *lphModule,
[in] DWORD cb,
[out] LPDWORD lpcbNeeded,
[in] DWORD dwFilterFlag
);
Once we have a list of module handles, the name could be retrieved with GetModuleBaseNameA
.
Final code:
#include <Windows.h>
#include <stdio.h>
#include <psapi.h>
#pragma comment(lib, "psapi.lib")
int ListModules(int pid){
HANDLE hProc;
HMODULE hModules[1024];
DWORD cb = sizeof(hModules);
DWORD lpcbNeeded;
DWORD numModules;
char lpFilename[1024];
hProc = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, FALSE, pid);
if(hProc != NULL){
if(!EnumProcessModulesEx(hProc, hModules, cb, &lpcbNeeded, LIST_MODULES_ALL)){
CloseHandle(hProc);
return -1;
}
numModules = lpcbNeeded/sizeof(HMODULE);
printf("[+] %d modules\n", numModules);
printf("%#25s\t\t\t%#10s\n", "Module", "Base Address");
printf("------------------------------------------------------------------------------\n");
for(int i=0; i<numModules; i++){
GetModuleBaseNameA(hProc, hModules[i], (LPSTR)lpFilename, 1024);
printf("%#25s\t\t\t0x%#10p\n", lpFilename, hModules[i]);
}
}
return 1;
}
int main(int argc, char ** argv) {
int pid = 3584;
ListModules(pid);
return 0;
}
VirtualQueryEx (WinAPI)
VirtualQueryEx
retrieves information about a range of pages within the virtual address space of a specified process.
SIZE_T VirtualQueryEx(
[in] HANDLE hProcess,
[in, optional] LPCVOID lpAddress,
[out] PMEMORY_BASIC_INFORMATION lpBuffer,
[in] SIZE_T dwLength
);
We need to parse MEMORY_BASIC_INFORMATION
in order to find the base address and the name of the module.
Final code:
#include <Windows.h>
#include <stdio.h>
#include <psapi.h>
#pragma comment(lib, "psapi.lib")
int ListModules(int pid) {
HANDLE hProcess;
MEMORY_BASIC_INFORMATION mbi;
char * base = NULL;
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProcess == NULL)
return -1;
// Query the process memory starting from NULL
while (VirtualQueryEx(hProcess, base, &mbi, sizeof(mbi)) == sizeof(MEMORY_BASIC_INFORMATION)) {
char szModName[MAX_PATH];
// Only on the base address regions
if ((mbi.AllocationBase == mbi.BaseAddress) && (mbi.AllocationBase != NULL)) {
if (GetModuleFileNameEx(hProcess, (HMODULE) mbi.AllocationBase, (LPSTR) szModName, sizeof(szModName) / sizeof(TCHAR)))
printf("%#21llx\t%s\n", mbi.AllocationBase, szModName);
}
// Check the next region
base += mbi.RegionSize;
}
CloseHandle(hProcess);
return 0;
}
int main(int argc, char ** argv) {
int pid = 3584;
ListModules(pid);
return 0;
}