Skip to content

Commit

Permalink
sets current directory from parent process & minor updates to everywhere
Browse files Browse the repository at this point in the history
  • Loading branch information
ysmu committed Jul 3, 2017
1 parent 1609fba commit f8f84c4
Show file tree
Hide file tree
Showing 9 changed files with 336 additions and 14 deletions.
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
# windows-sudo
windows-sudo lets you run an arbitrary program with administrative privileges on Windows.
windows-sudo lets you run an arbitrary program with elevated privilege on Windows.
Remember, this is *different* from running the program as the Administrator user.

## Installation
Move the compiled ```sudo.exe``` into ```C:\Windows``` or into one of the folder in ```$PATH```.
This allows you to execute ```sudo.exe``` from anywhere.
1. Download the latest release from https://github.com/ysmu/windows-sudo/releases/latest
2. Unzip it and run ```install.bat```

## Example
```sudo cmd```

```sudo regedit```

## System Requirement
All functions of windows-sudo *should* be compatible with all 32bit and 64bit builds of Windows newer than Windows XP SP 2 (included). That being said, I will only be maintaining windows-sudo for Windows 10. windows-sudo has been tested on the following platform:

- Windows 10 x64 Build 1607
- Windows 10 x64 Build 1703

## License
MIT License

Expand Down
11 changes: 11 additions & 0 deletions scripts/install.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@echo off

reg query "HKLM\Hardware\Description\System\CentralProcessor\0" | find /i "x86" > NUL && set arch=86 || set arch=64

if %arch%==86 (
sudo cmd /c "copy sudo.exe %WINDIR%\system32\sudo.exe"
)
if %arch%==64 (
sudo cmd /c "copy sudo.exe %WINDIR%\SysWoW64\sudo.exe"
sudo cmd /c "copy sudo64.exe %WINDIR%\system32\sudo.exe"
)
2 changes: 2 additions & 0 deletions scripts/uninstall.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
sudo cmd /c "del %WINDIR%\SysWoW64\sudo.exe"
sudo cmd /c "del %WINDIR%\system32\sudo.exe"
119 changes: 119 additions & 0 deletions utils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#include <Windows.h>
#include <tlhelp32.h>
#include <tchar.h>
#include "windefs.h"

int GetParentProcessId()
{
PROCESSENTRY32 stPe32;
stPe32.dwSize = sizeof(PROCESSENTRY32);

HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (Process32First(hSnapshot, &stPe32))
{
do
{
if (stPe32.th32ProcessID == GetCurrentProcessId())
{
CloseHandle(hSnapshot);
return stPe32.th32ParentProcessID;
}
} while (Process32Next(hSnapshot, &stPe32));
}

CloseHandle(hSnapshot);
return -1;
}

bool GetProcessCurrentDirectory(wchar_t wszPath[MAX_PATH])
{
ZeroMemory(wszPath, MAX_PATH * sizeof(wchar_t));

//open parent process
int ppid = GetParentProcessId();
if (ppid < 0)
{
return false;
}
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ppid);
if (hProcess == NULL)
{
return false;
}

