D

Deleted member 65228

Guest
#41
Thanks.:)
What do you mean by manual map DLL? It looks like reflective DLL injection, but some things have to be done manually? If so, then would it be possible to make a reflective DLL loader to inject into a UWP process?
Oh, my apologies... I should have explained it better.

As far as I am aware, 'reflective' DLL loading is the same as 'manual mapping' a DLL. They both do the same thing. The end result is the target DLL is loaded into memory and its entry point (e.g. DllMain -> DLL_PROCESS_ATTACH) is successfully called, however at the same time the DLL will not be linked to the Process Environment Block. Since the loaded module will not be linked to the Process Environment Block, when you enumerate through the loaded modules of the affected process, you will not find the DLL loaded via this technique as a module. In other words, it will be "hidden".

I am used to referring to the technique as 'manual mapping' but they should both work the same therefore you can use either terms.

The reason you cannot use the normal injection method for DLLs into UWP processes via a remote thread to call LoadLibraryA is either because of internal checks performed by lower functions like LdrLoadDll (or lower via LdrpLoadDll where initialisation for the Shim engine (which was introduced in Windows 8) takes place for the record), or because UWP applications monitor thread creation and block it when the address is for a function like LoadLibraryA.

Since you can perform virtual memory operations and thread creation just fine with UWP processes, code-cave injection will work fine as well. However, depending on how the anti-DLL loading mechanism is implemented, even if you used code-cave to then have the injected code make a call to LdrLoadDll, it might still not work. Regardless, you can copy the bytes for the target DLL into the address space of the target UWP process remotely and then perform shell-code/code-cave injection (where the injected code will handle the finalisation steps for the manual mapping operation).

Honestly though, in the case of a "sophisticated attack" by an experienced developer, manual mapping will probably be avoided. Not because manual mapping a DLL is not "secretive" enough, but because experienced malware authors know that dropping a DLL to disk is not a good idea - however they may hard-code the bytes of the DLL instead and have it used from memory manually. That too is possible and would work very similarly... You would determine the total size, allocate enough memory, copy across the bytes (representing executable code), etc.

@Opcode, I'm just reading my old stuff :)

So yes, using raw system calls instead of normal high level API is obviously unusual and unnecessarily uncomfortable, except if you want to evade some monitoring/hooking software and obtain a basic code obfuscation.
The problem here is on every Windows version too syscall numbers may vary and it seems there is no official way to obtain the correct values for the system your application is running.
By “official ways” I mean we can always extract those values from the ntdll library we can find during runtime.
But if we can load it with a simple LoadLibrary, obtain a pointer to the API we are interested ( let’s say NtCreateFile ) with GetProcAddress and examine the first opcodes in it, can we could achieve the same result without loading the library but manually inspecting its content as a portable executable file?

Correct me, can we easily open ntdll.dll, inspect its export directory, obtain the RVA and raw offset of NtCreateFile and then check the first bytes of opcodes?

Thank you :)
You don't actually have to handle system calls manually most of the time. There is an easier, and still very effective technique that would work just as well. It would be manual mapping a duplicate copy of NTDLL (you would need to do checks to determine whether you need to use the copy available in "\\??\\Windows\\System32\\" or "\\??\\Windows\\SysWOW64\\" depending on if you are within an x64 environment under WOW64 (X86-X64 process) though). After manual mapping the duplicate, you would setup custom trampolines by allocating memory (32-bit NTDLL uses 15 bytes for the system call stubs whereas 64-bit NTDLL uses 21 bytes for the system call stubs). To finalise, you should be able to free the memory where the manual mapped re-named duplicate of NTDLL was loaded and then use the addresses for the function calls which point to the custom trampolines in memory (same bytes for the function prologues).

Don't try and do this with Ldr* or Rtl* functions though. It won't work out well because those Native API functions don't actually perform system calls, they will make use of other functions; you would need to resolve all the addresses which is more work than necessary. Functions like LdrLoadDll will call unexported NTDLL functions internally anyway, it would just be a huge mess of sick to clean-up which would be a waste of time IMO.

You're right about there not being any "official" way to determine the system call IDs for the Native API functions, this is completely true. There never has been and I doubt there ever will be. Microsoft don't want us to use the NTDLL functions manually, they would rather us stick to documented higher-level Win32 API functions which handle it all for us for compatibility and stability purposes.

At run-time of your application, you can make custom trampolines for the Native API functions however you must be cautious about code injection having occurred before your code even executes. If someone is capable of performing code injection before the main thread of your process is resumed, it would allow them to perform manipulations to the bytes at specific NTDLL functions (e.g. NtOpenProcess). In this situation, whenever you call OpenProcess -> flow lands at NtOpenProcess -> the attackers inserted bytes are executed. Even if you were to make a custom trampoline, you'd be copying the manipulated function prologue across to this trampoline; getting the address through dynamic imports (e.g. from the Export Address Table) would still land you at a destination which had been manipulated by an attacker (or security software).

