C#(禁止系統執行某個程序的簡單方法)
一、解決方法
1、理論
要對一個任意程序(包括系統安全程序和服務程序)進行指定了寫相關的訪問權的OpenProcess操作,只要當前程序具有SeDeDebug許可權就可以了。
要是一個使用者是Administrator或是被給予了相應的許可權,就可以具有該許可權。可是,就算我們用Administrator帳號對一個系統安全程序執行OpenProcess(PROCESS_ALL_ACCESS,FALSE, dwProcessID)還是會遇到“訪問拒絕”的錯誤。
什麼原因呢?原來在預設的情況下程序的一些訪問許可權是沒有被啟用(Enabled)的,所以我們要做的首先是啟用這些許可權。與此相關的一些API函式有OpenProcessToken、LookupPrivilegevalue、AdjustTokenPrivileges
GetCurrentProcess得到得到的稱之為"偽控制代碼",只是一個標識,你可以發現,其實就是返回$FFFFFFFF。
每個程序得控制代碼都是一樣的,只是實用於程序內部得使用.如果你想得到實際得控制代碼,在程序間進行通訊,必需要進行轉化,
呼叫DuplicateHandle,注意,得實控制代碼使用完成以後,你必須要呼叫CloseHandle去關閉.
其實,你應該明白了為何"偽控制代碼"得存在,就是使用簡單,不用關閉,不會造成記憶體洩漏.。
核心物件的控制代碼會在新程序中,產生一條記錄,並且該核心物件計數增加。根據引用計數,這裡會引出該函式的一種巧妙用法,檔案鎖定或者叫檔案佔坑,
原理如下:向系統程序中,複製開啟的檔案控制代碼,核心物件在所有引用未刪除時不會銷燬
2、程式碼實現
- #include <Windows.h>
- //提權函式
- void RaiseToDebugP()
- {
- HANDLE hToken;
- HANDLE hProcess = GetCurrentProcess();
- if ( OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken) )
- {
- TOKEN_PRIVILEGES tkp;
- if ( LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tkp.Privileges[0].Luid) )
- {
- tkp.PrivilegeCount = 1;
- tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
- BOOL bREt = AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, 0) ;
- }
- CloseHandle(hToken);
- }
- }
- BOOL OccupyFile( LPCTSTR lpFileName )
- {
- BOOL bRet;
- //提升自身許可權
- RaiseToDebugP();
- //開啟一個pid為4的程序,只要是存在的程序,都可以
- HANDLE hProcess = OpenProcess( PROCESS_DUP_HANDLE, FALSE, 4); // 4為system程序號
- if ( hProcess == NULL )
- {
- return FALSE;
- }
- HANDLE hFile;
- HANDLE hTargetHandle;
- //以獨佔模式開啟目標檔案
- hFile = CreateFile( lpFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL);
- if ( hFile == INVALID_HANDLE_VALUE )
- {
- CloseHandle( hProcess );
- return FALSE;
- }
- //把檔案控制代碼複製到pid=4的程序中去,這樣,只要pid=4的程序不退出,誰也動不了目標檔案
- bRet = DuplicateHandle( GetCurrentProcess(), hFile, hProcess, &hTargetHandle,
- 0, FALSE, DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE);
- CloseHandle( hProcess );
- return bRet;
- }
- //入口函式
- int main()
- {
- OccupyFile("D:\\Program Files\\IDA\\idag.exe");
- return 0;
- }
二、API函式說明
1、 OpenProcessToken
使用OpenProcessToken()用於得到指定程序的訪問令牌,而第三個引數定義設定不正確可能導致該函式呼叫失敗。
以下舉例說明:
- HANDLE hProc;
- hProc = GetCurrentProcess();
- // Method1 - Error(998)
- HANDLE *hToken;
- OpenProcessToken(hProc, TOKEN_ADJUST_PRIVILEGES, hToken);
- // Method2 - Success
- HANDLE hToken;
- OpenProcessToken(hProc, TOKEN_ADJUST_PRIVILEGES, &hToken);
以上是獲取訪問令牌的呼叫,OpenProcessToken()函式原型如下:
- BOOL OpenProcessToken(
- __in HANDLE ProcessHandle, //要修改訪問許可權的程序控制代碼
- __in DWORD DesiredAccess, //指定你要進行的操作型別
- __out PHANDLE TokenHandle //返回的訪問令牌指標
- );
方法1和方法2都使用HANDLE型別定義,方法1定義指標,方法2定義變數。
方法1呼叫函式返回失敗(通過GetLastError()可知錯誤程式碼為998——拒絕訪問);
方法2呼叫函式則能成功獲取訪問令牌。為什麼出現這種情況呢?WinNT.h中相關的定義引起,如下:
- #ifdef STRICT
- typedefvoid *HANDLE;
- #define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name
- #else
- typedefPVOIDHANDLE;
- #define DECLARE_HANDLE(name) typedef HANDLE name
- #endif
- typedefHANDLE *PHANDLE;
由此可見可以把任意一種型別的指標賦值給PVOID型,因此PVOID*賦給PVOID型是可以的,而把PVOID型賦值給PVOID*型也可以。
2、AdjustTokenPrivileges
AdjustTokenPrivileges的原型如下:
- BOOL AdjustTokenPrivileges
- (
- HANDLE TokenHandle, // handle to token
- BOOL DisableAllPrivileges, // disabling option
- PTOKEN_PRIVILEGES NewState, // privilege information
- DWORD BufferLength, // size of buffer
- PTOKEN_PRIVILEGES PreviousState, // original state buffer
- PDWORD ReturnLength // required buffer size
- );
第一個引數是訪問令牌的控制代碼;
第二個引數決定是進行許可權修改還是喪失(Disable)所有許可權;
第三個引數指明要修改的許可權,是一個指向TOKEN_PRIVILEGES結構的指標,該結構包含一個數組,資料組的每個項指明瞭許可權的型別和要進行的操作;
第四個引數是結構PreviousState的長度,如果PreviousState為空,該引數應為NULL;
第五個引數也是一個指向TOKEN_PRIVILEGES結構的指標,存放修改前的訪問許可權的資訊,可空;
最後一個引數為實際PreviousState結構返回的大小。
在使用這個函式前再看一下TOKEN_PRIVILEGES這個結構,其宣告如下:
- typedefstruct _TOKEN_PRIVILEGES
- {
- DWORD PrivilegeCount;
- LUID_AND_ATTRIBUTES Privileges[];
- } TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;
PrivilegeCount指的陣列元素的個數,接著是一個LUID_AND_ATTRIBUTES型別的陣列,再來看一下LUID_AND_ATTRIBUTES這個結構的內容,宣告如下:
- typedefstruct _LUID_AND_ATTRIBUTES
- {
- LUID Luid;
- DWORD Attributes;
- } LUID_AND_ATTRIBUTES, *PLUID_AND_ATTRIBUTES
第一個引數就是指許可權的型別,是一個LUID的值,LUID就是指locally unique identifier,我想GUID大家是比較熟悉的,和GUID的要求保證全域性唯一不同,LUID只要保證區域性唯一,就是指在系統的每一次執行期間保證是唯一的就可以了。另外和GUID相同的一點,LUID也是一個64位的值,相信大家都看過GUID那一大串的值,我們要怎麼樣才能知道一個許可權對應的LUID值是多少呢?
第二個引數就指明瞭我們要進行的操作型別,有三個可選項: SE_PRIVILEGE_ENABLED、SE_PRIVILEGE_ENABLED_BY_DEFAULT、SE_PRIVILEGE_USED_FOR_ACCESS。要使能一個許可權就指定Attributes為SE_PRIVILEGE_ENABLED。
3、LookupPrivilegevalue
其原形如下:
- BOOL LookupPrivilegevalue(
- LPCTSTR lpSystemName, // system name
- LPCTSTR lpName, // privilege name
- PLUID lpLuid // locally unique identifier
- );
(1)第一個引數是系統的名稱,如果是本地系統只要指明為NULL就可以了;
(2)第二個引數就是指明瞭許可權的名稱,如“SeDebugPrivilege”。
在Winnt.h中還定義了一些許可權名稱的巨集,如:
- #define SE_BACKUP_NAME TEXT("SeBackupPrivilege")
- #define SE_RESTORE_NAME TEXT("SeRestorePrivilege")
- #define SE_SHUTDOWN_NAME TEXT("SeShutdownPrivilege")
- #define SE_DEBUG_NAME TEXT("SeDebugPrivilege")
(3)第三個引數就是返回LUID的指標;
4、DuplicateHandle
The DuplicateHandle function creates a duplicate handle. The returned duplicate is in the caller's process space.(從當前程序複製控制代碼到其他程序空間)
- BOOL DuplicateHandle(
- HANDLE hSourceProcessHandle, // handle to source process
- HANDLE hSourceHandle, // handle