Question About ZwOpenProcess specified client ID not valid

Hello, I have been working with ntopenprocess and zwopenprocess for a while, trying to figure out how to promote a usermode handle in kernel. What I have came up with is this.

NTSTATUS PromoteHandleManual(PromoteHandle* kk)
{
NTSTATUS status;
status = STATUS_SUCCESS;
OBJECT_ATTRIBUTES obj_attr;
CLIENT_ID cid;
InitializeObjectAttributes(&obj_attr, NULL, 0, NULL, NULL);
cid.UniqueProcess = kk->PID;
cid.UniqueThread = (HANDLE)0;
status = ZwOpenProcess(&kk->handle, kk->access, &obj_attr, &cid);
if (status == STATUS_SUCCESS)
{
DbgPrint(“Handle Has Been Promoted”);
}
if (status == STATUS_INVALID_CID)
{
DbgPrint(“The specified client ID is not valid.”);
}
if (status == STATUS_INVALID_PARAMETER)
{
DbgPrint(“The requested access rights are not valid for a process object.”);
}
if (status == STATUS_ACCESS_DENIED)
{
DbgPrint(“The requested access rights cannot be granted.”);
}
return status;
}

The return value is The specified client ID is not valid. STATUS_INVALID_CID
If anyone could shine some light on what I am doing wrong with this I would appreciate it.

> If anyone could shine some light on what I am doing wrong with this I would appreciate it.

Look what the documentation says on the topic

https://msdn.microsoft.com/en-us/library/windows/hardware/ff567022(v=vs.85).aspx

Now look what you do:

cid.UniqueProcess = kk->PID;
cid.UniqueThread = (HANDLE)0;

Do you really think 0 is a valid thread ID???

Anton Bassov

I am kind of confused on that part, for the UniqueThread. I read the documentation, and I still dont fully understand what the “unique thread” is?

I just tried to used PsGetThreadId for the Unique Thread and bsod, I am not to sure what to input so any further help would be appreciated.

this code
cid.UniqueProcess = kk->PID;
cid.UniqueThread = (HANDLE)0;
is absolute correct - 0 is valid value for UniqueThread in ZwOpenProcess api in ANY version of windows. so if you got STATUS_INVALID_CID - kk->PID is incorrect value

Ok, thanks for the info harald. But I did what you said fixed the pid issue and now I am extremly confused, the reason for that is because I am receiving an error that is not in the msdn of the function for example here is my code.
NTSTATUS PromoteHandleManual(NTHandle* k)
{
NTSTATUS status1;
NTSTATUS status;
status = STATUS_SUCCESS;
status1 = STATUS_SUCCESS;
OBJECT_ATTRIBUTES obj_attr;
CLIENT_ID cid;

status1 = PsLookupProcessByProcessId(k->PID, &proc);

if (NT_SUCCESS(status1)) {
cid.UniqueProcess = (HANDLE)k->PID;
cid.UniqueThread = (HANDLE)0;
InitializeObjectAttributes(&obj_attr, NULL, 0, NULL, NULL);
status = NtOpenProcess(&k->handle, PROCESS_ALL_ACCESS, &obj_attr, &cid);
DbgPrint(“Handle Should Have Data”);
if (status == STATUS_SUCCESS)
{
DbgPrint(“Handle Has Been Promoted”);
}
if (status == STATUS_INVALID_CID)
{
DbgPrint(“The specified client ID is not valid.”);
}
if (status == STATUS_INVALID_PARAMETER)
{
DbgPrint(“The requested access rights are not valid for a process object.”);
}
if (status == STATUS_ACCESS_DENIED)
{
DbgPrint(“The requested access rights cannot be granted.”);
}
if (!status == STATUS_SUCCESS)
{
DbgPrint(“Some Thing Went Wrong”);
}
}
else
{
DbgPrint(“PsLookupProcessByProcessId Failed”);
}
return status;
}

and than here is the screen shot of what I get.

http://i.imgur.com/zNB306T.png

for what so complex text DbgPrint ? just print status as is in binary form:
status = ZwOpenProcess(); // Zw not Nt !!
DbgPrint(“OpenProcess(%p)=%x\n”, cid.UniqueProcess, status);

when you use NtOpenProcess - I think you got c0000005 - because previous mode can be user and this case, but your pointers above MmHigestUserAddress.

Alright so I changed to Zw and it “says” it works correctly. My code is now as follows.