When you call LoadLibraryA (or W for Unicode), it will not re-load a module which is already loaded. This functionality is enforced within LdrLoadDll/LdrpLoadDll where it checks for duplicates of the module before it maps the DLL into memory and handles the rest of the module loading (e.g. NtMapViewOfSection will be called for example at these stages). Therefore, if you call LoadLibraryA/W for NTDLL, you'll just be given back a HMODULE for the existent loaded copy (which may have been manipulated in memory).

When it comes to hooking of the Import Address Table, this can be escaped through getting the address from the Export Address Table. Sometimes the Shim hooks (introduced on Windows 8) can redirect you by spoofing you back an address for apphelp.dll instead of ntdll.dll under specific circumstances, maybe if it thinks something "fishy" is going on - using this as an example, getting the address from the Export Address Table would circumvent this (since Windows relies on a hook on LdrGetProcedureAddress to enforce this, which is called by GetProcAddress).

When it comes to escaping detours at function prologues for stubs within NTDLL, system calls are your best bet. More often than not, the trick I mentioned with loading a re-named duplicate of NTDLL (you don't even have to necessarily manual map it actually) will work fine in most scenarios...

To answer your question properly, my answer is Yes. However it really depends on the scenario because the outcome may not always be the same... If you are inspecting the bytes from the version of NTDLL already loaded in your process, it is not really that reliable because of the reasons mentioned above (e.g. manipulations before your code even got a chance to execute -> rootkits can do this by injecting early on with their process monitoring capabilities, as can security software). A better idea would be to try and map NTDLL into memory (read the bytes into memory) and then use that to perform the inspection and extraction of the bytes. Still, tasks like these can be prevented as well... It would be extremely rare, but an attacker could spoof the bytes read into memory from NTDLL and/or manipulate the memory operations when making the trampolines (e.g. NtAllocateVirtualMemory -> RtlCopyMemory (macro for memcpy) (leads to NtWriteVirtualMemory using NtCurrentProcess() )).

All in all, my favourite of them all would be the duplicated NTDLL being loaded (either normally or via manual map/reflective DLL loading) and then on top of this, custom trampolines to hold the function bytes.

With all of this being said, system calls are not full-proof. They will not bypass kernel-mode callbacks, and for an X86-X64 process they are not as reliable unless you have a working Heavens Gate implementation since WOW64 can be hooked as well! :)

Experimenting with such topics can be good for general education and studying Windows Internals, but is not practical for normal software development. If you are developing security software then I'd perfectly understand (because in the case of Self-Protection becoming exploited and RCE occurring, you would be able to bypass hooks set by the attacker -> although in this scenario they would be able to just suspend/shutdown your process anyway). Even though things like this would be very beneficial to malware depending on how it is working (not all the time because traditional and well-developed security software rely on documented and officially supported (by Microsoft) kernel-mode callbacks nowadays, unlike in the XP days where everyone resorted to patching the kernel), I doubt you will find a sample in the wild especially these days which does anything like this. It does require genuine knowledge and most people dipping into such topics who do not have totally "genuine" intent are focusing on cheats for games as opposed to malware; threats like sophisticated rootkits are not even that prevalent anymore in my opinion, it is more about ransomware and adware as far as I can see...

I hope this helped. :)
 
Last edited by a moderator:

tim one

Level 21
AV-Tester
Verified
Joined
Jul 31, 2014
Messages
1,071
Operating System
Windows 10
Antivirus
F-Secure
#42
Oh, my apologies... I should have explained it better.

As far as I am aware, 'reflective' DLL loading is the same as 'manual mapping' a DLL. They both do the same thing. The end result is the target DLL is loaded into memory and its entry point (e.g. DllMain -> DLL_PROCESS_ATTACH) is successfully called, however at the same time the DLL will not be linked to the Process Environment Block. Since the loaded module will not be linked to the Process Environment Block, when you enumerate through the loaded modules of the affected process, you will not find the DLL loaded via this technique as a module. In other words, it will be "hidden".

I am used to referring to the technique as 'manual mapping' but they should both work the same therefore you can use either terms.

The reason you cannot use the normal injection method for DLLs into UWP processes via a remote thread to call LoadLibraryA is either because of internal checks performed by lower functions like LdrLoadDll (or lower via LdrpLoadDll where initialisation for the Shim engine (which was introduced in Windows 8) takes place for the record), or because UWP applications monitor thread creation and block it when the address is for a function like LoadLibraryA.

Since you can perform virtual memory operations and thread creation just fine with UWP processes, code-cave injection will work fine as well. However, depending on how the anti-DLL loading mechanism is implemented, even if you used code-cave to then have the injected code make a call to LdrLoadDll, it might still not work. Regardless, you can copy the bytes for the target DLL into the address space of the target UWP process remotely and then perform shell-code/code-cave injection (where the injected code will handle the finalisation steps for the manual mapping operation).

