トップ回答者
SeBackupPrivilegeについて

質問
回答
-
Shared Sub Main(ByVal abc() As String) ModifyState("SeBackupPrivilege", True) '現在のコンソールに表示させる場合 Dim psi As New ProcessStartInfo("whoami.exe", "/priv") psi.UseShellExecute = False Using p As Process = Process.Start(psi) p.WaitForExit() End Using 'MsgBox で表示させる場合 psi = New ProcessStartInfo("whoami.exe", "/priv") psi.UseShellExecute = False psi.RedirectStandardOutput = True Dim msg As String Using p As Process = Process.Start(psi) msg = p.StandardOutput.ReadToEnd() p.WaitForExit() End Using MsgBox(msg, MsgBoxStyle.Information Or MsgBoxStyle.SystemModal) Console.WriteLine("End!") Console.ReadKey() End Sub
- 回答としてマーク Luky9 2019年7月4日 7:57
-
.NET のソースに特権を操作している箇所があります。
https://referencesource.microsoft.com/#mscorlib/system/security/accesscontrol/privilege.cs
"SeTakeOwnershipPrivilege" の TakeOwnership のように、ダブルクリックすると使われている箇所が左のフレームに出てくるのですが、"SeBackupPrivilege" の Backup についてはダブルクリックしても出てこないので、定義はあるものの、残念ながら使われていないようです。
あとは、6/12 に ShiroYuki_Mot さんが紹介してくださった記事(の英語版です)
https://support.microsoft.com/en-us/help/318744/how-to-use-visual-basic-to-programmatically-change-ownership-of-a-file
を見てゴリゴリ書いていくしかなさそうです。
- 回答としてマーク Luky9 2019年7月4日 7:58
-
https://support.microsoft.com/en-us/help/318744/how-to-use-visual-basic-to-programmatically-change-ownership-of-a-file
この記事で必要なのは
Public Function ModifyState(Privilege As String, _
Enable As Boolean) As Boolean
の中身です。
GetCurrentProcess
OpenProcessToken
LookupPrivilegeValue
AdjustTokenPrivileges
CloseHandle
これら API の定義と使用している構造体については、.NET のソース(C#)を見て、VB.NET にコンバートしていけばよいです。
出来上がったら
ModifyState("SeBackupPrivilege", True)
で特権が有効になり
ModifyState("SeBackupPrivilege", False)
で無効になります。- 回答としてマーク Luky9 2019年7月4日 7:58
-
「MyPrives.Privileges(0).Luid = PrivilegeId」でエラー発生しています。
コンパイルエラーなのかコンパイル警告なのか実行時例外なのかすらわからないので、何のエラーかぐらいは書いて欲しかった所ですが…これは配列が未初期化なのが原因ですね。
「If MyPrives.Privileges Is Nothing OrElse MyPrives.Privileges.Length = 0 Then」が真となる状況なら、未初期化による NullReferenceException (もしくは要素不足による IndexOutOfRangeException)になりそうです。
TOKEN_PRIVILEGES 構造体の宣言に
Public Sub New(count As Integer) PrivilegeCount = CUInt(count) Privileges = New LUID_AND_ATTRIBUTES(count - 1) {} End Sub
というコンストラクタを追加しておき、利用時には
'Dim MyPrives As TOKEN_PRIVILEGES Dim MyPrives As New TOKEN_PRIVILEGES(ANYSIZE_ARRAY)
と書き換えれば、この点は解決されると思います。- 今のコードだと、IntPtr 型や Boolean 型で宣言すべき場所で As Long 変数が使われているといった問題があります。データ型の指定ミスを減らすためにも、「Option Strict On」を必ず付与するようにしましょう。
- Or → OrElse への変更も忘れずに。
- OpenProcessToken の最後の引数は出力引数なので、「<Out> ByRef TokenHandle As IntPtr」のように Out 属性を付与した方がベターです。また、ここに渡す変数は IntPtr 型でなければなりません。
- AdjustTokenPrivileges の最後の引数も出力引数です。ここは「ByRef ReturnLength As IntPtr」では誤りで、正しくは「<Out> ByRef ReturnLength As Integer」として、Integer 型の変数を渡すようにします。ただし、最後の引数から値を受け取る必要が無い場合には、宣言を「ByVal ReturnLength As IntPtr」としておき、ここに IntPtr.Zero を渡すという方法が使えます。
- 回答としてマーク Luky9 2019年7月4日 7:58
-
エラーコードは 998 ですね?
Dim ex As New System.ComponentModel.Win32Exception(998)
Debug.Print(ex.ToString())
で、内容が確認できますが、「メモリ ロケーションへのアクセスが無効です。」なので、AdjustTokenPrivileges の宣言が間違っていると思われます。
<DllImport("advapi32.dll", SetLastError:=True)> Shared Function AdjustTokenPrivileges( ByVal TokenHandle As IntPtr, ByVal DisableAllPrivileges As Boolean, ByRef NewState As TOKEN_PRIVILEGES, ByVal BufferLength As Integer, ByVal PreviousState As IntPtr, ByVal ReturnLength As IntPtr) As Boolean End Function Result = AdjustTokenPrivileges(hToken, False, MyPrives, 0, IntPtr.Zero, IntPtr.Zero)
アドバイスどおりに書くと、こうなるはずです。
- 回答としてマーク Luky9 2019年7月4日 7:58
-
Visual Studio の [ツール] メニューに [エラー検索] がある場合、そこから ErrLook.exe を起動できるようになっています。
ちなみにエラーコード 1300 は WinError.h で定義されています。
// // MessageId: ERROR_NOT_ALL_ASSIGNED // // MessageText: // // Not all privileges or groups referenced are assigned to the caller. // // 参照された特権またはグループのうち、一部の特権が呼び出し側に割り当てられていません。 // #define ERROR_NOT_ALL_ASSIGNED 1300L
- 回答としてマーク Luky9 2019年7月4日 7:58
すべての返信
-
.NET のソースに特権を操作している箇所があります。
https://referencesource.microsoft.com/#mscorlib/system/security/accesscontrol/privilege.cs
"SeTakeOwnershipPrivilege" の TakeOwnership のように、ダブルクリックすると使われている箇所が左のフレームに出てくるのですが、"SeBackupPrivilege" の Backup についてはダブルクリックしても出てこないので、定義はあるものの、残念ながら使われていないようです。
あとは、6/12 に ShiroYuki_Mot さんが紹介してくださった記事(の英語版です)
https://support.microsoft.com/en-us/help/318744/how-to-use-visual-basic-to-programmatically-change-ownership-of-a-file
を見てゴリゴリ書いていくしかなさそうです。
- 回答としてマーク Luky9 2019年7月4日 7:58
-
https://support.microsoft.com/en-us/help/318744/how-to-use-visual-basic-to-programmatically-change-ownership-of-a-file
この記事で必要なのは
Public Function ModifyState(Privilege As String, _
Enable As Boolean) As Boolean
の中身です。
GetCurrentProcess
OpenProcessToken
LookupPrivilegeValue
AdjustTokenPrivileges
CloseHandle
これら API の定義と使用している構造体については、.NET のソース(C#)を見て、VB.NET にコンバートしていけばよいです。
出来上がったら
ModifyState("SeBackupPrivilege", True)
で特権が有効になり
ModifyState("SeBackupPrivilege", False)
で無効になります。- 回答としてマーク Luky9 2019年7月4日 7:58
-
ご返信ありがとうございます。下記の通りに実装しまたが 「MyPrives.Privileges(0).Luid = PrivilegeId」でエラー発生しています。vb.netに詳しい方いらしゃいましたら教えていただけますでしょうか。宜しくお願い致します。
Imports System.Runtime.InteropServices
Public Class Class1
Const ANYSIZE_ARRAY As Integer = 1
Const TOKEN_ADJUST_PRIVILEGES As Integer = &H20
Const SE_PRIVILEGE_ENABLED As Integer = &H2
<DllImport("kernel32.dll", EntryPoint:="CloseHandle", SetLastError:=True)>
Private Shared Function CloseHandle(ByVal hObject As IntPtr) As <MarshalAsAttribute(UnmanagedType.Bool)> Boolean
End Function
<StructLayout(LayoutKind.Sequential)>
Public Structure LUID
Public LowPart As UInt32
Public HighPart As UInt32
End Structure
<StructLayout(LayoutKind.Sequential)>
Public Structure LUID_AND_ATTRIBUTES
Public Luid As LUID
Public Attributes As UInt32
End Structure
<StructLayout(LayoutKind.Sequential)>
Public Structure TOKEN_PRIVILEGES
Public PrivilegeCount As UInt32
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=ANYSIZE_ARRAY)>
Public Privileges() As LUID_AND_ATTRIBUTES
End Structure
<DllImport("advapi32.dll", SetLastError:=True)>
Shared Function LookupPrivilegeValue(ByVal lpSystemName As String, ByVal lpName As String, ByRef lpLuid As LUID) As Boolean
End Function
<DllImport("advapi32.dll", SetLastError:=True)>
Shared Function OpenProcessToken(ByVal ProcessHandle As IntPtr, ByVal DesiredAccess As Integer, ByRef TokenHandle As IntPtr) As Boolean
End Function
<DllImport("advapi32.dll", SetLastError:=True)>
Shared Function AdjustTokenPrivileges(ByVal TokenHandle As IntPtr, ByVal DisableAllPrivileges As Boolean, ByRef NewState As TOKEN_PRIVILEGES, ByVal BufferLength As Integer, ByRef PreviousState As TOKEN_PRIVILEGES, ByRef ReturnLength As IntPtr) As Boolean
End Function
Public Shared Function ModifyState(Privilege As String, Enable As Boolean) As Boolean
Dim MyPrives As TOKEN_PRIVILEGES
Dim PrivilegeId As LUID
Dim hToken As Long
Dim Result As Long
Dim hProc As IntPtr = Process.GetCurrentProcess().Handle
Result = OpenProcessToken(hProc, TOKEN_ADJUST_PRIVILEGES, hToken)
If (Result = 0) Then
ModifyState = False
Exit Function
End If
Result = LookupPrivilegeValue(vbNullString, Privilege, PrivilegeId)
If (Result = 0) Then
ModifyState = False
Exit Function
End If
MyPrives.Privileges(0).Luid = PrivilegeId
MyPrives.PrivilegeCount = 1
If (Enable) Then
MyPrives.Privileges(0).Attributes = SE_PRIVILEGE_ENABLED
Else
MyPrives.Privileges(0).Attributes = 0
End If
Result = AdjustTokenPrivileges(hToken, False, MyPrives, 0, MyPrives, 0)
If (Result = 0 Or Err.LastDllError <> 0) Then
ModifyState = False
Exit Function
End If
CloseHandle(hToken)
ModifyState = True
End Function
Shared Sub Main(ByVal abc() As String)
ModifyState("SeBackupPrivilege", True)
Console.WriteLine("End!")
Console.ReadKey()
End Sub
End Class
Luky9
-
「MyPrives.Privileges(0).Luid = PrivilegeId」でエラー発生しています。
コンパイルエラーなのかコンパイル警告なのか実行時例外なのかすらわからないので、何のエラーかぐらいは書いて欲しかった所ですが…これは配列が未初期化なのが原因ですね。
「If MyPrives.Privileges Is Nothing OrElse MyPrives.Privileges.Length = 0 Then」が真となる状況なら、未初期化による NullReferenceException (もしくは要素不足による IndexOutOfRangeException)になりそうです。
TOKEN_PRIVILEGES 構造体の宣言に
Public Sub New(count As Integer) PrivilegeCount = CUInt(count) Privileges = New LUID_AND_ATTRIBUTES(count - 1) {} End Sub
というコンストラクタを追加しておき、利用時には
'Dim MyPrives As TOKEN_PRIVILEGES Dim MyPrives As New TOKEN_PRIVILEGES(ANYSIZE_ARRAY)
と書き換えれば、この点は解決されると思います。- 今のコードだと、IntPtr 型や Boolean 型で宣言すべき場所で As Long 変数が使われているといった問題があります。データ型の指定ミスを減らすためにも、「Option Strict On」を必ず付与するようにしましょう。
- Or → OrElse への変更も忘れずに。
- OpenProcessToken の最後の引数は出力引数なので、「<Out> ByRef TokenHandle As IntPtr」のように Out 属性を付与した方がベターです。また、ここに渡す変数は IntPtr 型でなければなりません。
- AdjustTokenPrivileges の最後の引数も出力引数です。ここは「ByRef ReturnLength As IntPtr」では誤りで、正しくは「<Out> ByRef ReturnLength As Integer」として、Integer 型の変数を渡すようにします。ただし、最後の引数から値を受け取る必要が無い場合には、宣言を「ByVal ReturnLength As IntPtr」としておき、ここに IntPtr.Zero を渡すという方法が使えます。
- 回答としてマーク Luky9 2019年7月4日 7:58
-
ご返信ありがとうございます。今は「Result = AdjustTokenPrivileges(hToken, False, MyPrives, 0, 0, 0)」にエラー発生しています。
Option Strict On
Imports System.Runtime.InteropServices
Public Class Class1
Const ANYSIZE_ARRAY As Integer = 1
Const TOKEN_ADJUST_PRIVILEGES As Integer = &H20
Const SE_PRIVILEGE_ENABLED As Integer = &H2
<DllImport("kernel32.dll", EntryPoint:="CloseHandle", SetLastError:=True)>
Private Shared Function CloseHandle(ByVal hObject As IntPtr) As <MarshalAsAttribute(UnmanagedType.Bool)> Boolean
End Function
<StructLayout(LayoutKind.Sequential)>
Public Structure LUID
Public LowPart As UInt32
Public HighPart As UInt32
End Structure
<StructLayout(LayoutKind.Sequential)>
Public Structure LUID_AND_ATTRIBUTES
Public Luid As LUID
Public Attributes As UInt32
End Structure
<StructLayout(LayoutKind.Sequential)>
Public Structure TOKEN_PRIVILEGES
Public PrivilegeCount As UInt32
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=ANYSIZE_ARRAY)>
Public Privileges() As LUID_AND_ATTRIBUTES
Public Sub New(count As Integer)
PrivilegeCount = CUInt(count)
Privileges = New LUID_AND_ATTRIBUTES(count - 1) {}
End Sub
End Structure
<DllImport("advapi32.dll", SetLastError:=True)>
Shared Function LookupPrivilegeValue(ByVal lpSystemName As String, ByVal lpName As String, ByRef lpLuid As LUID) As Boolean
End Function
<DllImport("advapi32.dll", SetLastError:=True)>
Shared Function OpenProcessToken(ByVal ProcessHandle As IntPtr, ByVal DesiredAccess As Integer, <Out> ByRef TokenHandle As IntPtr) As Boolean
End Function
<DllImport("advapi32.dll", SetLastError:=True)>
Shared Function AdjustTokenPrivileges(ByVal TokenHandle As IntPtr, ByVal DisableAllPrivileges As Boolean,
NewState As TOKEN_PRIVILEGES, ByVal BufferLength As Long,
ByVal PreviousState As Long, <Out> ByRef ReturnLength As Integer) As Boolean
End Function
Public Shared Function ModifyState(Privilege As String, Enable As Boolean) As Boolean
Dim MyPrives As New TOKEN_PRIVILEGES(ANYSIZE_ARRAY)
Dim PrivilegeId As LUID
Dim hToken As IntPtr
Dim Result As Boolean
Dim hProc As IntPtr = Process.GetCurrentProcess().Handle
Result = OpenProcessToken(hProc, TOKEN_ADJUST_PRIVILEGES, hToken)
If (Result = False) Then
ModifyState = False
Exit Function
End If
Result = LookupPrivilegeValue(vbNullString, Privilege, PrivilegeId)
If (Result = False) Then
ModifyState = False
Exit Function
End If
MyPrives.Privileges(0).Luid = PrivilegeId
MyPrives.PrivilegeCount = 1
If (Enable) Then
MyPrives.Privileges(0).Attributes = SE_PRIVILEGE_ENABLED
Else
MyPrives.Privileges(0).Attributes = 0
End If
'If MyPrives.Privileges Is Nothing OrElse MyPrives.Privileges.Length = 0 Then
Result = AdjustTokenPrivileges(hToken, False, MyPrives, 0, 0, 0)
If (Result = False OrElse Err.LastDllError <> 0) Then
ModifyState = False
Console.WriteLine("AdjustTokenPrivileges failed with error code " & Err.LastDllError)
Exit Function
End If
'End If
CloseHandle(hToken)
ModifyState = True
End Function
Shared Sub Main(ByVal abc() As String)
ModifyState("SeBackupPrivilege", True)
Console.WriteLine("End!")
Console.ReadKey()
End Sub
End Class
- 編集済み Luky9 2019年7月4日 5:44
-
エラーコードは 998 ですね?
Dim ex As New System.ComponentModel.Win32Exception(998)
Debug.Print(ex.ToString())
で、内容が確認できますが、「メモリ ロケーションへのアクセスが無効です。」なので、AdjustTokenPrivileges の宣言が間違っていると思われます。
<DllImport("advapi32.dll", SetLastError:=True)> Shared Function AdjustTokenPrivileges( ByVal TokenHandle As IntPtr, ByVal DisableAllPrivileges As Boolean, ByRef NewState As TOKEN_PRIVILEGES, ByVal BufferLength As Integer, ByVal PreviousState As IntPtr, ByVal ReturnLength As IntPtr) As Boolean End Function Result = AdjustTokenPrivileges(hToken, False, MyPrives, 0, IntPtr.Zero, IntPtr.Zero)
アドバイスどおりに書くと、こうなるはずです。
- 回答としてマーク Luky9 2019年7月4日 7:58
-
Visual Studio の [ツール] メニューに [エラー検索] がある場合、そこから ErrLook.exe を起動できるようになっています。
ちなみにエラーコード 1300 は WinError.h で定義されています。
// // MessageId: ERROR_NOT_ALL_ASSIGNED // // MessageText: // // Not all privileges or groups referenced are assigned to the caller. // // 参照された特権またはグループのうち、一部の特権が呼び出し側に割り当てられていません。 // #define ERROR_NOT_ALL_ASSIGNED 1300L
- 回答としてマーク Luky9 2019年7月4日 7:58
-
すみません。管理者で実行したらエラーがないですがSeBackupPrivilegeは有効ならない状況です。本当に大変ですね。
Option Strict On
Imports System.Runtime.InteropServices
Public Class Class1
Const ANYSIZE_ARRAY As Integer = 1
Const TOKEN_ADJUST_PRIVILEGES As Integer = &H20
Const SE_PRIVILEGE_ENABLED As Integer = &H2
<DllImport("kernel32.dll", EntryPoint:="CloseHandle", SetLastError:=True)>
Private Shared Function CloseHandle(ByVal hObject As IntPtr) As <MarshalAsAttribute(UnmanagedType.Bool)> Boolean
End Function
<StructLayout(LayoutKind.Sequential)>
Public Structure LUID
Public LowPart As UInt32
Public HighPart As UInt32
End Structure
<StructLayout(LayoutKind.Sequential)>
Public Structure LUID_AND_ATTRIBUTES
Public Luid As LUID
Public Attributes As UInt32
End Structure
<StructLayout(LayoutKind.Sequential)>
Public Structure TOKEN_PRIVILEGES
Public PrivilegeCount As UInt32
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=ANYSIZE_ARRAY)>
Public Privileges() As LUID_AND_ATTRIBUTES
Public Sub New(count As Integer)
PrivilegeCount = CUInt(count)
Privileges = New LUID_AND_ATTRIBUTES(count - 1) {}
End Sub
End Structure
<DllImport("advapi32.dll", SetLastError:=True)>
Shared Function LookupPrivilegeValue(ByVal lpSystemName As String, ByVal lpName As String, ByRef lpLuid As LUID) As Boolean
End Function
<DllImport("advapi32.dll", SetLastError:=True)>
Shared Function OpenProcessToken(ByVal ProcessHandle As IntPtr, ByVal DesiredAccess As Integer, <Out> ByRef TokenHandle As IntPtr) As Boolean
End Function
<DllImport("advapi32.dll", SetLastError:=True)>
Shared Function AdjustTokenPrivileges(ByVal TokenHandle As IntPtr, ByVal DisableAllPrivileges As Boolean, ByRef NewState As TOKEN_PRIVILEGES, ByVal BufferLength As Integer, ByVal PreviousState As IntPtr, ByVal ReturnLength As IntPtr) As Boolean
End Function
Public Shared Function ModifyState(Privilege As String, Enable As Boolean) As Boolean
Dim MyPrives As New TOKEN_PRIVILEGES(ANYSIZE_ARRAY)
Dim PrivilegeId As LUID
Dim hToken As IntPtr
Dim Result As Boolean
Dim hProc As IntPtr = Process.GetCurrentProcess().Handle
Result = OpenProcessToken(hProc, TOKEN_ADJUST_PRIVILEGES, hToken)
If (Result = False) Then
ModifyState = False
Exit Function
End If
Result = LookupPrivilegeValue(vbNullString, Privilege, PrivilegeId)
If (Result = False) Then
ModifyState = False
Exit Function
End If
MyPrives.Privileges(0).Luid = PrivilegeId
MyPrives.PrivilegeCount = 1
If (Enable) Then
MyPrives.Privileges(0).Attributes = SE_PRIVILEGE_ENABLED
Else
MyPrives.Privileges(0).Attributes = 0
End If
Result = AdjustTokenPrivileges(hToken, False, MyPrives, 0, IntPtr.Zero, IntPtr.Zero)
If (Result = False OrElse Err.LastDllError <> 0) Then
ModifyState = False
Console.WriteLine("AdjustTokenPrivileges failed with error code " & Err.LastDllError)
Exit Function
End If
CloseHandle(hToken)
ModifyState = True
End Function
Shared Sub Main(ByVal abc() As String)
If ModifyState("SeBackupPrivilege", True) Then
Console.WriteLine("OK")
End If
Console.WriteLine("End!")
Console.ReadKey()
End Sub
End Class
Luky9
-
Shared Sub Main(ByVal abc() As String) ModifyState("SeBackupPrivilege", True) '現在のコンソールに表示させる場合 Dim psi As New ProcessStartInfo("whoami.exe", "/priv") psi.UseShellExecute = False Using p As Process = Process.Start(psi) p.WaitForExit() End Using 'MsgBox で表示させる場合 psi = New ProcessStartInfo("whoami.exe", "/priv") psi.UseShellExecute = False psi.RedirectStandardOutput = True Dim msg As String Using p As Process = Process.Start(psi) msg = p.StandardOutput.ReadToEnd() p.WaitForExit() End Using MsgBox(msg, MsgBoxStyle.Information Or MsgBoxStyle.SystemModal) Console.WriteLine("End!") Console.ReadKey() End Sub
- 回答としてマーク Luky9 2019年7月4日 7:57
-
理解していただけたようで何より。
特権は、必要なときに有効にして、使い終わったら無効にしてください。
あと3点ほど。
(1) LookupPrivilegeValue や AdjustTokenPrivileges がエラーになると、トークンハンドルが開きっぱなしになるので、ちゃんと CloseHandle しましょう。
(2) このような列挙体を作って
Public Enum SePrivileges
SeCreateTokenPrivilege
SeAssignPrimaryTokenPrivilege
SeLockMemoryPrivilege
SeIncreaseQuotaPrivilege
SeUnsolicitedInputPrivilege
SeMachineAccountPrivilege
SeTcbPrivilege
SeSecurityPrivilege
SeTakeOwnershipPrivilege
SeLoadDriverPrivilege
SeSystemProfilePrivilege
SeSystemtimePrivilege
SeProfileSingleProcessPrivilege
SeIncreaseBasePriorityPrivilege
SeCreatePagefilePrivilege
SeCreatePermanentPrivilege
SeBackupPrivilege
SeRestorePrivilege
SeShutdownPrivilege
SeDebugPrivilege
SeAuditPrivilege
SeSystemEnvironmentPrivilege
SeChangeNotifyPrivilege
SeRemoteShutdownPrivilege
SeUndockPrivilege
SeSyncAgentPrivilege
SeEnableDelegationPrivilege
SeManageVolumePrivilege
SeImpersonatePrivilege
SeCreateGlobalPrivilege
SeTrustedCredManAccessPrivilege
SeReserveProcessorPrivilege
End Enum
Public Shared Function ModifyState(privilege As SePrivileges, Enable As Boolean) As Boolean
Return ModifyState(privilege.ToString(), Enable)
End Function
のようにしておくと、
ModifyState(SePrivileges.SeBackupPrivilege, True)
のように使えるのでタイプミスが防げます。
(3) API の宣言は NativeMethods クラスにまとめましょう。
https://docs.microsoft.com/ja-jp/visualstudio/code-quality/ca1060-move-p-invokes-to-nativemethods-class?view=vs-2019