I'm trying to write a program that can mask its command line arguments after it reads them. I know this is stored in the PEB, so I tried using the answer to "How to get the Process Environment Block (PEB) address using assembler (x64 OS)?" by Sirmabus to get that and modify it there. Here's a minimal program that does that:
#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();
}
I compiled this both as 32-bit and 64-bit, and tested it on both 32-bit and 64-bit versions of Windows. I looked for the command line using Process Explorer, and also by using this PowerShell command to fetch it via WMI:
Get-WmiObject Win32_Process -Filter "name = 'overwrite.exe'" | Select-Object CommandLine
I've found that this works in every combination I tested it in, except for using WMI on a WOW64 process. Summarizing my test results in a table:
| Architecture | Process Explorer | WMI |
|---|---|---|
| 64-bit executable on 64-bit OS (native) | ✔️ xxxxxxxxxxxxx | ✔️ xxxxxxxxxxxxx |
| 32-bit executable on 64-bit OS (WOW64) | ✔️ xxxxxxxxxxxxx | ❌ overwrite.exe |
| 32-bit executable on 32-bit OS (native) | ✔️ xxxxxxxxxxxxx | ✔️ xxxxxxxxxxxxx |
How can I modify my code to make this work in the WMI WOW64 case too?
wow64 processes have 2 PEB (32 and 64 bit) and 2 different ProcessEnvironmentBlock (again 32 and 64). the command line exist in both. some tools take command line correct (from 32 ProcessEnvironmentBlock for 32bit processes) and some unconditional from 64bit ProcessEnvironmentBlock (on 64 bit os). so you want zero (all or first char) of command line in both blocks. for do this in "native" block we not need access TEB/PEB/ProcessEnvironmentBlock - the
GetCommandLineWreturn the direct pointer to the command-line string in ProcessEnvironmentBlock. so next code is enough:or simply
is enough
as side note, for get TEB pointer not need write own macro -
NtCurrentTeb()macro already exist in winnt.haccess 64 bit ProcessEnvironmentBlock from 32 bit process already not trivial. one way suggested in comment. another way more simply, but not documented - call
NtQueryInformationProcesswithProcessWow64Informationso this value receive some pointer. but msdn not say for what he point . in reality this pointer to 64 PEB of process in wow64 process.
so code can be next:
but declare and use 64 bit structures in 32bit process very not comfortable (need all time check that pointer < 0x100000000 )
another original way - execute small 64bit shellcode which do the task.
the code doing approximately the following:
you need create asm, file (if yet not have it in project) with the next code
the code in the
DQs came from this:custom build:
ml /c /Cp $(InputFileName)->$(InputName).objdeclare in c++
and call it.