Honestly though, in the case of a "sophisticated attack" by an experienced developer, manual mapping will probably be avoided. Not because manual mapping a DLL is not "secretive" enough, but because experienced malware authors know that dropping a DLL to disk is not a good idea - however they may hard-code the bytes of the DLL instead and have it used from memory manually. That too is possible and would work very similarly... You would determine the total size, allocate enough memory, copy across the bytes (representing executable code), etc.


You don't actually have to handle system calls manually most of the time. There is an easier, and still very effective technique that would work just as well. It would be manual mapping a duplicate copy of NTDLL (you would need to do checks to determine whether you need to use the copy available in "\\??\\Windows\\System32\\" or "\\??\\Windows\\SysWOW64\\" depending on if you are within an x64 environment under WOW64 (X86-X64 process) though). After manual mapping the duplicate, you would setup custom trampolines by allocating memory (32-bit NTDLL uses 15 bytes for the system call stubs whereas 64-bit NTDLL uses 21 bytes for the system call stubs). To finalise, you should be able to free the memory where the manual mapped re-named duplicate of NTDLL was loaded and then use the addresses for the function calls which point to the custom trampolines in memory (same bytes for the function prologues).

Don't try and do this with Ldr* or Rtl* functions though. It won't work out well because those Native API functions don't actually perform system calls, they will make use of other functions; you would need to resolve all the addresses which is more work than necessary. Functions like LdrLoadDll will call unexported NTDLL functions internally anyway, it would just be a huge mess of sick to clean-up which would be a waste of time IMO.

You're right about there not being any "official" way to determine the system call IDs for the Native API functions, this is completely true. There never has been and I doubt there ever will be. Microsoft don't want us to use the NTDLL functions manually, they would rather us stick to documented higher-level Win32 API functions which handle it all for us for compatibility and stability purposes.

At run-time of your application, you can make custom trampolines for the Native API functions however you must be cautious about code injection having occurred before your code even executes. If someone is capable of performing code injection before the main thread of your process is resumed, it would allow them to perform manipulations to the bytes at specific NTDLL functions (e.g. NtOpenProcess). In this situation, whenever you call OpenProcess -> flow lands at NtOpenProcess -> the attackers inserted bytes are executed. Even if you were to make a custom trampoline, you'd be copying the manipulated function prologue across to this trampoline; getting the address through dynamic imports (e.g. from the Export Address Table) would still land you at a destination which had been manipulated by an attacker (or security software).

When you call LoadLibraryA (or W for Unicode), it will not re-load a module which is already loaded. This functionality is enforced within LdrLoadDll/LdrpLoadDll where it checks for duplicates of the module before it maps the DLL into memory and handles the rest of the module loading (e.g. NtMapViewOfSection will be called for example at these stages). Therefore, if you call LoadLibraryA/W for NTDLL, you'll just be given back a HMODULE for the existent loaded copy (which may have been manipulated in memory).

When it comes to hooking of the Import Address Table, this can be escaped through getting the address from the Export Address Table. Sometimes the Shim hooks (introduced on Windows 8) can redirect you by spoofing you back an address for apphelp.dll instead of ntdll.dll under specific circumstances, maybe if it thinks something "fishy" is going on - using this as an example, getting the address from the Export Address Table would circumvent this (since Windows relies on a hook on LdrGetProcedureAddress to enforce this, which is called by GetProcAddress).

When it comes to escaping detours at function prologues for stubs within NTDLL, system calls are your best bet. More often than not, the trick I mentioned with loading a re-named duplicate of NTDLL (you don't even have to necessarily manual map it actually) will work fine in most scenarios...

To answer your question properly, my answer is Yes. However it really depends on the scenario because the outcome may not always be the same... If you are inspecting the bytes from the version of NTDLL already loaded in your process, it is not really that reliable because of the reasons mentioned above (e.g. manipulations before your code even got a chance to execute -> rootkits can do this by injecting early on with their process monitoring capabilities, as can security software). A better idea would be to try and map NTDLL into memory (read the bytes into memory) and then use that to perform the inspection and extraction of the bytes. Still, tasks like these can be prevented as well... It would be extremely rare, but an attacker could spoof the bytes read into memory from NTDLL and/or manipulate the memory operations when making the trampolines (e.g. NtAllocateVirtualMemory -> RtlCopyMemory (macro for memcpy) (leads to NtWriteVirtualMemory using NtCurrentProcess() )).

All in all, my favourite of them all would be the duplicated NTDLL being loaded (either normally or via manual map/reflective DLL loading) and then on top of this, custom trampolines to hold the function bytes.

With all of this being said, system calls are not full-proof. They will not bypass kernel-mode callbacks, and for an X86-X64 process they are not as reliable unless you have a working Heavens Gate implementation since WOW64 can be hooked as well! :)

I hope this helped. :)
Thank you so much mate :)
 
D

Deleted member 65228