BOOL isWow64;
IsWow64Process(GetCurrentProcess(), &isWow64);
if (isWow64)
{
PEB_WOW64 stPEB;
PROCESS_BASIC_INFORMATION_WOW64 stPbi;

//read PEB
NtQueryInformationProcessFunc NtQueryInformationProcess = (NtQueryInformationProcessFunc)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtWow64QueryInformationProcess64");
if (NtQueryInformationProcess == NULL)
{
CloseHandle(hProcess);
return false;
}
if (NtQueryInformationProcess(hProcess, ProcessBasicInformation, &stPbi, sizeof PROCESS_BASIC_INFORMATION_WOW64, NULL) != 0)
{
CloseHandle(hProcess);
return false;
}
NtWow64ReadVirtualMemory64Func NtWow64ReadVirtualMemoryWow64 = (NtWow64ReadVirtualMemory64Func)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtWow64ReadVirtualMemory64");
if (NtWow64ReadVirtualMemoryWow64(hProcess, stPbi.PebBaseAddress, &stPEB, sizeof PEB_WOW64, NULL) != 0)
{
CloseHandle(hProcess);
return false;
}

RTL_USER_PROCESS_PARAMETERS_WOW64 stUPP;
if (NtWow64ReadVirtualMemoryWow64(hProcess, stPEB.ProcessParameters, &stUPP, sizeof RTL_USER_PROCESS_PARAMETERS_WOW64, NULL) != 0)
{
CloseHandle(hProcess);
return false;
}
if (NtWow64ReadVirtualMemoryWow64(hProcess, stUPP.CurrentDirectory.DosPath.Buffer, wszPath, stUPP.CurrentDirectory.DosPath.Length, NULL) != 0)
{
CloseHandle(hProcess);
return false;
}
}
else
{
PEB stPEB;
PROCESS_BASIC_INFORMATION stPbi;

//read PEB
NtQueryInformationProcessFunc NtQueryInformationProcess = (NtQueryInformationProcessFunc)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtQueryInformationProcess");
if (NtQueryInformationProcess == NULL)
{
CloseHandle(hProcess);
return false;
}
if (NtQueryInformationProcess(hProcess, ProcessBasicInformation, &stPbi, sizeof PROCESS_BASIC_INFORMATION, NULL) != 0)
{
CloseHandle(hProcess);
return false;
}
if (ReadProcessMemory(hProcess, stPbi.PebBaseAddress, &stPEB, sizeof PEB, NULL) == 0)
{
CloseHandle(hProcess);
return false;
}

RTL_USER_PROCESS_PARAMETERS stUPP;
if (ReadProcessMemory(hProcess, stPEB.ProcessParameters, &stUPP, sizeof RTL_USER_PROCESS_PARAMETERS, NULL) == 0)
{
CloseHandle(hProcess);
return false;
}
if (ReadProcessMemory(hProcess, stUPP.CurrentDirectory.DosPath.Buffer, wszPath, stUPP.CurrentDirectory.DosPath.Length, NULL) == 0)
{
CloseHandle(hProcess);
return false;
}
}
CloseHandle(hProcess);
return true;
}
3 changes: 3 additions & 0 deletions utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once
int GetParentProcessId();
bool GetProcessCurrentDirectory(wchar_t wszPath[MAX_PATH]);
139 changes: 139 additions & 0 deletions windefs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#pragma once

typedef enum _PROCESSINFOCLASS {
ProcessBasicInformation = 0,
ProcessDebugPort = 7,
ProcessWow64Information = 26,
ProcessImageFileName = 27,
ProcessBreakOnTermination = 29
} PROCESSINFOCLASS;

// ======================
// For programs whose bitness is the same as that of the kernel
// i.e. 32bit program on 32bit kernel, 64bit program on 64 bit kernel
// ======================
// we only need the structure up to ProcessParameters
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING;

typedef struct _CURDIR
{
UNICODE_STRING DosPath;
PVOID Handle;
} CURDIR, *PCURDIR;

