前言:
今天逆向一個非常實用的函數RtlAdjustPrivliege
這個函數封裝在NtDll.dll中(在所有DLL加載之前加載),被微軟嚴格保密,就是說你在MSDN上查不到關於他的任何信息。
先來看看這個函數的定義(Winehq給出):
參數的含義:
很多人大概沒有聽說過他的大名,但是相信有很多人見過進程提權的過程
拷一段我寫的提權上來吧
:
BOOL ImproveProcPriv()
{
HANDLE token;
//提升權限
if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&token))
{
MessageBox(NULL,"打開進程令牌失敗...","錯誤",MB_ICONSTOP);
return FALSE;
}
TOKEN_PRIVILEGES tkp;
tkp.PrivilegeCount = 1;
::LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&tkp.Privileges[0].Luid); // 獲得 SE_DEBUG_NAME 特權
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if(!AdjustTokenPrivileges(token,FALSE,&tkp,sizeof(tkp),NULL,NULL))
{
MessageBox(NULL,"調整令牌權限失敗...","錯誤",MB_ICONSTOP);
return FALSE;
}
CloseHandle(token);
return TRUE;
}
看看吧,這個提權快要累死了...
但是 如果有這個函數就不一樣了,你可以只用一個函數就實現這個功能,甚至功能遠多於上面的代碼...
通過恰當的IDE設置和必要的Defination,上面這個函數的功能你完全可以通過一行代碼來實現。
RtlAdjustPrivilege(SE_DEBUG_NAME,1,0,NULL);
正文:
下面我們看一下這個函數是怎麼運行的,順便學習下強大的IDA
IDA 載入ntdll.dll (我這裏載入的是 WinDBG自動下載的 Symbol裏面的英文版本 可能不同的Windows版本略有不同)
先把函數的原型給輸入IDA 方便一下閱讀,然後開始閱讀彙編代碼了(黨和國家考驗我們的時候到了)。
看看Graph View 真的是很牛啊...
看看函數最開頭...
判斷是調整進程權限還是線程權限,
CurrentThread == TRUE
CurrentThread == FALSE
然後兩個代碼塊同時指向這裏
若 執行成功
判斷是否執行成功之後,開始輸出最後一個參數
若 OldState != 0 則
若 OldState == 0 則
這個函數大致流程就是這樣。
到這裏差不多可以按一下傳說中的F5了
int __stdcall RtlAdjustPrivilege(int Privilege, char Enable,
char CurrentThread, int Enabled)
{
int result; // eax@2
signed int AdjustResult; // esi@4
char returnValue; // al@7
int v7; // [sp+2Ch] [bp-4h]@1
int IsEnabled; // [sp+4h] [bp-2Ch]@1
int TokenHandle; // [sp+8h] [bp-28h]@2
int dwPrivilege; // [sp+20h] [bp-10h]@4
signed int NewState; // [sp+1Ch] [bp-14h]@4
int v12; // [sp+24h] [bp-Ch]@4
int v13; // [sp+28h] [bp-8h]@4
int OldState; // [sp+Ch] [bp-24h]@4
char ReturnLength; // [sp+0h] [bp-30h]@4
unsigned int v16; // [sp+18h] [bp-18h]@11
v7 = dword_7C97B0C8;
IsEnabled = Enabled;
if ( CurrentThread == 1 )
result = ZwOpenThreadToken(-2, 40, 0, &TokenHandle);
else
result = NtOpenProcessToken(-1, 40, &TokenHandle);
if ( result >= 0 )
{
dwPrivilege = Privilege;
NewState = 1;
v12 = 0;
v13 = -(Enable != 0) & 2;
AdjustResult = NtAdjustPrivilegesToken(TokenHandle, 0, &NewState, 16, &OldState, &ReturnLength);
ZwClose(TokenHandle);
if ( AdjustResult == 262 )
AdjustResult = -1073741727;
if ( AdjustResult >= 0 )
{
if ( OldState )
returnValue = (v16 >> 1) & 1;
else
returnValue = Enable;
*(_BYTE *)IsEnabled = returnValue;
}
result = AdjustResult;
}
return result;
}
可讀性好像仍然不高,看看這個...
/******************************************************************************
* RtlAdjustPrivilege [NTDLL.@]
*
* Enables or disables a privilege from the calling thread or process.
*
* PARAMS
* Privilege [I] Privilege index to change.
* Enable [I] If TRUE, then enable the privilege otherwise disable.
* CurrentThread [I] If TRUE, then enable in calling thread, otherwise process.
* Enabled [O] Whether privilege was previously enabled or disabled.
*
* RETURNS
* Success: STATUS_SUCCESS.
* Failure: NTSTATUS code.
*
* SEE ALSO
* NtAdjustPrivilegesToken, NtOpenThreadToken, NtOpenProcessToken.
*
*/
NTSTATUS WINAPI
RtlAdjustPrivilege(ULONG Privilege,
BOOLEAN Enable,
BOOLEAN CurrentThread,
PBOOLEAN Enabled)
{
TOKEN_PRIVILEGES NewState;
TOKEN_PRIVILEGES OldState;
ULONG ReturnLength;
HANDLE TokenHandle;
NTSTATUS Status;
TRACE("(%d, %s, %s, %p)/n", Privilege, Enable ? "TRUE" :
"FALSE",
CurrentThread ? "TRUE" : "FALSE", Enabled);
if (CurrentThread)
{
Status = NtOpenThreadToken(GetCurrentThread(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
FALSE,
&TokenHandle);
}
else
{
Status = NtOpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&TokenHandle);
}
if (!NT_SUCCESS(Status))
{
WARN("Retrieving token handle failed (Status %x)/n", Status);
return Status;
}
OldState.PrivilegeCount = 1;
NewState.PrivilegeCount = 1;
NewState.Privileges[0].Luid.LowPart = Privilege;
NewState.Privileges[0].Luid.HighPart = 0;
NewState.Privileges[0].Attributes = (Enable) ? SE_PRIVILEGE_ENABLED : 0;
Status = NtAdjustPrivilegesToken(TokenHandle,
FALSE,
&NewState,
sizeof(TOKEN_PRIVILEGES),
&OldState,
&ReturnLength);
NtClose (TokenHandle);
if (Status == STATUS_NOT_ALL_ASSIGNED)
{
TRACE("Failed to assign all privileges/n");
return STATUS_PRIVILEGE_NOT_HELD;
}
if (!NT_SUCCESS(Status))
{
WARN("NtAdjustPrivilegesToken() failed (Status %x)/n", Status);
return Status;
}
if (OldState.PrivilegeCount == 0)
*Enabled = Enable;
else
*Enabled = (OldState.Privileges[0].Attributes & SE_PRIVILEGE_ENABLED);
return STATUS_SUCCESS;
}