Guest
#43
threats like sophisticated rootkits are not even that prevalent anymore in my opinion, it is more about ransomware and adware as far as I can see...
I will add banking malware to this as well, however they are usually based in user-mode entirely and even the "sophisticated"-deemed ones these days don't do things like system calls.

Banking malware like Carberp made use of kernel-mode components (had a bootkit component too), and the famous greek-style named banking malware Kronos had a bootkit component and other functionality (e.g. I am pretty sure it had sandbox evasion and a zero-day (at the time) User Account Control bypass). However, threats like Zeus aren't as complex compared to Carberp or Kronos IMO and just rely on normal user-mode injection and patching (AFAIK, unless there has been some big update I never heard of).

Threats like Carberp, Kronos and Zeus were from a long time ago now. Carberp is the oldest of all three I think. Carberp also had a bootkit component... It relied on kernel-mode APC injection, but it supported many other code injection techniques.

I think that one of the most sophisticated "rootkits" I have seen relied on real virtualisation using the hardware (e.g. Intel/AMD processor) as leverage. Most modern Intel processors support Intel VT-x (virtualisation support) and AMD have SVM (Secure Virtual Machine)/AMD-V. You can use virtualisation through the hyper-visor. I remember there was a female researcher (maybe she was Polish?) who made some sort of Proof-Of-Concept using virtualisation a very long time ago (it must have been around 2008) which supported both x86 and x64 systems. Virtualisation on x64 systems also removes the restriction of having to be told what to do by Kernel Patch Protection (KPP) embedded within PatchGuard for x64 systems starting on Windows Vista - you can leverage virtualisation to add kernel-mode patching support, so you can perform actions such as MSR hooking.

Most old kernel-mode rootkits simply relied on SSDT (System Service Dispatch Table) hooking or DKOM (Direct Kernel Object Manipulation) though. User-mode rootkits normally rely on code injection into the target processes and then API hooking (user-mode patching methods such as manipulation of bytes at function stubs, altering addresses in the Import or Export Address Table). PatchGuard certainly helped make kernel-mode rootkits less prevalent though, especially after the multiple versions of Windows to improve it internally...

Sorry for going a bit off-topic. I went from answering questions related to code injection to discussing banking malware and rootkits...
 

Andy Ful

Level 33
Content Creator
Verified
Joined
Dec 23, 2014
Messages
2,243
Operating System
Windows 10
Antivirus
Windows Defender
#45
...
Explorer.exe is a standard rights process as well which is why this startled me more than it should have. Surely I cannot be the only person who has noticed that ntoskrnl.exe is loaded as a module in a standard rights process on modern versions of Windows, and has wondered what it is actually used for in explorer.exe?
...
I noticed the difference between Windows 10 and the prior Windows versions. On Windows 8.1 and prior versions, the application when running with high rights can run Explorer with high rights, too. That is not possible on Windows (it will run as standard user).
 
D

Deleted member 65228

Guest
#46
I noticed the difference between Windows 10 and the prior Windows versions. On Windows 8.1 and prior versions, the application when running with high rights can run Explorer with high rights, too. That is not possible on Windows (it will run as standard user).
You can still run explorer.exe as elevated on modern versions of Windows if you are doing it from an elevated process. If you restart explorer.exe with Process Hacker (elevated) after a few tries it should be re-spawned elevated. :)
 
Likes: tim one

Andy Ful

Level 33
Content Creator
Verified
Joined
Dec 23, 2014
Messages
2,243
Operating System
Windows 10
Antivirus
Windows Defender
#47
You can still run explorer.exe as elevated on modern versions of Windows if you are doing it from an elevated process. If you restart explorer.exe with Process Hacker (elevated) after a few tries it should be re-spawned elevated. :)
Tried with procexp.exe - did not work. Also, Hard_Configurator is running with high rights, and even when refreshing Explorer (closing all Explorer threads and start Explorer) it always run as standard user on Windows 10. Is Process Hacker somewhat special with this?
 
D

Deleted member 65228

Guest
#48
Tried with procexp.exe - did not work. Also, Hard_Configurator is running with high rights, and even when refreshing Explorer (closing all Explorer threads and start Explorer) it always run as standard user on Windows 10. Is Process Hacker somewhat special with this?
I think that it must be related to the tokens. For example, if you have a Windows Service you can steal the SYSTEM token from a process like winlogon.exe and then call CreateProcessAsUser to spawn any process with SYSTEM rights (under NT Authority Account). Therefore, explorer.exe being started up with elevated rights is most likely done by starting it up with a custom token handle (but without requiring a Windows Service since that is only required when you are trying to start a program with the SYSTEM token - since Windows Vista that is).
 
Last edited by a moderator:
Likes: tim one

Andy Ful

