我正在嘗試撰寫一個程式,該程式可以在讀取其命令列引數后對其進行屏蔽。我知道這存盤在 PEB 中,所以我嘗試使用“如何使用匯編程式(x64 作業系統)獲取行程環境塊(PEB)地址?”的答案。由 Sirmabus獲取并在那里修改它。這是一個執行此操作的最小程式:
#include <wchar.h>
#include <windows.h>
#include <winnt.h>
#include <winternl.h>
// Thread Environment Block (TEB)
#if defined(_M_X64) // x64
PTEB tebPtr = reinterpret_cast<PTEB>(__readgsqword(reinterpret_cast<DWORD_PTR>(&static_cast<NT_TIB*>(nullptr)->Self)));
#else // x86
PTEB tebPtr = reinterpret_cast<PTEB>(__readfsdword(reinterpret_cast<DWORD_PTR>(&static_cast<NT_TIB*>(nullptr)->Self)));
#endif
// Process Environment Block (PEB)
PPEB pebPtr = tebPtr->ProcessEnvironmentBlock;
int main() {
UNICODE_STRING *s = &pebPtr->ProcessParameters->CommandLine;
wmemset(s->Buffer, 'x', s->Length / sizeof *s->Buffer);
getwchar();
}
我將它編譯為 32 位和 64 位,并在 32 位和 64 位版本的 Windows 上對其進行了測驗。我使用Process Explorer查找命令列,并使用此 PowerShell 命令通過 WMI 獲取它:
Get-WmiObject Win32_Process -Filter "name = 'overwrite.exe'" | Select-Object CommandLine
我發現這在我測驗過的每個組合中都有效,除了在 WOW64 行程上使用 WMI。在表格中總結我的測驗結果:
| 建筑學 | 行程瀏覽器 | WMI |
|---|---|---|
| 64 位作業系統上的 64 位可執行檔案(本機) | ?? xxxxxxxxxxxxx | ?? xxxxxxxxxxxxx |
| 64 位作業系統 (WOW64) 上的 32 位可執行檔案 | ?? xxxxxxxxxxxxx | ?覆寫.exe |
| 32 位作業系統上的 32 位可執行檔案(本機) | ?? xxxxxxxxxxxxx | ?? xxxxxxxxxxxxx |
如何修改我的代碼以使其也適用于 WMI WOW64 案例?
uj5u.com熱心網友回復:
wow64 行程有 2 個 PEB(32 和 64 位)和 2 個不同的 ProcessEnvironmentBlock(同樣是 32 和 64)。命令列都存在于兩者中。一些工具使用正確的命令列(來自 32 位行程的 32 ProcessEnvironmentBlock)和一些無條件的 64 位 ProcessEnvironmentBlock(在 64 位作業系統上)。所以你想要兩個塊中的命令列為零(全部或第一個字符)。為了在“本機”塊中執行此操作,我們不需要訪問 TEB/PEB/ProcessEnvironmentBlock -GetCommandLineW回傳指向 ProcessEnvironmentBlock 中命令列字串的直接指標。所以下一個代碼就足夠了:
PWSTR psz = GetCommandLineW();
while (*psz) *psz = 0;
或者干脆
*GetCommandLineW() = 0;
足夠的
作為旁注,獲取 TEB 指標不需要撰寫自己的宏 - winnt.hNtCurrentTeb()中已經存在宏
從 32 位行程訪問 64 位 ProcessEnvironmentBlock 已經不是微不足道的了。
評論中建議的一種方法。另一種更簡單但沒有記錄NtQueryInformationProcess的 方式 - 呼叫ProcessWow64Information
當 ProcessInformationClass 引數為 ProcessWow64Information 時,ProcessInformation 引數指向的緩沖區應該足夠大以容納 ULONG_PTR。如果此值非零,則該行程正在 WOW64 環境中運行。否則,該行程不會在 WOW64 環境中運行。
所以這個值接收一些指標。但msdn沒有說他點什么。實際上這個指標指向 wow64 行程中行程的 64 PEB。
所以代碼可以是下一個:
#ifndef _WIN64
PEB64* peb64;
if (0 <= NtQueryInformationProcess(NtCurrentProcess(),
ProcessWow64Information, &peb64, sizeof(peb64), 0) && peb64)
{
// ...
}
#endif
但是在 32 位行程中宣告和使用 64 位結構非常不舒服(需要一直檢查指標 < 0x100000000 )
另一種原始方式 - 執行執行任務的小型 64 位 shellcode。
代碼大約執行以下操作:
#include <winternl.h>
#include <intrin.h>
void ZeroCmdLine()
{
PUNICODE_STRING CommandLine =
&NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->CommandLine;
if (USHORT Length = CommandLine->Length)
{
//*CommandLine->Buffer = 0;
__stosw((PUSHORT)CommandLine->Buffer, 0, Length / sizeof(WCHAR));
}
}
您需要使用下一個代碼創建 asm、檔案(如果專案中還沒有)
.686
.MODEL FLAT
.code
@ZeroCmdLine@0 proc
push ebp
mov ebp,esp
and esp,not 15
push 33h
call @@1
; x64
sub esp,20h
call @@0
add esp,20h
retf
@@0:
DQ 000003025048b4865h
DQ 0408b4860408b4800h
DQ 00de3677048b70f20h
DQ 033e9d178788b4857h
DQ 0ccccc35fab66f3c0h
;-------- x64 ---------
@@1:
call fword ptr [esp]
leave
ret
@ZeroCmdLine@0 endp
end
s中的代碼DQ來自于此:
mov rax,gs:30h
mov rax,[rax 60h]
mov rax,[rax 20h]
movzx ecx,word ptr [rax 70h]
jecxz @@2
push rdi
mov rdi,[rax 78h]
shr ecx,1
xor eax,eax
rep stosw
pop rdi
@@2:
ret
int3
int3
自定義構建:ml /c /Cp $(InputFileName)->$(InputName).obj
在C 中宣告
#ifdef __cplusplus
extern "C"
#endif
void FASTCALL ZeroCmdLine(void);
并呼叫它。
#ifndef _WIN64
BOOL bWow;
if (IsWow64Process(GetCurrentProcess(), &bWow) && bWow)
{
ZeroCmdLine();
}
#endif
uj5u.com熱心網友回復:
明確說明差異的原因是,對于 WOW64 行程,Process Explorer 將從 32 位 PEB 讀取,而 WMI 將從 64 位 PEB 讀取。為了完整起見,這是一個用 NASM 和 C 撰寫的 WOW64 程式,它將把它的命令列更改3為 Process Explorer 所見的 all 和6WMI 所見的 all :
global _memcpy64, _wmemset64, _readgsqword64
section .text
BITS 32
_memcpy64:
push edi
push esi
call 0x33:.heavensgate
pop esi
pop edi
ret
BITS 64
.heavensgate:
mov rdi, [esp 20]
mov rsi, [esp 28]
mov rcx, [esp 36]
mov rdx, rdi
rep movsb
mov eax, edx
shr rdx, 32
retf
BITS 32
_wmemset64:
push edi
call 0x33:.heavensgate
pop edi
ret
BITS 64
.heavensgate:
mov rdi, [esp 16]
mov eax, [esp 24]
mov rcx, [esp 28]
mov rdx, rdi
rep stosw
mov eax, edx
shr rdx, 32
retf
BITS 32
_readgsqword64:
call 0x33:.heavensgate
ret
BITS 64
.heavensgate:
mov rdx, [rsp 12]
mov rdx, gs:[rdx]
mov eax, edx
shr rdx, 32
retf
#include <windows.h>
#include <winternl.h>
#include <stdint.h>
typedef struct _TEB64 {
PVOID64 Reserved1[12];
PVOID64 ProcessEnvironmentBlock;
PVOID64 Reserved2[399];
BYTE Reserved3[1952];
PVOID64 TlsSlots[64];
BYTE Reserved4[8];
PVOID64 Reserved5[26];
PVOID64 ReservedForOle; // Windows 2000 only
PVOID64 Reserved6[4];
PVOID64 TlsExpansionSlots;
} TEB64;
typedef struct _PEB64 {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[21];
PVOID64 LoaderData;
PVOID64 ProcessParameters;
BYTE Reserved3[520];
PVOID64 PostProcessInitRoutine;
BYTE Reserved4[136];
ULONG SessionId;
} PEB64;
typedef struct _UNICODE_STRING64 {
USHORT Length;
USHORT MaximumLength;
PVOID64 Buffer;
} UNICODE_STRING64;
typedef struct _RTL_USER_PROCESS_PARAMETERS64 {
BYTE Reserved1[16];
PVOID64 Reserved2[10];
UNICODE_STRING64 ImagePathName;
UNICODE_STRING64 CommandLine;
} RTL_USER_PROCESS_PARAMETERS64;
PVOID64 memcpy64(PVOID64 dest, PVOID64 src, uint64_t count);
PVOID64 wmemset64(PVOID64 dest, wchar_t c, uint64_t count);
uint64_t readgsqword64(uint64_t offset);
PVOID64 NtCurrentTeb64(void) {
return (PVOID64)readgsqword64(FIELD_OFFSET(NT_TIB64, Self));
}
int main(void) {
UNICODE_STRING *pcmdline = &NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->CommandLine;
wmemset(pcmdline->Buffer, '3', pcmdline->Length / sizeof(wchar_t));
TEB64 teb;
memcpy64(&teb, NtCurrentTeb64(), sizeof teb);
PEB64 peb;
memcpy64(&peb, teb.ProcessEnvironmentBlock, sizeof peb);
RTL_USER_PROCESS_PARAMETERS64 params;
memcpy64(¶ms, peb.ProcessParameters, sizeof params);
wmemset64(params.CommandLine.Buffer, '6', params.CommandLine.Length / sizeof(wchar_t));
getwchar();
}
(執行此操作的真實程式可能應該包括一些錯誤檢查和健全性測驗,以確保它在預期的體系結構上運行。)
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/493354.html
上一篇:LineTo()在錯誤的地方畫線