NTSTATUS PromoteHandleManual(NTHandle* k)
{
NTSTATUS status1;
NTSTATUS status;
status = STATUS_SUCCESS;
status1 = STATUS_SUCCESS;
OBJECT_ATTRIBUTES obj_attr;
CLIENT_ID cid;

status1 = PsLookupProcessByProcessId(k->PID, &proc);

if (NT_SUCCESS(status1)) {
cid.UniqueProcess = (HANDLE)k->PID;
cid.UniqueThread = (HANDLE)0;
InitializeObjectAttributes(&obj_attr, NULL, 0, NULL, NULL);
status = ZwOpenProcess(&k->handle, PROCESS_ALL_ACCESS, &obj_attr, &cid);
DbgPrint(“Handle Should Have Data”);
if (status == STATUS_SUCCESS)
{
DbgPrint(“Handle Has Been Promoted”);
}
if (status == STATUS_INVALID_CID)
{
DbgPrint(“The specified client ID is not valid.”);
}
if (status == STATUS_INVALID_PARAMETER)
{
DbgPrint(“The requested access rights are not valid for a process object.”);
}
if (status == STATUS_ACCESS_DENIED)
{
DbgPrint(“The requested access rights cannot be granted.”);
}
if (!status == STATUS_SUCCESS)
{
DbgPrint(“Some Thing Went Wrong”);
}
}
else
{
DbgPrint(“PsLookupProcessByProcessId Failed”);
}
return status;
}

Also the Driver prints out this

http://i.imgur.com/IJk5Hgv.png

But my user app shows that the handle is still NULL

http://i.imgur.com/ZhYet0H.png

What I do in my user app is

bool PromoteHandlex(HANDLE hand){
Handle.PID = (HANDLE)pid;
Handle.handle = hand;
QQ = DeviceIoControl(swag, PromoteHandleM, &Handle, sizeof(Handle), hand, sizeof hand, &bytes, 0);
return true;
}
HANDLE Han;
PromoteHandlex(Han);
cout << "Handle Data ";
cout << SWAGz << endl;

I meant to do cout << Han << endl;

He seemed to be opening a handle with NULL as the permissions, therefore the handle returned would be 0x0. Which I assume doesn’t work, try opening the handle with some basic permission.

Also, this line :

“Handle.PID = (HANDLE)pid;”

When you want to elevate your own handle, you have to use your own pid, the pid of the program that owns the handle. AKA the program that opens the handle originally.

Ok, you will probably want to disregard my above post because I was thinking about manually elevating the handle using the object table.

>DeviceIoControl(swag, PromoteHandleM, &Handle, sizeof(Handle), hand, sizeof hand, &bytes, 0);
mistake. mast be
DeviceIoControl(swag, PromoteHandleM, &Handle, sizeof(Handle), &hand, sizeof hand, &bytes, 0);

So, I did what you said and I also printed out some values and added some new ones.
What I want to do is transfer the Full Privileged handle to user mode, so here is what I have now
http://i.imgur.com/UaQINuA.png

NTSTATUS PromoteHandleManual(NTHandle* k)
{
NTSTATUS status1;
NTSTATUS status;
status = STATUS_SUCCESS;
status1 = STATUS_SUCCESS;
OBJECT_ATTRIBUTES obj_attr;
CLIENT_ID cid;
HANDLE handlemagic;

status1 = PsLookupProcessByProcessId(k->PID, &proc);

if (NT_SUCCESS(status1)) {
cid.UniqueProcess = (HANDLE)k->PID;
cid.UniqueThread = (HANDLE)0;
InitializeObjectAttributes(&obj_attr, NULL, 0, NULL, NULL);
status = ZwOpenProcess(&handlemagic, PROCESS_ALL_ACCESS, &obj_attr, &cid);

MmCopyVirtualMemory(PsGetCurrentProcess(), handlemagic, PsGetCurrentProcess(), k->handle, sizeof k->handle, KernelMode, &sizek);

DbgPrint(“Handle Should Have Data”);
if (status == STATUS_SUCCESS)
{
DbgPrint(“ZwOpenProcess Handle Magic (%x)”, &handlemagic);
DbgPrint(“k->handle (%x)”, &k->handle);
DbgPrint(“Handle Has Been Promoted”);
}
if (status == STATUS_INVALID_CID)
{
DbgPrint(“The specified client ID is not valid.”);
}
if (status == STATUS_INVALID_PARAMETER)
{
DbgPrint(“The requested access rights are not valid for a process object.”);
}
if (status == STATUS_ACCESS_DENIED)
{
DbgPrint(“The requested access rights cannot be granted.”);
}
if (!status == STATUS_SUCCESS)
{
DbgPrint(“Some Thing Went Wrong”);
}
}
else
{
DbgPrint(“PsLookupProcessByProcessId Failed”);
}
return status;
}