Level 33
Content Creator
Verified
Joined
Dec 23, 2014
Messages
2,243
Operating System
Windows 10
Antivirus
Windows Defender
#49
I think that it must be related to the tokens. For example, if you have a Windows Service you can steal the SYSTEM token from a process like winlogon.exe and then call CreateProcessAsUser to spawn any process with SYSTEM rights (under NT Authority Account). Therefore, explorer.exe being started up with elevated rights is most likely done by starting it up with a custom token handle (but without requiring a Windows Service since that is only required when you are trying to start a program with the SYSTEM token - since Windows Vista that is).
Tried with ProcessHacker (ran high), but still Explorer in Windows 10 Creators Update is running as standard user.
Edit.
It seems that in Creators update, even ProcessHacker cannot do it. I also tried RunAsSystem (QwertyLab) with the same result.
 
Last edited:
D

Deleted member 65228

Guest
#50
Tried with ProcessHacker (ran high), but still Explorer in Windows 10 Creators Update is running as standard user.
I looked into it more for you and it turns out that explorer.exe supports an argument which will prevent it from performing its UAC checks - I was wrong about it being token related completely.

Explorer.exe has an argument which can be used /NOUACCHECK.






If Process Hacker cannot restart explorer.exe elevated when it is running with administrative rights after the latest Creators Update then Microsoft may have changed how it works, I am not sure. I am not on the latest update yet.
 
Last edited by a moderator:

Andy Ful

Level 33
Content Creator
Verified
Joined
Dec 23, 2014
Messages
2,243
Operating System
Windows 10
Antivirus
Windows Defender
#51
I looked into it more for you and it turns out that explorer.exe supports an argument which will prevent it from performing its UAC checks - I was wrong about it being token related completely.

Explorer.exe has an argument which can be used /NOUACCHECK.





If Process Hacker cannot restart explorer.exe elevated when it is running with administrative rights after the latest Creators Update then Microsoft may have changed how it works, I am not sure. I am not on the latest update yet.
'Explorer.exe /nouaccheck' will not work when ran normally from ProcessExplorer or ProcessHacker (run elevated from Explorer shell) . But, it works when the application first closes all Explorer threads and next run 'Explorer.exe /nouaccheck'. The below autoit script can do it:
Code:
Func RefreshExplorer()
While ProcessExists("explorer.exe")
   Run("explorer.exe",Call(ProcessClose("explorer.exe")))
WEnd
;  EnvUpdate()
  Run("Explorer.exe /nouaccheck")
EndFunc
 

Andy Ful

Level 33
Content Creator
Verified
Joined
Dec 23, 2014
Messages
2,243
Operating System
Windows 10
Antivirus
Windows Defender
#52
In this way, one can quickly change the split-token admin account (default Administrator Account) into full Administrator Account (all applications will run as administrator without UAC prompt).
 
D

Deleted member 65228

Guest
#53
'Explorer.exe /nouaccheck' will not work when ran normally from ProcessExplorer or ProcessHacker (run elevated from Explorer shell) . But, it works when the application first closes all Explorer threads and next run 'Explorer.exe /nouaccheck'. The below autoit script can do it:
Code:
Func RefreshExplorer()
While ProcessExists("explorer.exe")
   Run("explorer.exe",Call(ProcessClose("explorer.exe")))
WEnd
;  EnvUpdate()
  Run("Explorer.exe /nouaccheck")
EndFunc
If you have Visual Studio with C++ support you can try the following I wrote earlier (tested on latest Creators Update by a friend). I removed the code because it isn't heavily tested and is a bit messy, it was just a quick test... (if it doesn't work by the second attempt then it probably won't work).

Code:
#include <Windows.h>
#include <TlHelp32.h>
#include <iostream>
using namespace std;

#define STATUS_SUCCESS 0x00000000
#define NtCurrentProcess() ((HANDLE)(LONG_PTR) -1)

#ifndef _NTDEF_
typedef _Return_type_success_(return >= 0) LONG NTSTATUS;
typedef NTSTATUS *PNTSTATUS;
#endif

#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif

#ifndef InitializeObjectAttributes
#define InitializeObjectAttributes( p, n, a, r, s ) { \
    (p)->Length = sizeof( OBJECT_ATTRIBUTES );          \
    (p)->RootDirectory = r;                             \
    (p)->Attributes = a;                                \
    (p)->ObjectName = n;                                \
    (p)->SecurityDescriptor = s;                        \
    (p)->SecurityQualityOfService = NULL;               \
    }
#endif

typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
typedef const UNICODE_STRING *PCUNICODE_STRING;

typedef struct _CLIENT_ID {
    PVOID UniqueProcess;
    PVOID UniqueThread;
}CLIENT_ID, *PCLIENT_ID;

