卸载远端进程的模块(张佩)
我看到了很多用创建远端线程的方法注入dll的文章,内容大同小异。但奇怪的是,没有一篇文章介绍如何把注入的远端线程卸载掉的方法。为了实践自己的好奇心,我试着实现了一下,使用的是类似注入dll的方法。
1.首先我想到调用什么API卸载DLL。我想到用遍历IAT的方法,找到唯一的dll名字,然后将它隐藏。我虽然没有实际去做,但我立刻就意识到了此方法的缺点:只是修改了IAT,而没有真正地卸载,因为我还不知道实现卸载的技术细节。后来我想到用FreeLibrary函数。其实看到注入过程使用了LoadLibrary函数,应该条件反应地想到用FreeLibrary。但我并没有第一反应地想到它。
2.实现方法:创建远端线程。
好了,来看看FreeLibrary这个函数吧,很幸运我可以用它来作为远端线程的回调函数,看看它的声明是怎样的:
BOOL FreeLibrary(HMODULE hModule);
如果要想成为远端线程的回调函数,其声明格式应该是这样的:
DWORD WINAPI ThreadProc(LPVOID lpParameter);
LPVOID可以强转成HMODULE句柄,DWORD也可以强转成BOOL型变量。所以FreeLibrary是可以作为远端线程的回调函数的。FreeLibrary需要一个参数,HMODULE句柄。为了得到这个句柄,必须遍历进程的句柄列表。
// 传入指定进程的进程ID,还有你要查找的模块地址。
HMODULE GetProcessModule (DWORD dwPID, LPWSTR czDllName)
{
HMODULE hMod = NULL;
BOOL bFound = FALSE;
HANDLE hModuleSnap = NULL;
MODULEENTRY32W me32 = {0};
// Take a snapshot of all modules in the specified process.
hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
if (hModuleSnap == INVALID_HANDLE_VALUE)
return (FALSE);
// Fill the size of the structure before using it.
me32.dwSize = sizeof(MODULEENTRY32W);
// Walk the module list of the process, and find the module of
// interest. Then copy the information to the buffer pointed
// to by lpMe32 so that it can be returned to the caller.
if (Module32FirstW(hModuleSnap, &me32))
{
do
{
if(0 == lstrcmpiW(czDllName, me32.szExePath)){
hMod = me32.hModule;
}
printf("%S/n", me32.szExePath);
}
while (hMod == NULL && Module32NextW(hModuleSnap, &me32));
}
else
hMod = NULL; // could not walk module list
// Do not forget to clean up the snapshot object.
CloseHandle (hModuleSnap);
return hMod;
}
从这个函数返回的是一个模块句柄,它将作为回调函数的参数被写入指定进程中。写入过程和注入DLL时使用的方法是一样的。
获得FreeLibrary函数全局指针:
pfnFreeLibrary = (PTHREAD_START_ROUTINE)
GetProcAddress( GetModuleHandleW(L"Kernel32"), "FreeLibrary" );
if( pfnFreeLibrary==NULL )
{
printf( "Err 0x%08x: GetProcAddressW/n", GetLastError() );
goto ERROR_EXIT;
}
写入模块句柄参数:
hRemoteProcess = OpenProcess( PROCESS_QUERY_INFORMATION|PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ,
FALSE,
pid );
if( hRemoteProcess==NULL )
{
printf( "Err 0x%08x: OpenProcess/n", GetLastError() );
goto ERROR_EXIT;
}
dwSize = 4;
szRemoteDllPath = (WCHAR*)VirtualAllocEx(
hRemoteProcess,
NULL,
dwSize,
MEM_COMMIT,
PAGE_READWRITE );
if( szRemoteDllPath==NULL )
{
printf( "Err 0x%08x: VirtualAllocEx/n", GetLastError() );
goto ERROR_EXIT;
}
rc = WriteProcessMemory(
hRemoteProcess,
szRemoteDllPath,
(PVOID)(&hM),
dwSize,
NULL );
if( rc==0 )
{
printf( "Err 0x%08x: WriteProcessMemory/n", GetLastError() );
goto ERROR_EXIT;
}
创建远端线程并等其执行结束:
hRemoteThread = CreateRemoteThread(
hRemoteProcess,
NULL,
0,
pfnFreeLibrary,
hM,
0,
NULL );
if( hRemoteThread==NULL )
{
printf( "Err 0x%08x: CreateRemoteThread/n", GetLastError() );
goto ERROR_EXIT;
}
rc = WaitForSingleObject( hRemoteThread, 5000 );
if( rc!=WAIT_OBJECT_0 )
{
if( szRemoteDllPath!=NULL )
{
VirtualFreeEx( hRemoteProcess, szRemoteDllPath, 0, MEM_RELEASE );
}
}
到此完工,转载请注明出处,作者张佩。
我看到了很多用创建远端线程的方法注入dll的文章,内容大同小异。但奇怪的是,没有一篇文章介绍如何把注入的远端线程卸载掉的方法。为了实践自己的好奇心,我试着实现了一下,使用的是类似注入dll的方法。
1.首先我想到调用什么API卸载DLL。我想到用遍历IAT的方法,找到唯一的dll名字,然后将它隐藏。我虽然没有实际去做,但我立刻就意识到了此方法的缺点:只是修改了IAT,而没有真正地卸载,因为我还不知道实现卸载的技术细节。后来我想到用FreeLibrary函数。其实看到注入过程使用了LoadLibrary函数,应该条件反应地想到用FreeLibrary。但我并没有第一反应地想到它。
2.实现方法:创建远端线程。
好了,来看看FreeLibrary这个函数吧,很幸运我可以用它来作为远端线程的回调函数,看看它的声明是怎样的:
BOOL FreeLibrary(HMODULE hModule);
如果要想成为远端线程的回调函数,其声明格式应该是这样的:
DWORD WINAPI ThreadProc(LPVOID lpParameter);
LPVOID可以强转成HMODULE句柄,DWORD也可以强转成BOOL型变量。所以FreeLibrary是可以作为远端线程的回调函数的。FreeLibrary需要一个参数,HMODULE句柄。为了得到这个句柄,必须遍历进程的句柄列表。
// 传入指定进程的进程ID,还有你要查找的模块地址。
HMODULE GetProcessModule (DWORD dwPID, LPWSTR czDllName)
{
HMODULE hMod = NULL;
BOOL bFound = FALSE;
HANDLE hModuleSnap = NULL;
MODULEENTRY32W me32 = {0};
// Take a snapshot of all modules in the specified process.
hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
if (hModuleSnap == INVALID_HANDLE_VALUE)
return (FALSE);
// Fill the size of the structure before using it.
me32.dwSize = sizeof(MODULEENTRY32W);
// Walk the module list of the process, and find the module of
// interest. Then copy the information to the buffer pointed
// to by lpMe32 so that it can be returned to the caller.
if (Module32FirstW(hModuleSnap, &me32))
{
do
{
if(0 == lstrcmpiW(czDllName, me32.szExePath)){
hMod = me32.hModule;
}
printf("%S/n", me32.szExePath);
}
while (hMod == NULL && Module32NextW(hModuleSnap, &me32));
}
else
hMod = NULL; // could not walk module list
// Do not forget to clean up the snapshot object.
CloseHandle (hModuleSnap);
return hMod;
}
从这个函数返回的是一个模块句柄,它将作为回调函数的参数被写入指定进程中。写入过程和注入DLL时使用的方法是一样的。
获得FreeLibrary函数全局指针:
pfnFreeLibrary = (PTHREAD_START_ROUTINE)
GetProcAddress( GetModuleHandleW(L"Kernel32"), "FreeLibrary" );
if( pfnFreeLibrary==NULL )
{
printf( "Err 0x%08x: GetProcAddressW/n", GetLastError() );
goto ERROR_EXIT;
}
写入模块句柄参数:
hRemoteProcess = OpenProcess( PROCESS_QUERY_INFORMATION|PROCESS_CREATE_THREAD|PROCESS_VM_OPERATION|PROCESS_VM_WRITE|PROCESS_VM_READ,
FALSE,
pid );
if( hRemoteProcess==NULL )
{
printf( "Err 0x%08x: OpenProcess/n", GetLastError() );
goto ERROR_EXIT;
}
dwSize = 4;
szRemoteDllPath = (WCHAR*)VirtualAllocEx(
hRemoteProcess,
NULL,
dwSize,
MEM_COMMIT,
PAGE_READWRITE );
if( szRemoteDllPath==NULL )
{
printf( "Err 0x%08x: VirtualAllocEx/n", GetLastError() );
goto ERROR_EXIT;
}
rc = WriteProcessMemory(
hRemoteProcess,
szRemoteDllPath,
(PVOID)(&hM),
dwSize,
NULL );
if( rc==0 )
{
printf( "Err 0x%08x: WriteProcessMemory/n", GetLastError() );
goto ERROR_EXIT;
}
创建远端线程并等其执行结束:
hRemoteThread = CreateRemoteThread(
hRemoteProcess,
NULL,
0,
pfnFreeLibrary,
hM,
0,
NULL );
if( hRemoteThread==NULL )
{
printf( "Err 0x%08x: CreateRemoteThread/n", GetLastError() );
goto ERROR_EXIT;
}
rc = WaitForSingleObject( hRemoteThread, 5000 );
if( rc!=WAIT_OBJECT_0 )
{
if( szRemoteDllPath!=NULL )
{
VirtualFreeEx( hRemoteProcess, szRemoteDllPath, 0, MEM_RELEASE );
}
}
到此完工,转载请注明出处,作者张佩。