Malware Analysis Code injection identification [Malware Analysis]

Discussion in 'Malware Analysis' started by Opcode, Sep 20, 2017.

  1. Opcode

    Opcode Level 18
    Content Creator

    Aug 17, 2017
    890
    6,285
    Caille
    Windows 10
    #41 Opcode, Oct 24, 2017
    Last edited: Oct 24, 2017
    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! :)

    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. :)
     
    Sunshine-boy, XhenEd, frogboy and 4 others like this.
  2. tim one

    tim one Level 18
    Trusted AV Tester

    Jul 31, 2014
    885
    8,975
    Europe
    Windows 10
    Emsisoft
    Thank you so much mate :)
     
    Sunshine-boy, XhenEd, frogboy and 3 others like this.
  3. Opcode

    Opcode Level 18
    Content Creator

    Aug 17, 2017
    890
    6,285
    Caille
    Windows 10
    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...
     
  4. Opcode

    Opcode Level 18
    Content Creator

    Aug 17, 2017
    890
    6,285
    Caille
    Windows 10
    #44 Opcode, Oct 27, 2017
    Last edited: Oct 27, 2017
    [Post removed]
     
    harlan4096 likes this.
  5. Andy Ful

    Andy Ful Level 21

    Dec 23, 2014
    1,076
    4,581
    business
    Poland
    Windows 10
    Microsoft
    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).
     
    tim one and Opcode like this.
  6. Opcode

    Opcode Level 18
    Content Creator

    Aug 17, 2017
    890
    6,285
    Caille
    Windows 10
    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. :)
     
    tim one likes this.
  7. Andy Ful

    Andy Ful Level 21

    Dec 23, 2014
    1,076
    4,581
    business
    Poland
    Windows 10
    Microsoft
    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?
     
    tim one and Opcode like this.
  8. Opcode

    Opcode Level 18
    Content Creator

    Aug 17, 2017
    890
    6,285
    Caille
    Windows 10
    #48 Opcode, Oct 27, 2017
    Last edited: Oct 27, 2017
    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).
     
    tim one likes this.
  9. Andy Ful

    Andy Ful Level 21

    Dec 23, 2014
    1,076
    4,581
    business
    Poland
    Windows 10
    Microsoft
    #49 Andy Ful, Oct 27, 2017
    Last edited: Oct 27, 2017
    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.
     
    tim one and Opcode like this.
  10. Opcode

    Opcode Level 18
    Content Creator

    Aug 17, 2017
    890
    6,285
    Caille
    Windows 10
    #50 Opcode, Oct 27, 2017
    Last edited: Oct 27, 2017
    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.

    [​IMG]

    [​IMG]


    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.
     
    tim one, lowdetection and Andy Ful like this.
  11. Andy Ful

    Andy Ful Level 21

    Dec 23, 2014
    1,076
    4,581
    business
    Poland
    Windows 10
    Microsoft
    '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
     
    tim one and Opcode like this.
  12. Andy Ful

    Andy Ful Level 21

    Dec 23, 2014
    1,076
    4,581
    business
    Poland
    Windows 10
    Microsoft
    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).
     
    Opcode likes this.
  13. Opcode

    Opcode Level 18
    Content Creator

    Aug 17, 2017
    890
    6,285
    Caille
    Windows 10
    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 :)
     
    Vasudev, tim one and Andy Ful like this.
  14. Opcode

    Opcode Level 18
    Content Creator

    Aug 17, 2017
    890
    6,285
    Caille
    Windows 10
    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.
     
    tim one and Andy Ful like this.
  15. Andy Ful

    Andy Ful Level 21

    Dec 23, 2014
    1,076
    4,581
    business
    Poland
    Windows 10
    Microsoft
    I am curious if there is the way back. Starting from Explorer high to refresh it as standard user. Something like: "explorer.exe /DropRights" .
     
  16. Opcode

    Opcode Level 18
    Content Creator

    Aug 17, 2017
    890
    6,285
    Caille
    Windows 10
    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.
     
  17. Opcode

    Opcode Level 18
    Content Creator

    Aug 17, 2017
    890
    6,285
    Caille
    Windows 10
    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! :)
     
    Vasudev, tim one, Zhou He and 4 others like this.
  18. Sunshine-boy

    Sunshine-boy Level 22

    Apr 1, 2017
    1,167
    5,166
    IRAN
    Windows 10
    ESET
    Yes,also thank you for the answers you gave :)
     
    tim one and Opcode like this.
  19. Zhou He

    Zhou He Level 1

    Mar 13, 2017
    29
    76
    China
    Windows 10
    ESET
    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
     
    Vasudev, upnorth, tim one and 2 others like this.
  20. Opcode

    Opcode Level 18
    Content Creator

    Aug 17, 2017
    890
    6,285
    Caille
    Windows 10
    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

    [​IMG]

    The function KsepGetLoadedModulesList (called by KseRegisterShimEx) -> ZwQuerySystemInformation

    [​IMG]

    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.

    [​IMG]

    [​IMG]

    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.
     
    Andy Ful likes this.
Loading...