typedef struct _OBJECT_ATTRIBUTES {
    ULONG Length;
    HANDLE RootDirectory;
    PUNICODE_STRING ObjectName;
    ULONG Attributes;
    PVOID SecurityDescriptor;
    PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES;
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;

typedef NTSTATUS(NTAPI *pNtOpenProcess)(
    PHANDLE ProcessHandle,
    ACCESS_MASK DesiredAccess,
    POBJECT_ATTRIBUTES ObjectAttributes,
    PCLIENT_ID ClientId
    );

typedef NTSTATUS(NTAPI *pNtTerminateProcess)(
    HANDLE ProcessHandle,
    NTSTATUS ExitStatus
    );

DWORD ReturnProcessId(
    CHAR *ProcessName
)
{
    DWORD dwProcessId = 0;
    HANDLE ProcessHandle = 0;
    PROCESSENTRY32 ProcessEntry32 = { 0 };

    ProcessHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
    ProcessEntry32.dwSize = sizeof(PROCESSENTRY32);

    if (ProcessHandle)
    {
        do {
            if (!strcmp(ProcessEntry32.szExeFile, ProcessName))
            {
                dwProcessId = ProcessEntry32.th32ProcessID;
                break;
            }
        } while (Process32Next(ProcessHandle, &ProcessEntry32));

        CloseHandle(ProcessHandle);
    }

    return dwProcessId;
}

BOOL RestartExplorer()
{
    NTSTATUS NtStatus = STATUS_SUCCESS;
    DWORD dwProcessId = 0;
    HANDLE ProcessHandle = 0;
    OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
    CLIENT_ID ClientId = { 0 };
    STARTUPINFO StartupInfo = { 0 };
    PROCESS_INFORMATION ProcessInfo = { 0 };

    FARPROC fpFunctionAddresses[2] = {
        GetProcAddress(GetModuleHandle("ntdll.dll"), "NtOpenProcess"),
        GetProcAddress(GetModuleHandle("ntdll.dll"), "NtTerminateProcess"),
    };

    for (FARPROC &fpAddress : fpFunctionAddresses)
    {
        if (!fpAddress)
        {
            return FALSE;
        }
    }

    pNtOpenProcess fNtOpenProcess = (pNtOpenProcess)fpFunctionAddresses[0];
    pNtTerminateProcess fNtTerminateProcess = (pNtTerminateProcess)fpFunctionAddresses[1];

    if (!fNtOpenProcess ||
        !fNtTerminateProcess)
    {
        return FALSE;
    }

    dwProcessId = ReturnProcessId("explorer.exe");

    if (!dwProcessId)
    {
        return FALSE;
    }

    InitializeObjectAttributes(&ObjectAttributes,
        NULL,
        NULL,
        NULL,
        NULL);

    ClientId.UniqueProcess = (PVOID)dwProcessId;
    ClientId.UniqueThread = (PVOID)NULL;

    NtStatus = fNtOpenProcess(&ProcessHandle,
        PROCESS_TERMINATE,
        &ObjectAttributes,
        &ClientId);

    if (!NT_SUCCESS(NtStatus))
    {
        return FALSE;
    }

    NtStatus = fNtTerminateProcess(ProcessHandle,
        NULL);

    if (!NT_SUCCESS(NtStatus))
    {
        return FALSE;
    }

    memset(&StartupInfo, NULL, sizeof(STARTUPINFO));
    memset(&ProcessInfo, NULL, sizeof(PROCESS_INFORMATION));

    StartupInfo.cb = sizeof(STARTUPINFO);

    // uncomment the next 2 lines if it fails 2 times in a row -> added them there just for a test but may not necessarily be required
    //ProcessInfo.dwProcessId = 1347871440;
   //ProcessInfo.dwThreadId = 16;

    if (!CreateProcess(NULL,
        "C:\\Windows\\explorer.exe /NOUACCHECK",
        NULL,
        NULL,
        FALSE,
        NULL,
        NULL,
        "C:\\Windows\\System32\\",
        &StartupInfo,
        &ProcessInfo))
    {
        return FALSE;
    }
  
    return TRUE;
}

int main()
{
    BOOL bStatus = RestartExplorer();

    getchar();
    return 0;
}
I was just messing around with it for a short amount of time, it tends to work for me on the 2nd try each time. Of course NtOpenProcess/NtTerminateProcess isn't required though, may as well let Win32 API handle it (-> NTDLL automatically) via OpenProcess/TerminateProcess.

The code is not stable or tested much though so chances are there'll be bugs and potential problems. Use a VM to save hassle if you test it out

Glad I managed to find out what you were looking for though :)
 
D

Deleted member 65228

Guest
#54
In this way, one can quickly change the admin split token account (default Administrator Account) into full Administrator Account (all applications will run as administrator without UAC prompt).
If I recall correctly, standard rights processes will be able to adjust token privileges (e.g. debugging rights) without elevation and no UAC prompts will be displayed when running programs which require elevation (auto-elevation) when explorer.exe is running elevated with administrative rights.
 

Andy Ful

Level 33
Content Creator
Verified
Joined
Dec 23, 2014
Messages
2,243
Operating System
Windows 10
Antivirus
Windows Defender
#55
If you have Visual Studio with C++ support you can try the following I wrote earlier (tested on latest Creators Update by a friend). I removed the code because it isn't heavily tested and is a bit messy, it was just a quick test... (if it doesn't work by the second attempt then it probably won't work).

