UnLoadDll
羊禄
2023-12-01
// 程序功能:结束进程中的一个模块。
// 程序日期:2006.10.8
// 程序说明:这个程序写于2003年,主要针对一些木马注入程序。以往结束远程注入木马(dll)时需要
// 结束进程,这个程序不用结束进程而直接结束单个DLL。结束后会出现一些问题,某些情况
// 下会导致整个进程异常,这是很正常的,例如结束了一个进程需要调用的DLL;或者结束后DLL
// 又被主进程加载,例如mfc42.dll。
// 程序原理:根据DLL地址范围找到进程用的DLL线程,结束这个线程即DLL。
// 调试参数:explorer.exe secur32.dll
#include <windows.h>
#include <stdio.h>
#include <TlHelp32.h>
#pragma warning(disable:4996)
#define OS_SDK 0
#define BUFSIZE 80
typedef enum _THREAD_INFORMATION_CLASS {
ThreadBasicInformation,
ThreadTimes,
ThreadPriority,
ThreadBasePriority,
ThreadAffinityMask,
ThreadImpersonationToken,
ThreadDescriptorTableEntry,
ThreadEnableAlignmentFaultFixup,
ThreadEventPair,
ThreadQuerySetWin32StartAddress,
ThreadZeroTlsCell,
ThreadPerformanceCount,
ThreadAmILastThread,
ThreadIdealProcessor,
ThreadPriorityBoost,
ThreadSetTlsArrayAddress,
ThreadIsIoPending,
ThreadHideFromDebugger
} THREAD_INFORMATION_CLASS, *PTHREAD_INFORMATION_CLASS;
typedef DWORD (CALLBACK* NTQUERYINFORMATIONTHREAD)(HANDLE,DWORD,PVOID,DWORD,PDWORD);
int GetVersionInfo()
{
OSVERSIONINFOEX osvi;
BOOL bOsVersionInfoEx;
// Try calling GetVersionEx using the OSVERSIONINFOEX structure.
// If that fails, try using the OSVERSIONINFO structure.
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) )
{
osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
if (! GetVersionEx ( (OSVERSIONINFO *) &osvi) )
return FALSE;
}
switch (osvi.dwPlatformId)
{
// Test for the Windows NT product family.
case VER_PLATFORM_WIN32_NT:
// Test for the specific product family.
if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 )
printf ("Microsoft Windows .NET Server 2003 family, ");
if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1 )
printf ("Microsoft Windows XP ");
if ( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 )
printf ("Microsoft Windows 2000 ");
if ( osvi.dwMajorVersion <= 4 )
printf("Microsoft Windows NT ");
// Test for specific product on Windows NT 4.0 SP6 and later.
if( bOsVersionInfoEx )
{
#if OS_SDK
// Test for the workstation type.
if ( osvi.wProductType == VER_NT_WORKSTATION )
{
if( osvi.dwMajorVersion == 4 )
printf ( "Workstation 4.0 " );
else if( osvi.wSuiteMask & VER_SUITE_PERSONAL )
printf ( "Home Edition " );
else
printf ( "Professional " );
}
// Test for the server type.
else if ( osvi.wProductType == VER_NT_SERVER )
{
if( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2 )
{
if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
printf ( "Datacenter Edition " );
else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
printf ( "Enterprise Edition " );
else if ( osvi.wSuiteMask == VER_SUITE_BLADE )
printf ( "Web Edition " );
else
printf ( "Standard Edition " );
}
else if( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 )
{
if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
printf ( "Datacenter Server " );
else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
printf ( "Advanced Server " );
else
printf ( "Server " );
}
else // Windows NT 4.0
{
if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
printf ("Server 4.0, Enterprise Edition " );
else
printf ( "Server 4.0 " );
}
}
#endif
}
else // Test for specific product on Windows NT 4.0 SP5 and earlier
{
HKEY hKey;
char szProductType[BUFSIZE];
DWORD dwBufLen=BUFSIZE;
LONG lRet;
lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
"SYSTEM//CurrentControlSet//Control//ProductOptions",
0, KEY_QUERY_VALUE, &hKey );
if( lRet != ERROR_SUCCESS )
return FALSE;
lRet = RegQueryValueEx( hKey, "ProductType", NULL, NULL,
(LPBYTE) szProductType, &dwBufLen);
if( (lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE) )
return FALSE;
RegCloseKey( hKey );
if ( lstrcmpi( "WINNT", szProductType) == 0 )
printf( "Workstation " );
if ( lstrcmpi( "LANMANNT", szProductType) == 0 )
printf( "Server " );
if ( lstrcmpi( "SERVERNT", szProductType) == 0 )
printf( "Advanced Server " );
printf( "%d.%d ", osvi.dwMajorVersion, osvi.dwMinorVersion );
}
// Display service pack (if any) and build number.
if( osvi.dwMajorVersion == 4 &&
lstrcmpi( osvi.szCSDVersion, "Service Pack 6" ) == 0 )
{
HKEY hKey;
LONG lRet;
// Test for SP6 versus SP6a.
lRet = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
"SOFTWARE//Microsoft//Windows NT//CurrentVersion//Hotfix//Q246009",
0, KEY_QUERY_VALUE, &hKey );
if( lRet == ERROR_SUCCESS )
printf( "Service Pack 6a (Build %d)/n", osvi.dwBuildNumber & 0xFFFF );
else // Windows NT 4.0 prior to SP6a
{
printf( "%s (Build %d)/n",
osvi.szCSDVersion,
osvi.dwBuildNumber & 0xFFFF);
}
RegCloseKey( hKey );
}
else // Windows NT 3.51 and earlier or Windows 2000 and later
{
printf( "%s (Build %d)/n",
osvi.szCSDVersion,
osvi.dwBuildNumber & 0xFFFF);
}
break;
// Test for the Windows 95 product family.
case VER_PLATFORM_WIN32_WINDOWS:
if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
{
printf ("Microsoft Windows 95 ");
if ( osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B' )
printf("OSR2 " );
return 0;
}
if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
{
printf ("Microsoft Windows 98 ");
if ( osvi.szCSDVersion[1] == 'A' )
printf("SE " );
return 0;
}
if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
{
printf ("Microsoft Windows Millennium Edition/n");
return 0;
}
break;
case VER_PLATFORM_WIN32s:
printf ("Microsoft Win32s/n");
return 0;
break;
}
return TRUE;
}
// 函数功能:设置权限
BOOL SetPrivilege(LPCTSTR Privilege, BOOL bEnablePrivilege)
{
HANDLE hToken, h;
TOKEN_PRIVILEGES tkp;
// 获得令牌
typedef VOID (WINAPI *MYPROC1)(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle);
MYPROC1 ProcAdd1 = (MYPROC1)GetProcAddress(GetModuleHandle(TEXT("Advapi32")), "OpenProcessToken");
if (ProcAdd1 == NULL)
return FALSE;
h = GetCurrentProcess();
if (h == NULL)
return FALSE;
ProcAdd1(h, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
// 开机关机权限
typedef VOID (WINAPI *MYPROC2)( LPCTSTR lpSystemName, LPCTSTR lpName, PLUID lpLuid);
MYPROC2 ProcAdd2 = (MYPROC2)GetProcAddress(GetModuleHandle(TEXT("Advapi32")), "LookupPrivilegeValueA");
if (ProcAdd2 == NULL)
return FALSE;
(ProcAdd2)(NULL, Privilege, &tkp.Privileges[0].Luid);
// 第一次
tkp.PrivilegeCount = 1; // one privilege to set
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
typedef VOID (WINAPI *MYPROC3)( HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength);
MYPROC3 ProcAdd3 = (MYPROC3)GetProcAddress(GetModuleHandle(TEXT("Advapi32")), "AdjustTokenPrivileges");
if (ProcAdd3 == NULL)
return FALSE;
(ProcAdd3)(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
// 第二次
tkp.PrivilegeCount = 1; // one privilege to set
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if(bEnablePrivilege)
tkp.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
else
tkp.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED & tkp.Privileges[0].Attributes);
(ProcAdd3)(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
return TRUE;
}
// 函数功能:获取关机/重启权限
BOOL SetPrivilege_ShutDown()
{
return SetPrivilege(SE_SHUTDOWN_NAME,true);
}
// 函数功能:获取关闭其它进程权限
int SetPrivilege_Debug()
{
return SetPrivilege(SE_DEBUG_NAME,true);
}
// 函数功能:获取文件的大小
// 函数返回:文件大小
DWORD GetFileSize(char *pFileName)
{
FILE *pFile;
DWORD dwPos;
DWORD dwFileSize;
if( (pFile = fopen(pFileName, "rb" )) == NULL )
{
printf( "The file 'data' was not opened/n" );
return 0;
}
dwPos = ftell(pFile);
fseek(pFile, 0, SEEK_END);
dwFileSize = ftell(pFile);
fseek(pFile, dwPos, SEEK_SET);
fclose(pFile);
return dwFileSize;
}
// 函数功能:杀进程中的模块
typedef HANDLE (WINAPI *MYPROC1)(DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId);
//int KillModule(char *strPName, char *strMName)
int KillModule(char *strMName)
{
char strDllName[MAX_PATH];
HANDLE hProcess, hThread;
DWORD dwStartAddr = 0;
DWORD dwRetLen = 0;
DWORD dwDllSize = 0;
PWSTR pszLibFileRemote = NULL;
int nKilled = 0;
BOOL fOk, fOK1;
HANDLE hmeSnapshot;
BOOL fME;
char *pdest;
HMODULE hNtdll;
int cch;
int cb;
int nDllKillNum;
MYPROC1 ProcAdd1;
PTHREAD_START_ROUTINE pfnThreadRtn;
NTQUERYINFORMATIONTHREAD NtQueryInformationThread;
HANDLE hthSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 pe = { sizeof(pe) };
MODULEENTRY32 me = { sizeof(me) };
char szMsg[MAX_PATH] = {0};
// 遍历所有进程
fOk = Process32First(hthSnapshot, &pe);
for (; fOk; fOk = Process32Next(hthSnapshot, &pe))
{
// 找到远程进程
//if (stricmp(pe.szExeFile, strPName) == 0)
if (1)
{
//wsprintf(szMsg, "process name = %s /n", pe.szExeFile);
//printf("process name = %s /n", pe.szExeFile);
//OutputDebugString(szMsg);
// 遍历模块
hmeSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pe.th32ProcessID);
fME = Module32First(hmeSnapshot, &me);
for (; fME; fME = Module32Next(hmeSnapshot, &me))
{
strcpy(strDllName, me.szExePath);
pdest = strrchr(strDllName, '//');
strcpy(strDllName, ++pdest);
// 找到远程进程中的模块, 杀之,3个步骤
if (stricmp(strDllName, strMName) == 0)
{
//printf("dll name = %s /n", strDllName);
//OutputDebugString(szMsg);
__try
{
// 1.遍历模块中的线程,如果有结束
dwDllSize = GetFileSize(me.szExePath);
HANDLE hthSnapshotT = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, me.th32ProcessID);
if (hthSnapshot == NULL) __leave;
THREADENTRY32 te = { sizeof(te) };
fOK1 = Thread32First(hthSnapshotT, &te);
// 遍历线程
for (; fOK1; fOK1 = Thread32Next(hthSnapshotT, &te))
{
if (te.th32OwnerProcessID == pe.th32ProcessID)
{
//printf("te.th32OwnerProcessID = %d /n", te.th32OwnerProcessID);
__try
{
// 得到线程句柄
ProcAdd1 = (MYPROC1)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "OpenThread");
if (ProcAdd1 == NULL)
return FALSE;
hThread = (ProcAdd1(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID));
if (hThread == NULL) __leave;
// 找到ntdll.dll中函数NtQueryInformationThread地址
hNtdll = LoadLibrary( "ntdll.dll" );
if (!hNtdll) return 0;
NtQueryInformationThread = (NTQUERYINFORMATIONTHREAD)GetProcAddress(hNtdll, "NtQueryInformationThread");
// 获取线程入口地址
NtQueryInformationThread(hThread, ThreadQuerySetWin32StartAddress, &dwStartAddr, 0x4, &dwRetLen);
if (dwStartAddr != NULL)
{
// 判断线程入口地址是否在模块中?????????????????
if ((dwStartAddr - (DWORD)me.hModule) <= dwDllSize)
{
// 结束线程
TerminateThread(hThread, 0);
CloseHandle(hThread);
//printf("TerminateThread successed! /n");
}
}
}
// 释放资源
__except(EXCEPTION_EXECUTE_HANDLER)
{
printf("exception~~~/n");
return 0;
}
}
} // for
// 2.释放DLL
// 获取远程进程中的DLL句柄
hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION | // Required by Alpha
PROCESS_CREATE_THREAD | // For CreateRemoteThread
PROCESS_VM_OPERATION | // For VirtualAllocEx/VirtualFreeEx
PROCESS_VM_WRITE, // For WriteProcessMemory
FALSE, me.th32ProcessID);
if (hProcess == NULL) __leave;
// 计算DLL名称需要的字节数
cch = 1 + strlen(me.szExePath);
cb = cch * sizeof(CHAR);
// 分配远程进程路径名空间
pszLibFileRemote = (PWSTR)VirtualAllocEx(hProcess, NULL, cb, MEM_COMMIT, PAGE_READWRITE);
if (pszLibFileRemote == NULL) __leave;
// 考贝DLL路径名到远程进程空间
if (!WriteProcessMemory(hProcess, pszLibFileRemote, (PVOID)me.szExePath, cb, NULL)) __leave;
// 得到GetModuleHandle在Kernel32.dll中的地址
pfnThreadRtn = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "FreeLibrary");
if (pfnThreadRtn == NULL) __leave;
// 创建远程进程,调用GetModuleHandle(DLLPathname)
nDllKillNum = (me.GlblcntUsage > me.ProccntUsage) ? me.GlblcntUsage : me.ProccntUsage;
if (nDllKillNum == 65535)
nDllKillNum = 3;
for (int i = 0; i < nDllKillNum; i++)
{
hThread = CreateRemoteThread(hProcess, NULL, 0, pfnThreadRtn, me.hModule, 0, NULL);
if (hThread == NULL) __leave;
}
// 3.删除DLL
//DeleteFile(me.szExePath);
CloseHandle(hProcess);
CloseHandle(hThread);
printf("Killed !!!/n");
printf(" in process : %s /n", pe.szExeFile);
nKilled = 1;
}
__finally
{
//printf("exception emun process~~~/n");
//if (hthSnapshot != NULL)
// CloseHandle(hthSnapshot);
}
}// if
} // for
}//end if
}// for
if (hthSnapshot != NULL)
CloseHandle(hthSnapshot);
if (nKilled == 0)
printf("Sorry, No found!/n");
return 0;
}
int main(int argc, char **argv)
{
printf("Force Free Library!/n");
if (argc < 2)
{
printf("Parameter error./n");
printf("arg1: DLL filename/n");
printf("Example: command myDll.dll/n/n");
return 0;
}
// 看版本号
if (!GetVersionInfo())
{
printf("Don't run at this OS./n");
return 0;
}
// 获得权限
SetPrivilege_Debug();
// 结束模块
KillModule(argv[1]);
//KillModule("Win32Hook.dll");
//getchar();
return 0;
}