Short disclaimer: As this question includes topics regarding hacking/pentesting, I'd like to state that this question is only asked for educational purposes as part of a school project. To prevent possible abuse, I will only post code that is necessary for understanding the problem.
To demonstrate dangers and vulnerabilities of Windows 10, I'm currently writing a small C++/WinAPI application that utilizes two common techniques:
A UAC bypass using the "fodhelper technique" (this works by simply setting a specific registry value to the path of the executable which is supposed to be elevated and then launching an automatically elevated Windows executable called "fodhelper.exe", which will then read the registry value and execute it as command/launch the specified application).
Performing PE injection, i.e. running a PE file from the address space of the current process (based on this example from github). The PE that gets injected in my program is a simple C++ Console Application (x86) that prints a message box. The shellcode is hardcoded in the injector binary (x86).
I managed to perform both of these techniques successfully in independent files. However, once I combine these two methods (i.e. first elevating, then injecting), a weird error appears.
Description of the problem
When the injector gets started manually (by double clicking), everything works fine, but when the injector is launched by System32\fodhelper.exe (x64) as a result of the UAC bypass, the following happens: After the injection has finished, the console window of the injected application appears, but instead of continuing the execution, I receive a bunch of error messages stating "The code execution cannot proceed because [garbage characters].dll was not found". This indicates that something went wrong with the offsets, and the Windows loader is trying to read the imports at a wrong position.
To summarize: The code injection works fine, unless the injector was started by fodhelper.exe. In this case the injected PE file is unable to run.
Things I have tried so far to find the origin of the issue
Debugging the injection using GetLastError and printing the various memory addresses used during the injection. There is no difference if the file is manually started (and the injection is successful) or if it gets started by fodhelper.exe (and the injection fails).
Replace the WriteProcessMemory calls with WriteFile to compare the output file when the injector gets manually launched or by fodhelper.exe. Both output files are exactly the same and runnable. This indicates that the injection itself is not the problem, but the Windows loader seems to act differently.
Manually elevating the injector using UAC or by using an elevated command prompt. In both cases, the injection is successful.
Copying fodhelper.exe to another location (for example to the desktop) and launching this copy. In this case, the injection is successful. The injection only fails if the injector gets started by the original fodhelper.exe in the System32 folder.
It seems that the injection behaves completely identical, but the indicators show that due to some unknown impact of fodhelper.exe that gets passed down to the injector, the Windows loader seems to behave differently.
I appreciate any explanation or assumption! Feel free to ask if you require more information.
Minimal reproducible example
(with limited debug info and comments):
https://0bin.net/paste/UPRIg12n#6nJvBok72UcDvIa56c-XEss7AibIh1Zrs+c3sUzvQMj
Note: See how the injection works if you exclude the elevateProcess function or manually elevate the exe with UAC, and how it fails when including said function.
Edit
According to the answer by user RbMm, this error is a result of a specific exploit protection attribute (PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY with the EnableModuleTamperingProtection value) that gets automatically applied onto fodhelper.exe and seemingly gets inherited by all child processes. According to this, removing/resetting this attribute when launching the target process should fix the error. So far I've tried the following, but couldn't achieve any change in the outcome:
DWORD resetPolicy = 0;
STARTUPINFOEXA siEx = { 0 };
SIZE_T AttributeListSize = 0;
siEx.StartupInfo.cb = sizeof(siEx);
InitializeProcThreadAttributeList(NULL, 1, 0, &AttributeListSize);
siEx.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, AttributeListSize);
InitializeProcThreadAttributeList(siEx.lpAttributeList, 1, 0, &AttributeListSize);
UpdateProcThreadAttribute(siEx.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, &resetPolicy, sizeof(resetPolicy), NULL, NULL);
...
CreateProcessA(CurrentFilePath, NULL, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT | CREATE_SUSPENDED, NULL, NULL, (LPSTARTUPINFOA)&siEx, &PI);
when process created via RunAs with elevation - the appinfo.dll call RAiLaunchAdminProcess function (this is in some svchost.exe) and this function, pass STARTUPINFOEX (and EXTENDED_STARTUPINFO_PRESENT flag) to CreateProcessAsUser. and here - lpAttributeList, in particular PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY attribute key is used for set several exploit mitigation policy for the child process (fodhelper.exe in your case). and here EnableModuleTamperingProtection is set for child process tree. effect of this - when system resolve import descriptor, it check (inside LdrpGetImportDescriptorForSnap) for this mitigation flag, and if it enabled - call LdrpCheckPagesForTampering api, it return true, if SharedOriginal is 0, this means this is a copy-on-write private copy of the EXE/IAT -- hence 'tampered' with.
after this LdrpMapCleanModuleView is called. at this point your try begin breaking
possible first public info about this, from Alex Ionescu -
LdrpCheckPagesForTampering/LdrpMapCleanModuleView (RS3) are pretty
cool antihollowing mitigations
(EPROCESS.EnableModuleTamperingProtection)
if you by self launch new process, you of course not call UpdateProcThreadAttribute for set PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY and in this case, your code sometime work. really only random and sometime - here exist many other errors and bad codding
Related
My program works flawlessly on Windows Vista Ultimate and Windows 7, however it fails on Windows XP.
First, my application creates a process of a system file, it calls GetThreadContext(remote_thread) and sets an LPVOID value to the value context->Eip, and then checks the values in the structure MEMORY_BASIC_INFORMATION set from VirtualQueryEx.
Here are the values VirtualQueryEx returned when called:
Windows XP
0 - allocation base
0 - allocation protect
2088828928 - base address
1 - protect
983040 - region size
65536 - state
0 - type
Windows 7
2003959808 - allocation base
128 - allocation protect
2004025344 - base address
32 - protect
876544 - region size
4096 - state
16777216 - type
Windows Vista
2006122496 - allocation base
128 - allocation protect
2006536192 - Base address
32 - protect
389120 - region size
4096 - state
16777216 - type
Why is it that when I run my application on Windows XP it has no allocation base and no allocation protect, as well as completely different values to Windows 7 and Windows Vista.
I plan to use VirtualProtectEx on the address (context->Eip), so If those are the values on XP then VirtualProtectEx will inevitably fail, as I would be accessing unaccessible memory.
Here is how I create my process :
if ( CreateProcessW(m_pwszContainerPath, NULL, NULL, NULL, FALSE, DETACHED_PROCESS | CREATE_SUSPENDED, NULL, NULL, &m_stStartInfo, &m_stProcessHandles) == TRUE )
{
// Get context of thread
m_stContext.ContextFlags = CONTEXT_FULL;
if ( GetThreadContext(m_stProcessHandles.hThread, &m_stContext) == FALSE )
goto _CLEANUP;
// Grab, Eip
m_pvLdrInitEip = (LPVOID)m_stContext.Eip;
}
The fact of the matter is: This works flawlessly on both Windows 7 and Windows Vista.
Is there something I am missing here?
Thank you for any help.
EDIT - Here goes a picture :
Here is a picture of two instances of olly running the executable, one in the XP virtual machine, one outside. From what I notice, the XP picture (bottom one) has it's EIP set to ModuleEntryPoint while the Windows 7 Instance has it set to ntdll..
I investigated further, and found that the EIP was, in fact in kernel32.dll image (on Windows XP), rather than ntdll.dll as it should be..
Creating a process with CREATE_SUSPENDED means the main process won't finish it's initialization before you run your code. the way the loader is implemented causes the different effects between XP and Vista/7, and since the CREATE_SUSPENDED documentation doesn't grantee any process initialization you can't really count on that method. the CREATE_SUSPENDED flag only states the process is created with the main thread suspended.
It's not exactly clear what the OP desires to accomplish, but a few methods to achive similar goals come to mind:
Write a debugger instead of remotely manipulating another process. a simple tutorial and code examples can be found Here. the debugger gets an event for every spawned thread, you could probably use that.
Modify the PE to execute your code before any other by either creating a new section for your code and placing a TLS entry in the PE to execute code inside the process's memory space. you're code will then run before the process's EntryPoint but after it was initialized.
Modify the PE and replace the EntryPoint in the PE header with your own code, just make sure you execute the original entry point yourself. some initalization will be missing but all the PE code sections will be loaded.
Inject a DLL into the process's memory address by either creating it suspended and loading a DLL from a different thread, or any other method. This article lists a few and you can Google for more. i'm not sure that'll work in all cases if you want to get the process initialized because of similar issues, but I do think that calling LoadLibrary will get you the desired efect. That is also a clean way to get code into another process and manipulate it while being more stealth than using a debugger.
You can also try scanning the entire memory for the code chunks you want to manipulate while the process is suspended, that might also work on XP.
You could try creating the process unsuspended and let it run for a short period of time before suspending the threads. after timing and a few tests you'll get a resonable feelling about how much time it takes to initialize. That's a bit risky but might work.
creating a debugger will be the easiest and most robust/generic method but will have the disadvtange of being easily detected (although you could use anti-anti-debugging tricks). loading a DLL will be the best way if you want to remain undetectable by the manipulated process (if it has any anti-debugging tricks) if you want more suggestions or recomendations for your specific needs please edit and describe in detail what exactly you want to accomplish as it is not clear from your question. a little more details about the program (is it native, or .net for example) would also be helpful.
EDIT:
another speculation suggested by friend was that the kernel did not finish the process initialization by the time the syscall returns and you call VirtualQueryEx. he said calling WaitForSingleObject on the process's handle will return once the process is fully initialized and you could access all the information and resume the execution afterwards.
CreateProcess(CREATE_SUSPENDED) only do partial initialization. You may try to VirtualAllocEx() the EIP region and explicitly COMMIT it, and then VirtualProtectEx, of course this is a quick hack, you can have a test, I'm not sure whether this can
fix the problem. BTW, what's your real purpose to do so? If you intend to hook at early stage of process execution, patch the entry point of PE header is better, since when instruction control flow reach the entry point, the process must have completed its initialization, however this also has its downside, e.g. TLS callback is invoked before the entry point get executed.
I am using WINAPI for a program that I am writing. The program has the ProcessId of another process and needs to get a handle of it (to be able to terminate it later, and also to periodically check if the process is alive and responding by using WaitForSingleObject). When I compile my program (in Embarcadero RAD Studio 2010 C++ Builder), it works well; the program seems to get the handle successfully and generally works as intended. However, if I launch it from the folder as a standalone exe, it seems to fail to get the handle properly. I checked it by comparing (Companion is a HANDLE and Companion_PID is a DWORD):
GetProcessId(Companion)
and
Companion_PID
Where, a few lines earlier, Companion is taken from Companion_PID in the following code:
Companion = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Companion_PID);
And the "GetProcessId(Companion)" results in 0 (which is a good sign that the OpenProcess failed to return a proper handle.
I'm pretty surprised that this code works differently when run from the compiler and as a standalone exe; I'm assuming in the first case the security attributes are inherited from the compiler itself, but I'd like to hear a possibly better explanation for this behaviour from someone more experienced in WINAPI and security attributes in particular.
Small update: yes, like I thought, OpenProcess results in error 0x5 = ERROR_ACCESS_DENIED.
From OpenProcess function page in MSDN:
To open a handle to another local process and obtain full access
rights, you must enable the SeDebugPrivilege privilege.
I believe your IDE (you're running your application from IDE, not from compiler) has SeDebugPrivilege enabled by default. When you run your application, your IDE (process) is creating a new process which inherits privileges from IDE, including SeDebugPrivilege and that's the reason why function succeeds when run from IDE.
Your application should check whether it has SeDebugPrivilege enabled, and if not, enable it.
I'm trying to detect all calls to CoCreateInstance in some process I'm starting (ideally, I'm able to detect calls in child processes as well).
To achieve this, using Microsoft Visual Studio 2008 on Windows 7, I create a proxy DLL which forwards all but one call in the standard ole32.dll library as described in various articles, e.g.
Intercepted: Windows Hacking via DLL Redirection. The resulting DLL looks fine, but I just can't make existing programs (I'm using the standard ActiveX Control Test Container (tstcon32.exe) as a test application) pick up my proxy DLL. No matter what I do, the programs always seem to pick up C:\Windows\SysWow64\ole32.dll according to Process Explorer. I tried a few things so far:
Prepend the directory which contains my proxy DLL to the PATH and then invoke the program; didn't seem to have any effect.
Copy my proxy DLL into the same directory as the invoked program; no luck.
Create a .local file in the same directory as the invoked program as described in the Dynamic-Link Library Redirection article and put my proxy DLL into the same directory - didn't work either. But then, I read that this stopped working on more recent Windows versions. Additionally, ole32.dll is a "known DLL" according to the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs registry setting, so .local-based redirection is probably not going to work anyway.
Use manifest-based redirection as described e.g. in the DLL redirection using manifests question, but that didn't seem to have any effect either. However, this approach seems to be non-trivial, so chances are I did something wrong.
Does anybody have experience with redirecting calls to standard DLLs such as ole32.dll using a stub DLL? How did you force the applications to pick up your stub DLL?
I realise this is a little late by about 6 months, but I was trying the same thing and have some additional notes:
You can take ownership of and remove ole32.dll from HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs. This allows you to get around the fact Windows has locked these keys.
Creating a key SafeDllSearch with the value 0 in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager is supposed to alter the search path.
Having applied both these techniques and rebooting, hooking still did not work. I went one further, booted up a VM with one of our rescue CDs (a Windows PE based environment) and overwrote the one in system32. Windows does not boot as a result - no symbol errors, but I never get as far as LogonUI.exe. It is possible my hooked functions are broken, so this may be the cause.
Anyway, that produced an actual, tangible hook effect - albeit one that screams "broken"!. Unfortunately it appears highly difficult to debug, and I may be resorting to the other method of hooking - namely IAT patching.
Edit another experiment I performed was to explicitly load the Dll myself into the target process' address space. A snippet of code that does this looks like this:
wchar_t* TargetPath = argv[1];
wchar_t DllPath[] = L"N:\\experiments\\ole32.dll";
STARTUPINFOW si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(STARTUPINFOW));
memset(&pi, 0, sizeof(PROCESS_INFORMATION));
// create process suspended
BOOL bResult = CreateProcess(NULL, TargetPath, NULL, NULL, FALSE,
CREATE_SUSPENDED, NULL, NULL, &si, &pi);
// write DLL name to remote process
void* RemoteAddr = VirtualAllocEx(pi.hProcess, NULL, sizeof(DllPath)+1,
MEM_RESERVE | MEM_COMMIT, PAGE_READONLY);
WriteProcessMemory(pi.hProcess, RemoteAddr, DllPath, sizeof(DllPath), &BytesWritten);
// get handle to LoadLibraryW
PTHREAD_START_ROUTINE pfLoadLibrary = (PTHREAD_START_ROUTINE)
GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW");
// create remote thread calling LoadLibraryW
HANDLE hThread = CreateRemoteThread(pi.hProcess, NULL,
0, pfLoadLibrary, RemoteAddr, 0, NULL);
// start remote process
ResumeThread(pi.hThread);
Error handling removed for brevity.
Basically, the objective was to force load my ole32.dll into the target's address space before it had chance to load ole32.dll from system32. In my case, ole32.dll was being loaded later on in the application's load routine, so this in theory should have worked. In practice, it did not. I am not sure why.
Update My original code failed because the DLL had unresolved symbol warnings at runtime. This technique does work So apparently, it loads both my ole32.dll AND the one from system32. To ensure the library was loading successfully, I added a LoadLibrary(DllPath) call to the code above.
Perhaps winapioverride can help you. It can log all win api calls without programming anything. It therefore injects dlls to the process that do the logging. If I recall it correctly it is also possible to inject own custom dlls - even before the process actually executes any code. The documentation has some information about spying com objects.
I'm building a custom authentication subpackage for MSV1_0 for Windows 7. I've used the msvsubauth sample in from the Windows SDK and I have 2 questions regarding some problems I'm facing with that:
When I'm trying just to make sure that the routine get's invoked and set the Auth0 property in the registry to my package and add a simple code at the end of the Msv1_0SubAuthenticationRoutine that creates a file:
//
// Cleanup up before returning.
//
Cleanup:
hTestFile = CreateFile(
TEXT("C:\\lsa\\lsa.txt"),
GENERIC_READ|GENERIC_WRITE, 0,
NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if(hTestFile != INVALID_HANDLE_VALUE) {
CloseHandle(hTestFile);
}
return Status;
} // Msv1_0SubAuthenticationRoutine
Apparently the package gets invoked because when I enter my password I get an error message from windows "the parameter is incorrect" which is a good sign. But why I'm getting that error? when the exactly same code is executed from a separate .exe file it runs perfectly and creates the test text file. I've checked the permissions and set "full control" for "everyone". Any ideas? the SDK doesn't exactly mention what kind of isolation LSA is creating for code within auth packages.
The second problem is testing the AP. Currently with every change I rebuild the library, copy it to a test VM and then to the System32 folder and reboot it. Is there an easier way to do that?
Thank in advance!
Debugging in Winlogon and LSASS makes for the most time consuming debugging.
To ease your debugging, you could write a proxy AP that exports the same functions. When loaded, you proxy_ap would
Copy the real AP from a known location to a temp locationand.
LoadLibrary that DLL, GetProcAddress of everything, and forward any calls it receives to that newly loaded DLL.
Watch for changes in the directory where the original AP was copied from
When a change occurs (and if your AP changed) FreeLibrary and goto step 2
But you need to keep a tight grip on what happens on your development target, because handling the dll switch while dealing with requests comming from many threads can become a worse nightmare that what you are trying to solve.
LogonUI.exe starts a new instance every time, but LSASS.exe is long lived.
+Have a look at CVSNT source code (http://cvsnt.sourcearchive.com/). They have a pretty nice AP that implements su. Run the sample in the local system account with psexec -s (from Microsoft/SysInternals pstools suite)
Perhaps your problem is Everyone only includes Authenticated users? This is just a guess.
I suggest you use Process Monitor to monitor for Access Denied messages or for your path. It is fantastic for debugging permission/path problems of all kinds.
http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx
If you experience the issue at the "Unlock Workstation" or "change Password" screens, and it doesn't prevent you logging in, this should be easy to do - set it running, reproduce the problem, log back in and hey presto.
Otherwise you might have to resort to tricks like executing that code path only for certain user accounts, on the Nth try, etc.
I have a Delphi web server providing some web services*. One of them is supposed to generate and return a PDF report.
The PDF creation is done with a QReport that is then exported into a PDF file with the ExportToFilter procedure.
The routine works fine when called from within an application, but when called behind a TIdTCPServer, it hangs and never finishes. Debugging it, I got tho the hanging point:
(note: I'm home right now and I don't have the source code. I'll try to reproduce quickrpt.pas' source as accurrate as I can remember).
procedure TCustomReport.ExportToFilter(TQRDocumentFilter filter);
...
AProgress := TQRFormProgress.Create(Application); // Hangs on this line
AProgress.Owner := QReport;
if ShowProgress then AProgress.Show;
QReport.Client := AProgress;
...
Searching the web, I found in this page (1) the suggestion to set ShowProgress to False, and edit the code so that it does not create the progress form when ShowProgress is set to false (apparently, this is due to QReport not being threadsafe).
So, I edited the code, and now I have this:
procedure TCustomReport.ExportToFilter(TQRDocumentFilter filter);
...
if ShowProgress then
begin
AProgress := TQRFormProgress.Create(Application);
AProgress.Owner := QReport;
AProgress.Show;
QReport.Client := AProgress
end;
...
Now, the report comes out. But then the service gets to an Invalid Pointer Exception (which I can't trace). Following calls to the service complete successfully, but when I shut down the service** it starts whining again with Invalid Pointer Exceptions, then the "MyServer has commited an invalid action and must be closed" windows message, then again a couple of times more, then just the pointer exception, then comes to error 216 (which as far as I could find out, is related to Windows access permissions).
Thanks!
Update (jan 5): Thanks Scott W. for your answer. Indeed, after some research, I found another suggestion that only the main thread can access some components. So I set the QR code back to normal and called the main method from a Synchronize call inside a TThread (so that way the main thread would handle it). But I still get the same error.
You mention you were able to generate PDF as a service with QR 4. Maybe that's why it's not working for me, since I'm using QR 3. On the other hand, you don't mention if you're doing that behind a TIdTCPServer (which is my case, providing web services) or if you run it by itself (for instance, during a batch process).
Anybody knows whether my QR version might be the problem? Thanks!
* Running Delphi 7 and QuickReport 3 on a Windows XP SP2. The server is based on Indy.
** I have two versions of the server: a Windows application and a Windows Service. Both call the same inner logic, and the problem occurs with both versions.
Update (mar 8): After all, my problem was that my printing routine was in another dll, and the default memory management module is somewhat crappy. Setting the first uses of my .dpr to be ShareMem overrides the memory management module with Borland's implementation, and solved my problem.
uses
ShareMem, ...
(1): http://coding.derkeiler.com/Archive/Delphi/borland.public.delphi.thirdpartytools.general/2006-09/msg00013.html
I'm guessing that QReport.Client is used somewhere later in the code, and with your modified code no longer assigning it to AProgress, you end up with an error.
Are you sure that you have to modify the QuickReport source? I have used QuickReport in a Windows Service to generate a PDF file and then attach to email message and all worked fine without having to modify the QR source. I don't recall exactly which settings had to be made, but it was done with Delphi 6 and QR 4.06.