Code:
#include <Windows.h>
#include <TlHelp32.h>
#include <iostream>
using namespace std;

#define STATUS_SUCCESS 0x00000000
#define NtCurrentProcess() ((HANDLE)(LONG_PTR) -1)

#ifndef _NTDEF_
typedef _Return_type_success_(return >= 0) LONG NTSTATUS;
typedef NTSTATUS *PNTSTATUS;
#endif

#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif

#ifndef InitializeObjectAttributes
#define InitializeObjectAttributes( p, n, a, r, s ) { \
    (p)->Length = sizeof( OBJECT_ATTRIBUTES );          \
    (p)->RootDirectory = r;                             \
    (p)->Attributes = a;                                \
    (p)->ObjectName = n;                                \
    (p)->SecurityDescriptor = s;                        \
    (p)->SecurityQualityOfService = NULL;               \
    }
#endif

typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
typedef const UNICODE_STRING *PCUNICODE_STRING;

typedef struct _CLIENT_ID {
    PVOID UniqueProcess;
    PVOID UniqueThread;
}CLIENT_ID, *PCLIENT_ID;

typedef struct _OBJECT_ATTRIBUTES {
    ULONG Length;
    HANDLE RootDirectory;
    PUNICODE_STRING ObjectName;
    ULONG Attributes;
    PVOID SecurityDescriptor;
    PVOID SecurityQualityOfService;
} OBJECT_ATTRIBUTES;
typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;

typedef NTSTATUS(NTAPI *pNtOpenProcess)(
    PHANDLE ProcessHandle,
    ACCESS_MASK DesiredAccess,
    POBJECT_ATTRIBUTES ObjectAttributes,
    PCLIENT_ID ClientId
    );

typedef NTSTATUS(NTAPI *pNtTerminateProcess)(
    HANDLE ProcessHandle,
    NTSTATUS ExitStatus
    );

DWORD ReturnProcessId(
    CHAR *ProcessName
)
{
    DWORD dwProcessId = 0;
    HANDLE ProcessHandle = 0;
    PROCESSENTRY32 ProcessEntry32 = { 0 };

    ProcessHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
    ProcessEntry32.dwSize = sizeof(PROCESSENTRY32);

    if (ProcessHandle)
    {
        do {
            if (!strcmp(ProcessEntry32.szExeFile, ProcessName))
            {
                dwProcessId = ProcessEntry32.th32ProcessID;
                break;
            }
        } while (Process32Next(ProcessHandle, &ProcessEntry32));

        CloseHandle(ProcessHandle);
    }

    return dwProcessId;
}

BOOL RestartExplorer()
{
    NTSTATUS NtStatus = STATUS_SUCCESS;
    DWORD dwProcessId = 0;
    HANDLE ProcessHandle = 0;
    OBJECT_ATTRIBUTES ObjectAttributes = { 0 };
    CLIENT_ID ClientId = { 0 };
    STARTUPINFO StartupInfo = { 0 };
    PROCESS_INFORMATION ProcessInfo = { 0 };

    FARPROC fpFunctionAddresses[2] = {
        GetProcAddress(GetModuleHandle("ntdll.dll"), "NtOpenProcess"),
        GetProcAddress(GetModuleHandle("ntdll.dll"), "NtTerminateProcess"),
    };

    for (FARPROC &fpAddress : fpFunctionAddresses)
    {
        if (!fpAddress)
        {
            return FALSE;
        }
    }

    pNtOpenProcess fNtOpenProcess = (pNtOpenProcess)fpFunctionAddresses[0];
    pNtTerminateProcess fNtTerminateProcess = (pNtTerminateProcess)fpFunctionAddresses[1];

    if (!fNtOpenProcess ||
        !fNtTerminateProcess)
    {
        return FALSE;
    }

    dwProcessId = ReturnProcessId("explorer.exe");

    if (!dwProcessId)
    {
        return FALSE;
    }

    InitializeObjectAttributes(&ObjectAttributes,
        NULL,
        NULL,
        NULL,
        NULL);

    ClientId.UniqueProcess = (PVOID)dwProcessId;
    ClientId.UniqueThread = (PVOID)NULL;

    NtStatus = fNtOpenProcess(&ProcessHandle,
        PROCESS_TERMINATE,
        &ObjectAttributes,
        &ClientId);

    if (!NT_SUCCESS(NtStatus))
    {
        return FALSE;
    }

    NtStatus = fNtTerminateProcess(ProcessHandle,
        NULL);

    if (!NT_SUCCESS(NtStatus))
    {
        return FALSE;
    }

    memset(&StartupInfo, NULL, sizeof(STARTUPINFO));
    memset(&ProcessInfo, NULL, sizeof(PROCESS_INFORMATION));

    StartupInfo.cb = sizeof(STARTUPINFO);

    // uncomment the next 2 lines if it fails 2 times in a row -> added them there just for a test but may not necessarily be required
    //ProcessInfo.dwProcessId = 1347871440;
   //ProcessInfo.dwThreadId = 16;

    if (!CreateProcess(NULL,
        "C:\\Windows\\explorer.exe /NOUACCHECK",
        NULL,
        NULL,
        FALSE,
        NULL,
        NULL,
        "C:\\Windows\\System32\\",
        &StartupInfo,
        &ProcessInfo))
    {
        return FALSE;
    }
 
    return TRUE;
}