for what here MmCopyVirtualMemory when you need copy in current process context only ??

MmCopyVirtualMemory(PsGetCurrentProcess(), handlemagic, PsGetCurrentProcess(), k->handle, sizeof k->handle, KernelMode, &sizek);

to what point handlemagic ?!? this is not pointer. this is handle! same and for k->handle
may be this code use ? - MmCopyVirtualMemory(PsGetCurrentProcess(), &handlemagic, PsGetCurrentProcess(), &k->handle, sizeof k->handle, KernelMode, &sizek);
but, if take to account PsGetCurrentProcess() - all what need:

k->handle = handlemagic;

DbgPrint(“ZwOpenProcess Handle Magic (%x)”, &handlemagic);
DbgPrint(“k->handle (%x)”, &k->handle);

what sense print address of handle (local var in stack) ?!?

may be you want ?
DbgPrint(“ZwOpenProcess Handle Magic (%p)”, handlemagic);
DbgPrint(“k->handle (%p)”, k->handle);

when need use & - you not use it, when not need use & - you use it

ObfDereferenceObject not need use after PsLookupProcessByProcessId (if success) ?

for what so many status check/dbgprint, when enough 1 dbgprint with binary status value

What I was attempting to do was take the handlemagic and send it back to the usermode application.

I fixed the code up now it looks like this

NTSTATUS PromoteHandleManual(NTHandle* k)
{
NTSTATUS status1;
NTSTATUS status;
status = STATUS_SUCCESS;
status1 = STATUS_SUCCESS;
OBJECT_ATTRIBUTES obj_attr;
CLIENT_ID cid;
HANDLE handlemagic;

status1 = PsLookupProcessByProcessId(k->PID, &proc);

if (NT_SUCCESS(status1)) {
cid.UniqueProcess = (HANDLE)k->PID;
cid.UniqueThread = (HANDLE)0;
InitializeObjectAttributes(&obj_attr, NULL, 0, NULL, NULL);
status = ZwOpenProcess(&handlemagic, PROCESS_ALL_ACCESS, &obj_attr, &cid);

k->handle = handlemagic;

DbgPrint(“Handle Should Have Data”);
if (status == STATUS_SUCCESS)
{
DbgPrint(“ZwOpenProcess Handle Magic (%p)”, handlemagic);
DbgPrint(“k->handle (%p)”, k->handle);
DbgPrint(“Handle Has Been Promoted”);
}
if (status == STATUS_INVALID_CID)
{
DbgPrint(“The specified client ID is not valid.”);
}
if (status == STATUS_INVALID_PARAMETER)
{
DbgPrint(“The requested access rights are not valid for a process object.”);
}
if (status == STATUS_ACCESS_DENIED)
{
DbgPrint(“The requested access rights cannot be granted.”);
}
if (!status == STATUS_SUCCESS)
{
DbgPrint(“Some Thing Went Wrong”);
}
}
else
{
DbgPrint(“PsLookupProcessByProcessId Failed”);
}
return status;
}

My return is http://i.imgur.com/toM17AJ.png

Why does it return nothing 000000000000 to my user application but says its a valid handle in kernel?

this you fix ?

DeviceIoControl(swag, PromoteHandleM, &Handle, sizeof(Handle), hand, sizeof hand, &bytes, 0); mistake. mast be
DeviceIoControl(swag, PromoteHandleM, &Handle, sizeof(Handle), &hand, sizeof hand, &bytes, 0);

what in iosb ? status and information

Yes I did that

bool PromoteHandlex(HANDLE hand){
Handle.PID = (HANDLE)pid;
Handle.handle = hand;
QQ = DeviceIoControl(swag, PromoteHandleM, &Handle, sizeof(Handle), &hand, sizeof hand, &bytes, 0);
return true;
}

and in bytes what ? 0 ? you use buffered io and forget set irp->iostatus.Information to size of copied bytes ? but good choice method_neither for this call

Bytes being DWORD bytes; what do you mean, I am able to use 2 other function just fine this way.

after call DeviceIoControl what value in bytes ? what is io method (buffered, neither) ? if buffered - are Information in IoStatus you set ?