//we only need the structure up to CurrentDirectory
typedef struct _RTL_USER_PROCESS_PARAMETERS
{
ULONG MaximumLength;
ULONG Length;
ULONG Flags;
ULONG DebugFlags;
PVOID ConsoleHandle;
PVOID ConsoleFlags;
PVOID StandardInput;
PVOID StandardOutput;
PVOID StandardError;
CURDIR CurrentDirectory;
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;

//ref: http://terminus.rewolf.pl/terminus/structures/ntdll/_PEB_combined.html
//we only need the structure up to ProcessParameters
typedef struct _PEB {
BYTE InheritedAddressSpace;
BYTE ReadImageFileExecOptions;
BYTE BeingDebugged;
BYTE Reserved;
PVOID Mutant; /* +0x4 */
PVOID ImageBaseAddress; /* +0x8 */
PVOID Ldr; /* +0xc */
PVOID ProcessParameters; /* +0x10 */
} PEB;

typedef struct _PROCESS_BASIC_INFORMATION {
PVOID Reserved1;
PVOID PebBaseAddress;
PVOID Reserved2[2];
ULONG_PTR UniqueProcessId;
PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;

typedef NTSTATUS(NTAPI* NtQueryInformationProcessFunc)(
IN HANDLE ProcessHandle,
ULONG ProcessInformationClass,
OUT PVOID ProcessInformation,
IN ULONG ProcessInformationLength,
OUT PULONG ReturnLength OPTIONAL
);

typedef NTSTATUS(NTAPI* NtReadVirtualMemoryFunc)(
IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
OUT PVOID Buffer,
IN SIZE_T Size,
OUT PSIZE_T NumberOfBytesRead
);

// ======================
// For 32bit programs under 64bit kernels (Wow64)
// ======================
// we only need the structure up to ProcessParameters
typedef struct _UNICODE_STRING_WOW64 {
USHORT Length;
USHORT MaximumLength;
DWORD _padding;
PVOID64 Buffer;
} UNICODE_STRING_WOW64;

typedef struct _CURDIR_WOW64
{
UNICODE_STRING_WOW64 DosPath;
ULONG Handle;
} CURDIR_WOW64, *PCURDIR_WOW64;

//we only need the structure up to CurrentDirectory
typedef struct _RTL_USER_PROCESS_PARAMETERS_WOW64
{
ULONG MaximumLength;
ULONG Length;
ULONG Flags;
ULONG DebugFlags;
PVOID64 ConsoleHandle;
PVOID64 ConsoleFlags;
PVOID64 StandardInput;
PVOID64 StandardOutput;
PVOID64 StandardError;
CURDIR_WOW64 CurrentDirectory;
} RTL_USER_PROCESS_PARAMETERS_WOW64, *PRTL_USER_PROCESS_PARAMETERS_WOW64;

//ref: http://terminus.rewolf.pl/terminus/structures/ntdll/_PEB_combined.html
//we only need the structure up to ProcessParameters
typedef struct _PEB_WOW64 {
BYTE InheritedAddressSpace;
BYTE ReadImageFileExecOptions;
BYTE BeingDebugged;
BYTE Reserved;
PVOID64 Mutant; /* +0x4 */
PVOID64 ImageBaseAddress; /* +0x10 */
PVOID64 Ldr; /* +0x18 */
PVOID64 ProcessParameters; /* +0x20 */
} PEB_WOW64, *PPEB_WOW64;

typedef struct _PROCESS_BASIC_INFORMATION_WOW64 {
PVOID64 Reserved1;
PVOID64 PebBaseAddress;
PVOID64 Reserved2[2];
ULONG_PTR UniqueProcessId;
PVOID64 Reserved3;
} PROCESS_BASIC_INFORMATION_WOW64;

typedef NTSTATUS(NTAPI* NtWow64ReadVirtualMemory64Func)(
IN HANDLE ProcessHandle,
IN PVOID64 BaseAddress,
OUT PVOID Buffer,
IN ULONG64 Size,
OUT PULONG64 NumberOfBytesRead
);
33 changes: 27 additions & 6 deletions windows-sudo.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <tchar.h>
#include <Windows.h>
#include <tchar.h>
#include "utils.h"
#include "resource.h"

#define MAX_LOAD_STRING 1024
Expand All @@ -26,24 +27,44 @@ int APIENTRY _tWinMain(HINSTANCE hInstance,
}
}

//We want to use the same current directory as our calling parent
//This way, when we do a `sudo cmd` in a cmd prompt,
//we can get a privileged cmd prompt in the same directory,
//instead of in the default %WINDIR%\system32 (SysWoW64),
wchar_t wszCurrentDirectory[MAX_PATH];
if (GetProcessCurrentDirectory(wszCurrentDirectory))
{
SetCurrentDirectoryW(wszCurrentDirectory);
}
else
{
//somehow, we're unable to retrieve our parent's current directory
//resort to user's home directory
if (GetEnvironmentVariable(L"USERPROFILE", wszCurrentDirectory, MAX_PATH) <= MAX_PATH)
{
SetCurrentDirectoryW(wszCurrentDirectory);
}
}

HINSTANCE hInst = ShellExecute(NULL, _T("open"), pFilename, pArgs, NULL, SW_SHOW);
if ((int)hInst > 32)
if ((long long)hInst > 32)
{
return 0;
}
else
{
//something went wrong
int errorCode = reinterpret_cast<int>(hInst);

TCHAR szMsgBoxTitle[MAX_LOAD_STRING];
LoadString(GetModuleHandle(NULL), IDS_ERROR, szMsgBoxTitle, MAX_LOAD_STRING);

TCHAR szError[MAX_LOAD_STRING];
if (LoadString(GetModuleHandle(NULL), (UINT)hInst, szError, MAX_LOAD_STRING) == 0)
if (LoadString(GetModuleHandle(NULL), errorCode, szError, MAX_LOAD_STRING) == 0)
{
LoadString(GetModuleHandle(NULL), IDS_UNKNOWN_ERROR, szError, MAX_LOAD_STRING);
}
MessageBox(NULL, szError, szMsgBoxTitle, MB_ICONERROR);
return -(int)hInst;
return -errorCode;
}
}

}
Loading

0 comments on commit f8f84c4

Please sign in to comment.