int main()
{
    BOOL bStatus = RestartExplorer();

    getchar();
    return 0;
}
I was just messing around with it for a short amount of time, it tends to work for me on the 2nd try each time. Of course NtOpenProcess/NtTerminateProcess isn't required though, may as well let Win32 API handle it (-> NTDLL automatically) via OpenProcess/TerminateProcess.

The code is not stable or tested much though so chances are there'll be bugs and potential problems. Use a VM to save hassle if you test it out

Glad I managed to find out what you were looking for though :)
I am curious if there is the way back. Starting from Explorer high to refresh it as standard user. Something like: "explorer.exe /DropRights" .
 
D

Deleted member 65228

Guest
#56
I am curious if there is the way back. Starting from Explorer high to refresh it as standard user. Something like: "explorer.exe /DropRights" .
I don't think there is an argument for that.

If you want to go back to the standard rights one then you can restart it via Task Manager. It may affect other running applications though so a reboot is probably best say-on-case (unless you used a Virtual Machine).

Spawning it normally without the /NOUACCHECK will leave it at standard rights, even if you try to spawn it elevated.
 
D

Deleted member 65228

Guest
#57
Opcode pls test Eset Hips in interactive mode, Sophos home premium and Q360 for having more fun:giggle:will you do that?
Sorry for my late response, I hope you didn't feel I was intentionally ignoring you. I've been planning on responding but I've been thinking what I will say to you in response...

Right now, I don't have any plans to make any public tests for ESET HIPS (Interactive Mode), Sophos Home Premium or Qihoo 360; not on any security software really. The reason being is that it takes a lot of time and effort to do a correct test on security software - evaluation must be performed regularly. You need to investigate each product in testing to understand how it works to the best of your ability (preferably internally so you can determine what will and won't make it tick - allowing you to discover and point out weaknesses in an appropriate manner).

There are companies who dedicate a lot of time and resources to carrying out tests on a wide variety of security software. One of these companies which I am a big fan of would be VirusBulletin (VB) because I know that they are really passionate and trust-worthy (they helped out a friend of mine once for nothing in return). There are many other testing companies which may interest you, such as AV-Comparatives, too. The people working at such companies are professionals, who have trained in the company and had hands-on experience with the other experienced elders there who make them the person they are today... Their actual job is to do this.

To answer your question in short, I won't be doing any public full tests on security software because I don't think it is actually necessary to do so, and can be much more troublesome than what it could be worth. However, I may post little updates from small tests I may perform every now and then if I am testing a security product against a specific attack for a reason.

I think you will probably agree with my decision based on the reasoning I left as an explanation for the decision! :)
 
Joined
Mar 13, 2017
Messages
29
Operating System
Windows 10
Antivirus
ESET
#59
You are crazy! kinda inhuman, It's impossible for normal human to write topics in such details.
Sorry for saying THANK YOU after reading all your posts, but I think I found place I was searching a long time. THANK YOU
 
D

Deleted member 65228

Guest
#60
The Shim engine is also supported in kernel-mode for device drivers.

1. ntoskrnl.exe!KeStartDynamicProcessor
2. ntoskrnl.exe!KiStartDynamicProcessor
3. ntoskrnl.exe!KxInitializeProcessorState
4. ntoskrnl.exe!KiSystemStartup
5. ntoskrnl.exe!KiInitializeKernel
6. ntoskrnl.exe!InitBootProcessor
7. ntoskrnl.exe!PspInitPhase0
8. ntoskrnl.exe!Phase1Initialization
9. ntoskrnl.exe!IoInitSystem
10. ntoskrnl.exe!IoInitSystemPreDrivers
11. ntoskrnl.exe!KseInitialize ->>>>> START OF THE SHIM ENGINE
12. ntoskrnl.exe!KseDriverScopeInitialize
13. ntoskrnl.exe!KseRegisterShim -> proxy routine as it will redirect to KseRegisterShimEx



The function KsepGetLoadedModulesList (called by KseRegisterShimEx) -> ZwQuerySystemInformation



Anyway when a driver image is loaded into memory, ntoskrnl.exe!MmLoadSystemImageEx will become invoked. This routine will call ntoskrnl.exe!KseDriverLoadImage which will call a routine called ntoskrnl.exe!KsepApplyShimsToDriver.





If you're wondering, the KsepEvntLogShimsApplied is called if the status return from KsepApplyApplyShimsToDriver indicates success.

It is used to apply Shim hooks on kernel-mode device drivers, but only for those with specific markings/configuration for them to be targeted it appears.
 
Likes: Andy Ful