├── loader ├── src │ ├── resources │ │ ├── messages.rc │ │ └── resource.h │ ├── loader │ │ ├── image_mapper.cpp │ │ ├── image_descriptor.h │ │ ├── api_stubs.h │ │ ├── image_descriptor.cpp │ │ ├── loader.h │ │ ├── relocations.cpp │ │ ├── process_patcher.cpp │ │ ├── tls_support.cpp │ │ ├── hash_patcher.cpp │ │ ├── loader.cpp │ │ ├── activation_context.cpp │ │ ├── api_stubs.cpp │ │ ├── dependencies.cpp │ │ └── ntldr.h │ ├── helpers.h │ ├── helpers │ │ ├── cmd.h │ │ ├── message_box.h │ │ ├── opendialog.h │ │ ├── string_resource.h │ │ ├── strings.h │ │ ├── message_box.cpp │ │ ├── opendialog.cpp │ │ ├── format.h │ │ ├── strings.cpp │ │ ├── string_resource.cpp │ │ ├── cmd.cpp │ │ └── format.cpp │ ├── system │ │ ├── dbgcl.h │ │ ├── syscalls.h │ │ ├── dbgcl.cpp │ │ ├── system.h │ │ └── system.cpp │ ├── main.cpp │ └── errors.h ├── loader.vcxproj.filters └── loader.vcxproj ├── .gitignore ├── debugger ├── src │ ├── dbgsrv.h │ ├── main.cpp │ └── dbgsrv.cpp ├── debugger.vcxproj.filters └── debugger.vcxproj ├── LICENSE.md ├── README.md └── pe-loader.sln /loader/src/resources/messages.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polycone/pe-loader/HEAD/loader/src/resources/messages.rc -------------------------------------------------------------------------------- /loader/src/resources/resource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polycone/pe-loader/HEAD/loader/src/resources/resource.h -------------------------------------------------------------------------------- /loader/src/loader/image_mapper.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/polycone/pe-loader/HEAD/loader/src/loader/image_mapper.cpp -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.obj 2 | *.exe 3 | *.pdb 4 | *.user 5 | *.aps 6 | *.pch 7 | *.vspscc 8 | *_i.c 9 | *_p.c 10 | *.ncb 11 | *.suo 12 | *.tlb 13 | *.tlh 14 | *.bak 15 | *.cache 16 | *.ilk 17 | *.log 18 | *.sdf 19 | *.lib 20 | *.sbr 21 | .vs/ 22 | build/ 23 | -------------------------------------------------------------------------------- /debugger/src/dbgsrv.h: -------------------------------------------------------------------------------- 1 | #ifndef _DBGSRV_H_ 2 | #define _DBGSRV_H_ 3 | 4 | #include 5 | #include 6 | 7 | #define INBOUND_BUFFER_SIZE 1024 8 | 9 | typedef void (*OnMessageReceive)(LPCWSTR lpMessage); 10 | 11 | int DbgListenPipe(LPCWSTR lpPipeName, OnMessageReceive onReceive); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /loader/src/helpers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Helpers assembly 3 | */ 4 | 5 | #ifndef _HELPERS_H_ 6 | #define _HELPERS_H_ 7 | 8 | #include "helpers\strings.h" 9 | #include "helpers\cmd.h" 10 | #include "helpers\format.h" 11 | #include "helpers\message_box.h" 12 | #include "helpers\string_resource.h" 13 | 14 | #endif // _HELPERS_H_ 15 | -------------------------------------------------------------------------------- /loader/src/helpers/cmd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Command string helpers defenition 3 | */ 4 | 5 | #ifndef _CMD_HELPER_H_ 6 | #define _CMD_HELPER_H_ 7 | 8 | #include 9 | 10 | namespace Helpers 11 | { 12 | 13 | LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs); 14 | 15 | } 16 | 17 | #endif // _CMD_HELPER_H_ 18 | -------------------------------------------------------------------------------- /loader/src/helpers/message_box.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Message box helper defenition 3 | */ 4 | 5 | #ifndef _MESSAGEBOX_HELPER_H_ 6 | #define _MESSAGEBOX_HELPER_H_ 7 | 8 | #include 9 | 10 | namespace Helpers 11 | { 12 | 13 | void ShowCriticalErrorBox(LPCWSTR lpText); 14 | 15 | } 16 | 17 | #endif // _MESSAGEBOX_HELPER_H_ 18 | -------------------------------------------------------------------------------- /loader/src/helpers/opendialog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Open dialog helpers defenition 3 | */ 4 | 5 | #ifndef _OPENDIALOG_HELPER_H_ 6 | #define _OPENDIALOG_HELPER_H_ 7 | 8 | #include 9 | 10 | namespace Helpers 11 | { 12 | 13 | LPWSTR ExecuteOpenFileDialog(LPCWSTR lpFilter, LPWSTR lpFileName, DWORD lpFileNameSize); 14 | 15 | } 16 | 17 | #endif // _OPENDIALOG_HELPER_H_ 18 | -------------------------------------------------------------------------------- /loader/src/helpers/string_resource.h: -------------------------------------------------------------------------------- 1 | /* 2 | * String resource helper defenition 3 | */ 4 | 5 | #ifndef _STRING_RES_HELPER_H_ 6 | #define _STRING_RES_HELPER_H_ 7 | 8 | #include 9 | 10 | namespace Helpers 11 | { 12 | 13 | int WINAPI LoadStringW(HINSTANCE instance, UINT resource_id, LPWSTR buffer, INT buflen); 14 | 15 | } 16 | 17 | #endif // _STRING_RES_HELPER_H_ 18 | -------------------------------------------------------------------------------- /debugger/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "dbgsrv.h" 3 | 4 | void OnReceive(LPCWSTR lpMessage) 5 | { 6 | wprintf(lpMessage); 7 | } 8 | 9 | int wmain() 10 | { 11 | setlocale(LC_ALL, ""); 12 | SetConsoleTitleW(L"PE Loader Debug Server"); 13 | if (DbgListenPipe(L"\\\\.\\pipe\\dbgldr", OnReceive) == -1) 14 | wprintf(L"Cannot create pipe\n"); 15 | system("pause"); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /loader/src/helpers/strings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * String helpers defenition 3 | */ 4 | 5 | #ifndef _STRINGS_HELPER_H_ 6 | #define _STRINGS_HELPER_H_ 7 | 8 | #include 9 | 10 | namespace Helpers 11 | { 12 | 13 | DWORD strlenW(LPCWSTR lpString); 14 | DWORD strlenA(LPCSTR lpString); 15 | LPWSTR strcpyW(LPWSTR dest, LPCWSTR src); 16 | LPCWSTR ExtractFileName(LPCWSTR lpFilePath); 17 | LPWSTR ExtractFileDirectory(LPCWSTR lpFilePath, LPWSTR lpDirectory); 18 | int strcmpA(LPCSTR s1, LPCSTR s2); 19 | int stricmpA(LPCSTR s1, LPCSTR s2); 20 | 21 | } 22 | 23 | #endif // _STRINGS_HELPER_H_ 24 | -------------------------------------------------------------------------------- /loader/src/system/dbgcl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Debug client defenition 3 | */ 4 | 5 | #ifndef _DBGCL_H_ 6 | #define _DBGCL_H_ 7 | 8 | #include 9 | 10 | #define OUTBOUND_BUFFER_SIZE 1024 11 | 12 | #define DBG_CLOSE 1 13 | #define DBG_CLEAR 2 14 | #define DBG_DISCONNECT 3 15 | 16 | HANDLE DbgInitPipe(LPCWSTR lpPipeName); 17 | void DbgClosePipe(HANDLE hPipe); 18 | void DbgMessage(HANDLE hPipe, LPCWSTR lpMessage, ...); 19 | void DbgMessageV(HANDLE hPipe, LPCWSTR lpMessage, va_list args); 20 | void DbgControl(HANDLE hPipe, DWORD dwOperation); 21 | 22 | #endif // _DBGCL_H_ 23 | -------------------------------------------------------------------------------- /loader/src/loader/image_descriptor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Image descriptor defenition 3 | */ 4 | 5 | #ifndef _IMAGE_DESCRIPTOR_H 6 | #define _IMAGE_DESCRIPTOR_H 7 | 8 | #include "ntldr.h" 9 | 10 | // Image descriptor 11 | typedef struct _IMAGE_DESCRIPTOR 12 | { 13 | LPVOID pImageBase; // Pointer to image base 14 | PIMAGE_DOS_HEADER pDosHeader; // DOS Header (MZ) 15 | PIMAGE_FILE_HEADER pFileHeader; // PE File Header 16 | PIMAGE_OPTIONAL_HEADER32 pOptionalHeader; // PE Optional Header 17 | LPVOID pSections; // Pointer to sections 18 | DWORD dwImageFileSize; // Image file size 19 | } IMAGE_DESCRIPTOR, *PIMAGE_DESCRIPTOR; 20 | 21 | #endif // _IMAGE_DESCRIPTOR_H 22 | -------------------------------------------------------------------------------- /loader/src/system/syscalls.h: -------------------------------------------------------------------------------- 1 | /* 2 | * System calls defenition 3 | */ 4 | 5 | #ifndef _SYSCALLS_H_ 6 | #define _SYSCALLS_H_ 7 | 8 | #include "system.h" 9 | 10 | #define strcpy(dest, src) (System::SysCall("strcpy", ccCdecl, 8, dest, src)) 11 | #define memcpy(dest, src, size) (System::SysCall("memcpy", ccCdecl, 12, dest, src, size)) 12 | #define memset(dst, val, size) (System::SysCall("memset", ccCdecl, 12, dst, val, size)) 13 | #define RtlInitUnicodeString(dest, src) (System::SysCall("RtlInitUnicodeString", ccStdcall, 8, dest, src)) 14 | #define RtlHashUnicodeString(String, CaseInSensitive, HashAlgorithm, HashValue) (System::SysCall("RtlHashUnicodeString", ccStdcall, 16, String, CaseInSensitive, HashAlgorithm, HashValue)) 15 | #define swprintf(dest, fmt, argLen, ...) (System::SysCall("swprintf", ccCdecl, 8 + (argLen), (dest), (fmt), ##__VA_ARGS__)) 16 | 17 | #endif // _SYSCALLS_H_ 18 | -------------------------------------------------------------------------------- /debugger/debugger.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 6 | h;hpp;hxx;hm;inl;inc;xsd 7 | 8 | 9 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 10 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 11 | 12 | 13 | 14 | 15 | Source 16 | 17 | 18 | Source 19 | 20 | 21 | 22 | 23 | Header 24 | 25 | 26 | -------------------------------------------------------------------------------- /loader/src/helpers/message_box.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Message box helper 3 | */ 4 | 5 | #include "message_box.h" 6 | #include "../system/system.h" 7 | #include "string_resource.h" 8 | 9 | namespace Helpers 10 | { 11 | 12 | /* 13 | Description: 14 | Shows critical error message box 15 | Arguments: 16 | lpText - error text 17 | */ 18 | void ShowCriticalErrorBox(LPCWSTR lpText) 19 | { 20 | typedef BOOL (APIENTRY *pMessageBox)(HWND, LPCWSTR, LPCWSTR, UINT); 21 | HMODULE hUser32 = LoadLibraryW(L"user32.dll"); 22 | if (hUser32 == NULL) 23 | { 24 | return; 25 | } 26 | pMessageBox MessageBox = (pMessageBox)GetProcAddress(hUser32, "MessageBoxW"); 27 | if (MessageBox == NULL) 28 | return; 29 | WCHAR lpCaption[1024]; 30 | Helpers::LoadStringW(System::GetHandle(), 20000, lpCaption, 1024); 31 | MessageBox(0, lpText, lpCaption, MB_ICONERROR); 32 | } 33 | 34 | } // namespace Helpers 35 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013 Denis Pakhorukov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Windows executable file loader 3 | This is Windows PE format file loader application that provides functionality similar to the OS internal executable file loader, but runs from the **user mode**. It maps an executable file to the memory, patches and initializes several mechanisms and then passes control flow to the loaded image. 4 | This project was developed for educational purposes. 5 | ## Usage 6 | The project can be built with Visual Studio 2013 / 2015 or MSBuild. 7 | 8 | Compiled executables can be found in `build\(Debug|Release)` 9 | Usage example: 10 | ```batch 11 | loader.exe "C:\WINDOWS\system32\ping.exe" -t 127.0.0.1 12 | ``` 13 | ## Limitations 14 | - Compatible mostly with Windows XP (tested on Windows XP, 7, 8) 15 | - 32-bit images only 16 | - Image validation in accordance with the official PE format documentation 17 | ## Support 18 | - Image memory mapping 19 | - Process information patching 20 | - Activation context 21 | - CUI 22 | - API redirection (EAT patching) 23 | - Image relocation 24 | - IAT processing 25 | - TLS (heuristic record location) 26 | ## Debug 27 | There is a debugger to debug loader. Loader use named pipes to send log messages to the debugger. 28 | Logging can be enabled with the following definitions: 29 | 30 | | Definition | Description | 31 | | --- | --- | 32 | | `_LDR_DEBUG_` | Enables debug logging | 33 | | `_LDR_DEBUG_VERBOSE_` | Enables verbose debug logging (redirected API calls) | 34 | -------------------------------------------------------------------------------- /pe-loader.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27703.2018 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "loader", "loader\loader.vcxproj", "{CA8BF6A1-326E-4480-938B-69F4F6B5CEBD}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "debugger", "debugger\debugger.vcxproj", "{F3963D5A-1F27-4E15-B787-5CA97002EC9E}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Win32 = Debug|Win32 13 | Release|Win32 = Release|Win32 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {CA8BF6A1-326E-4480-938B-69F4F6B5CEBD}.Debug|Win32.ActiveCfg = Debug|Win32 17 | {CA8BF6A1-326E-4480-938B-69F4F6B5CEBD}.Debug|Win32.Build.0 = Debug|Win32 18 | {CA8BF6A1-326E-4480-938B-69F4F6B5CEBD}.Release|Win32.ActiveCfg = Release|Win32 19 | {CA8BF6A1-326E-4480-938B-69F4F6B5CEBD}.Release|Win32.Build.0 = Release|Win32 20 | {F3963D5A-1F27-4E15-B787-5CA97002EC9E}.Debug|Win32.ActiveCfg = Debug|Win32 21 | {F3963D5A-1F27-4E15-B787-5CA97002EC9E}.Debug|Win32.Build.0 = Debug|Win32 22 | {F3963D5A-1F27-4E15-B787-5CA97002EC9E}.Release|Win32.ActiveCfg = Release|Win32 23 | EndGlobalSection 24 | GlobalSection(SolutionProperties) = preSolution 25 | HideSolutionNode = FALSE 26 | EndGlobalSection 27 | GlobalSection(ExtensibilityGlobals) = postSolution 28 | SolutionGuid = {99BD0F69-42AA-46EC-9BF6-822F2FD815F3} 29 | EndGlobalSection 30 | EndGlobal 31 | -------------------------------------------------------------------------------- /loader/src/helpers/opendialog.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Open dialog helper 3 | */ 4 | 5 | #include "opendialog.h" 6 | #include "../system/syscalls.h" 7 | 8 | namespace Helpers 9 | { 10 | 11 | /* 12 | Description: 13 | Execute windows open file dialog window 14 | Arguments: 15 | lpFilter - dialog filter ("Descriptopn \0 mask \0", ex.: "Text File\0*.txt\0") 16 | lpFileName - string which receive selected file name 17 | lpFileNameSize - size of lpFileName string 18 | Return Value: 19 | LPWSTR - error code 20 | */ 21 | LPWSTR ExecuteOpenFileDialog(LPCWSTR lpFilter, LPWSTR lpFileName, DWORD lpFileNameSize) 22 | { 23 | OPENFILENAMEW dlgOpen; 24 | memset(&dlgOpen, 0, sizeof(OPENFILENAMEW)); 25 | dlgOpen.lStructSize = sizeof(OPENFILENAMEW); 26 | dlgOpen.hInstance = GetModuleHandle(NULL); 27 | dlgOpen.nMaxFile = lpFileNameSize; 28 | dlgOpen.lpstrInitialDir = NULL; 29 | dlgOpen.lpstrFile = lpFileName; 30 | dlgOpen.lpstrFile[0] = 0; 31 | dlgOpen.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; 32 | dlgOpen.lpstrFilter = lpFilter; 33 | typedef BOOL (APIENTRY *pGOFNW)(LPOPENFILENAMEW); 34 | HMODULE hComDlg = LoadLibraryW(L"Comdlg32.dll"); 35 | if (hComDlg == NULL) 36 | return NULL; 37 | pGOFNW GetOpenFileNameW = (pGOFNW)GetProcAddress(hComDlg, "GetOpenFileNameW"); 38 | if (GetOpenFileNameW == NULL) 39 | return NULL; 40 | if (!GetOpenFileNameW(&dlgOpen)) 41 | return NULL; 42 | else 43 | return lpFileName; 44 | } 45 | 46 | } // namespace Helpers 47 | -------------------------------------------------------------------------------- /loader/src/helpers/format.h: -------------------------------------------------------------------------------- 1 | /* 2 | * String formatting helpers defenition 3 | */ 4 | 5 | #ifndef _FORMAT_HELPER_H_ 6 | #define _FORMAT_HELPER_H_ 7 | 8 | #include 9 | 10 | namespace Helpers 11 | { 12 | 13 | typedef enum 14 | { 15 | WPR_UNKNOWN, 16 | WPR_CHAR, 17 | WPR_WCHAR, 18 | WPR_STRING, 19 | WPR_WSTRING, 20 | WPR_SIGNED, 21 | WPR_UNSIGNED, 22 | WPR_HEXA 23 | } WPRINTF_TYPE; 24 | 25 | typedef struct 26 | { 27 | UINT flags; 28 | UINT width; 29 | UINT precision; 30 | WPRINTF_TYPE type; 31 | } WPRINTF_FORMAT; 32 | 33 | typedef union { 34 | WCHAR wchar_view; 35 | CHAR char_view; 36 | LPCSTR lpcstr_view; 37 | LPCWSTR lpcwstr_view; 38 | LONGLONG int_view; 39 | } WPRINTF_DATA; 40 | 41 | #define WPRINTF_LEFTALIGN 0x0001 /* Align output on the left ('-' prefix) */ 42 | #define WPRINTF_PREFIX_HEX 0x0002 /* Prefix hex with 0x ('#' prefix) */ 43 | #define WPRINTF_ZEROPAD 0x0004 /* Pad with zeros ('0' prefix) */ 44 | #define WPRINTF_LONG 0x0008 /* Long arg ('l' prefix) */ 45 | #define WPRINTF_SHORT 0x0010 /* Short arg ('h' prefix) */ 46 | #define WPRINTF_UPPER_HEX 0x0020 /* Upper-case hex ('X' specifier) */ 47 | #define WPRINTF_WIDE 0x0040 /* Wide arg ('w' prefix) */ 48 | #define WPRINTF_INTPTR 0x0080 /* Pointer-size arg ('I' prefix) */ 49 | #define WPRINTF_I64 0x0100 /* 64-bit arg ('I64' prefix) */ 50 | 51 | INT WINAPI wvsprintfW( LPWSTR buffer, LPCWSTR spec, va_list args ); 52 | 53 | } 54 | 55 | #endif // _FORMAT_HELPER_H_ 56 | -------------------------------------------------------------------------------- /loader/src/loader/api_stubs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Windows API stubs defenition 3 | */ 4 | 5 | #ifndef _APISTUBS_H_ 6 | #define _APISTUBS_H_ 7 | 8 | #include 9 | 10 | #include "ntldr.h" 11 | 12 | namespace SystemApi 13 | { 14 | 15 | // Windows API snap 16 | 17 | typedef struct _SYSCALL_POINTERS_SNAP 18 | { 19 | 20 | DWORD NtQuerySystemInformation; 21 | DWORD NtQueryInformationProcess; 22 | DWORD NtQueryVirtualMemory; 23 | DWORD ExitProcess; 24 | DWORD GetCommandLineA; 25 | DWORD GetCommandLineW; 26 | 27 | } SYSCALL_POINTERS_SNAP, *PSYSCALL_POINTERS_SNAP; 28 | 29 | // Windows API stubs 30 | 31 | LPSTR WINAPI GetCommandLineA(); 32 | 33 | LPWSTR WINAPI GetCommandLineW(); 34 | 35 | void WINAPI ExitProcess(UINT uCode); 36 | 37 | NTSTATUS WINAPI NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, 38 | PVOID ProcessInformation, ULONG ProcessInformationLength, 39 | PULONG ReturnLength); 40 | 41 | NTSTATUS WINAPI NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, 42 | ULONG SystemInformationLength, PULONG ReturnLength); 43 | 44 | NTSTATUS WINAPI NtQueryVirtualMemory(HANDLE ProcessHandle, PVOID BaseAddress, 45 | MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID MemoryInformation, 46 | SIZE_T MemoryInformationLength, PSIZE_T ReturnLength); 47 | 48 | } // namespace SystemApi 49 | 50 | extern SystemApi::SYSCALL_POINTERS_SNAP SysCallSnap; 51 | 52 | #endif // _APISTUBS_H_ 53 | -------------------------------------------------------------------------------- /debugger/src/dbgsrv.cpp: -------------------------------------------------------------------------------- 1 | #include "dbgsrv.h" 2 | 3 | int DbgListenPipe(LPCWSTR lpPipeName, OnMessageReceive onReceive) 4 | { 5 | WCHAR pBuffer[INBOUND_BUFFER_SIZE + 1]; 6 | pBuffer[INBOUND_BUFFER_SIZE] = 0; 7 | BOOL bStop = false; 8 | DWORD dwBytesRead = 0; 9 | BOOL bSuccess = false; 10 | while (!bStop) 11 | { 12 | HANDLE hPipe = CreateNamedPipeW(lpPipeName, PIPE_ACCESS_INBOUND, PIPE_TYPE_MESSAGE | 13 | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 14 | 0, INBOUND_BUFFER_SIZE * sizeof(WCHAR), 0, NULL); 15 | if (hPipe == INVALID_HANDLE_VALUE) 16 | return -1; 17 | if (ConnectNamedPipe(hPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED)) 18 | { 19 | while (true) 20 | { 21 | bSuccess = ReadFile(hPipe, pBuffer, INBOUND_BUFFER_SIZE * sizeof(WCHAR), &dwBytesRead, NULL); 22 | if (!bSuccess || dwBytesRead == 0) 23 | { 24 | CloseHandle(hPipe); 25 | break; 26 | } 27 | if (pBuffer[0] == 1) 28 | { 29 | CloseHandle(hPipe); 30 | bStop = true; 31 | break; 32 | } 33 | if (pBuffer[0] == 3) 34 | { 35 | CloseHandle(hPipe); 36 | break; 37 | } 38 | else if (pBuffer[0] == 2) 39 | system("cls"); 40 | else if (onReceive) 41 | onReceive(pBuffer); 42 | } 43 | } 44 | else 45 | { 46 | CloseHandle(hPipe); 47 | } 48 | } 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /loader/src/helpers/strings.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Strings helper functions 3 | */ 4 | 5 | #include "../system/syscalls.h" 6 | #include "../system/system.h" 7 | #include "strings.h" 8 | 9 | namespace Helpers 10 | { 11 | 12 | DWORD strlenW(LPCWSTR lpString) 13 | { 14 | PCWCHAR pLetter = lpString; 15 | DWORD dwLength = 0; 16 | while (*pLetter++ != 0) 17 | ++dwLength; 18 | return dwLength; 19 | } 20 | 21 | DWORD strlenA(LPCSTR lpString) 22 | { 23 | PCCH pLetter = lpString; 24 | DWORD dwLength = 0; 25 | while (*pLetter++ != 0) 26 | ++dwLength; 27 | return dwLength; 28 | } 29 | 30 | LPWSTR strcpyW(LPWSTR dest, LPCWSTR src) 31 | { 32 | memcpy(dest, src, (strlenW(src) + 1) * sizeof(WCHAR)); 33 | return dest; 34 | } 35 | 36 | int strcmpA(LPCSTR s1, LPCSTR s2) 37 | { 38 | DWORD dwLen1 = strlenA(s1); 39 | DWORD dwLen2 = strlenA(s2); 40 | if (dwLen1 != dwLen2) 41 | return -1; 42 | for (DWORD i = 0; i < dwLen1; ++i) 43 | { 44 | if (s1[i] != s2[i]) 45 | return s1[i] - s2[i]; 46 | } 47 | return 0; 48 | } 49 | 50 | int stricmpA(LPCSTR s1, LPCSTR s2) 51 | { 52 | return System::SysCall("_stricmp", ccCdecl, 8, s1, s2); 53 | } 54 | 55 | LPCWSTR ExtractFileName(LPCWSTR lpFilePath) 56 | { 57 | PCWCHAR pLetter = lpFilePath + strlenW(lpFilePath); 58 | while ((*pLetter != '\\') && (*pLetter != '/') && ((DWORD)pLetter > (DWORD)lpFilePath)) 59 | --pLetter; 60 | return ++pLetter; 61 | } 62 | 63 | LPWSTR ExtractFileDirectory(LPCWSTR lpFilePath, LPWSTR lpDirectory) 64 | { 65 | PCWCHAR pLetter = lpFilePath + strlenW(lpFilePath); 66 | while ((*pLetter != '\\') && (*pLetter != '/') && ((DWORD)pLetter > (DWORD)lpFilePath)) 67 | pLetter--; 68 | DWORD dwSize = (DWORD)++pLetter - (DWORD)lpFilePath; 69 | memcpy(lpDirectory, lpFilePath, dwSize); 70 | *(PWCHAR)((DWORD)lpDirectory + dwSize) = 0; 71 | return lpDirectory; 72 | } 73 | 74 | } // namespace Helpers 75 | -------------------------------------------------------------------------------- /loader/src/system/dbgcl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Debug client implementation 3 | */ 4 | 5 | #include "dbgcl.h" 6 | #include "../helpers.h" 7 | 8 | HANDLE DbgInitPipe(LPCWSTR lpPipeName) 9 | { 10 | HANDLE hPipe; 11 | int dwIter = 2; 12 | while (dwIter--) 13 | { 14 | hPipe = CreateFileW(lpPipeName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); 15 | if (hPipe == INVALID_HANDLE_VALUE && GetLastError() == ERROR_PIPE_BUSY) 16 | { 17 | if (!WaitNamedPipeW(lpPipeName, 2000)) 18 | return INVALID_HANDLE_VALUE; 19 | } 20 | else 21 | break; 22 | } 23 | DWORD dwMode = PIPE_READMODE_MESSAGE; 24 | if (!SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL)) 25 | { 26 | CloseHandle(hPipe); 27 | return INVALID_HANDLE_VALUE; 28 | } 29 | return hPipe; 30 | } 31 | 32 | void DbgClosePipe(HANDLE hPipe) 33 | { 34 | if (hPipe != INVALID_HANDLE_VALUE) 35 | CloseHandle(hPipe); 36 | } 37 | 38 | void DbgMessage(HANDLE hPipe, LPCWSTR lpMessage, ...) 39 | { 40 | if (hPipe == INVALID_HANDLE_VALUE) 41 | return; 42 | DWORD dwWritten = 0; 43 | WCHAR pBuffer[OUTBOUND_BUFFER_SIZE + 1]; 44 | pBuffer[OUTBOUND_BUFFER_SIZE] = 0; 45 | va_list va; 46 | va_start(va, lpMessage); 47 | Helpers::wvsprintfW(pBuffer, lpMessage, va); 48 | WriteFile(hPipe, (LPCVOID)pBuffer, (lstrlenW(pBuffer) + 1) * sizeof(WCHAR), &dwWritten, NULL); 49 | va_end(va); 50 | } 51 | 52 | void DbgMessageV(HANDLE hPipe, LPCWSTR lpMessage, va_list args) 53 | { 54 | if (hPipe == INVALID_HANDLE_VALUE) 55 | return; 56 | DWORD dwWritten = 0; 57 | WCHAR pBuffer[OUTBOUND_BUFFER_SIZE + 1]; 58 | pBuffer[OUTBOUND_BUFFER_SIZE] = 0; 59 | Helpers::wvsprintfW(pBuffer, lpMessage, args); 60 | WriteFile(hPipe, (LPCVOID)pBuffer, (lstrlenW(pBuffer) + 1) * sizeof(WCHAR), &dwWritten, NULL); 61 | } 62 | 63 | void DbgControl(HANDLE hPipe, DWORD dwOperation) 64 | { 65 | if (hPipe == INVALID_HANDLE_VALUE) 66 | return; 67 | switch (dwOperation) 68 | { 69 | case DBG_CLOSE: 70 | DbgMessage(hPipe, L"\1"); 71 | break; 72 | case DBG_CLEAR: 73 | DbgMessage(hPipe, L"\2"); 74 | break; 75 | case DBG_DISCONNECT: 76 | DbgMessage(hPipe, L"\3"); 77 | break; 78 | default: 79 | break; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /loader/src/loader/image_descriptor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Image descriptor functions 3 | */ 4 | 5 | #include "loader.h" 6 | #include "../errors.h" 7 | 8 | /* 9 | Description: 10 | Allocate image descriptor 11 | Return Value: 12 | PIMAGE_DESCRIPTOR - pointer to image descriptor if success 13 | NULL otherwise 14 | */ 15 | PIMAGE_DESCRIPTOR LdrCreateImageDescriptor() 16 | { 17 | return (PIMAGE_DESCRIPTOR)System::MmAlloc(sizeof(IMAGE_DESCRIPTOR), true); 18 | } 19 | 20 | /* 21 | Description: 22 | Free image descriptor 23 | Return Value: 24 | bool - true if success 25 | false if memory cannot be free (See System::GetLastError) 26 | */ 27 | bool LdrCloseImageDescriptor(PIMAGE_DESCRIPTOR pImage) 28 | { 29 | return System::MmFree((LPVOID)pImage); 30 | } 31 | 32 | /* 33 | Description: 34 | Obtains image descriptor for vaild loaded image 35 | Arguments: 36 | pImage - pointer to memory, which contains loaded image 37 | Return Value: 38 | PIMAGE_DESCRIPTOR - pointer to the image descriptor 39 | */ 40 | PIMAGE_DESCRIPTOR LdrObtainImageDescriptor(LPVOID pImageBase) 41 | { 42 | if (IS_NULL(pImageBase)) 43 | { 44 | System::SetErrorCode(E_INVALID_ARGUMENT, true, __FUNCTIONW__); 45 | return NULL; 46 | } 47 | PIMAGE_DESCRIPTOR pImage = LdrCreateImageDescriptor(); 48 | if (IS_NULL(pImage)) 49 | return NULL; 50 | __try 51 | { 52 | pImage->pImageBase = pImageBase; 53 | pImage->pDosHeader = (PIMAGE_DOS_HEADER)pImageBase; 54 | LPVOID lpPosition = MAKE_LPVOID(pImageBase, pImage->pDosHeader->e_lfanew + sizeof(DWORD)); 55 | pImage->pFileHeader = (PIMAGE_FILE_HEADER)lpPosition; 56 | lpPosition = MAKE_LPVOID(lpPosition, sizeof(IMAGE_FILE_HEADER)); 57 | pImage->pOptionalHeader = (PIMAGE_OPTIONAL_HEADER32)lpPosition; 58 | pImage->pSections = MAKE_LPVOID(lpPosition, sizeof(IMAGE_OPTIONAL_HEADER32)); 59 | pImage->dwImageFileSize = 0; 60 | return pImage; 61 | } 62 | __except(EXCEPTION_EXECUTE_HANDLER) 63 | { 64 | #ifdef _LDR_DEBUG_ 65 | System::SysDbgMessage(L"[X] Exception in %s [%s line %d]\n", __FUNCTIONW__, __FILEW__, __LINE__); 66 | #endif //_LDR_DEBUG_ 67 | System::SetErrorCode(E_EXCEPTION, true, __FUNCTIONW__); 68 | LdrCloseImageDescriptor(pImage); 69 | return NULL; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /loader/src/loader/loader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Loader assembly defenition 3 | */ 4 | 5 | #ifndef _LOADER_H_ 6 | #define _LOADER_H_ 7 | 8 | #include 9 | #include "image_descriptor.h" 10 | #include "../system/system.h" 11 | 12 | typedef struct _TLS_ENTRY 13 | { 14 | LPVOID lpImageBase; 15 | IMAGE_TLS_DIRECTORY Tls; 16 | } TLS_ENTRY, *PTLS_ENTRY; 17 | 18 | #define ROUND_DOWN(value, align) (((value) / (align)) * (align)) 19 | #define ROUND_UP(value, align) (ROUND_DOWN(value, align) + (((value) % (align) ? 1 : 0) * (align))) 20 | 21 | /* image_descriptor.cpp */ 22 | 23 | PIMAGE_DESCRIPTOR LdrObtainImageDescriptor(LPVOID lpImage); 24 | bool LdrCloseImageDescriptor(PIMAGE_DESCRIPTOR pImage); 25 | PIMAGE_DESCRIPTOR LdrObtainImageDescriptor(LPVOID lpImage); 26 | 27 | /* dependencies.cpp */ 28 | 29 | void LdrAllowImageDirectoryAccess(PIMAGE_DESCRIPTOR pImage, DWORD dwDataDirectory); 30 | int LdrSetExportAddress(PIMAGE_DESCRIPTOR pImage, LPCSTR lpName, LPVOID lpAddress); 31 | int LdrProcessImports(PIMAGE_DESCRIPTOR pImage); 32 | int LdrSetImportAddress(PIMAGE_DESCRIPTOR pImage, LPCSTR lpLibName, LPCSTR lpFuncName, LPVOID lpAddress); 33 | int LdrAllowSections(PIMAGE_DESCRIPTOR pImage); 34 | 35 | /* relocations.cpp */ 36 | 37 | int LdrProcessRelocations(PIMAGE_DESCRIPTOR pModule, DWORD dwCustomDelta = -1); 38 | 39 | /* image_mapper.cpp */ 40 | 41 | int LdrMapImage(PIMAGE_DESCRIPTOR lpImage, LPCWSTR lpFileName); 42 | int LdrProtectSections(PIMAGE_DESCRIPTOR lpImage); 43 | 44 | /* activation_context.cpp */ 45 | 46 | int LdrSetDefaultActivationContext(PIMAGE_DESCRIPTOR pImage, PIMAGE_ACTIVATION_CONTEXT pActivationContext); 47 | int LdrRestoreDefaultActivationContext(PIMAGE_ACTIVATION_CONTEXT pActivationContext); 48 | 49 | /* process_patcher.cpp */ 50 | 51 | int LdrPatchProcess(PIMAGE_DESCRIPTOR lpImage); 52 | 53 | /* tls_support.cpp */ 54 | 55 | LPVOID LdrLocateTlsRecord(); 56 | int LdrInitializeTls(PIMAGE_DESCRIPTOR pImage, PIMAGE_TLS_DIRECTORY pSystemTlsEntry, BOOL bCopyData); 57 | 58 | /* api_stubs.cpp */ 59 | 60 | int LdrSnapApi(); 61 | int LdrSetupApi(); 62 | int LdrRestoreApi(); 63 | 64 | /* hash_patcher.cpp */ 65 | 66 | int LdrPatchHashTable(PLDR_DATA_TABLE_ENTRY pLdrEntry, LPCWSTR lpOriginalName, LPCWSTR lpNewName); 67 | 68 | /* loader.cpp */ 69 | 70 | int LdrInitialize(); 71 | int LdrCheckCUI(PIMAGE_DESCRIPTOR pImage); 72 | int LdrExecuteImage(PIMAGE_DESCRIPTOR pModule); 73 | int LdrCheckDataDirectory(PIMAGE_DESCRIPTOR pImage, DWORD dwDataDirectory); 74 | 75 | /* globals */ 76 | 77 | extern PIMAGE_DESCRIPTOR pExecutingImage; // Executing image descriptor, used by system API stubs 78 | 79 | #endif //_LOADER_H_ 80 | -------------------------------------------------------------------------------- /loader/src/helpers/string_resource.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * String resource helper 3 | * This file use a part of dlls/user32/resource.c from Wine project 4 | * (http://sourceforge.net/projects/wine/files/Source/) 5 | */ 6 | 7 | /* 8 | * USER resource functions 9 | * 10 | * Copyright 1993 Robert J. Amstadt 11 | * Copyright 1995, 2009 Alexandre Julliard 12 | * 13 | * This library is free software; you can redistribute it and/or 14 | * modify it under the terms of the GNU Lesser General Public 15 | * License as published by the Free Software Foundation; either 16 | * version 2.1 of the License, or (at your option) any later version. 17 | * 18 | * This library is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 | * Lesser General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU Lesser General Public 24 | * License along with this library; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 26 | */ 27 | 28 | #include "string_resource.h" 29 | #include "../system/syscalls.h" 30 | 31 | namespace Helpers 32 | { 33 | 34 | int WINAPI LoadStringW(HINSTANCE instance, UINT resource_id, LPWSTR buffer, INT buflen) 35 | { 36 | HGLOBAL hmem; 37 | HRSRC hrsrc; 38 | WCHAR *p; 39 | int string_num; 40 | int i; 41 | 42 | if(buffer == NULL) 43 | return 0; 44 | 45 | /* Use loword (incremented by 1) as resourceid */ 46 | hrsrc = FindResourceW(instance, MAKEINTRESOURCEW((LOWORD(resource_id) >> 4) + 1), (LPWSTR)RT_STRING); 47 | if (!hrsrc) 48 | return 0; 49 | hmem = LoadResource(instance, hrsrc); 50 | if (!hmem) 51 | return 0; 52 | 53 | p = (PWCHAR)LockResource(hmem); 54 | string_num = resource_id & 0x000f; 55 | for (i = 0; i < string_num; i++) 56 | p += *p + 1; 57 | 58 | /*if buflen == 0, then return a read-only pointer to the resource itself in buffer 59 | it is assumed that buffer is actually a (LPWSTR *) */ 60 | if(buflen == 0) 61 | { 62 | *((LPWSTR *)buffer) = p + 1; 63 | return *p; 64 | } 65 | 66 | i = min(buflen - 1, *p); 67 | if (i > 0) 68 | { 69 | memcpy(buffer, p + 1, i * sizeof (WCHAR)); 70 | buffer[i] = 0; 71 | } 72 | else if (buflen > 1) 73 | { 74 | buffer[0] = 0; 75 | return 0; 76 | } 77 | 78 | return i; 79 | } 80 | 81 | } // namespace Helpers 82 | -------------------------------------------------------------------------------- /loader/src/loader/relocations.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Image relocation helper 3 | */ 4 | 5 | #include "loader.h" 6 | #include "../errors.h" 7 | 8 | /* 9 | Description: 10 | Process image relocations 11 | Arguments: 12 | pImage - pointer to valid image descriptor 13 | dwCustomDelta - delta value (offset from image default base address) 14 | if value is -1 function calculate delta 15 | Return Value: 16 | int - error code 17 | */ 18 | int LdrProcessRelocations(PIMAGE_DESCRIPTOR pImage, DWORD dwCustomDelta) 19 | { 20 | __try 21 | { 22 | if (IS_NULL(pImage)) 23 | return System::SetErrorCode(E_INVALID_ARGUMENT, true, __FUNCTIONW__); 24 | 25 | // Check for image relocation availability 26 | // and calculate delta value if needed 27 | 28 | DWORD dwDelta = 0; 29 | if (dwCustomDelta != -1) 30 | dwDelta = dwCustomDelta; 31 | else 32 | dwDelta = (DWORD)pImage->pImageBase - pImage->pOptionalHeader->ImageBase; 33 | if (dwDelta == 0) 34 | return System::SetErrorCode(E_RELOCATION_NOT_NEEDED); 35 | PIMAGE_DATA_DIRECTORY pRelocDirectory = &pImage->pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; 36 | if (pRelocDirectory->VirtualAddress == 0) 37 | return System::SetErrorCode(E_RELOCATION_NOT_FOUND, true); 38 | DWORD dwLimit = (DWORD)pImage->pImageBase + pRelocDirectory->VirtualAddress + pRelocDirectory->Size; 39 | PIMAGE_BASE_RELOCATION pRelocation = MAKE_PTR(PIMAGE_BASE_RELOCATION, pImage->pImageBase, 40 | pRelocDirectory->VirtualAddress); 41 | PIMAGE_RELOC pReloc; 42 | 43 | // Process image relocations 44 | 45 | while ((DWORD)pRelocation < dwLimit) 46 | { 47 | DWORD dwRelocLimit = (DWORD)pRelocation + pRelocation->SizeOfBlock; 48 | DWORD lpBase = (DWORD)pImage->pImageBase + pRelocation->VirtualAddress; 49 | pReloc = (PIMAGE_RELOC)((DWORD)pRelocation + sizeof(IMAGE_BASE_RELOCATION)); 50 | while ((DWORD)pReloc < dwRelocLimit) 51 | { 52 | switch (pReloc->wType) 53 | { 54 | case IMAGE_REL_BASED_ABSOLUTE: 55 | break; 56 | case IMAGE_REL_BASED_HIGH: 57 | *((WORD*)(lpBase + pReloc->wOffset)) += HIWORD(dwDelta); 58 | break; 59 | case IMAGE_REL_BASED_LOW: 60 | *((WORD*)(lpBase + pReloc->wOffset)) += LOWORD(dwDelta); 61 | break; 62 | case IMAGE_REL_BASED_HIGHLOW: 63 | *((DWORD*)(lpBase + pReloc->wOffset)) += dwDelta; 64 | break; 65 | case IMAGE_REL_BASED_DIR64: 66 | *((ULONGLONG*)(lpBase + pReloc->wOffset)) += dwDelta; 67 | break; 68 | case IMAGE_REL_BASED_HIGHADJ: 69 | { 70 | *((WORD*)(lpBase + pReloc->wOffset)) += HIWORD(dwDelta); 71 | *((WORD*)(lpBase + pReloc->wOffset + 2)) = (++pReloc)->wData; 72 | break; 73 | } 74 | default: 75 | return System::SetErrorCode(E_UNKNOWN_RELOC, true, pReloc->wType); 76 | } 77 | ++pReloc; 78 | } 79 | pRelocation = (PIMAGE_BASE_RELOCATION)pReloc; 80 | } 81 | } 82 | __except(EXCEPTION_EXECUTE_HANDLER) 83 | { 84 | #ifdef _LDR_DEBUG_ 85 | System::SysDbgMessage(L"[X] Exception in %s [%s line %d]\n", __FUNCTIONW__, __FILEW__, __LINE__); 86 | #endif 87 | return System::SetErrorCode(E_EXCEPTION, true, __FUNCTIONW__); 88 | } 89 | return System::SetErrorCode(E_SUCCESS); 90 | } 91 | -------------------------------------------------------------------------------- /loader/src/loader/process_patcher.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Process data patcher helper 3 | */ 4 | 5 | #include "loader.h" 6 | #include "../helpers.h" 7 | #include "../errors.h" 8 | #include "../system/syscalls.h" 9 | 10 | /* 11 | Description: 12 | Patch process information 13 | Arguments: 14 | pImage - pointer to a valid image descriptor 15 | Return Value: 16 | int - error code 17 | */ 18 | int LdrPatchProcess(PIMAGE_DESCRIPTOR pImage) 19 | { 20 | __try 21 | { 22 | PPEB pPeb = NtCurrentTeb()->Peb; 23 | PPEB_LDR_DATA pLdrData = pPeb->pLdr; 24 | PLDR_DATA_TABLE_ENTRY pLdrEntry = (PLDR_DATA_TABLE_ENTRY)pLdrData->InLoadOrderModuleList.Flink; 25 | 26 | LPCWSTR lpOriginalName = Helpers::ExtractFileName(System::GetCommandLineItem(0)); 27 | LPCWSTR lpNewName = Helpers::ExtractFileName(System::GetExecutableFileName()->Buffer); 28 | 29 | int result = 0; 30 | 31 | // Patch modules hash table 32 | 33 | result = LdrPatchHashTable(pLdrEntry, lpOriginalName, lpNewName); 34 | 35 | #ifdef _LDR_DEBUG_ 36 | if (result != E_SUCCESS) 37 | System::SysDbgMessage(L"[W] Unable to modify hashtable, GetModuleHandle may fail.\n"); 38 | #endif 39 | 40 | // Patch process parameters 41 | 42 | PRTL_USER_PROCESS_PARAMETERS pParameters = pPeb->lpProcessParameters; 43 | 44 | static WCHAR wcCurrentDir[MAX_PATH]; 45 | static WCHAR wcCmdLine[MAX_PATH]; 46 | static WCHAR wcFileName[MAX_PATH]; 47 | static WCHAR wcFilePath[MAX_PATH]; 48 | static UNICODE_STRING usFilePath; 49 | static UNICODE_STRING usBaseName; 50 | static UNICODE_STRING usCmdLine; 51 | 52 | Helpers::ExtractFileDirectory(System::GetExecutableFileName()->Buffer, wcCurrentDir); 53 | swprintf(wcCmdLine, L"\"%s\"", 4, System::GetExecutableFileName()->Buffer); 54 | memcpy(wcFileName, lpNewName, (Helpers::strlenW(lpNewName) + 1) * sizeof(WCHAR)); 55 | memcpy(wcFilePath, System::GetExecutableFileName()->Buffer, (Helpers::strlenW(System::GetExecutableFileName()->Buffer) + 1) * sizeof(WCHAR)); 56 | 57 | RtlInitUnicodeString(&usBaseName, wcFileName); 58 | RtlInitUnicodeString(&usFilePath, wcFilePath); 59 | RtlInitUnicodeString(&usCmdLine, wcCmdLine); 60 | 61 | // Set base address in peb 62 | 63 | pPeb->lpImageBaseAddress = pImage->pImageBase; 64 | 65 | // Set process image file name 66 | 67 | pParameters->ImagePathName = usFilePath; 68 | 69 | // Set process working directory 70 | 71 | int iResult = 1; 72 | iResult = SetCurrentDirectoryW(wcCurrentDir); 73 | 74 | #ifdef _LDR_DEBUG_ 75 | if (!iResult) 76 | System::SysDbgMessage(L"[W] Unable to set current directory. error: 0x%08X\n", GetLastError()); 77 | #endif 78 | 79 | // Set process command line, window title 80 | 81 | pParameters->CommandLine = usCmdLine; 82 | pParameters->WindowTitle = usFilePath; 83 | 84 | // Patch windows loader entry 85 | 86 | pLdrEntry->SizeOfImage = pImage->pOptionalHeader->SizeOfImage; 87 | pLdrEntry->ModuleBase = pImage->pImageBase; 88 | 89 | if (System::GetOSVersion() >= VER_WINDOWS_8) 90 | ((Windows8::PLDR_DATA_TABLE_ENTRY)pLdrEntry)->OriginalBase = pImage->pOptionalHeader->ImageBase; 91 | 92 | pLdrEntry->ModuleFileName = usFilePath; 93 | pLdrEntry->ModuleBaseName.Buffer = (PWSTR)Helpers::ExtractFileName(pLdrEntry->ModuleFileName.Buffer); 94 | pLdrEntry->ModuleBaseName.Length = (Helpers::strlenW(pLdrEntry->ModuleBaseName.Buffer) * sizeof(WCHAR)) & 0xFFFF; 95 | pLdrEntry->ModuleBaseName.MaximumLength = pLdrEntry->ModuleBaseName.Length + sizeof(WCHAR); 96 | pLdrEntry->EntryPoint = (PVOID)((DWORD)pImage->pImageBase + pImage->pOptionalHeader->AddressOfEntryPoint); 97 | 98 | } // __try 99 | __except(EXCEPTION_EXECUTE_HANDLER) 100 | { 101 | #ifdef _LDR_DEBUG_ 102 | System::SysDbgMessage(L"[X] Exception in %s [%s line %d]\n", __FUNCTIONW__, __FILEW__, __LINE__); 103 | #endif 104 | return System::SetErrorCode(E_EXCEPTION, true, __FUNCTIONW__); 105 | } 106 | return System::SetErrorCode(E_SUCCESS); 107 | } 108 | -------------------------------------------------------------------------------- /debugger/debugger.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {F3963D5A-1F27-4E15-B787-5CA97002EC9E} 15 | DebugServer 16 | debugger 17 | 8.1 18 | 19 | 20 | 21 | Application 22 | true 23 | MultiByte 24 | v120_xp 25 | 26 | 27 | Application 28 | false 29 | true 30 | MultiByte 31 | v120_xp 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | $(SolutionDir)build\$(Configuration)\ 45 | build\$(Configuration)\ 46 | 47 | 48 | $(SolutionDir)build\$(Configuration)\ 49 | build\$(Configuration)\ 50 | 51 | 52 | 53 | Level3 54 | Disabled 55 | MultiThreadedDebug 56 | 57 | 58 | true 59 | Console 60 | 61 | 62 | 63 | 64 | Level3 65 | MaxSpeed 66 | true 67 | true 68 | MultiThreaded 69 | 70 | 71 | true 72 | true 73 | true 74 | Console 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /loader/src/loader/tls_support.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Thread local storage helper 3 | */ 4 | 5 | #include "loader.h" 6 | #include "../errors.h" 7 | #include "../system/syscalls.h" 8 | 9 | __declspec(thread) DWORD dwEnableTlsDummy[1024]; 10 | 11 | // Piece of IMAGE_TLS_DIRECTORY 12 | typedef struct _IMAGE_TLS_COMPARE 13 | { 14 | DWORD StartAddressOfRawData; 15 | DWORD EndAddressOfRawData; 16 | DWORD AddressOfIndex; 17 | DWORD AddressOfCallBacks; 18 | } IMAGE_TLS_COMPARE, *PIMAGE_TLS_COMPARE; 19 | 20 | /* 21 | Description: 22 | Locates program entry of "LdrpTlsList" 23 | Return Value: 24 | LPVOID - pointer to system TLS list entry 25 | */ 26 | LPVOID LdrLocateTlsRecord() 27 | { 28 | int (__stdcall *memcmp)(DWORD dest, LPVOID src, DWORD sz); 29 | memcmp = (int (__stdcall *)(DWORD, LPVOID, DWORD))System::GetSysProcAddress("memcmp"); 30 | PPEB pPeb = NtCurrentTeb()->Peb; 31 | 32 | // 1. Locate heap base and size 33 | // 2. Scan heap for piece of IMAGE_TLS_DIRECTORY 34 | // 3. Found address - size of LIST_ENTRY = PIMAGE_TLS_DIRECTORY 35 | 36 | HANDLE hHeap = GetProcessHeap(); 37 | MEMORY_BASIC_INFORMATION mbi; 38 | VirtualQuery(hHeap, &mbi, sizeof(MEMORY_BASIC_INFORMATION)); 39 | DWORD dwHeapSize = mbi.RegionSize; 40 | PIMAGE_DESCRIPTOR pSelf = LdrObtainImageDescriptor(GetModuleHandleW(0)); 41 | IMAGE_TLS_COMPARE tlsSourceData; 42 | PIMAGE_TLS_COMPARE tlsSelf = MAKE_PTR(PIMAGE_TLS_COMPARE, pSelf->pImageBase, 43 | pSelf->pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress); 44 | tlsSourceData = *tlsSelf; 45 | DWORD dwPosition = (DWORD)hHeap; 46 | DWORD dwHeapEnd = dwPosition + dwHeapSize - sizeof(IMAGE_TLS_COMPARE); 47 | LPVOID lpEntry = NULL; 48 | for (; dwPosition < dwHeapEnd; dwPosition += sizeof(DWORD)) 49 | { 50 | if (memcmp(dwPosition, &tlsSourceData, sizeof(IMAGE_TLS_COMPARE)) == 0) 51 | { 52 | lpEntry = (LPVOID)(dwPosition - sizeof(LIST_ENTRY)); 53 | break; 54 | } 55 | } 56 | return lpEntry; 57 | } 58 | 59 | /* 60 | Description: 61 | Initialize TLS 62 | Arguments: 63 | pImage - pointer to valid image descriptor 64 | pSystemTlsEntry - pointer to a valid program TLS list entry field "tls" 65 | Return Value: 66 | int - error code 67 | */ 68 | int LdrInitializeTls(PIMAGE_DESCRIPTOR pImage, PIMAGE_TLS_DIRECTORY pSystemTlsEntry, BOOL bCopyData) 69 | { 70 | // For the TLS support use __declspec(thread) variable once 71 | 72 | dwEnableTlsDummy[0] = 1; 73 | 74 | if (IS_NULL(pImage)) 75 | return System::SetErrorCode(E_INVALID_ARGUMENT, true, __FUNCTIONW__); 76 | 77 | // Check for TLS availability 78 | 79 | if (LdrCheckDataDirectory(pImage, IMAGE_DIRECTORY_ENTRY_TLS) != E_SUCCESS) 80 | return System::SetErrorCode(E_TLS_NOT_FOUND); 81 | 82 | DWORD dwTlsOffset = pImage->pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress; 83 | PIMAGE_TLS_DIRECTORY pNewTls = MAKE_PTR(PIMAGE_TLS_DIRECTORY, pImage->pImageBase, dwTlsOffset); 84 | 85 | // Fill TLS entry with appropriate values 86 | 87 | pSystemTlsEntry->AddressOfCallBacks = pNewTls->AddressOfCallBacks; 88 | DWORD dwTlsIndex = *(DWORD*)pSystemTlsEntry->AddressOfIndex; 89 | PTEB pTeb = NtCurrentTeb(); 90 | 91 | // Reallocate allocated TLS memory 92 | 93 | if (bCopyData) 94 | { 95 | LPVOID *lppIndexPtr = (LPVOID*)((DWORD*)pTeb->ThreadLocalStoragePointer + dwTlsIndex); 96 | System::MmFree(*lppIndexPtr); 97 | *lppIndexPtr = System::MmAlloc(pNewTls->EndAddressOfRawData - pNewTls->StartAddressOfRawData, true); 98 | memcpy(*lppIndexPtr, pNewTls->StartAddressOfRawData, 99 | pNewTls->EndAddressOfRawData - pNewTls->StartAddressOfRawData); 100 | } 101 | 102 | *(DWORD*)pNewTls->AddressOfIndex = dwTlsIndex; 103 | pSystemTlsEntry->AddressOfIndex = pNewTls->AddressOfIndex; 104 | pSystemTlsEntry->EndAddressOfRawData = pNewTls->EndAddressOfRawData; 105 | pSystemTlsEntry->StartAddressOfRawData = pNewTls->StartAddressOfRawData; 106 | 107 | // Call callbacks 108 | if (bCopyData && pSystemTlsEntry->AddressOfCallBacks) { 109 | PDWORD pCallback = (PDWORD)pSystemTlsEntry->AddressOfCallBacks; 110 | DWORD dwCallback = 0; 111 | DWORD dwBase = (DWORD)pImage->pImageBase; 112 | while (*pCallback) 113 | { 114 | dwCallback = *pCallback++; 115 | System::CustomCall(dwCallback, ccStdcall, 12, pImage->pImageBase, DLL_PROCESS_ATTACH, 0); 116 | } 117 | } 118 | return System::SetErrorCode(E_SUCCESS); 119 | } 120 | -------------------------------------------------------------------------------- /loader/src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Main function 3 | */ 4 | 5 | #include "system/system.h" 6 | #include "loader/loader.h" 7 | #include "helpers/strings.h" 8 | #include "helpers/opendialog.h" 9 | #include "system/syscalls.h" 10 | 11 | /* 12 | Description: 13 | Gets executing image file name 14 | Arguments: 15 | plpFileName - valid pointer to unicode string 16 | argc - arguments count (cmd) 17 | argv - argument variables (cmd) 18 | Return Value: 19 | BOOL - true if image file name was obtained via dialog 20 | false if via command line 21 | */ 22 | BOOL GetImageFileName(LPWSTR *plpFileName, int argc, LPCWSTR *argv) 23 | { 24 | __try 25 | { 26 | *plpFileName = (LPWSTR)System::MmAlloc(MAX_PATH * sizeof(WCHAR), true); 27 | 28 | // 1. Check for argv[1] availability 29 | // 2. If not available start open dialog 30 | 31 | if (argc > 1) 32 | if (argv[1]) 33 | { 34 | Helpers::strcpyW(*plpFileName, argv[1]); 35 | return false; 36 | } 37 | if (!Helpers::ExecuteOpenFileDialog(L"Windows Image File (*.exe)\0*.exe\0All Files\0*.*\0", *plpFileName, MAX_PATH)) 38 | { 39 | System::MmFree(*plpFileName); 40 | *plpFileName = NULL; 41 | } 42 | return true; 43 | } 44 | __except(EXCEPTION_EXECUTE_HANDLER) 45 | { 46 | #ifdef _LDR_DEBUG_ 47 | System::SysDbgMessage(L"[X] Exception in %s [%s line %d]\n", __FUNCTIONW__, __FILEW__, __LINE__); 48 | #endif 49 | return System::SetErrorCode(E_EXCEPTION, true, __FUNCTIONW__); 50 | } 51 | } 52 | 53 | /* 54 | Description: 55 | Restarts loader if open dialog was showed 56 | Arguments: 57 | plpFileName - valid pointer to unicode string 58 | argc - arguments count (cmd) 59 | argv - argument variables (cmd) 60 | Return Value: 61 | int - error code 62 | */ 63 | int CheckImageFileName(LPWSTR *lpFileName, int argc, LPCWSTR *argv) 64 | { 65 | if (GetImageFileName(lpFileName, argc, argv)) 66 | { 67 | if (!*lpFileName) 68 | return System::SetErrorCode(E_FILE_IS_NULL, true); 69 | 70 | #ifdef _LDR_DEBUG_ 71 | System::SysDbgMessage(L"[I] Configure to launch: %s\n", *lpFileName); 72 | System::SysDbgMessage(L"[I] Disconnecting from pipe\n"); 73 | System::SysDbgMessage(L"\3"); // DBG_DISCONNECT 74 | #endif 75 | 76 | // If open dialog was showed program have to reload to free libraries 77 | 78 | __try 79 | { 80 | STARTUPINFOW sInfo; 81 | PROCESS_INFORMATION pInfo; 82 | memset(&sInfo, 0, sizeof(STARTUPINFOW)); 83 | memset(&pInfo, 0, sizeof(PROCESS_INFORMATION)); 84 | sInfo.cb = sizeof(STARTUPINFOW); 85 | LPWSTR lpCmd = (LPWSTR)System::MmAlloc(BUFFER_SIZE, true); 86 | swprintf(lpCmd, L"\"%s\" \"%s\"", 8, argv[0], *lpFileName); 87 | 88 | // Create loader process with new command line 89 | 90 | CreateProcessW(0, lpCmd, 0, 0, false, 0, 0, 0, &sInfo, &pInfo); 91 | System::MmFree(*lpFileName); 92 | System::MmFree(lpCmd); 93 | return System::SetErrorCode(E_FORWARDED); 94 | } 95 | __except(EXCEPTION_EXECUTE_HANDLER) 96 | { 97 | #ifdef _LDR_DEBUG_ 98 | System::SysDbgMessage(L"[X] Exception in %s [%s line %d]\n", __FUNCTIONW__, __FILEW__, __LINE__); 99 | #endif 100 | System::MmFree(*lpFileName); 101 | return System::SetErrorCode(E_EXCEPTION, true, __FUNCTIONW__); 102 | } 103 | } 104 | return System::SetErrorCode(E_SUCCESS); 105 | } 106 | 107 | /* 108 | Description: 109 | System main function (runs after SysInit and befor SysFree) 110 | Arguments: 111 | argc - arguments count (cmd) 112 | argv - argument variables (cmd) 113 | Return Value: 114 | int - error code 115 | */ 116 | int SysMain(int argc, LPCWSTR *argv) 117 | { 118 | LPWSTR lpFileName = NULL; 119 | int errorCode = 0; 120 | IMAGE_ACTIVATION_CONTEXT hActCtx; 121 | IMAGE_DESCRIPTOR image; 122 | 123 | // Obtain file name of image to execute 124 | 125 | if (CheckImageFileName(&lpFileName, argc, argv) != E_SUCCESS) 126 | return (System::GetErrorCode(false) == E_FORWARDED) ? E_FORWARDED : System::GetErrorCode(true); 127 | 128 | if (!lpFileName) 129 | return System::SetErrorCode(E_FILE_IS_NULL, true); 130 | 131 | // Map selected image 132 | 133 | if (LdrMapImage(&image, lpFileName) != E_SUCCESS) 134 | return System::GetErrorCode(true); 135 | 136 | // Patch process 137 | 138 | if (LdrPatchProcess(&image) != E_SUCCESS) 139 | return System::GetErrorCode(true); 140 | 141 | // Set process activation context 142 | 143 | errorCode = LdrSetDefaultActivationContext(&image, &hActCtx); 144 | if (errorCode != E_SUCCESS && errorCode != E_NO_MANIFEST) 145 | return System::GetErrorCode(true); 146 | 147 | // Execute loaded and mapped image 148 | 149 | errorCode = LdrExecuteImage(&image); 150 | 151 | // Free resources and restore process activation context 152 | // Normally ExitProcess should be called before 153 | 154 | LdrRestoreDefaultActivationContext(&hActCtx); 155 | System::MmFree(lpFileName); 156 | return errorCode; 157 | } 158 | -------------------------------------------------------------------------------- /loader/src/errors.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Global program error defenition 3 | */ 4 | 5 | #ifndef _ERRORS_H_ 6 | #define _ERRORS_H_ 7 | 8 | #define E_ERROR -1 // Error 9 | #define E_SUCCESS 0 // Success 10 | #define E_ALLOC_FAIL 1 // Allocation failed 11 | #define E_OPEN_FAIL 2 // CreateFile error 12 | #define E_EXCEPTION 3 // Excception occured 13 | #define E_MAP_FAIL 4 // CreateFileMapping error 14 | #define E_VIEW_FAIL 5 // MapViewOfFile error 15 | #define E_BASE_FAILED 10 // Failed to allocate image at base address 16 | #define E_VIRTUAL_FAILED 11 // Failed to allocate virtual memory 17 | #define E_RELOCATION_NOT_NEEDED 13 // Relocation isn't needed 18 | #define E_UNKNOWN_RELOC 14 // Unknown relocation type 19 | #define E_LIBRARY_FAIL 15 // Load library fail 20 | #define E_NO_IMPORT 17 // Image has no import data 21 | #define E_PROTECT_FAIL 18 // Failed to protect virtual memory 22 | #define E_NO_SYSTEM_DLL 20 // No system DLL (ntdll) found 23 | #define E_FREE_ERROR 21 // Failed to free heap memory 24 | #define E_NO_EXPORT 22 // Image contains no export data 25 | #define E_NO_EXPORT_NAMES 23 // Image export contains no names 26 | #define E_NO_ACCESS 25 // No memory access 27 | #define E_NO_EXPORT_PROC 26 // Image has no function with target name 28 | #define E_NO_ACTIVATION_CONTEXT 27 // Cannot create an activation context 29 | #define E_NO_MANIFEST 29 // Image has no manifest 30 | 31 | #define E_CUI_SUBSYSTEM_FAIL 31 // Failed to initialize CUI subsystem 32 | #define E_HASH_ERROR 32 // RtlHashUnicodeString fail 33 | #define E_HASH_HEAD_NOT_FOUND 33 // Failed to find hash table head 34 | #define E_INVALID_ARGUMENT 34 // Invalid parameter 35 | #define E_MODULE_NOT_FOUND 35 // Failed to obtain module handle 36 | #define E_FUNCTION_NOT_FOUND 36 // Failed to obtain import function address 37 | #define E_FUNCTION_NOT_FOUND_ORD 24 // Failed to obtain import function address (for ordinals) 38 | #define E_FILE_IS_NULL 37 // Failed to start loader, beacause source file path is null 39 | #define E_FORWARDED 38 // Loader have to forward himself 40 | #define E_REALLOC_FAIL 39 // Failed to reallocate memory 41 | 42 | #define E_MOVED_FREE_FAIL 40 // Failed to free old loader memory if loader was relocated 43 | #define E_LOADER_RELOCATION 41 // Loader needs to relocate 44 | 45 | #define E_THREAD_EXIT_CODE_FAIL 50 // Failed to get thread exit code 46 | #define E_CREATE_THREAD_FAIL 51 // Failed to create thread 47 | 48 | #define E_FILE_TOO_BIG 55 // File is bigger than 2GB 49 | 50 | #define E_HOOK_FAIL 60 // Failed to hook system api 51 | 52 | #define E_INVALID_SECTION 65 // PE Image has an invalid section 53 | 54 | #define E_BAD_DIRECTORY 70 // Invalid data directory 55 | 56 | #define E_NO_DOS_HEADER 100 // Image has no MZ DOS header 57 | #define E_NO_PE 101 // Image has no PE header 58 | #define E_MACHINE_NOT_I386 102 // Image can be launched only on i386-like 59 | #define E_NO_OPTIONAL_HEADER 103 // Image has no optional PE header 60 | #define E_NON_EXECUTABLE 104 // Image is non executable 61 | #define E_IMAGE_IS_DLL 105 // Attempt to load dll image 62 | #define E_IMAGE_IS_NOT_32BIT 106 // Image is not 32-bit 63 | #define E_AFFINITY_FAIL 107 // Image can be run only on single-processor machine, but set process affinity fails 64 | #define E_UNKNOWN_PE 108 // Unknown PE magic 65 | #define E_NO_ENTRYPOINT 109 // Image has no entry point 66 | #define E_BAD_ALIGNMENT 110 // Image alignment errors 67 | #define E_UNSUPPORTED_VERSION 111 // Image OS version is greater than the current OS 68 | #define E_UNSUPPORTED_SUBSYSTEM 112 // Unsupported image subsystem 69 | #define E_LOADER_OVERLAP 113 // Image overlaps with loader 70 | 71 | #define E_NOT_A_WIN32 150 // Image is not an application for Win32 72 | 73 | #define E_RELOCATION_NOT_FOUND 200 // Image has no relocations 74 | 75 | #define E_TLS_NOT_FOUND 300 // Image has no tls 76 | 77 | #define E_NO_ORIGINAL_THUNK 400 // Image has no original thunk data 78 | #define E_INVALID_IMPORT_NAME 401 // Image bound directory refs to invalid image 79 | #define E_IMPORT_NOT_FOUND 402 // Defined import (lib!func) not found 80 | 81 | #define E_SNAP_ERROR 500 // Failed to snap ntdll functions 82 | 83 | #define E_UNSUPPORTED_SYSTEM 600 // Unsupported Windows Version 84 | #define E_ACCESS_DENIED 601 // Access denied 85 | 86 | #endif // _ERRORS_H_ 87 | -------------------------------------------------------------------------------- /loader/loader.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {9b79a87a-1d84-43bc-97b5-8d0cd0e92304} 10 | 11 | 12 | {e5a8aa46-77e9-4e9a-b584-fc91e18bd21f} 13 | 14 | 15 | {a7f08d1a-12bb-49c0-bd19-a18d1527e155} 16 | 17 | 18 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 19 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 20 | 21 | 22 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 23 | h;hpp;hxx;hm;inl;inc;xsd 24 | 25 | 26 | {bc0d584d-f3c3-4545-ba00-9e964d4d2d92} 27 | 28 | 29 | {7da85747-640a-4370-83ae-1808b938597e} 30 | 31 | 32 | {d76ac8ae-fd0f-4e4f-b127-e0da46bd853d} 33 | 34 | 35 | 36 | 37 | Source 38 | 39 | 40 | Source\Loader 41 | 42 | 43 | Source\Loader 44 | 45 | 46 | Source\Loader 47 | 48 | 49 | Source\Loader 50 | 51 | 52 | Source\Loader 53 | 54 | 55 | Source\Loader 56 | 57 | 58 | Source\Loader 59 | 60 | 61 | Source\Loader 62 | 63 | 64 | Source\Loader 65 | 66 | 67 | Source\Loader 68 | 69 | 70 | Source\System 71 | 72 | 73 | Source\System 74 | 75 | 76 | Source\Helpers 77 | 78 | 79 | Source\Helpers 80 | 81 | 82 | Source\Helpers 83 | 84 | 85 | Source\Helpers 86 | 87 | 88 | Source\Helpers 89 | 90 | 91 | Source\Helpers 92 | 93 | 94 | 95 | 96 | Header 97 | 98 | 99 | Header 100 | 101 | 102 | Header\Loader 103 | 104 | 105 | Header\Loader 106 | 107 | 108 | Header\Loader 109 | 110 | 111 | Header\Loader 112 | 113 | 114 | Header\Helpers 115 | 116 | 117 | Header\Helpers 118 | 119 | 120 | Header\Helpers 121 | 122 | 123 | Header\Helpers 124 | 125 | 126 | Header\Helpers 127 | 128 | 129 | Header\Helpers 130 | 131 | 132 | Header\System 133 | 134 | 135 | Header\System 136 | 137 | 138 | Header\System 139 | 140 | 141 | Header 142 | 143 | 144 | 145 | 146 | Resource 147 | 148 | 149 | -------------------------------------------------------------------------------- /loader/src/system/system.h: -------------------------------------------------------------------------------- 1 | /* 2 | * System defenition 3 | */ 4 | 5 | #ifndef _SYSTEM_H_ 6 | #define _SYSTEM_H_ 7 | 8 | #include 9 | #include "dbgcl.h" 10 | #include "errors.h" 11 | #include "../loader/image_descriptor.h" 12 | 13 | #define BUFFER_SIZE 1024 // Max wvsprintfW buffer size 14 | 15 | #define ERROR_DATA_LEN 1024 // Max error data length 16 | #define ERROR_DATA_LEN_S 1025 // ERROR_DATA_LEN + 1 17 | 18 | #define MAX_MESSAGE_RESOURCE 512 // Max string resouce length 19 | 20 | #ifdef _LDR_DEBUG_ 21 | #define DEBUG_PIPE_NAME L"\\\\.\\pipe\\dbgldr" 22 | #endif 23 | 24 | #define VER_WINDOWS_XP 0x00050001 25 | #define VER_WINDOWS_SERVER_2003 0x00050002 26 | #define VER_WINDOWS_VISTA 0x00060000 27 | #define VER_WINDOWS_7 0x00060001 28 | #define VER_WINDOWS_8 0x00060002 29 | 30 | #define MAKE_PTR(cast, ptr, addValue) (cast)((DWORD)(ptr) + (DWORD)(addValue)) 31 | #define MAKE_LPVOID(ptr, addValue) (MAKE_PTR(LPVOID, (ptr), (addValue))) 32 | #define FLAGS_PRESENT(value, flags) (((value) & (flags)) == (flags)) 33 | #define IS_NULL(arg) ((arg) == NULL) 34 | #define MAKE_VERSION(major, minor) (DWORD)(((major) << 16) | (minor)) 35 | 36 | // Check if range [a1, b1] overlaps with [a2, b2] 37 | #define IS_RANGE_OVERLAPPED(a1, b1, a2, b2) (((b1) >= (a2)) && ((a1) <= (b2))) 38 | 39 | // Check if range [a1, a1 + sz1] overlaps with [a2, a2 + sz2] 40 | #define IS_RANGE_OVERLAPPED_SZ(a1, sz1, a2, sz2) (IS_RANGE_OVERLAPPED(a1, (a1) + (sz1), a2, (a2) + (sz2))) 41 | 42 | // Check if p in [a, b] 43 | #define IS_IN_RANGE(p, a, b) (IS_RANGE_OVERLAPPED(a, b, p, p)) 44 | 45 | // Check if p in [a, a + b] 46 | #define IS_IN_RANGE_SZ(p, a, s) (IS_IN_RANGE(p, a, (a) + (s))) 47 | 48 | #define IS_POWER_OF_2(x) (((x) != 0) && !((x) & ((x) - 1))) 49 | 50 | typedef struct _IMAGE_ACTIVATION_CONTEXT 51 | { 52 | HANDLE hOldActivationContext; 53 | HANDLE hActivationContext; 54 | HANDLE hFileActivationContext; 55 | ULONG_PTR ulFileCookie; 56 | } IMAGE_ACTIVATION_CONTEXT, *PIMAGE_ACTIVATION_CONTEXT; 57 | 58 | enum CallingConversion 59 | { 60 | ccStdcall, 61 | ccCdecl 62 | }; 63 | 64 | typedef struct _FILE_MAP 65 | { 66 | HANDLE hFileMap; 67 | DWORD dwFileSize; 68 | LPVOID lpView; 69 | LPWSTR lpFileName; 70 | } FILE_MAP, *PFILE_MAP; 71 | 72 | namespace System 73 | { 74 | 75 | typedef DWORD (*SYSCALL)(); 76 | 77 | typedef struct _SYSTEM_RELOCATION_DATA 78 | { 79 | LPVOID lpReqBase; 80 | DWORD dwReqSize; 81 | LPVOID lpJumpPoint; 82 | IMAGE_DESCRIPTOR relocatedLoader; 83 | } SYSTEM_RELOCATION_DATA, *PSYSTEM_RELOCATION_DATA; 84 | 85 | // Program run-time environment 86 | typedef struct _SYSTEM 87 | { 88 | IMAGE_DESCRIPTOR loader; // Loader image descriptor 89 | HANDLE hHeap; // Process heap 90 | HMODULE hSystemDll; // Pointer to ntdll 91 | HANDLE hPipe; // Debug pipe 92 | LPWSTR *argv; // Command line arguments 93 | int argc; // Command line arguments count 94 | LPWSTR lpCmdW; // Unicode command line for new module 95 | LPSTR lpCmdA; // Ansi command line for new module 96 | UNICODE_STRING lpFileNameW; // Unicode executable name 97 | UNICODE_STRING lpBaseNameW; // Unicode module name 98 | UNICODE_STRING lpNtFileNameW; // Unicode NT file name 99 | DWORD dwLastError; // Last error 100 | DWORD dwError; // Windows error code 101 | WCHAR lpErrorString[ERROR_DATA_LEN_S]; // Error data string 102 | BOOL bErrorFlag; // Set to 1 if error occured 103 | BOOL bBlockError; // Blocks critical error changes 104 | DWORD dwVersion; // Windows version 105 | DWORD dwProcessId; // Current process id 106 | SYSTEM_INFO sysInfo; // System information, such as granularity 107 | SYSTEM_RELOCATION_DATA sysRelocationData; // System relocation data for E_BASE_FAILED 108 | LPVOID lpTlsDataEntry; // TLS data entry for loader module 109 | } SYSTEM, *PSYSTEM; 110 | 111 | // Main system functions 112 | 113 | int EntryPoint(); 114 | int SysInit(); 115 | int SysFree(); 116 | 117 | // Callers 118 | 119 | DWORD SysCall(LPCSTR lpFunc, CallingConversion cc, DWORD dwStackSize, ...); 120 | DWORD CustomCall(DWORD dwRoutineAddress, CallingConversion cc, DWORD dwStackSize, ...); 121 | DWORD GetSysProcAddress(LPCSTR lpFunc); 122 | 123 | // Errors 124 | 125 | int SetErrorCode(int sysError, BOOL bMessage = false, ...); 126 | int GetErrorCode(BOOL bBlockError); 127 | void SetErrorBlock(BOOL bBlockError); 128 | int GetLastError(); 129 | 130 | // Memory 131 | 132 | LPVOID MmAlloc(size_t size, bool zeroMem); 133 | bool MmFree(LPVOID lpAllocation); 134 | LPVOID MmReAlloc(LPVOID lpMem, size_t size, bool zeroMem); 135 | int MmCreateMap(PFILE_MAP pFileMap, LPCWSTR lpFileName); 136 | LPVOID MmCreateView(PFILE_MAP pFileMap, DWORD dwOffset, DWORD dwSize); 137 | void MmFreeView(PFILE_MAP pFileMap); 138 | void MmFreeMap(PFILE_MAP pFileMap); 139 | 140 | // Input/Output 141 | 142 | HANDLE IoOpen(LPCWSTR fileName, DWORD dwDesiredAccess, DWORD dwCreationDisposition); 143 | void IoClose(HANDLE hFile); 144 | 145 | // System variables resolvers 146 | 147 | LPSTR GetActiveCommandLineA(); 148 | LPWSTR GetActiveCommandLineW(); 149 | LPWSTR GetCommandLineItem(DWORD dwIndex); 150 | PUNICODE_STRING GetExecutableFileName(); 151 | PUNICODE_STRING GetExecutableBaseName(); 152 | DWORD GetProcessId(); 153 | DWORD GetOSVersion(); 154 | LPSYSTEM_INFO GetSystemInfo(); 155 | PLDRP_TLS_ENTRY GetTlsEntry(); 156 | PUNICODE_STRING GetExecutableNtFileName(); 157 | 158 | // System data 159 | 160 | PLDR_DATA_TABLE_ENTRY GetSystemLdrTableEntry(HMODULE hModule); 161 | void SetRelocationData(LPVOID lpReqBase, DWORD dwReqSize); 162 | HMODULE GetHandle(); 163 | PIMAGE_DESCRIPTOR GetLoader(); 164 | 165 | // Debug 166 | 167 | #ifdef _LDR_DEBUG_ 168 | 169 | void SysDbgMessage(LPCWSTR lpMessage, ...); 170 | 171 | #endif 172 | 173 | } // namespace System 174 | 175 | #endif // _SYSTEM_H_ 176 | -------------------------------------------------------------------------------- /loader/src/loader/hash_patcher.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Windows loader data table hash patcher 3 | */ 4 | 5 | #include "loader.h" 6 | #include "../errors.h" 7 | #include "../system/syscalls.h" 8 | 9 | namespace WindowsXP 10 | { 11 | 12 | /* 13 | Description: 14 | Windows XP native loader hash function 15 | Arguments: 16 | pString - pointer to a valid uncode string 17 | pHashValue - pointer to hash value receiver 18 | Return Value: 19 | int - error code 20 | */ 21 | int HashUnicodeString(PUNICODE_STRING pString, PULONG pHashValue) 22 | { 23 | if (IS_NULL(pString) || IS_NULL(pHashValue)) 24 | return System::SetErrorCode(E_INVALID_ARGUMENT, true, __FUNCTIONW__); 25 | *pHashValue = 0; 26 | if (pString->Length != 0) 27 | *pHashValue = System::SysCall("RtlUpcaseUnicodeChar", ccStdcall, 4, pString->Buffer[0]) - 1; 28 | return System::SetErrorCode(E_SUCCESS); 29 | } 30 | 31 | } // namespace WindowsXP 32 | 33 | namespace Windows7 34 | { 35 | 36 | /* 37 | Description: 38 | Windows 7 native loader hash function 39 | Arguments: 40 | pString - pointer to a valid uncode string 41 | pHashValue - pointer to hash value receiver 42 | Return Value: 43 | int - error code 44 | */ 45 | int HashUnicodeString(PUNICODE_STRING pString, PULONG pHashValue) 46 | { 47 | if (IS_NULL(pString) || IS_NULL(pHashValue)) 48 | return System::SetErrorCode(E_INVALID_ARGUMENT, true, __FUNCTIONW__); 49 | HMODULE hSystemDll = GetModuleHandleW(L"ntdll.dll"); 50 | WCHAR (__stdcall *RtlUpcaseUnicodeChar)(WCHAR wChar) = NULL; 51 | RtlUpcaseUnicodeChar = (WCHAR (__stdcall *)(WCHAR))GetProcAddress(hSystemDll, "RtlUpcaseUnicodeChar"); 52 | if (IS_NULL(RtlUpcaseUnicodeChar)) 53 | return System::SetErrorCode(E_HASH_ERROR); 54 | *pHashValue = 0; 55 | if (pString->Length != 0) 56 | { 57 | LPCWCHAR lpChar = MAKE_PTR(LPCWCHAR, pString->Buffer, pString->Length - sizeof(WCHAR)); 58 | WCHAR wUpcase = 0; 59 | while (lpChar >= pString->Buffer) 60 | { 61 | wUpcase = RtlUpcaseUnicodeChar(*lpChar); 62 | *pHashValue += (ULONG)wUpcase * 0x1003F; 63 | --lpChar; 64 | } 65 | } 66 | return System::SetErrorCode(E_SUCCESS); 67 | } 68 | 69 | } // namespace Windows7 70 | 71 | /* 72 | Description: 73 | Windows 7/8 native loader hash functions assembly 74 | Arguments: 75 | lpString - pointer to a valid uncode string 76 | pHashValue - pointer to hash value receiver 77 | Return Value: 78 | int - error code 79 | */ 80 | int LdrHashUnicodeString(LPCWSTR lpString, PULONG pHashValue) 81 | { 82 | if (IS_NULL(pHashValue)) 83 | return System::SetErrorCode(E_INVALID_ARGUMENT, true, __FUNCTIONW__); 84 | UNICODE_STRING usData; 85 | RtlInitUnicodeString(&usData, lpString); 86 | switch (System::GetOSVersion()) 87 | { 88 | case VER_WINDOWS_8: 89 | if (RtlHashUnicodeString(&usData, true, 0, pHashValue) != 0) 90 | return System::SetErrorCode(E_HASH_ERROR); 91 | return System::SetErrorCode(E_SUCCESS); 92 | case VER_WINDOWS_7: 93 | return Windows7::HashUnicodeString(&usData, pHashValue); 94 | case VER_WINDOWS_XP: 95 | case VER_WINDOWS_SERVER_2003: 96 | case VER_WINDOWS_VISTA: 97 | return WindowsXP::HashUnicodeString(&usData, pHashValue); 98 | default: 99 | return System::SetErrorCode(E_UNSUPPORTED_SYSTEM); 100 | } 101 | return System::SetErrorCode(E_ERROR); 102 | } 103 | 104 | /* 105 | Description: 106 | Patches windows system loader hash table 107 | Arguments: 108 | pLdrEntry - pointer to a valid system loader data table entry 109 | lpOriginalName - original module name 110 | lpNewName - new module name 111 | Return Value: 112 | int - error code 113 | */ 114 | int LdrPatchHashTable(PLDR_DATA_TABLE_ENTRY pLdrEntry, LPCWSTR lpOriginalName, LPCWSTR lpNewName) 115 | { 116 | if (IS_NULL(pLdrEntry) || IS_NULL(lpOriginalName) || IS_NULL(lpNewName)) 117 | return System::SetErrorCode(E_INVALID_ARGUMENT, true, __FUNCTIONW__); 118 | __try 119 | { 120 | ULONG uHashValue = 0; 121 | if (LdrHashUnicodeString(lpOriginalName, &uHashValue) != E_SUCCESS) 122 | return System::GetErrorCode(false); 123 | 124 | // Try to find loader hash table first element 125 | // 1. calculate hash table index 126 | // 2. find hash table entry (head for hash links) 127 | // 3. get pointer to hash table 128 | 129 | DWORD dwTableIndex = uHashValue & LDR_HASH_TABLE_MASK; 130 | DWORD dwNtdllBase = (DWORD)GetModuleHandleW(L"ntdll.dll"); 131 | PLIST_ENTRY pHashLink = &pLdrEntry->HashLinks; 132 | 133 | // Find list head (list head is a static const value in the ntdll). 134 | 135 | PLIST_ENTRY pCurrentItem = pHashLink; 136 | PLIST_ENTRY pListCycle = pCurrentItem; 137 | do 138 | { 139 | pCurrentItem = pCurrentItem->Blink; 140 | } 141 | while (((DWORD)pCurrentItem < dwNtdllBase) && (pCurrentItem != pListCycle)); 142 | 143 | if (pCurrentItem == pListCycle) 144 | return System::SetErrorCode(E_HASH_HEAD_NOT_FOUND); 145 | 146 | PLIST_ENTRY pHashTable = (PLIST_ENTRY)((DWORD)pCurrentItem - dwTableIndex * sizeof(LIST_ENTRY)); 147 | ULONG uNewHash = 0; 148 | if (LdrHashUnicodeString(lpNewName, &uNewHash) != E_SUCCESS) 149 | return System::GetErrorCode(false); 150 | 151 | //Allow to write to ntdll memory 152 | 153 | DWORD dwOldProtect; 154 | if (!VirtualProtect(pHashTable, LDR_HASH_TABLE_SIZE * sizeof(LIST_ENTRY), PAGE_READWRITE, &dwOldProtect)) 155 | return System::SetErrorCode(E_ACCESS_DENIED); 156 | 157 | //Remove data from old hash list 158 | 159 | pHashLink->Blink->Flink = pHashLink->Flink; 160 | pHashLink->Flink->Blink = pHashLink->Blink; 161 | 162 | //Insert data into new hash entry 163 | 164 | DWORD dwNewIndex = uNewHash & LDR_HASH_TABLE_MASK; 165 | 166 | PLIST_ENTRY pNewHashList = pHashTable + dwNewIndex; 167 | LIST_ENTRY pHashListOrig = *pNewHashList; 168 | 169 | pHashListOrig.Blink->Flink = pHashLink; 170 | pHashLink->Blink = pHashListOrig.Blink; 171 | pNewHashList->Blink = pHashLink; 172 | pHashLink->Flink = pNewHashList; 173 | 174 | // Do the platform-dependent operations 175 | 176 | if (System::GetOSVersion() >= VER_WINDOWS_8) 177 | { 178 | ((Windows8::PLDR_DATA_TABLE_ENTRY)pLdrEntry)->BaseNameHashValue = uNewHash; 179 | } 180 | 181 | } 182 | __except(EXCEPTION_EXECUTE_HANDLER) 183 | { 184 | #ifdef _LDR_DEBUG_ 185 | System::SysDbgMessage(L"[X] Exception in %s [%s line %d]\n", __FUNCTIONW__, __FILEW__, __LINE__); 186 | #endif 187 | return System::SetErrorCode(E_EXCEPTION, true, __FUNCTIONW__); 188 | } 189 | return System::SetErrorCode(E_SUCCESS); 190 | } 191 | -------------------------------------------------------------------------------- /loader/src/loader/loader.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Image loader functions 3 | */ 4 | 5 | #include 6 | #include 7 | #include "loader.h" 8 | #include "../system/system.h" 9 | #include "../system/syscalls.h" 10 | #include "../errors.h" 11 | 12 | /* 13 | Description: 14 | Check parent console availability 15 | Return Value: 16 | BOOL - TRUE if parent have console 17 | */ 18 | bool LdrCheckParentConsole() 19 | { 20 | // Get parent process id 21 | 22 | int pid = -1; 23 | HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 24 | PROCESSENTRY32 pe; 25 | memset(&pe, 0, sizeof(pe)); 26 | pe.dwSize = sizeof(PROCESSENTRY32); 27 | pid = GetCurrentProcessId(); 28 | if(Process32First(hSnap, &pe)) 29 | { 30 | do 31 | { 32 | if (pe.th32ProcessID == pid) { 33 | pid = pe.th32ParentProcessID; 34 | break; 35 | } 36 | } 37 | while(Process32Next(hSnap, &pe)); 38 | } 39 | CloseHandle(hSnap); 40 | 41 | // Open parent process 42 | 43 | HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, pid); 44 | if (hProc == INVALID_HANDLE_VALUE) 45 | return false; 46 | 47 | // Get process PEB 48 | 49 | PROCESS_BASIC_INFORMATION pbi; 50 | if (System::SysCall("NtQueryInformationProcess", ccStdcall, 20, hProc, 0, &pbi, sizeof(pbi), 0) != 0) 51 | return false; 52 | 53 | // Get process parameters field "ConsoleHandle" 54 | 55 | LPVOID pProcParams = 0; 56 | DWORD dwReaded = 0; 57 | BOOL bRes = false; 58 | bRes = ReadProcessMemory(hProc, (PVOID)((DWORD)pbi.PebBaseAddress + FIELD_OFFSET(PEB, lpProcessParameters)), &pProcParams, 4, &dwReaded); 59 | if (!bRes || (dwReaded == 0)) 60 | return false; 61 | bRes = ReadProcessMemory(hProc, (PVOID)((DWORD)pProcParams + FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, ConsoleHandle)), &pProcParams, 4, &dwReaded); 62 | if (!bRes || (dwReaded == 0)) 63 | return false; 64 | if (pProcParams != 0) 65 | return true; 66 | return false; 67 | } 68 | 69 | /* 70 | Description: 71 | Check image data directory for availability 72 | Arguments: 73 | pImage - pointer to a valid image descriptor 74 | dwDataDirectory - data directory index 75 | Return Value: 76 | int - error code 77 | */ 78 | int LdrCheckDataDirectory(PIMAGE_DESCRIPTOR pImage, DWORD dwDataDirectory) 79 | { 80 | if (dwDataDirectory > pImage->pOptionalHeader->NumberOfRvaAndSizes) 81 | return System::SetErrorCode(E_BAD_DIRECTORY); 82 | PIMAGE_DATA_DIRECTORY pDirectory = &pImage->pOptionalHeader->DataDirectory[dwDataDirectory]; 83 | if ((pDirectory->VirtualAddress == 0) || 84 | (pDirectory->Size == 0)) 85 | return System::SetErrorCode(E_BAD_DIRECTORY); 86 | 87 | DWORD section = 0; 88 | PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)pImage->pSections; 89 | for (section = 0; section < pImage->pFileHeader->NumberOfSections; ++section, ++pSection) 90 | { 91 | if (IS_RANGE_OVERLAPPED_SZ(ROUND_DOWN(pSection->VirtualAddress, pImage->pOptionalHeader->SectionAlignment), 92 | min(pSection->Misc.VirtualSize, pSection->SizeOfRawData), 93 | pDirectory->VirtualAddress, 94 | pDirectory->Size)) 95 | { 96 | if (pSection->PointerToRawData != 0) 97 | return System::SetErrorCode(E_SUCCESS); 98 | } 99 | } 100 | 101 | return System::SetErrorCode(E_BAD_DIRECTORY); 102 | } 103 | 104 | /* 105 | Description: 106 | Check image subsystem information 107 | Allocates console if needed 108 | Arguments: 109 | pImage - pointer to a valid image descriptor 110 | Return Value: 111 | int - error code 112 | */ 113 | int LdrCheckCUI(PIMAGE_DESCRIPTOR pImage) 114 | { 115 | if (IS_NULL(pImage)) 116 | return System::SetErrorCode(E_INVALID_ARGUMENT, true, __FUNCTIONW__); 117 | __try 118 | { 119 | if (pImage->pOptionalHeader->Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI) 120 | { 121 | if (LdrCheckParentConsole()) 122 | { 123 | if (!AttachConsole(ATTACH_PARENT_PROCESS)) 124 | { 125 | if (!AllocConsole()) 126 | { 127 | return System::SetErrorCode(E_CUI_SUBSYSTEM_FAIL, true); 128 | } 129 | } 130 | } 131 | else 132 | { 133 | if (!AllocConsole()) 134 | { 135 | return System::SetErrorCode(E_CUI_SUBSYSTEM_FAIL, true); 136 | } 137 | } 138 | } 139 | } 140 | __except(EXCEPTION_EXECUTE_HANDLER) 141 | { 142 | #ifdef _LDR_DEBUG_ 143 | System::SysDbgMessage(L"[X] Exception in %s [%s line %d]\n", __FUNCTIONW__, __FILEW__, __LINE__); 144 | #endif 145 | return System::SetErrorCode(E_EXCEPTION, true, __FUNCTIONW__); 146 | } 147 | return System::SetErrorCode(E_SUCCESS); 148 | } 149 | 150 | /* 151 | Description: 152 | Execute the mapped image 153 | Arguments: 154 | pImage - pointer to a valid image descriptor 155 | Return Value: 156 | int - error code 157 | */ 158 | PIMAGE_DESCRIPTOR pExecutingImage; // global image descriptor used for some api stubs 159 | 160 | int LdrExecuteImage(PIMAGE_DESCRIPTOR pImage) 161 | { 162 | if (IS_NULL(pImage)) 163 | return System::SetErrorCode(E_INVALID_ARGUMENT, true, __FUNCTIONW__); 164 | 165 | #ifdef _LDR_DEBUG_ 166 | System::SysDbgMessage(L"[I] Preparing for executing\n"); 167 | #endif 168 | // Set global image descriptor pointer 169 | 170 | pExecutingImage = pImage; 171 | 172 | // Save system API 173 | 174 | LdrSnapApi(); 175 | 176 | DWORD lpEntryPoint = MAKE_PTR(DWORD, pImage->pImageBase, pImage->pOptionalHeader->AddressOfEntryPoint); 177 | int errorCode = E_SUCCESS; 178 | 179 | // Prepare for executing 180 | // 1. Check for console UI and allocates the console if needed 181 | // 2. Setup API 182 | // 3. Process relocations 183 | // 4. Process image imports 184 | // 5. Protect image sections 185 | // 6. Initialize TLS 186 | 187 | #ifdef _LDR_DEBUG_ 188 | System::SysDbgMessage(L"[I] Check for CUI\n"); 189 | #endif 190 | if (LdrCheckCUI(pImage) != E_SUCCESS) 191 | return System::GetErrorCode(true); 192 | 193 | #ifdef _LDR_DEBUG_ 194 | System::SysDbgMessage(L"[I] Setup API\n"); 195 | #endif 196 | if (LdrSetupApi() != E_SUCCESS) 197 | return System::GetErrorCode(true); 198 | 199 | #ifdef _LDR_DEBUG_ 200 | System::SysDbgMessage(L"[I] Process relocations\n"); 201 | #endif 202 | errorCode = LdrProcessRelocations(pImage); 203 | if (errorCode != E_SUCCESS && errorCode != E_RELOCATION_NOT_NEEDED) 204 | return System::GetErrorCode(true); 205 | 206 | #ifdef _LDR_DEBUG_ 207 | System::SysDbgMessage(L"[I] Process imports\n"); 208 | #endif 209 | if (LdrProcessImports(pImage) != E_SUCCESS) 210 | return System::GetErrorCode(true); 211 | 212 | // Continue anyway if protection fails 213 | 214 | LdrProtectSections(pImage); 215 | 216 | #ifdef _LDR_DEBUG_ 217 | System::SysDbgMessage(L"[I] Initialize TLS\n"); 218 | #endif 219 | errorCode = LdrInitializeTls(pImage, &System::GetTlsEntry()->Tls, true); 220 | if (errorCode != E_SUCCESS && errorCode != E_TLS_NOT_FOUND) 221 | return System::GetErrorCode(true); 222 | 223 | // All preparations done. Call image entrypoint 224 | 225 | #ifdef _LDR_DEBUG_ 226 | System::SysDbgMessage(L"[I] Detegate flow\n"); 227 | #endif 228 | 229 | __asm call lpEntryPoint; 230 | 231 | // Exit process 232 | 233 | __asm mov errorCode, eax; 234 | ExitProcess(errorCode); 235 | } 236 | -------------------------------------------------------------------------------- /loader/loader.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {CA8BF6A1-326E-4480-938B-69F4F6B5CEBD} 15 | Loader 16 | loader 17 | 8.1 18 | 19 | 20 | 21 | Application 22 | true 23 | MultiByte 24 | v120_xp 25 | 26 | 27 | Application 28 | false 29 | false 30 | MultiByte 31 | v120_xp 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | false 45 | $(SolutionDir)build\$(Configuration)\ 46 | $(ProjectName) 47 | build\$(Configuration)\ 48 | 49 | 50 | false 51 | $(SolutionDir)build\$(Configuration)\ 52 | $(ProjectName) 53 | build\$(Configuration)\ 54 | 55 | 56 | 57 | Level3 58 | Disabled 59 | false 60 | UNICODE;_LDR_DEBUG_;PSAPI_VERSION=1;%(PreprocessorDefinitions) 61 | false 62 | Default 63 | MultiThreadedDebug 64 | 65 | 66 | false 67 | 68 | 69 | true 70 | psapi.lib;%(AdditionalDependencies) 71 | Windows 72 | System::EntryPoint 73 | 0x08400000 74 | false 75 | false 76 | false 77 | false 78 | 79 | 80 | 81 | 82 | Level3 83 | Disabled 84 | 85 | 86 | false 87 | false 88 | UNICODE;PSAPI_VERSION=1;%(PreprocessorDefinitions) 89 | false 90 | Default 91 | MultiThreaded 92 | 93 | 94 | false 95 | true 96 | Default 97 | ProgramDatabase 98 | 99 | 100 | false 101 | 102 | 103 | 104 | 105 | psapi.lib;%(AdditionalDependencies) 106 | Windows 107 | System::EntryPoint 108 | 0x40400000 109 | false 110 | false 111 | false 112 | true 113 | true 114 | false 115 | 5.01 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | -------------------------------------------------------------------------------- /loader/src/helpers/cmd.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Command line helper 3 | * This file use a part of dlls/shell32/shell32_main.c from Wine project 4 | * (http://sourceforge.net/projects/wine/files/Source/) 5 | */ 6 | 7 | /* 8 | * Shell basics 9 | * 10 | * Copyright 1998 Marcus Meissner 11 | * Copyright 1998 Juergen Schmied (jsch) * 12 | * 13 | * This library is free software; you can redistribute it and/or 14 | * modify it under the terms of the GNU Lesser General Public 15 | * License as published by the Free Software Foundation; either 16 | * version 2.1 of the License, or (at your option) any later version. 17 | * 18 | * This library is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 | * Lesser General Public License for more details. 22 | * 23 | * You should have received a copy of the GNU Lesser General Public 24 | * License along with this library; if not, write to the Free Software 25 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 26 | */ 27 | 28 | 29 | #include "../system/syscalls.h" 30 | #include "cmd.h" 31 | #include "strings.h" 32 | 33 | namespace Helpers 34 | { 35 | 36 | LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs) 37 | { 38 | DWORD argc; 39 | LPWSTR *argv; 40 | LPCWSTR s; 41 | LPWSTR d; 42 | LPWSTR cmdline; 43 | int qcount,bcount; 44 | 45 | if(!numargs) 46 | { 47 | SetLastError(ERROR_INVALID_PARAMETER); 48 | return NULL; 49 | } 50 | 51 | if (*lpCmdline==0) 52 | { 53 | /* Return the path to the executable */ 54 | DWORD len, deslen=MAX_PATH, size; 55 | 56 | size = sizeof(LPWSTR) + deslen*sizeof(WCHAR) + sizeof(LPWSTR); 57 | for (;;) 58 | { 59 | if (!(argv = (LPWSTR*)LocalAlloc(LMEM_FIXED, size))) return NULL; 60 | len = GetModuleFileNameW(0, (LPWSTR)(argv+1), deslen); 61 | if (!len) 62 | { 63 | LocalFree(argv); 64 | return NULL; 65 | } 66 | if (len < deslen) break; 67 | deslen*=2; 68 | size = sizeof(LPWSTR) + deslen*sizeof(WCHAR) + sizeof(LPWSTR); 69 | LocalFree( argv ); 70 | } 71 | argv[0]=(LPWSTR)(argv+1); 72 | *numargs=1; 73 | 74 | return argv; 75 | } 76 | 77 | /* --- First count the arguments */ 78 | argc=1; 79 | s=lpCmdline; 80 | /* The first argument, the executable path, follows special rules */ 81 | if (*s=='"') 82 | { 83 | /* The executable path ends at the next quote, no matter what */ 84 | s++; 85 | while (*s) 86 | if (*s++=='"') 87 | break; 88 | } 89 | else 90 | { 91 | /* The executable path ends at the next space, no matter what */ 92 | while (*s && *s!=' ' && *s!='\t') 93 | s++; 94 | } 95 | /* skip to the first argument, if any */ 96 | while (*s==' ' || *s=='\t') 97 | s++; 98 | if (*s) 99 | argc++; 100 | 101 | /* Analyze the remaining arguments */ 102 | qcount=bcount=0; 103 | while (*s) 104 | { 105 | if ((*s==' ' || *s=='\t') && qcount==0) 106 | { 107 | /* skip to the next argument and count it if any */ 108 | while (*s==' ' || *s=='\t') 109 | s++; 110 | if (*s) 111 | argc++; 112 | bcount=0; 113 | } 114 | else if (*s=='\\') 115 | { 116 | /* '\', count them */ 117 | bcount++; 118 | s++; 119 | } 120 | else if (*s=='"') 121 | { 122 | /* '"' */ 123 | if ((bcount & 1)==0) 124 | qcount++; /* unescaped '"' */ 125 | s++; 126 | bcount=0; 127 | /* consecutive quotes, see comment in copying code below */ 128 | while (*s=='"') 129 | { 130 | qcount++; 131 | s++; 132 | } 133 | qcount=qcount % 3; 134 | if (qcount==2) 135 | qcount=0; 136 | } 137 | else 138 | { 139 | /* a regular character */ 140 | bcount=0; 141 | s++; 142 | } 143 | } 144 | 145 | /* Allocate in a single lump, the string array, and the strings that go 146 | * with it. This way the caller can make a single LocalFree() call to free 147 | * both, as per MSDN. 148 | */ 149 | argv = (LPWSTR*)LocalAlloc(LMEM_FIXED, argc*sizeof(LPWSTR)+(strlenW(lpCmdline)+1)*sizeof(WCHAR)); 150 | if (!argv) 151 | return NULL; 152 | cmdline=(LPWSTR)(argv+argc); 153 | strcpyW(cmdline, lpCmdline); 154 | 155 | /* --- Then split and copy the arguments */ 156 | argv[0]=d=cmdline; 157 | argc=1; 158 | /* The first argument, the executable path, follows special rules */ 159 | if (*d=='"') 160 | { 161 | /* The executable path ends at the next quote, no matter what */ 162 | s=d+1; 163 | while (*s) 164 | { 165 | if (*s=='"') 166 | { 167 | s++; 168 | break; 169 | } 170 | *d++=*s++; 171 | } 172 | } 173 | else 174 | { 175 | /* The executable path ends at the next space, no matter what */ 176 | while (*d && *d!=' ' && *d!='\t') 177 | d++; 178 | s=d; 179 | if (*s) 180 | s++; 181 | } 182 | /* close the executable path */ 183 | *d++=0; 184 | /* skip to the first argument and initialize it if any */ 185 | while (*s==' ' || *s=='\t') 186 | s++; 187 | if (!*s) 188 | { 189 | /* There are no parameters so we are all done */ 190 | *numargs=argc; 191 | return argv; 192 | } 193 | 194 | /* Split and copy the remaining arguments */ 195 | argv[argc++]=d; 196 | qcount=bcount=0; 197 | while (*s) 198 | { 199 | if ((*s==' ' || *s=='\t') && qcount==0) 200 | { 201 | /* close the argument */ 202 | *d++=0; 203 | bcount=0; 204 | 205 | /* skip to the next one and initialize it if any */ 206 | do { 207 | s++; 208 | } while (*s==' ' || *s=='\t'); 209 | if (*s) 210 | argv[argc++]=d; 211 | } 212 | else if (*s=='\\') 213 | { 214 | *d++=*s++; 215 | bcount++; 216 | } 217 | else if (*s=='"') 218 | { 219 | if ((bcount & 1)==0) 220 | { 221 | /* Preceded by an even number of '\', this is half that 222 | * number of '\', plus a quote which we erase. 223 | */ 224 | d-=bcount/2; 225 | qcount++; 226 | } 227 | else 228 | { 229 | /* Preceded by an odd number of '\', this is half that 230 | * number of '\' followed by a '"' 231 | */ 232 | d=d-bcount/2-1; 233 | *d++='"'; 234 | } 235 | s++; 236 | bcount=0; 237 | /* Now count the number of consecutive quotes. Note that qcount 238 | * already takes into account the opening quote if any, as well as 239 | * the quote that lead us here. 240 | */ 241 | while (*s=='"') 242 | { 243 | if (++qcount==3) 244 | { 245 | *d++='"'; 246 | qcount=0; 247 | } 248 | s++; 249 | } 250 | if (qcount==2) 251 | qcount=0; 252 | } 253 | else 254 | { 255 | /* a regular character */ 256 | *d++=*s++; 257 | bcount=0; 258 | } 259 | } 260 | *d='\0'; 261 | *numargs=argc; 262 | 263 | return argv; 264 | } 265 | 266 | } -------------------------------------------------------------------------------- /loader/src/loader/activation_context.cpp: -------------------------------------------------------------------------------- 1 | #include "loader.h" 2 | #include "../errors.h" 3 | #include "../helpers.h" 4 | #include "../system/syscalls.h" 5 | 6 | /* 7 | Description: 8 | Finds first RT_MANIFEST resource 9 | Arguments: 10 | pImage - pointer to a valid image descriptor 11 | lpName - pointer to the variable that receives the name pointer 12 | Return Value: 13 | BOOL - true if resource was found 14 | */ 15 | BOOL LdrFindManifestResource(PIMAGE_DESCRIPTOR pImage, LPWSTR *lpName) 16 | { 17 | if (IS_NULL(pImage) || IS_NULL(lpName)) 18 | return false; 19 | 20 | if (LdrCheckDataDirectory(pImage, IMAGE_DIRECTORY_ENTRY_RESOURCE) != E_SUCCESS) 21 | return false; 22 | 23 | // Fall into root "type" directory 24 | 25 | LPVOID lpBase = MAKE_PTR(PIMAGE_RESOURCE_DIRECTORY, pImage->pImageBase, 26 | pImage->pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress); 27 | 28 | PIMAGE_RESOURCE_DIRECTORY pResourceDirectory = (PIMAGE_RESOURCE_DIRECTORY)lpBase; 29 | PIMAGE_RESOURCE_DIRECTORY_ENTRY pResourceEntry = MAKE_PTR(PIMAGE_RESOURCE_DIRECTORY_ENTRY, lpBase, 30 | sizeof(IMAGE_RESOURCE_DIRECTORY)); 31 | pResourceEntry += pResourceDirectory->NumberOfNamedEntries; 32 | for (int i = 0; i < pResourceDirectory->NumberOfIdEntries; ++i, ++pResourceEntry) 33 | { 34 | 35 | // if resource entry is RT_MANIFEST 36 | 37 | if (pResourceEntry->Id == (WORD)RT_MANIFEST) 38 | { 39 | if (pResourceEntry->DataIsDirectory) 40 | { 41 | 42 | // Fall into "name" directory 43 | 44 | pResourceDirectory = MAKE_PTR(PIMAGE_RESOURCE_DIRECTORY, lpBase, 45 | pResourceEntry->OffsetToDirectory); 46 | pResourceEntry = MAKE_PTR(PIMAGE_RESOURCE_DIRECTORY_ENTRY, pResourceDirectory, 47 | sizeof(IMAGE_RESOURCE_DIRECTORY)); 48 | 49 | // Get the first resource name 50 | 51 | if (pResourceDirectory->NumberOfNamedEntries + pResourceDirectory->NumberOfIdEntries) 52 | { 53 | if (pResourceEntry->NameIsString) 54 | { 55 | PIMAGE_RESOURCE_DIRECTORY_STRING pString = MAKE_PTR(PIMAGE_RESOURCE_DIRECTORY_STRING, lpBase, 56 | pResourceEntry->NameOffset); 57 | *lpName = (LPWSTR)System::MmAlloc((pString->Length + 1) * sizeof(WCHAR), true); 58 | memcpy(*lpName, pString->NameString, (pString->Length + 1) * sizeof(WCHAR)); 59 | } 60 | else 61 | { 62 | *lpName = (LPWSTR)pResourceEntry->Id; 63 | } 64 | } 65 | break; 66 | } 67 | } 68 | } 69 | return true; 70 | } 71 | 72 | /* 73 | Description: 74 | Sets process default activation context 75 | Arguments: 76 | pImage - pointer to a valid image descriptor 77 | pActivationContext - pointer to an image activation context what receive created context 78 | Return Value: 79 | int - error code 80 | */ 81 | int LdrSetDefaultActivationContext(PIMAGE_DESCRIPTOR pImage, PIMAGE_ACTIVATION_CONTEXT pActivationContext) 82 | { 83 | if (IS_NULL(pImage) || IS_NULL(pActivationContext)) 84 | return System::SetErrorCode(E_INVALID_ARGUMENT, true, __FUNCTIONW__); 85 | LPWSTR lpDirectory = NULL; 86 | __try 87 | { 88 | PPEB pPeb = NtCurrentTeb()->Peb; 89 | pActivationContext->hActivationContext = INVALID_HANDLE_VALUE; 90 | pActivationContext->hFileActivationContext = INVALID_HANDLE_VALUE; 91 | pActivationContext->ulFileCookie = 0; 92 | pActivationContext->hOldActivationContext = pPeb->lpActivationContextData; 93 | 94 | ACTCTXW actCtx; 95 | memset(&actCtx, 0, sizeof(ACTCTXW)); 96 | actCtx.cbSize = sizeof(actCtx); 97 | 98 | // Firstly try to find first RT_MANIFEST resource 99 | 100 | DWORD dwLength = Helpers::strlenW(System::GetExecutableFileName()->Buffer); 101 | lpDirectory = (LPWSTR)System::MmAlloc((dwLength + 1) * sizeof(WCHAR), true); 102 | lpDirectory = Helpers::ExtractFileDirectory(System::GetExecutableFileName()->Buffer, lpDirectory); 103 | 104 | LPWSTR lpName = NULL; 105 | bool bLoaded = false; 106 | LdrFindManifestResource(pImage, &lpName); 107 | 108 | // If resource found try to create activation context from it 109 | 110 | if (!IS_NULL(lpName)) 111 | { 112 | actCtx.dwFlags = ACTCTX_FLAG_HMODULE_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID; 113 | actCtx.hModule = (HMODULE)pImage->pImageBase; 114 | actCtx.lpResourceName = lpName; 115 | actCtx.lpAssemblyDirectory = lpDirectory; 116 | pActivationContext->hActivationContext = CreateActCtxW(&actCtx); 117 | if (pActivationContext->hActivationContext != INVALID_HANDLE_VALUE) 118 | { 119 | bLoaded = true; 120 | } 121 | #ifdef _LDR_DEBUG_ 122 | else 123 | { 124 | System::SysDbgMessage(L"[W] CreateActCtx return invalid handle value, error: 0x%08X\n", GetLastError()); 125 | } 126 | #endif 127 | if (!IS_INTRESOURCE(lpName)) 128 | System::MmFree(lpName); 129 | } 130 | #ifdef _LDR_DEBUG_ 131 | else 132 | { 133 | LPCWSTR lpFileName = Helpers::ExtractFileName(System::GetExecutableFileName()->Buffer); 134 | System::SysDbgMessage(L"[W] Image contain no manifest resources, check for %s.manifest\n", lpFileName); 135 | } 136 | #endif 137 | 138 | // try to load data from "filename.extension.manifest" 139 | 140 | memset(&actCtx, 0, sizeof(ACTCTXW)); 141 | actCtx.cbSize = sizeof(actCtx); 142 | actCtx.lpAssemblyDirectory = lpDirectory; 143 | actCtx.dwFlags = ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID; 144 | 145 | LPWSTR lpManifest = (LPWSTR)System::MmAlloc((dwLength + 10) * sizeof(WCHAR), true); 146 | memcpy(lpManifest, System::GetExecutableFileName()->Buffer, dwLength * sizeof(WCHAR)); 147 | memcpy(lpManifest + dwLength, L".manifest", 9 * sizeof(WCHAR)); 148 | 149 | actCtx.lpSource = lpManifest; 150 | pActivationContext->hFileActivationContext = CreateActCtxW(&actCtx); 151 | System::MmFree(lpManifest); 152 | if ((pActivationContext->hFileActivationContext != INVALID_HANDLE_VALUE) || 153 | (pActivationContext->hActivationContext != INVALID_HANDLE_VALUE)) 154 | { 155 | bLoaded = true; 156 | } 157 | #ifdef _LDR_DEBUG_ 158 | else 159 | { 160 | System::SysDbgMessage(L"[W] CreateActCtx return invalid handle value, error: 0x%08X\n", GetLastError()); 161 | } 162 | #endif 163 | 164 | if (!bLoaded) 165 | { 166 | // If both, resource nor manifest file not exists or have invalid data 167 | 168 | #ifdef _LDR_DEBUG_ 169 | System::SysDbgMessage(L"[W] Application has no manifest\n"); 170 | #endif 171 | System::MmFree(lpDirectory); 172 | return System::SetErrorCode(E_NO_MANIFEST); 173 | } 174 | 175 | // Set process default activation context data 176 | pActivationContext->ulFileCookie = 0; 177 | if ((pActivationContext->hFileActivationContext != INVALID_HANDLE_VALUE) && 178 | (pActivationContext->hActivationContext != INVALID_HANDLE_VALUE)) 179 | ActivateActCtx(pActivationContext->hFileActivationContext, &pActivationContext->ulFileCookie); 180 | 181 | DWORD actCtxOffset = 0; 182 | 183 | switch (System::GetOSVersion()) 184 | { 185 | case VER_WINDOWS_XP: 186 | case VER_WINDOWS_SERVER_2003: 187 | actCtxOffset = ACTIVATION_CONTEXT_DATA_OFFSET_XP; 188 | break; 189 | case VER_WINDOWS_VISTA: 190 | case VER_WINDOWS_7: 191 | case VER_WINDOWS_8: 192 | actCtxOffset = ACTIVATION_CONTEXT_DATA_OFFSET_WIN8; 193 | break; 194 | } 195 | if (pActivationContext->hActivationContext != INVALID_HANDLE_VALUE) 196 | pPeb->lpActivationContextData = (LPVOID)*MAKE_PTR(PDWORD, pActivationContext->hActivationContext, actCtxOffset); 197 | else if (pActivationContext->hFileActivationContext != INVALID_HANDLE_VALUE) 198 | pPeb->lpActivationContextData = (LPVOID)*MAKE_PTR(PDWORD, pActivationContext->hFileActivationContext, actCtxOffset); 199 | } // __try 200 | __except(EXCEPTION_EXECUTE_HANDLER) 201 | { 202 | #ifdef _LDR_DEBUG_ 203 | System::SysDbgMessage(L"[X] Exception in %s [%s line %d]\n", __FUNCTIONW__, __FILEW__, __LINE__); 204 | #endif 205 | System::MmFree(lpDirectory); 206 | return System::SetErrorCode(E_EXCEPTION, true, __FUNCTIONW__); 207 | } 208 | System::MmFree(lpDirectory); 209 | return System::SetErrorCode(E_SUCCESS); 210 | } 211 | 212 | /* 213 | Description: 214 | Restore process default activation context 215 | Arguments: 216 | pActivationContext - pointer to an image activation context 217 | Return Value: 218 | int - error code 219 | */ 220 | int LdrRestoreDefaultActivationContext(PIMAGE_ACTIVATION_CONTEXT pActivationContext) 221 | { 222 | if (IS_NULL(pActivationContext)) 223 | return System::SetErrorCode(E_INVALID_ARGUMENT, true, __FUNCTIONW__); 224 | __try 225 | { 226 | PPEB pPeb = NtCurrentTeb()->Peb; 227 | 228 | if (pActivationContext->ulFileCookie != 0) 229 | DeactivateActCtx(0, pActivationContext->ulFileCookie); 230 | 231 | pPeb->lpActivationContextData = pActivationContext->hOldActivationContext; 232 | if (pActivationContext->hActivationContext != INVALID_HANDLE_VALUE) 233 | ReleaseActCtx(pActivationContext->hActivationContext); 234 | if (pActivationContext->hFileActivationContext != INVALID_HANDLE_VALUE) 235 | ReleaseActCtx(pActivationContext->hFileActivationContext); 236 | } 237 | __except(EXCEPTION_EXECUTE_HANDLER) 238 | { 239 | #ifdef _LDR_DEBUG_ 240 | System::SysDbgMessage(L"[X] Exception in %s [%s line %d]\n", __FUNCTIONW__, __FILEW__, __LINE__); 241 | #endif 242 | return System::SetErrorCode(E_EXCEPTION, true, __FUNCTIONW__); 243 | } 244 | return System::SetErrorCode(E_SUCCESS); 245 | } 246 | -------------------------------------------------------------------------------- /loader/src/helpers/format.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * wvsprintfW helper 3 | * This file use a part of dlls/shlwapi/wsprintf.c from Wine project 4 | * (http://sourceforge.net/projects/wine/files/Source/) 5 | */ 6 | 7 | /* 8 | * wsprintf functions 9 | * 10 | * Copyright 1996 Alexandre Julliard 11 | * 12 | * This library is free software; you can redistribute it and/or 13 | * modify it under the terms of the GNU Lesser General Public 14 | * License as published by the Free Software Foundation; either 15 | * version 2.1 of the License, or (at your option) any later version. 16 | * 17 | * This library is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | * Lesser General Public License for more details. 21 | * 22 | * You should have received a copy of the GNU Lesser General Public 23 | * License along with this library; if not, write to the Free Software 24 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 25 | * 26 | */ 27 | 28 | #include "../system/syscalls.h" 29 | #include "format.h" 30 | 31 | namespace Helpers 32 | { 33 | 34 | static const CHAR null_stringA[] = "(null)"; 35 | static const WCHAR null_stringW[] = { '(', 'n', 'u', 'l', 'l', ')', 0 }; 36 | 37 | INT WPRINTF_ParseFormatW( LPCWSTR format, WPRINTF_FORMAT *res ) 38 | { 39 | LPCWSTR p = format; 40 | 41 | res->flags = 0; 42 | res->width = 0; 43 | res->precision = 0; 44 | if (*p == '-') { res->flags |= WPRINTF_LEFTALIGN; p++; } 45 | if (*p == '#') { res->flags |= WPRINTF_PREFIX_HEX; p++; } 46 | if (*p == '0') { res->flags |= WPRINTF_ZEROPAD; p++; } 47 | while ((*p >= '0') && (*p <= '9')) /* width field */ 48 | { 49 | res->width = res->width * 10 + *p - '0'; 50 | p++; 51 | } 52 | if (*p == '.') /* precision field */ 53 | { 54 | p++; 55 | while ((*p >= '0') && (*p <= '9')) 56 | { 57 | res->precision = res->precision * 10 + *p - '0'; 58 | p++; 59 | } 60 | } 61 | if (*p == 'l') { res->flags |= WPRINTF_LONG; p++; } 62 | else if (*p == 'h') { res->flags |= WPRINTF_SHORT; p++; } 63 | else if (*p == 'w') { res->flags |= WPRINTF_WIDE; p++; } 64 | else if (*p == 'I') 65 | { 66 | if (p[1] == '6' && p[2] == '4') { res->flags |= WPRINTF_I64; p += 3; } 67 | else if (p[1] == '3' && p[2] == '2') p += 3; 68 | else { res->flags |= WPRINTF_INTPTR; p++; } 69 | } 70 | switch(*p) 71 | { 72 | case 'c': 73 | res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR; 74 | break; 75 | case 'C': 76 | res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR; 77 | break; 78 | case 'd': 79 | case 'i': 80 | res->type = WPR_SIGNED; 81 | break; 82 | case 's': 83 | res->type = ((res->flags & WPRINTF_SHORT) && !(res->flags & WPRINTF_WIDE)) ? WPR_STRING : WPR_WSTRING; 84 | break; 85 | case 'S': 86 | res->type = (res->flags & (WPRINTF_LONG|WPRINTF_WIDE)) ? WPR_WSTRING : WPR_STRING; 87 | break; 88 | case 'u': 89 | res->type = WPR_UNSIGNED; 90 | break; 91 | case 'p': 92 | res->width = 2 * sizeof(void *); 93 | res->flags |= WPRINTF_ZEROPAD | WPRINTF_INTPTR; 94 | /* fall through */ 95 | case 'X': 96 | res->flags |= WPRINTF_UPPER_HEX; 97 | /* fall through */ 98 | case 'x': 99 | res->type = WPR_HEXA; 100 | break; 101 | default: 102 | res->type = WPR_UNKNOWN; 103 | p--; /* print format as normal char */ 104 | break; 105 | } 106 | return (INT)(p - format) + 1; 107 | } 108 | 109 | UINT WPRINTF_GetLen( WPRINTF_FORMAT *format, WPRINTF_DATA *arg, 110 | LPSTR number, UINT maxlen ) 111 | { 112 | UINT len; 113 | 114 | if (format->flags & WPRINTF_LEFTALIGN) format->flags &= ~WPRINTF_ZEROPAD; 115 | if (format->width > maxlen) format->width = maxlen; 116 | switch(format->type) 117 | { 118 | case WPR_CHAR: 119 | case WPR_WCHAR: 120 | return (format->precision = 1); 121 | case WPR_STRING: 122 | if (!arg->lpcstr_view) arg->lpcstr_view = null_stringA; 123 | for (len = 0; !format->precision || (len < format->precision); len++) 124 | if (!*(arg->lpcstr_view + len)) break; 125 | if (len > maxlen) len = maxlen; 126 | return (format->precision = len); 127 | case WPR_WSTRING: 128 | if (!arg->lpcwstr_view) arg->lpcwstr_view = null_stringW; 129 | for (len = 0; !format->precision || (len < format->precision); len++) 130 | if (!*(arg->lpcwstr_view + len)) break; 131 | if (len > maxlen) len = maxlen; 132 | return (format->precision = len); 133 | case WPR_SIGNED: 134 | case WPR_UNSIGNED: 135 | case WPR_HEXA: 136 | { 137 | const char *digits = (format->flags & WPRINTF_UPPER_HEX) ? "0123456789ABCDEF" : "0123456789abcdef"; 138 | ULONGLONG num = arg->int_view; 139 | int base = format->type == WPR_HEXA ? 16 : 10; 140 | char buffer[20], *p = buffer, *dst = number; 141 | 142 | if (format->type == WPR_SIGNED && arg->int_view < 0) 143 | { 144 | *dst++ = '-'; 145 | num = -arg->int_view; 146 | } 147 | if (format->flags & WPRINTF_INTPTR) num = (UINT_PTR)num; 148 | else if (!(format->flags & WPRINTF_I64)) num = (UINT)num; 149 | 150 | do 151 | { 152 | *p++ = digits[num % base]; 153 | num /= base; 154 | } while (num); 155 | while (p > buffer) *dst++ = *(--p); 156 | *dst = 0; 157 | len = dst - number; 158 | break; 159 | } 160 | default: 161 | return 0; 162 | } 163 | if (len > maxlen) len = maxlen; 164 | if (format->precision < len) format->precision = len; 165 | if (format->precision > maxlen) format->precision = maxlen; 166 | if ((format->flags & WPRINTF_ZEROPAD) && (format->width > format->precision)) 167 | format->precision = format->width; 168 | if (format->flags & WPRINTF_PREFIX_HEX) len += 2; 169 | return len; 170 | } 171 | 172 | INT wvsnprintfW( LPWSTR buffer, UINT maxlen, LPCWSTR spec, va_list args ) 173 | { 174 | WPRINTF_FORMAT format; 175 | LPWSTR p = buffer; 176 | UINT i, len, sign; 177 | CHAR number[21]; /* 64bit number can be 18446744073709551616 which is 20 chars. and a \0 */ 178 | WPRINTF_DATA argData; 179 | 180 | while (*spec && (maxlen > 1)) 181 | { 182 | if (*spec != '%') { *p++ = *spec++; maxlen--; continue; } 183 | spec++; 184 | if (*spec == '%') { *p++ = *spec++; maxlen--; continue; } 185 | spec += WPRINTF_ParseFormatW( spec, &format ); 186 | 187 | switch(format.type) 188 | { 189 | case WPR_WCHAR: 190 | argData.wchar_view = (WCHAR)va_arg( args, int ); 191 | break; 192 | case WPR_CHAR: 193 | argData.char_view = (CHAR)va_arg( args, int ); 194 | break; 195 | case WPR_STRING: 196 | argData.lpcstr_view = va_arg( args, LPCSTR ); 197 | break; 198 | case WPR_WSTRING: 199 | argData.lpcwstr_view = va_arg( args, LPCWSTR ); 200 | break; 201 | case WPR_HEXA: 202 | case WPR_SIGNED: 203 | case WPR_UNSIGNED: 204 | if (format.flags & WPRINTF_INTPTR) argData.int_view = va_arg(args, INT_PTR); 205 | else if (format.flags & WPRINTF_I64) argData.int_view = va_arg(args, LONGLONG); 206 | else argData.int_view = va_arg(args, INT); 207 | break; 208 | default: 209 | argData.wchar_view = 0; 210 | break; 211 | } 212 | 213 | len = WPRINTF_GetLen( &format, &argData, number, maxlen - 1 ); 214 | sign = 0; 215 | if (!(format.flags & WPRINTF_LEFTALIGN)) 216 | for (i = format.precision; i < format.width; i++, maxlen--) 217 | *p++ = ' '; 218 | switch(format.type) 219 | { 220 | case WPR_WCHAR: 221 | *p++ = argData.wchar_view; 222 | break; 223 | case WPR_CHAR: 224 | *p++ = argData.char_view; 225 | break; 226 | case WPR_STRING: 227 | { 228 | LPCSTR ptr = argData.lpcstr_view; 229 | for (i = 0; i < len; i++) *p++ = (BYTE)*ptr++; 230 | } 231 | break; 232 | case WPR_WSTRING: 233 | if (len) memcpy( p, argData.lpcwstr_view, len * sizeof(WCHAR) ); 234 | p += len; 235 | break; 236 | case WPR_HEXA: 237 | if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3)) 238 | { 239 | *p++ = '0'; 240 | *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x'; 241 | maxlen -= 2; 242 | len -= 2; 243 | } 244 | /* fall through */ 245 | case WPR_SIGNED: 246 | /* Transfer the sign now, just in case it will be zero-padded*/ 247 | if (number[0] == '-') 248 | { 249 | *p++ = '-'; 250 | sign = 1; 251 | } 252 | /* fall through */ 253 | case WPR_UNSIGNED: 254 | for (i = len; i < format.precision; i++, maxlen--) *p++ = '0'; 255 | for (i = sign; i < len; i++) *p++ = (BYTE)number[i]; 256 | break; 257 | case WPR_UNKNOWN: 258 | continue; 259 | } 260 | if (format.flags & WPRINTF_LEFTALIGN) 261 | for (i = format.precision; i < format.width; i++, maxlen--) 262 | *p++ = ' '; 263 | maxlen -= len; 264 | } 265 | *p = 0; 266 | return (maxlen > 1) ? (INT)(p - buffer) : -1; 267 | } 268 | 269 | INT WINAPI wvsprintfW( LPWSTR buffer, LPCWSTR spec, va_list args ) 270 | { 271 | INT res = wvsnprintfW( buffer, 1024, spec, args ); 272 | return ( res == -1 ) ? 1024 : res; 273 | } 274 | 275 | } // namespace Helpers -------------------------------------------------------------------------------- /loader/src/loader/api_stubs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Windows system API stubs/wrappers 3 | */ 4 | 5 | #include "api_stubs.h" 6 | #include "../system/system.h" 7 | 8 | #include "../errors.h" 9 | #include "ntldr.h" 10 | #include "loader.h" 11 | 12 | #define BOOL_STRING(value) ((value)) ? L"true" : L"false" 13 | 14 | SystemApi::SYSCALL_POINTERS_SNAP SysCallSnap; // System calls snap holder 15 | 16 | // Some defines for debug output support 17 | 18 | #ifdef _LDR_DEBUG_ 19 | #define LdrSetExportAddressEx(pImage, lpName, lpNewAddress, dwCode) \ 20 | dwCode = LdrSetExportAddress(pImage, lpName, lpNewAddress); \ 21 | System::SysDbgMessage(L"[I] Setup API \"%S\": %s (%d)\n", (lpName), ((dwCode) == E_SUCCESS) ? L"ok" : L"fail", (dwCode)) 22 | #else 23 | #define LdrSetExportAddressEx(pImage, lpName, lpNewAddress, dwCode) \ 24 | dwCode = LdrSetExportAddress(pImage, lpName, lpNewAddress) 25 | #endif 26 | 27 | #ifdef _LDR_DEBUG_ 28 | #define LdrSetImportAddressEx(pImage, lpLib, lpName, lpAddress, dwCode) \ 29 | dwCode = LdrSetImportAddress(pImage, lpLib, lpName, lpAddress);\ 30 | System::SysDbgMessage(L"[I] Setup import \"%S\": %s (%d)\n", (lpName), ((dwCode) == E_SUCCESS) ? L"ok" : L"fail", (dwCode)) 31 | #else 32 | #define LdrSetImportAddressEx(pImage, lpLib, lpName, lpAddress, dwCode) \ 33 | dwCode = LdrSetImportAddress(pImage, lpLib, lpName, lpAddress) 34 | #endif 35 | 36 | /* 37 | Description: 38 | Snap system call addresses 39 | Return Value: 40 | int - error code 41 | */ 42 | int LdrSnapApi() 43 | { 44 | HMODULE hSystemDll = GetModuleHandleW(L"ntdll.dll"); 45 | HMODULE hKernel32 = GetModuleHandleW(L"kernel32.dll"); 46 | 47 | if (IS_NULL(hSystemDll) || IS_NULL(hKernel32)) 48 | return System::SetErrorCode(E_MODULE_NOT_FOUND, true, L"ntdll.dll"); 49 | 50 | SysCallSnap.NtQueryInformationProcess = (DWORD)GetProcAddress(hSystemDll, "NtQueryInformationProcess"); 51 | SysCallSnap.NtQuerySystemInformation = (DWORD)GetProcAddress(hSystemDll, "NtQuerySystemInformation"); 52 | SysCallSnap.NtQueryVirtualMemory = (DWORD)GetProcAddress(hSystemDll, "NtQueryVirtualMemory"); 53 | 54 | SysCallSnap.GetCommandLineA = (DWORD)GetProcAddress(hKernel32, "GetCommandLineA"); 55 | SysCallSnap.GetCommandLineW = (DWORD)GetProcAddress(hKernel32, "GetCommandLineW"); 56 | SysCallSnap.ExitProcess = (DWORD)GetProcAddress(hKernel32, "ExitProcess"); 57 | 58 | for (int i = 0; i < (sizeof(SysCallSnap) / sizeof(DWORD)); ++i) 59 | if (IS_NULL(*MAKE_PTR(PDWORD, &SysCallSnap, i * sizeof(DWORD)))) 60 | return System::SetErrorCode(E_SNAP_ERROR); 61 | 62 | return System::SetErrorCode(E_SUCCESS); 63 | } 64 | 65 | /* 66 | Description: 67 | Setup system API stubs 68 | Return Value: 69 | int - error code 70 | */ 71 | int LdrSetupApi() 72 | { 73 | DWORD dwErrorCode = 0; 74 | PIMAGE_DESCRIPTOR pKernel = LdrObtainImageDescriptor(GetModuleHandleA("kernel32.dll")); 75 | PIMAGE_DESCRIPTOR pKernelBase = LdrObtainImageDescriptor(GetModuleHandleA("kernelbase.dll")); 76 | PIMAGE_DESCRIPTOR pSystemDll = LdrObtainImageDescriptor(GetModuleHandleA("ntdll.dll")); 77 | PIMAGE_DESCRIPTOR pPsapi = LdrObtainImageDescriptor(GetModuleHandleA("psapi.dll")); 78 | if (IS_NULL(pKernel)) 79 | return System::SetErrorCode(E_MODULE_NOT_FOUND, true, L"kernel32.dll"); 80 | if (IS_NULL(pSystemDll)) 81 | return System::SetErrorCode(E_MODULE_NOT_FOUND, true, L"ntdll.dll"); 82 | if (IS_NULL(pPsapi)) 83 | return System::SetErrorCode(E_MODULE_NOT_FOUND, true, L"psapi.dll"); 84 | 85 | // Replace kernel32 API 86 | 87 | LdrSetExportAddressEx(pKernel, "ExitProcess", SystemApi::ExitProcess, dwErrorCode); 88 | LdrSetExportAddressEx(pKernel, "GetCommandLineA", SystemApi::GetCommandLineA, dwErrorCode); 89 | LdrSetExportAddressEx(pKernel, "GetCommandLineW", SystemApi::GetCommandLineW, dwErrorCode); 90 | 91 | // Replace native API 92 | 93 | LdrSetExportAddressEx(pSystemDll, "NtQueryInformationProcess", SystemApi::NtQueryInformationProcess, dwErrorCode); 94 | LdrSetExportAddressEx(pSystemDll, "NtQuerySystemInformation", SystemApi::NtQuerySystemInformation, dwErrorCode); 95 | LdrSetExportAddressEx(pSystemDll, "NtQueryVirtualMemory", SystemApi::NtQueryVirtualMemory, dwErrorCode); 96 | 97 | // Replace native links in kernel32.dll / kernelbase.dll (>= Windows Vista) 98 | 99 | LdrSetImportAddressEx(pKernel, "ntdll.dll", "NtQueryInformationProcess", SystemApi::NtQueryInformationProcess, dwErrorCode); 100 | LdrSetImportAddressEx(pKernel, "ntdll.dll", "NtQuerySystemInformation", SystemApi::NtQuerySystemInformation, dwErrorCode); 101 | LdrSetImportAddressEx(pKernel, "ntdll.dll", "NtQueryVirtualMemory", SystemApi::NtQueryVirtualMemory, dwErrorCode); 102 | 103 | if (!IS_NULL(pKernelBase)) // For Windows XP compatibility 104 | { 105 | LdrSetImportAddressEx(pKernelBase, "ntdll.dll", "NtQueryInformationProcess", SystemApi::NtQueryInformationProcess, dwErrorCode); 106 | LdrSetImportAddressEx(pKernelBase, "ntdll.dll", "NtQuerySystemInformation", SystemApi::NtQuerySystemInformation, dwErrorCode); 107 | LdrSetImportAddressEx(pKernelBase, "ntdll.dll", "NtQueryVirtualMemory", SystemApi::NtQueryVirtualMemory, dwErrorCode); 108 | } 109 | 110 | // Replace native links in psapi.dll for Windows XP/Vista 111 | 112 | if (System::GetOSVersion() <= VER_WINDOWS_VISTA) 113 | { 114 | LdrSetImportAddressEx(pPsapi, "ntdll.dll", "NtQueryInformationProcess", SystemApi::NtQueryInformationProcess, dwErrorCode); 115 | LdrSetImportAddressEx(pPsapi, "ntdll.dll", "NtQuerySystemInformation", SystemApi::NtQuerySystemInformation, dwErrorCode); 116 | LdrSetImportAddressEx(pPsapi, "ntdll.dll", "NtQueryVirtualMemory", SystemApi::NtQueryVirtualMemory, dwErrorCode); 117 | } 118 | 119 | // Set these dlls time to zero to force bound image import table refresh 120 | 121 | System::GetSystemLdrTableEntry((HMODULE)pKernel->pImageBase)->TimeDateStamp = 0; 122 | if (!IS_NULL(pKernelBase)) 123 | System::GetSystemLdrTableEntry((HMODULE)pKernelBase->pImageBase)->TimeDateStamp = 0; 124 | System::GetSystemLdrTableEntry((HMODULE)pSystemDll->pImageBase)->TimeDateStamp = 0; 125 | System::GetSystemLdrTableEntry((HMODULE)pPsapi->pImageBase)->TimeDateStamp = 0; 126 | 127 | LdrProtectSections(pKernel); 128 | LdrCloseImageDescriptor(pKernel); 129 | LdrProtectSections(pKernelBase); 130 | LdrCloseImageDescriptor(pKernelBase); 131 | LdrProtectSections(pSystemDll); 132 | LdrCloseImageDescriptor(pSystemDll); 133 | LdrProtectSections(pPsapi); 134 | LdrCloseImageDescriptor(pPsapi); 135 | 136 | return System::SetErrorCode(E_SUCCESS); 137 | } 138 | 139 | namespace SystemApi 140 | { 141 | 142 | /* 143 | ExitProcess API stub 144 | */ 145 | void WINAPI ExitProcess(UINT uCode) 146 | { 147 | #if defined(_LDR_DEBUG_) && defined(_LDR_DEBUG_VERBOSE_) 148 | System::SysDbgMessage(L"[H] ExitProcess\n"); 149 | System::SysDbgMessage(L" uCode: %d\n", uCode); 150 | #endif 151 | System::CustomCall(SysCallSnap.ExitProcess, ccStdcall, 4, uCode); 152 | } 153 | 154 | /* 155 | GetCommandLineA API stub 156 | */ 157 | LPSTR WINAPI GetCommandLineA() 158 | { 159 | #if defined(_LDR_DEBUG_) && defined(_LDR_DEBUG_VERBOSE_) 160 | System::SysDbgMessage(L"[-H] GetCommandLineA\n"); 161 | #endif 162 | return System::GetActiveCommandLineA(); 163 | } 164 | 165 | /* 166 | GetCommandLineW API stub 167 | */ 168 | LPWSTR WINAPI GetCommandLineW() 169 | { 170 | #if defined(_LDR_DEBUG_) && defined(_LDR_DEBUG_VERBOSE_) 171 | System::SysDbgMessage(L"[-H] GetCommandLineW\n"); 172 | #endif 173 | return System::GetActiveCommandLineW(); 174 | } 175 | 176 | /* 177 | NtQueryInformationProcess API stub 178 | do the real query and 179 | fill fields with appropriate values if needed 180 | */ 181 | NTSTATUS WINAPI NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, 182 | PVOID ProcessInformation, ULONG ProcessInformationLength, 183 | PULONG ReturnLength) 184 | { 185 | #if defined(_LDR_DEBUG_) && defined(_LDR_DEBUG_VERBOSE_) 186 | System::SysDbgMessage(L"[-H] NtQueryInformationProcess\n"); 187 | System::SysDbgMessage(L" ProcessInformationClass: %d\n", ProcessInformationClass); 188 | #endif 189 | NTSTATUS ntStatus = System::CustomCall(SysCallSnap.NtQueryInformationProcess, ccStdcall, 20, ProcessHandle, ProcessInformationClass, 190 | ProcessInformation, ProcessInformationLength, ReturnLength); 191 | 192 | PROCESS_BASIC_INFORMATION pPbi; 193 | NTSTATUS ntResult = System::CustomCall(SysCallSnap.NtQueryInformationProcess, ccStdcall, 20, ProcessHandle, ProcessBasicInformation, 194 | &pPbi, sizeof(PROCESS_BASIC_INFORMATION), NULL); 195 | 196 | if ((ntResult == 0) && 197 | (ntStatus == 0) && 198 | ((ProcessHandle == (HANDLE)-1 || 199 | pPbi.UniqueProcessId == (HANDLE)System::GetProcessId()) && 200 | !IS_NULL(ProcessInformation))) 201 | { 202 | 203 | // Change real executable file name 204 | // Change executable params 205 | 206 | if (ProcessInformationClass == ProcessImageFileNameWin32) 207 | *(PUNICODE_STRING)ProcessInformation= *System::GetExecutableFileName(); 208 | else if (ProcessInformationClass == ProcessImageFileName) 209 | *(PUNICODE_STRING)ProcessInformation = *System::GetExecutableNtFileName(); 210 | else if (ProcessInformationClass == ProcessImageInformation) 211 | { 212 | PSECTION_IMAGE_INFORMATION iInf = (PSECTION_IMAGE_INFORMATION)ProcessInformation; 213 | iInf->TransferAddress = MAKE_PTR(PVOID, pExecutingImage->pImageBase, pExecutingImage->pOptionalHeader->AddressOfEntryPoint); 214 | iInf->CheckSum = pExecutingImage->pOptionalHeader->CheckSum; 215 | iInf->DllCharacteristics = pExecutingImage->pOptionalHeader->DllCharacteristics; 216 | iInf->ImageFileSize = pExecutingImage->dwImageFileSize; 217 | iInf->ImageCharacteristics = pExecutingImage->pFileHeader->Characteristics; 218 | iInf->SubSystemType = pExecutingImage->pOptionalHeader->Subsystem; 219 | iInf->SubSystemMajorVersion = pExecutingImage->pOptionalHeader->MajorSubsystemVersion; 220 | iInf->SubSystemMinorVersion = pExecutingImage->pOptionalHeader->MinorSubsystemVersion; 221 | } 222 | } 223 | #if defined(_LDR_DEBUG_) && defined(_LDR_DEBUG_VERBOSE_) 224 | System::SysDbgMessage(L" procId: %d\n", pPbi.UniqueProcessId); 225 | System::SysDbgMessage(L" result: 0x%08X\n", ntStatus); 226 | #endif 227 | return ntStatus; 228 | } 229 | 230 | /* 231 | NtQuerySystemInformation API stub 232 | do the real query and 233 | fill fields with appropriate values if needed 234 | */ 235 | NTSTATUS WINAPI NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, 236 | ULONG SystemInformationLength, PULONG ReturnLength) 237 | { 238 | #if defined(_LDR_DEBUG_) && defined(_LDR_DEBUG_VERBOSE_) 239 | System::SysDbgMessage(L"[-H] NtQuerySystemInformation\n"); 240 | System::SysDbgMessage(L" SystemInformationClass: %d\n", SystemInformationClass); 241 | #endif 242 | NTSTATUS ntStatus = System::CustomCall(SysCallSnap.NtQuerySystemInformation, ccStdcall, 16, SystemInformationClass, SystemInformation, 243 | SystemInformationLength, ReturnLength); 244 | if ((SystemInformationClass == SystemProcessInformation || 245 | SystemInformationClass == SystemExtendedProcessInformation) && 246 | !IS_NULL(SystemInformation) && 247 | (ntStatus == 0)) 248 | { 249 | PSYSTEM_PROCESS_INFORMATION pSpiHead = (PSYSTEM_PROCESS_INFORMATION)SystemInformation; 250 | PSYSTEM_PROCESS_INFORMATION pSpi = pSpiHead; 251 | HANDLE CurentProcessId = (HANDLE)System::GetProcessId(); 252 | while (true) 253 | { 254 | if (pSpi->UniqueProcessId == CurentProcessId) 255 | { 256 | pSpi->ImageName = *System::GetExecutableBaseName(); 257 | } 258 | if (pSpi->NextEntryOffset == NULL) 259 | break; 260 | pSpi = MAKE_PTR(PSYSTEM_PROCESS_INFORMATION, pSpi, pSpi->NextEntryOffset); 261 | } 262 | } 263 | #if defined(_LDR_DEBUG_) && defined(_LDR_DEBUG_VERBOSE_) 264 | System::SysDbgMessage(L" result: 0x%08X\n", ntStatus); 265 | #endif 266 | return ntStatus; 267 | } 268 | 269 | /* 270 | NtQueryVirtualMemory API stub 271 | do the real query and 272 | fill fields with appropriate values if needed 273 | shows that the mapped image has SEC_IMAGE flag 274 | (used for exception handler validation in _ValidateEH3RN) 275 | */ 276 | NTSTATUS WINAPI NtQueryVirtualMemory(HANDLE ProcessHandle, PVOID BaseAddress, 277 | MEMORY_INFORMATION_CLASS MemoryInformationClass, PVOID MemoryInformation, 278 | SIZE_T MemoryInformationLength, PSIZE_T ReturnLength) 279 | { 280 | #if defined(_LDR_DEBUG_) && defined(_LDR_DEBUG_VERBOSE_) 281 | System::SysDbgMessage(L"[-H] NtQueryVirtualMemory\n"); 282 | System::SysDbgMessage(L" BaseAddress: 0x%08X\n", BaseAddress); 283 | System::SysDbgMessage(L" MemoryInformationClass: %d\n", MemoryInformationClass); 284 | #endif 285 | NTSTATUS ntStatus = System::CustomCall(SysCallSnap.NtQueryVirtualMemory, ccStdcall, 24, ProcessHandle, BaseAddress, 286 | MemoryInformationClass, MemoryInformation, 287 | MemoryInformationLength, ReturnLength); 288 | PROCESS_BASIC_INFORMATION pPbi; 289 | NTSTATUS ntResult = System::CustomCall(SysCallSnap.NtQueryInformationProcess, ccStdcall, 20, ProcessHandle, ProcessBasicInformation, 290 | &pPbi, sizeof(PROCESS_BASIC_INFORMATION), NULL); 291 | if ((ntResult == 0) && 292 | (ntStatus == 0) && 293 | ((ProcessHandle == (HANDLE)-1 || pPbi.UniqueProcessId == (HANDLE)System::GetProcessId()) && 294 | !IS_NULL(MemoryInformation))) 295 | { 296 | if (MemoryInformationClass == MemoryBasicInformation) 297 | { 298 | if (((DWORD)BaseAddress >= (DWORD)pExecutingImage->pImageBase) && 299 | ((DWORD)BaseAddress <= MAKE_PTR(DWORD, pExecutingImage->pImageBase, 300 | pExecutingImage->pOptionalHeader->SizeOfImage))) 301 | { 302 | PMEMORY_BASIC_INFORMATION32 pMbi = (PMEMORY_BASIC_INFORMATION32)MemoryInformation; 303 | pMbi->Type = MEM_IMAGE; 304 | } 305 | } 306 | } 307 | #if defined(_LDR_DEBUG_) && defined(_LDR_DEBUG_VERBOSE_) 308 | System::SysDbgMessage(L" procId: %d\n", pPbi.UniqueProcessId); 309 | System::SysDbgMessage(L" result: 0x%08X\n", ntStatus); 310 | #endif 311 | return ntStatus; 312 | } 313 | 314 | } // namespace SystemApi 315 | -------------------------------------------------------------------------------- /loader/src/loader/dependencies.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Image import & export table helpers 3 | */ 4 | 5 | #include 6 | #include 7 | #include "loader.h" 8 | #include "../errors.h" 9 | #include "../helpers.h" 10 | 11 | /* 12 | Description: 13 | Set section (which contains selected data directory) protection flags to "rwe" 14 | Arguments: 15 | pImage - pointer to a valid image descriptor 16 | dwDataDirectory - data directory code 17 | */ 18 | void LdrAllowImageDirectoryAccess(PIMAGE_DESCRIPTOR pImage, DWORD dwDataDirectory) 19 | { 20 | __try 21 | { 22 | if (LdrCheckDataDirectory(pImage, dwDataDirectory) != E_SUCCESS) 23 | return; 24 | DWORD dwDirectory = pImage->pOptionalHeader->DataDirectory[dwDataDirectory].VirtualAddress; 25 | PIMAGE_SECTION_HEADER pSection = (PIMAGE_SECTION_HEADER)pImage->pSections; 26 | DWORD dwProtect = 0; 27 | 28 | // Scan image sections to find section which contains data directory 29 | 30 | for (int section = 0; section < pImage->pFileHeader->NumberOfSections; ++section, ++pSection) 31 | { 32 | if (IS_IN_RANGE_SZ(dwDirectory, pSection->VirtualAddress, pSection->Misc.VirtualSize)) 33 | { 34 | VirtualProtect(MAKE_LPVOID(pImage->pImageBase, pSection->VirtualAddress), 35 | pSection->Misc.VirtualSize, PAGE_EXECUTE_WRITECOPY, &dwProtect); 36 | break; 37 | } 38 | } 39 | } 40 | __except(EXCEPTION_EXECUTE_HANDLER) 41 | { 42 | #ifdef _LDR_DEBUG_ 43 | System::SysDbgMessage(L"[X] Exception in %s [%s line %d]\n", __FUNCTIONW__, __FILEW__, __LINE__); 44 | #endif //_LDR_DEBUG_ 45 | } 46 | } 47 | 48 | /* 49 | LdrSetExportAddress helper routine (For details see: LdrSetExportAddress) 50 | */ 51 | int LdrSetExportAddressHelper(PIMAGE_DESCRIPTOR pImage, LPCSTR lpName, LPVOID lpAddress) 52 | { 53 | if (IS_NULL(pImage) || IS_NULL(lpName)) 54 | return System::SetErrorCode(E_INVALID_ARGUMENT, true, __FUNCTIONW__); 55 | __try 56 | { 57 | if (LdrCheckDataDirectory(pImage, IMAGE_DIRECTORY_ENTRY_EXPORT) != E_SUCCESS) 58 | return System::SetErrorCode(E_NO_EXPORT); 59 | PIMAGE_EXPORT_DIRECTORY pExport = MAKE_PTR(PIMAGE_EXPORT_DIRECTORY, pImage->pImageBase, 60 | pImage->pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); 61 | if (IS_NULL(pExport)) 62 | return System::SetErrorCode(E_NO_EXPORT); 63 | if (pExport->NumberOfNames == 0) 64 | return System::SetErrorCode(E_NO_EXPORT_NAMES); 65 | 66 | // Scan image export directory for matching name (lpName) 67 | 68 | PDWORD pName = (PDWORD)pExport->AddressOfNames; 69 | PWORD pOrdinals = MAKE_PTR(PWORD, pImage->pImageBase, pExport->AddressOfNameOrdinals); 70 | for (unsigned int i = 0; i < pExport->NumberOfNames; ++i, ++pName) 71 | { 72 | DWORD dwNameAddr = (DWORD)pImage->pImageBase + (DWORD)pName; 73 | dwNameAddr = (DWORD)pImage->pImageBase + *(DWORD*)dwNameAddr; 74 | LPSTR lpExportName = (LPSTR)(dwNameAddr); 75 | if (Helpers::strcmpA(lpName, lpExportName) == 0) 76 | { 77 | PDWORD dwExportAddress = MAKE_PTR(PDWORD, pImage->pImageBase, 78 | pExport->AddressOfFunctions + sizeof(PDWORD) * (pOrdinals[i])); 79 | __try 80 | { 81 | *dwExportAddress = (DWORD)lpAddress - (DWORD)pImage->pImageBase; 82 | } 83 | __except(EXCEPTION_EXECUTE_HANDLER) 84 | { 85 | #ifdef _LDR_DEBUG_ 86 | System::SysDbgMessage(L"[X] Exception in %s [%s line %d]\n", __FUNCTIONW__, __FILEW__, __LINE__); 87 | #endif //_LDR_DEBUG_ 88 | return System::SetErrorCode(E_NO_ACCESS); 89 | } 90 | return System::SetErrorCode(E_SUCCESS); 91 | } 92 | } 93 | return System::SetErrorCode(E_NO_EXPORT_PROC); 94 | } 95 | __except(EXCEPTION_EXECUTE_HANDLER) 96 | { 97 | #ifdef _LDR_DEBUG_ 98 | System::SysDbgMessage(L"[X] Exception in %s [%s line %d]\n", __FUNCTIONW__, __FILEW__, __LINE__); 99 | #endif //_LDR_DEBUG_ 100 | return System::SetErrorCode(E_EXCEPTION, true, __FUNCTIONW__); 101 | } 102 | } 103 | 104 | /* 105 | Description: 106 | Replace selected function pointer in the image export table to the defined value 107 | Arguments: 108 | pImage - pointer to a valid image descriptor 109 | lpName - export function name 110 | lpNewAddress - new address of exported function 111 | Return Value: 112 | int - error code 113 | */ 114 | int LdrSetExportAddress(PIMAGE_DESCRIPTOR pImage, LPCSTR lpName, LPVOID lpNewAddress) 115 | { 116 | int errorCode = LdrSetExportAddressHelper(pImage, lpName, lpNewAddress); 117 | if (errorCode == E_NO_ACCESS) 118 | { 119 | // Try to get access to exported function table if program naven't it yet 120 | 121 | LdrAllowImageDirectoryAccess(pImage, IMAGE_DIRECTORY_ENTRY_EXPORT); 122 | errorCode = LdrSetExportAddressHelper(pImage, lpName, lpNewAddress); 123 | } 124 | return errorCode; 125 | } 126 | 127 | /* 128 | Description: 129 | Binds image import thunk 130 | Arguments: 131 | pImageBase - pointer to a valid image base address 132 | hBindLibrary - handle of the binding library 133 | pLookup - address of image lookup table entry 134 | pThunk - address of image thunk table entry 135 | Return Value: 136 | int - error code 137 | */ 138 | int LdrBindImportThunk(LPVOID pImageBase, HMODULE hBindLibrary, PIMAGE_THUNK_DATA pLookup, PIMAGE_THUNK_DATA pThunk) 139 | { 140 | DWORD dwOriginalThunk = pLookup->u1.Function; 141 | if(pLookup->u1.Ordinal & IMAGE_ORDINAL_FLAG) 142 | pThunk->u1.Function = (DWORD)GetProcAddress(hBindLibrary, (char*)(IMAGE_ORDINAL(pLookup->u1.Ordinal))); 143 | else 144 | pThunk->u1.Function = (DWORD)GetProcAddress(hBindLibrary, (LPCSTR)(MAKE_PTR(PIMAGE_IMPORT_BY_NAME, 145 | pImageBase, pLookup->u1.AddressOfData))->Name); 146 | if (IS_NULL(pThunk->u1.Function)) 147 | { 148 | 149 | WCHAR lpLibraryName[MAX_PATH]; 150 | GetModuleBaseNameW((HANDLE)-1, hBindLibrary, lpLibraryName, MAX_PATH); 151 | #ifdef _LDR_DEBUG_ 152 | if(dwOriginalThunk & IMAGE_ORDINAL_FLAG) 153 | System::SysDbgMessage(L"[E] Failed to obtain address of index %d from %s\n", 154 | IMAGE_ORDINAL(pLookup->u1.Ordinal), lpLibraryName); 155 | else 156 | System::SysDbgMessage(L"[E] Failed to obtain address of index %d from %s\n", 157 | (MAKE_PTR(PIMAGE_IMPORT_BY_NAME, pImageBase, dwOriginalThunk))->Name, 158 | lpLibraryName); 159 | #endif //_LDR_DEBUG_ 160 | 161 | if(dwOriginalThunk & IMAGE_ORDINAL_FLAG) 162 | return System::SetErrorCode(E_FUNCTION_NOT_FOUND_ORD, true, IMAGE_ORDINAL(pLookup->u1.Ordinal), 163 | lpLibraryName); 164 | else 165 | return System::SetErrorCode(E_FUNCTION_NOT_FOUND, true, (MAKE_PTR(PIMAGE_IMPORT_BY_NAME, 166 | pImageBase, dwOriginalThunk))->Name, lpLibraryName); 167 | } 168 | return System::SetErrorCode(E_SUCCESS); 169 | } 170 | 171 | /* 172 | Description: 173 | Binds image import table 174 | Arguments: 175 | pImage - pointer to a valid image descriptor 176 | hBindLibrary - handle of the binding library 177 | pImport - pointer to valid entry in image import table 178 | bBindForwadingOnly - if true, bind only forwarded functions 179 | Return Value: 180 | int - error code 181 | */ 182 | int LdrBindImport(PIMAGE_DESCRIPTOR pImage, HMODULE hBindLibrary, PIMAGE_IMPORT_DESCRIPTOR pImport, bool bBindForwadingOnly) 183 | { 184 | PIMAGE_THUNK_DATA pThunk, pLookup; 185 | 186 | if (bBindForwadingOnly) 187 | { 188 | // Bind only forwarder chain functions 189 | 190 | ULONG ulForwarderChain = pImport->ForwarderChain; 191 | while (ulForwarderChain != -1) 192 | { 193 | pLookup = MAKE_PTR(PIMAGE_THUNK_DATA, pImage->pImageBase, 194 | pImport->OriginalFirstThunk + (ulForwarderChain * sizeof(IMAGE_THUNK_DATA))); 195 | pThunk = MAKE_PTR(PIMAGE_THUNK_DATA, pImage->pImageBase, 196 | pImport->FirstThunk + (ulForwarderChain * sizeof(IMAGE_THUNK_DATA))); 197 | ulForwarderChain = (ULONG)pThunk->u1.Ordinal; 198 | 199 | if (LdrBindImportThunk(pImage->pImageBase, hBindLibrary, pLookup, pThunk) != E_SUCCESS) 200 | return System::GetErrorCode(false); 201 | } 202 | 203 | } 204 | else if (pImport->FirstThunk) 205 | { 206 | pThunk = MAKE_PTR(PIMAGE_THUNK_DATA, pImage->pImageBase, pImport->FirstThunk); 207 | 208 | if (pImport->OriginalFirstThunk < pImage->pOptionalHeader->SizeOfHeaders || 209 | pImport->OriginalFirstThunk >= pImage->pOptionalHeader->SizeOfImage) 210 | { 211 | pLookup = pThunk; 212 | } 213 | else 214 | { 215 | pLookup = (PIMAGE_THUNK_DATA)((pImport->OriginalFirstThunk == 0) ? pThunk : MAKE_LPVOID(pImage->pImageBase, 216 | pImport->OriginalFirstThunk)); 217 | } 218 | 219 | // Bind each image import thunk 220 | 221 | while (pLookup->u1.Ordinal != 0) 222 | { 223 | if (LdrBindImportThunk(pImage->pImageBase, hBindLibrary, pLookup, pThunk) != E_SUCCESS) 224 | return System::GetErrorCode(false); 225 | ++pLookup; 226 | ++pThunk; 227 | } 228 | } 229 | return System::SetErrorCode(E_SUCCESS); 230 | } 231 | 232 | /* 233 | Description: 234 | Fills the image import address table with apropriate values 235 | Arguments: 236 | pImage - pointer to a valid image descriptor 237 | bBreakOnFail - immediate return with appropriate error code if 238 | some imported function cannot be resolved 239 | Return Value: 240 | int - error code 241 | */ 242 | int LdrProcessImports(PIMAGE_DESCRIPTOR pImage) 243 | { 244 | HMODULE hLib; 245 | if (IS_NULL(pImage)) 246 | return System::SetErrorCode(E_INVALID_ARGUMENT, true, __FUNCTIONW__); 247 | __try 248 | { 249 | PIMAGE_BOUND_IMPORT_DESCRIPTOR pBoundImport = NULL; 250 | if (LdrCheckDataDirectory(pImage, IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT) == E_SUCCESS) 251 | pBoundImport = MAKE_PTR(PIMAGE_BOUND_IMPORT_DESCRIPTOR, pImage->pImageBase, 252 | pImage->pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress); 253 | PIMAGE_IMPORT_DESCRIPTOR pImport = NULL; 254 | if (LdrCheckDataDirectory(pImage, IMAGE_DIRECTORY_ENTRY_IMPORT) == E_SUCCESS) 255 | pImport = MAKE_PTR(PIMAGE_IMPORT_DESCRIPTOR, pImage->pImageBase, 256 | pImage->pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); 257 | 258 | if (!IS_NULL(pBoundImport)) 259 | { 260 | LPSTR lpLbraryNameBase = (LPSTR)pBoundImport; 261 | bool bDirtyBinding = false; 262 | 263 | // Walk bound import libraries 264 | 265 | while (pBoundImport->OffsetModuleName) 266 | { 267 | LPSTR lpLibraryName = lpLbraryNameBase + pBoundImport->OffsetModuleName; 268 | #ifdef _LDR_DEBUG_ 269 | System::SysDbgMessage(L"[I] Loading: %S\n", lpLibraryName); 270 | #endif //_LDR_DEBUG_ 271 | hLib = LoadLibraryA(lpLibraryName); 272 | if (IS_NULL(hLib)) 273 | { 274 | #ifdef _LDR_DEBUG_ 275 | System::SysDbgMessage(L"[E] Failed to load %S\n", lpLibraryName); 276 | #endif //_LDR_DEBUG_ 277 | return System::SetErrorCode(E_LIBRARY_FAIL, true, lpLibraryName); 278 | } 279 | 280 | PLDR_DATA_TABLE_ENTRY pLdrEntry = System::GetSystemLdrTableEntry(hLib); 281 | if (pBoundImport->TimeDateStamp != pLdrEntry->TimeDateStamp || 282 | (pLdrEntry->Flags && LDRP_IMAGE_NOT_AT_BASE)) 283 | bDirtyBinding = true; 284 | 285 | PIMAGE_BOUND_FORWARDER_REF pBoundForwarder = (PIMAGE_BOUND_FORWARDER_REF)(pBoundImport + 1); 286 | 287 | // Walk module forwarder references 288 | 289 | for (int i = 0; i < pBoundImport->NumberOfModuleForwarderRefs; ++i) 290 | { 291 | LPSTR lpModuleName = lpLbraryNameBase + pBoundForwarder->OffsetModuleName; 292 | #ifdef _LDR_DEBUG_ 293 | System::SysDbgMessage(L"[I] Loading: %S\n", lpModuleName); 294 | #endif //_LDR_DEBUG_ 295 | HMODULE hLib = LoadLibraryA(lpModuleName); 296 | 297 | if (IS_NULL(hLib)) 298 | { 299 | #ifdef _LDR_DEBUG_ 300 | System::SysDbgMessage(L"[E] Failed to load %S\n", lpModuleName); 301 | #endif //_LDR_DEBUG_ 302 | return System::SetErrorCode(E_LIBRARY_FAIL, true, lpModuleName); 303 | } 304 | PLDR_DATA_TABLE_ENTRY pLdrEntry = System::GetSystemLdrTableEntry(hLib); 305 | if (pBoundImport->TimeDateStamp != pLdrEntry->TimeDateStamp || 306 | (pLdrEntry->Flags && LDRP_IMAGE_NOT_AT_BASE)) 307 | bDirtyBinding = true; 308 | 309 | ++pBoundForwarder; 310 | } 311 | 312 | pBoundImport = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)pBoundForwarder; 313 | 314 | if (bDirtyBinding) 315 | { 316 | 317 | // If binding is invalid use the default IAT 318 | 319 | PIMAGE_IMPORT_DESCRIPTOR pImportDesc = pImport; 320 | if (IS_NULL(pImportDesc)) 321 | return System::SetErrorCode(E_NO_IMPORT, true, lpLibraryName); 322 | 323 | while (pImport->Name) 324 | { 325 | LPSTR lpImportName = MAKE_PTR(LPSTR, pImage->pImageBase, pImport->Name); 326 | if (!Helpers::stricmpA(lpImportName, lpLibraryName)) 327 | break; 328 | ++pImport; 329 | } 330 | if (IS_NULL(pImport->Name)) 331 | return System::SetErrorCode(E_INVALID_IMPORT_NAME); 332 | if (LdrBindImport(pImage, hLib, pImport, false) != E_SUCCESS) 333 | return System::GetErrorCode(false); 334 | } 335 | } 336 | 337 | } 338 | else if (!IS_NULL(pImport)) 339 | { 340 | LPCSTR lpLibraryName; 341 | bool bBindForwardingOnly = false; 342 | PLDR_DATA_TABLE_ENTRY pLdrEntry; 343 | 344 | // Load each library from image import table 345 | 346 | while (pImport->Name != 0 && pImport->FirstThunk) 347 | { 348 | bBindForwardingOnly = false; 349 | 350 | if (IS_NULL((MAKE_PTR(PIMAGE_THUNK_DATA, pImage->pImageBase, pImport->FirstThunk))->u1.Function)) 351 | goto _bypass_library; 352 | 353 | lpLibraryName = MAKE_PTR(LPCSTR, pImage->pImageBase, pImport->Name); 354 | #ifdef _LDR_DEBUG_ 355 | System::SysDbgMessage(L"[I] Loading: %S\n", lpLibraryName); 356 | #endif //_LDR_DEBUG_ 357 | 358 | hLib = LoadLibraryA(lpLibraryName); 359 | if (IS_NULL(hLib)) 360 | { 361 | #ifdef _LDR_DEBUG_ 362 | System::SysDbgMessage(L"[E] Failed to load %S\n", lpLibraryName); 363 | #endif //_LDR_DEBUG_ 364 | return System::SetErrorCode(E_LIBRARY_FAIL, true, lpLibraryName); 365 | } 366 | 367 | // Check if image has been bound 368 | 369 | if (pImport->OriginalFirstThunk) 370 | { 371 | pLdrEntry = System::GetSystemLdrTableEntry(hLib); 372 | if (pImport->TimeDateStamp && pImport->TimeDateStamp == pLdrEntry->TimeDateStamp && 373 | (!pLdrEntry->Flags && LDRP_IMAGE_NOT_AT_BASE)) 374 | { 375 | if (pImport->ForwarderChain == -1) 376 | goto _bypass_library; 377 | bBindForwardingOnly = true; 378 | } 379 | } 380 | 381 | if (LdrBindImport(pImage, hLib, pImport, bBindForwardingOnly) != E_SUCCESS) 382 | return System::GetErrorCode(false); 383 | _bypass_library: 384 | ++pImport; 385 | } 386 | } 387 | } 388 | __except(EXCEPTION_EXECUTE_HANDLER) 389 | { 390 | #ifdef _LDR_DEBUG_ 391 | System::SysDbgMessage(L"[X] Exception in %s [%s line %d] (le:%d)\n", __FUNCTIONW__, __FILEW__, __LINE__, GetLastError()); 392 | #endif //_LDR_DEBUG_ 393 | return System::SetErrorCode(E_EXCEPTION, true, __FUNCTIONW__); 394 | } 395 | return System::SetErrorCode(E_SUCCESS); 396 | } 397 | 398 | /* 399 | LdrSetImportAddress helper routine (For details see: LdrSetImportAddress) 400 | */ 401 | int LdrSetImportAddressHelper(PIMAGE_DESCRIPTOR pImage, LPCSTR lpLibName, LPCSTR lpFuncName, LPVOID lpAddress) 402 | { 403 | __try 404 | { 405 | PIMAGE_IMPORT_DESCRIPTOR pImport = MAKE_PTR(PIMAGE_IMPORT_DESCRIPTOR, pImage->pImageBase, 406 | pImage->pOptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); 407 | PIMAGE_THUNK_DATA pThunk, pLookup; 408 | LPCSTR pLibraryName; 409 | 410 | // Scan for selected library 411 | 412 | while (pImport->Name != 0) 413 | { 414 | pLibraryName = MAKE_PTR(LPCSTR, pImage->pImageBase, pImport->Name); 415 | if (Helpers::stricmpA(pLibraryName, lpLibName) == 0) 416 | { 417 | pThunk = MAKE_PTR(PIMAGE_THUNK_DATA, pImage->pImageBase, pImport->FirstThunk); 418 | pLookup = (PIMAGE_THUNK_DATA)((pImport->OriginalFirstThunk == 0) ? pThunk : MAKE_LPVOID(pImage->pImageBase, 419 | pImport->OriginalFirstThunk)); 420 | 421 | // Check for original thunk 422 | 423 | if (pThunk->u1.Function == pLookup->u1.Function) 424 | return System::SetErrorCode(E_NO_ORIGINAL_THUNK); 425 | 426 | // Scan imported functions names 427 | 428 | LPCSTR lpName = NULL; 429 | while (pLookup->u1.Ordinal != 0) 430 | { 431 | if(!(pLookup->u1.Ordinal & IMAGE_ORDINAL_FLAG)) 432 | { 433 | lpName = (LPCSTR)(MAKE_PTR(PIMAGE_IMPORT_BY_NAME, 434 | pImage->pImageBase, pLookup->u1.AddressOfData))->Name; 435 | 436 | if (Helpers::strcmpA(lpName, lpFuncName) == 0) 437 | { 438 | __try 439 | { 440 | pThunk->u1.Function = (DWORD)lpAddress; 441 | } 442 | __except(EXCEPTION_EXECUTE_HANDLER) 443 | { 444 | #ifdef _LDR_DEBUG_ 445 | System::SysDbgMessage(L"[X] Exception in %s [%s line %d]\n", __FUNCTIONW__, __FILEW__, __LINE__); 446 | #endif //_LDR_DEBUG_ 447 | return System::SetErrorCode(E_NO_ACCESS); 448 | } 449 | return System::SetErrorCode(E_SUCCESS); 450 | } 451 | } 452 | ++pLookup; 453 | ++pThunk; 454 | } 455 | } 456 | ++pImport; 457 | } 458 | } 459 | __except(EXCEPTION_EXECUTE_HANDLER) 460 | { 461 | #ifdef _LDR_DEBUG_ 462 | System::SysDbgMessage(L"[X] Exception in %s [%s line %d]\n", __FUNCTIONW__, __FILEW__, __LINE__); 463 | #endif //_LDR_DEBUG_ 464 | return System::SetErrorCode(E_EXCEPTION, true, __FUNCTIONW__); 465 | } 466 | return System::SetErrorCode(E_IMPORT_NOT_FOUND); 467 | } 468 | 469 | /* 470 | Description: 471 | Set image import address of selected library and function name (only if original thunk is persist) 472 | Arguments: 473 | pImage - pointer to a valid image descriptor 474 | lpLibName - library name from which function was imported 475 | lpFuncName - import function name 476 | lpAddress - new function address 477 | Return Value: 478 | int - error code 479 | */ 480 | int LdrSetImportAddress(PIMAGE_DESCRIPTOR pImage, LPCSTR lpLibName, LPCSTR lpFuncName, LPVOID lpAddress) 481 | { 482 | if (IS_NULL(pImage) || IS_NULL(lpLibName) || IS_NULL(lpFuncName)) 483 | return System::SetErrorCode(E_INVALID_ARGUMENT, true, __FUNCTIONW__); 484 | int errorCode = LdrSetImportAddressHelper(pImage, lpLibName, lpFuncName, lpAddress); 485 | if (errorCode == E_NO_ACCESS) 486 | { 487 | // Try to get access to import function table if program naven't it yet 488 | 489 | LdrAllowImageDirectoryAccess(pImage, IMAGE_DIRECTORY_ENTRY_IMPORT); 490 | LdrAllowImageDirectoryAccess(pImage, IMAGE_DIRECTORY_ENTRY_IAT); 491 | errorCode = LdrSetImportAddressHelper(pImage, lpLibName, lpFuncName, lpAddress); 492 | } 493 | return errorCode; 494 | } 495 | -------------------------------------------------------------------------------- /loader/src/loader/ntldr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Windows loader structures defenition 3 | */ 4 | 5 | #ifndef _NTLDR_H_ 6 | #define _NTLDR_H_ 7 | 8 | #include 9 | 10 | #define LDR_HASH_TABLE_SIZE 32 11 | #define LDR_HASH_TABLE_MASK 31 12 | 13 | // Practically found offset of pointer to activation context data 14 | #define ACTIVATION_CONTEXT_DATA_OFFSET_WIN8 16 15 | #define ACTIVATION_CONTEXT_DATA_OFFSET_XP 8 16 | 17 | typedef struct _UNICODE_STRING { 18 | USHORT Length; 19 | USHORT MaximumLength; 20 | PWSTR Buffer; 21 | } UNICODE_STRING; 22 | typedef UNICODE_STRING *PUNICODE_STRING; 23 | 24 | typedef struct _OBJECT_ATTRIBUTES { 25 | ULONG Length; 26 | HANDLE RootDirectory; 27 | PUNICODE_STRING ObjectName; 28 | ULONG Attributes; 29 | PVOID SecurityDescriptor; 30 | PVOID SecurityQualityOfService; 31 | } OBJECT_ATTRIBUTES; 32 | typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES; 33 | 34 | typedef struct _IMAGE_RELOC 35 | { 36 | union 37 | { 38 | struct 39 | { 40 | WORD wOffset:12; 41 | WORD wType:4; 42 | }; 43 | WORD wData; 44 | }; 45 | } IMAGE_RELOC, *PIMAGE_RELOC; 46 | 47 | typedef struct _LDRP_CSLIST 48 | { 49 | PSINGLE_LIST_ENTRY Tail; 50 | } LDRP_CSLIST, *PLDRP_CSLIST; 51 | 52 | typedef struct _LDR_SERVICE_TAG_RECORD 53 | { 54 | struct _LDR_SERVICE_TAG_RECORD *Next; 55 | ULONG ServiceTag; 56 | } LDR_SERVICE_TAG_RECORD, *PLDR_SERVICE_TAG_RECORD; 57 | 58 | typedef enum _LDR_DDAG_STATE 59 | { 60 | LdrModulesMerged = -5, 61 | LdrModulesInitError = -4, 62 | LdrModulesSnapError = -3, 63 | LdrModulesUnloaded = -2, 64 | LdrModulesUnloading = -1, 65 | LdrModulesPlaceHolder = 0, 66 | LdrModulesMapping = 1, 67 | LdrModulesMapped = 2, 68 | LdrModulesWaitingForDependencies = 3, 69 | LdrModulesSnapping = 4, 70 | LdrModulesSnapped = 5, 71 | LdrModulesCondensed = 6, 72 | LdrModulesReadyToInit = 7, 73 | LdrModulesInitializing = 8, 74 | LdrModulesReadyToRun = 9 75 | } LDR_DDAG_STATE; 76 | 77 | typedef struct _LDR_DDAG_NODE 78 | { 79 | LIST_ENTRY Modules; 80 | PLDR_SERVICE_TAG_RECORD ServiceTagList; 81 | ULONG LoadCount; 82 | ULONG ReferenceCount; 83 | ULONG DependencyCount; 84 | union 85 | { 86 | LDRP_CSLIST Dependencies; 87 | SINGLE_LIST_ENTRY RemovalLink; 88 | }; 89 | LDRP_CSLIST IncomingDependencies; 90 | LDR_DDAG_STATE State; 91 | SINGLE_LIST_ENTRY CondenseLink; 92 | ULONG PreorderNumber; 93 | ULONG LowestLink; 94 | } LDR_DDAG_NODE, *PLDR_DDAG_NODE; 95 | 96 | typedef struct _RTL_BALANCED_NODE 97 | { 98 | union 99 | { 100 | struct _RTL_BALANCED_NODE *Children[2]; 101 | struct 102 | { 103 | struct _RTL_BALANCED_NODE *Left; 104 | struct _RTL_BALANCED_NODE *Right; 105 | }; 106 | }; 107 | union 108 | { 109 | UCHAR Red : 1; 110 | UCHAR Balance : 2; 111 | ULONG_PTR ParentValue; 112 | }; 113 | } RTL_BALANCED_NODE, *PRTL_BALANCED_NODE; 114 | 115 | typedef enum _LDR_DLL_LOAD_REASON 116 | { 117 | LoadReasonStaticDependency, 118 | LoadReasonStaticForwarderDependency, 119 | LoadReasonDynamicForwarderDependency, 120 | LoadReasonDelayloadDependency, 121 | LoadReasonDynamicLoad, 122 | LoadReasonAsImageLoad, 123 | LoadReasonAsDataLoad, 124 | LoadReasonUnknown = -1 125 | } LDR_DLL_LOAD_REASON, *PLDR_DLL_LOAD_REASON; 126 | 127 | #define LDRP_STATIC_LINK 0x00000002 128 | #define LDRP_IMAGE_DLL 0x00000004 129 | #define LDRP_LOAD_IN_PROGRESS 0x00001000 130 | #define LDRP_UNLOAD_IN_PROGRESS 0x00002000 131 | #define LDRP_ENTRY_PROCESSED 0x00004000 132 | #define LDRP_ENTRY_INSERTED 0x00008000 133 | #define LDRP_CURRENT_LOAD 0x00010000 134 | #define LDRP_FAILED_BUILTIN_LOAD 0x00020000 135 | #define LDRP_DONT_CALL_FOR_THREADS 0x00040000 136 | #define LDRP_PROCESS_ATTACH_CALLED 0x00080000 137 | #define LDRP_DEBUG_SYMBOLS_LOADED 0x00100000 138 | #define LDRP_IMAGE_NOT_AT_BASE 0x00200000 139 | #define LDRP_COR_IMAGE 0x00400000 140 | #define LDR_COR_OWNS_UNMAP 0x00800000 141 | #define LDRP_SYSTEM_MAPPED 0x01000000 142 | #define LDRP_IMAGE_VERIFYING 0x02000000 143 | #define LDRP_DRIVER_DEPENDENT_DLL 0x04000000 144 | #define LDRP_ENTRY_NATIVE 0x08000000 145 | #define LDRP_REDIRECTED 0x10000000 146 | #define LDRP_NON_PAGED_DEBUG_INFO 0x20000000 147 | #define LDRP_MM_LOADED 0x40000000 148 | #define LDRP_COMPAT_DATABASE_PROCESSED 0x80000000 149 | 150 | typedef struct _LDR_DATA_TABLE_ENTRY 151 | { 152 | LIST_ENTRY InLoadOrderModuleList; 153 | LIST_ENTRY InMemoryOrderModuleList; 154 | LIST_ENTRY InInitializationOrderModuleList; 155 | PVOID ModuleBase; 156 | PVOID EntryPoint; 157 | ULONG SizeOfImage; 158 | UNICODE_STRING ModuleFileName; 159 | UNICODE_STRING ModuleBaseName; 160 | union 161 | { 162 | UCHAR FlagGroup[4]; 163 | ULONG Flags; 164 | }; 165 | SHORT LoadCount; 166 | SHORT TlsIndex; 167 | LIST_ENTRY HashLinks; 168 | ULONG TimeDateStamp; 169 | struct _ACTIVATION_CONTEXT *EntryPointActivationContext; 170 | PVOID PatchInformation; 171 | } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; 172 | 173 | namespace Windows8 174 | { 175 | 176 | typedef struct _LDR_DATA_TABLE_ENTRY 177 | { 178 | LIST_ENTRY InLoadOrderModuleList; 179 | LIST_ENTRY InMemoryOrderModuleList; 180 | LIST_ENTRY InInitializationOrderModuleList; 181 | PVOID ModuleBase; 182 | PVOID EntryPoint; 183 | ULONG SizeOfImage; 184 | UNICODE_STRING ModuleFileName; 185 | UNICODE_STRING ModuleBaseName; 186 | union 187 | { 188 | UCHAR FlagGroup[4]; 189 | ULONG Flags; 190 | struct 191 | { 192 | ULONG PackagedBinary : 1; 193 | ULONG MarkedForRemoval : 1; 194 | ULONG ImageDll : 1; 195 | ULONG LoadNotificationsSent : 1; 196 | ULONG TelemetryEntryProcessed : 1; 197 | ULONG ProcessStaticImport : 1; 198 | ULONG InLegacyLists : 1; 199 | ULONG InIndexes : 1; 200 | ULONG ShimDll : 1; 201 | ULONG InExceptionTable : 1; 202 | ULONG ReservedFlags1 : 2; 203 | ULONG LoadInProgress : 1; 204 | ULONG ReservedFlags2 : 1; 205 | ULONG EntryProcessed : 1; 206 | ULONG ReservedFlags3 : 3; 207 | ULONG DontCallForThreads : 1; 208 | ULONG ProcessAttachCalled : 1; 209 | ULONG ProcessAttachFailed : 1; 210 | ULONG CorDeferredValidate : 1; 211 | ULONG CorImage : 1; 212 | ULONG Relocated : 1; 213 | ULONG CorILOnly : 1; 214 | ULONG ReservedFlags5 : 3; 215 | ULONG Redirected : 1; 216 | ULONG ReservedFlags6 : 2; 217 | ULONG CompatDatabaseProcessed : 1; 218 | }; 219 | }; 220 | SHORT LoadCount; 221 | SHORT TlsIndex; 222 | LIST_ENTRY HashLinks; 223 | ULONG TimeDateStamp; 224 | struct _ACTIVATION_CONTEXT *EntryPointActivationContext; 225 | PVOID PatchInformation; 226 | PLDR_DDAG_NODE DdagNode; 227 | LIST_ENTRY NodeModuleLink; 228 | struct _LDRP_DLL_SNAP_CONTEXT *SnapContext; 229 | PVOID ParentDllBase; 230 | PVOID SwitchBackContext; 231 | RTL_BALANCED_NODE BaseAddressIndexNode; 232 | RTL_BALANCED_NODE MappingInfoIndexNode; 233 | ULONG_PTR OriginalBase; 234 | LARGE_INTEGER LoadTime; 235 | ULONG BaseNameHashValue; 236 | LDR_DLL_LOAD_REASON LoadReason; 237 | } LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; 238 | 239 | } // namespace Windows 8 240 | 241 | typedef struct _PEB_LDR_DATA 242 | { 243 | DWORD dwLength; 244 | DWORD dwInitialized; 245 | LPVOID lpSsHandle; 246 | LIST_ENTRY InLoadOrderModuleList; 247 | LIST_ENTRY InMemoryOrderModuleList; 248 | LIST_ENTRY InInitializationOrderModuleList; 249 | LPVOID lpEntryInProgress; 250 | UCHAR ShutdownInProgress; 251 | LPVOID ShutdownThreadId; 252 | } PEB_LDR_DATA, * PPEB_LDR_DATA; 253 | 254 | typedef struct _PEB_FREE_BLOCK 255 | { 256 | struct _PEB_FREE_BLOCK * pNext; 257 | DWORD dwSize; 258 | } PEB_FREE_BLOCK, * PPEB_FREE_BLOCK; 259 | 260 | typedef struct _RTL_DRIVE_LETTER_CURDIR { 261 | USHORT Flags; 262 | USHORT Length; 263 | ULONG TimeStamp; 264 | UNICODE_STRING DosPath; 265 | } RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR; 266 | 267 | #define RTL_MAX_DRIVE_LETTERS 0x20 268 | 269 | typedef struct _RTL_USER_PROCESS_PARAMETERS { 270 | ULONG MaximumLength; 271 | ULONG Length; 272 | ULONG Flags; 273 | ULONG DebugFlags; 274 | PVOID ConsoleHandle; 275 | ULONG ConsoleFlags; 276 | HANDLE StdInputHandle; 277 | HANDLE StdOutputHandle; 278 | HANDLE StdErrorHandle; 279 | UNICODE_STRING CurrentDirectoryPath; 280 | HANDLE CurrentDirectoryHandle; 281 | UNICODE_STRING DllPath; 282 | UNICODE_STRING ImagePathName; 283 | UNICODE_STRING CommandLine; 284 | PVOID Environment; 285 | ULONG StartingPositionLeft; 286 | ULONG StartingPositionTop; 287 | ULONG Width; 288 | ULONG Height; 289 | ULONG CharWidth; 290 | ULONG CharHeight; 291 | ULONG ConsoleTextAttributes; 292 | ULONG WindowFlags; 293 | ULONG ShowWindowFlags; 294 | UNICODE_STRING WindowTitle; 295 | UNICODE_STRING DesktopName; 296 | UNICODE_STRING ShellInfo; 297 | UNICODE_STRING RuntimeData; 298 | RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[RTL_MAX_DRIVE_LETTERS]; 299 | ULONG EnvironmentSize; 300 | ULONG EnvironmentVersion; 301 | PVOID PackageDependencyData; 302 | ULONG ProcessGroupId; 303 | } RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; 304 | 305 | typedef struct _LDRP_TLS_ENTRY { 306 | LIST_ENTRY Links; 307 | IMAGE_TLS_DIRECTORY Tls; 308 | } LDRP_TLS_ENTRY, *PLDRP_TLS_ENTRY; 309 | 310 | typedef struct __PEB 311 | { 312 | BYTE bInheritedAddressSpace; 313 | BYTE bReadImageFileExecOptions; 314 | BYTE bBeingDebugged; 315 | BYTE bSpareBool; 316 | LPVOID lpMutant; 317 | LPVOID lpImageBaseAddress; 318 | PPEB_LDR_DATA pLdr; 319 | PRTL_USER_PROCESS_PARAMETERS lpProcessParameters; 320 | LPVOID lpSubSystemData; 321 | LPVOID lpProcessHeap; 322 | PRTL_CRITICAL_SECTION pFastPebLock; 323 | LPVOID lpFastPebLockRoutine; 324 | LPVOID lpFastPebUnlockRoutine; 325 | DWORD dwEnvironmentUpdateCount; 326 | LPVOID lpKernelCallbackTable; 327 | DWORD dwSystemReserved; 328 | DWORD dwAtlThunkSListPtr32; 329 | PPEB_FREE_BLOCK pFreeList; 330 | DWORD dwTlsExpansionCounter; 331 | LPVOID lpTlsBitmap; 332 | DWORD dwTlsBitmapBits[2]; 333 | LPVOID lpReadOnlySharedMemoryBase; 334 | LPVOID lpReadOnlySharedMemoryHeap; 335 | LPVOID lpReadOnlyStaticServerData; 336 | LPVOID lpAnsiCodePageData; 337 | LPVOID lpOemCodePageData; 338 | LPVOID lpUnicodeCaseTableData; 339 | DWORD dwNumberOfProcessors; 340 | DWORD dwNtGlobalFlag; 341 | LARGE_INTEGER liCriticalSectionTimeout; 342 | DWORD dwHeapSegmentReserve; 343 | DWORD dwHeapSegmentCommit; 344 | DWORD dwHeapDeCommitTotalFreeThreshold; 345 | DWORD dwHeapDeCommitFreeBlockThreshold; 346 | DWORD dwNumberOfHeaps; 347 | DWORD dwMaximumNumberOfHeaps; 348 | LPVOID lpProcessHeaps; 349 | LPVOID lpGdiSharedHandleTable; 350 | LPVOID lpProcessStarterHelper; 351 | DWORD dwGdiDCAttributeList; 352 | LPVOID lpLoaderLock; 353 | DWORD dwOSMajorVersion; 354 | DWORD dwOSMinorVersion; 355 | WORD wOSBuildNumber; 356 | WORD wOSCSDVersion; 357 | DWORD dwOSPlatformId; 358 | DWORD dwImageSubsystem; 359 | DWORD dwImageSubsystemMajorVersion; 360 | DWORD dwImageSubsystemMinorVersion; 361 | DWORD dwImageProcessAffinityMask; 362 | DWORD dwGdiHandleBuffer[34]; 363 | LPVOID lpPostProcessInitRoutine; 364 | LPVOID lpTlsExpansionBitmap; 365 | DWORD dwTlsExpansionBitmapBits[32]; 366 | DWORD dwSessionId; 367 | ULARGE_INTEGER liAppCompatFlags; 368 | ULARGE_INTEGER liAppCompatFlagsUser; 369 | LPVOID lppShimData; 370 | LPVOID lpAppCompatInfo; 371 | UNICODE_STRING usCSDVersion; 372 | LPVOID lpActivationContextData; 373 | LPVOID lpProcessAssemblyStorageMap; 374 | LPVOID lpSystemDefaultActivationContextData; 375 | LPVOID lpSystemAssemblyStorageMap; 376 | DWORD dwMinimumStackCommit; 377 | } PEB, * PPEB; 378 | 379 | typedef struct _CLIENT_ID 380 | { 381 | DWORD UniqueProcess; 382 | DWORD UniqueThread; 383 | } CLIENT_ID; 384 | 385 | typedef struct _GDI_TEB_BATCH 386 | { 387 | DWORD Offset; 388 | HANDLE HDC; 389 | DWORD Buffer[310]; 390 | } GDI_TEB_BATCH, *PGDI_TEB_BATCH; 391 | 392 | typedef struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME 393 | { 394 | _RTL_ACTIVATION_CONTEXT_STACK_FRAME *Previous; 395 | LPVOID ActivationContext; 396 | DWORD Flags; 397 | } RTL_ACTIVATION_CONTEXT_STACK_FRAME, *PRTL_ACTIVATION_CONTEXT_STACK_FRAME; 398 | 399 | typedef struct _ACTIVATION_CONTEXT_STACK 400 | { 401 | PRTL_ACTIVATION_CONTEXT_STACK_FRAME ActiveFrame; 402 | LIST_ENTRY FrameListCache; 403 | DWORD Flags; 404 | DWORD NextCookieSequenceNumber; 405 | DWORD StackId; 406 | } ACTIVATION_CONTEXT_STACK, *PACTIVATION_CONTEXT_STACK; 407 | 408 | typedef struct _EXCEPTION_REGISTRATION_RECORD 409 | { 410 | _EXCEPTION_REGISTRATION_RECORD *Next; 411 | LPVOID Handler; 412 | } EXCEPTION_REGISTRATION_RECORD, *PEXCEPTION_REGISTRATION_RECORD; 413 | 414 | typedef struct _TIB { 415 | struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; 416 | PVOID StackBase; 417 | PVOID StackLimit; 418 | PVOID SubSystemTib; 419 | union { 420 | PVOID FiberData; 421 | DWORD Version; 422 | }; 423 | PVOID ArbitraryUserPointer; 424 | struct _NT_TIB *Self; 425 | } TIB, *PTIB; 426 | 427 | typedef struct _TEB 428 | { 429 | TIB Tib; 430 | PVOID EnvironmentPointer; 431 | CLIENT_ID Cid; 432 | PVOID ActiveRpcHandle; 433 | PVOID ThreadLocalStoragePointer; 434 | PPEB Peb; 435 | ULONG LastErrorValue; 436 | ULONG CountOfOwnedCriticalSections; 437 | PVOID CsrClientThread; 438 | PVOID Win32ThreadInfo; 439 | ULONG Win32ClientInfo[0x1F]; 440 | PVOID WOW32Reserved; 441 | ULONG CurrentLocale; 442 | ULONG FpSoftwareStatusRegister; 443 | PVOID SystemReserved1[0x36]; 444 | ULONG ExceptionCode; 445 | PACTIVATION_CONTEXT_STACK ActivationContextStackPointer; 446 | ULONG SpareBytes[0x18]; 447 | PVOID TxFsContext; 448 | GDI_TEB_BATCH GdiTebBatch; 449 | CLIENT_ID RealClientId; 450 | PVOID GdiCachedProcessHandle; 451 | ULONG GdiClientPID; 452 | ULONG GdiClientTID; 453 | PVOID GdiThreadLocaleInfo; 454 | PVOID UserReserved[5]; 455 | PVOID GlDispatchTable[0x118]; 456 | ULONG GlReserved1[0x1A]; 457 | PVOID GlReserved2; 458 | PVOID GlSectionInfo; 459 | PVOID GlSection; 460 | PVOID GlTable; 461 | PVOID GlCurrentRC; 462 | PVOID GlContext; 463 | NTSTATUS LastStatusValue; 464 | UNICODE_STRING StaticUnicodeString; 465 | WCHAR StaticUnicodeBuffer[0x105]; 466 | PVOID DeallocationStack; 467 | PVOID TlsSlots[0x40]; 468 | LIST_ENTRY TlsLinks; 469 | PVOID Vdm; 470 | PVOID ReservedForNtRpc; 471 | PVOID DbgSsReserved[0x2]; 472 | ULONG HardErrorDisabled; 473 | PVOID Instrumentation[0x10]; 474 | PVOID WinSockData; 475 | ULONG GdiBatchCount; 476 | ULONG Spare2; 477 | ULONG Spare3; 478 | ULONG Spare4; 479 | PVOID ReservedForOle; 480 | ULONG WaitingOnLoaderLock; 481 | PVOID StackCommit; 482 | PVOID StackCommitMax; 483 | PVOID StackReserved; 484 | } TEB, *PTEB; 485 | 486 | typedef enum _SYSTEM_INFORMATION_CLASS 487 | { 488 | SystemProcessInformation = 5, 489 | SystemExtendedProcessInformation = 57 490 | } SYSTEM_INFORMATION_CLASS; 491 | 492 | typedef LONG KPRIORITY; 493 | 494 | typedef enum _KWAIT_REASON 495 | { 496 | Executive, 497 | FreePage, 498 | PageIn, 499 | PoolAllocation, 500 | DelayExecution, 501 | Suspended, 502 | UserRequest, 503 | WrExecutive, 504 | WrFreePage, 505 | WrPageIn, 506 | WrPoolAllocation, 507 | WrDelayExecution, 508 | WrSuspended, 509 | WrUserRequest, 510 | WrEventPair, 511 | WrQueue, 512 | WrLpcReceive, 513 | WrLpcReply, 514 | WrVirtualMemory, 515 | WrPageOut, 516 | WrRendezvous, 517 | WrKeyedEvent, 518 | WrTerminated, 519 | WrProcessInSwap, 520 | WrCpuRateControl, 521 | WrCalloutStack, 522 | WrKernel, 523 | WrResource, 524 | WrPushLock, 525 | WrMutex, 526 | WrQuantumEnd, 527 | WrDispatchInt, 528 | WrPreempted, 529 | WrYieldExecution, 530 | WrFastMutex, 531 | WrGuardedMutex, 532 | WrRundown, 533 | MaximumWaitReason 534 | } KWAIT_REASON, *PKWAIT_REASON; 535 | 536 | typedef struct _SYSTEM_THREAD_INFORMATION 537 | { 538 | LARGE_INTEGER KernelTime; 539 | LARGE_INTEGER UserTime; 540 | LARGE_INTEGER CreateTime; 541 | ULONG WaitTime; 542 | PVOID StartAddress; 543 | CLIENT_ID ClientId; 544 | KPRIORITY Priority; 545 | LONG BasePriority; 546 | ULONG ContextSwitches; 547 | ULONG ThreadState; 548 | KWAIT_REASON WaitReason; 549 | } SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION; 550 | 551 | typedef struct _SYSTEM_PROCESS_INFORMATION 552 | { 553 | ULONG NextEntryOffset; 554 | ULONG NumberOfThreads; 555 | LARGE_INTEGER WorkingSetPrivateSize; 556 | ULONG HardFaultCount; 557 | ULONG NumberOfThreadsHighWatermark; 558 | ULONGLONG CycleTime; 559 | LARGE_INTEGER CreateTime; 560 | LARGE_INTEGER UserTime; 561 | LARGE_INTEGER KernelTime; 562 | UNICODE_STRING ImageName; 563 | KPRIORITY BasePriority; 564 | HANDLE UniqueProcessId; 565 | HANDLE InheritedFromUniqueProcessId; 566 | ULONG HandleCount; 567 | ULONG SessionId; 568 | ULONG_PTR UniqueProcessKey; 569 | SIZE_T PeakVirtualSize; 570 | SIZE_T VirtualSize; 571 | ULONG PageFaultCount; 572 | SIZE_T PeakWorkingSetSize; 573 | SIZE_T WorkingSetSize; 574 | SIZE_T QuotaPeakPagedPoolUsage; 575 | SIZE_T QuotaPagedPoolUsage; 576 | SIZE_T QuotaPeakNonPagedPoolUsage; 577 | SIZE_T QuotaNonPagedPoolUsage; 578 | SIZE_T PagefileUsage; 579 | SIZE_T PeakPagefileUsage; 580 | SIZE_T PrivatePageCount; 581 | LARGE_INTEGER ReadOperationCount; 582 | LARGE_INTEGER WriteOperationCount; 583 | LARGE_INTEGER OtherOperationCount; 584 | LARGE_INTEGER ReadTransferCount; 585 | LARGE_INTEGER WriteTransferCount; 586 | LARGE_INTEGER OtherTransferCount; 587 | SYSTEM_THREAD_INFORMATION Threads[1]; 588 | } SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION; 589 | 590 | typedef enum _PROCESSINFOCLASS 591 | { 592 | ProcessBasicInformation = 0, 593 | ProcessImageFileName = 27, 594 | ProcessImageInformation = 37, 595 | ProcessImageFileNameWin32 = 43 596 | } PROCESSINFOCLASS, PROCESS_INFORMATION_CLASS; 597 | 598 | typedef struct _SECTION_IMAGE_INFORMATION 599 | { 600 | PVOID TransferAddress; 601 | ULONG ZeroBits; 602 | SIZE_T MaximumStackSize; 603 | SIZE_T CommittedStackSize; 604 | ULONG SubSystemType; 605 | union 606 | { 607 | struct 608 | { 609 | USHORT SubSystemMinorVersion; 610 | USHORT SubSystemMajorVersion; 611 | }; 612 | ULONG SubSystemVersion; 613 | }; 614 | ULONG GpValue; 615 | USHORT ImageCharacteristics; 616 | USHORT DllCharacteristics; 617 | USHORT Machine; 618 | BOOLEAN ImageContainsCode; 619 | union 620 | { 621 | UCHAR ImageFlags; 622 | struct 623 | { 624 | UCHAR ComPlusNativeReady : 1; 625 | UCHAR ComPlusILOnly : 1; 626 | UCHAR ImageDynamicallyRelocated : 1; 627 | UCHAR ImageMappedFlat : 1; 628 | UCHAR BaseBelow4gb : 1; 629 | UCHAR Reserved : 3; 630 | }; 631 | }; 632 | ULONG LoaderFlags; 633 | ULONG ImageFileSize; 634 | ULONG CheckSum; 635 | } SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION; 636 | 637 | typedef enum _MEMORY_INFORMATION_CLASS 638 | { 639 | MemoryBasicInformation = 0, 640 | MemoryWorkingSetInformation, 641 | MemoryMappedFilenameInformation, 642 | MemoryRegionInformation, 643 | MemoryWorkingSetExInformation 644 | } MEMORY_INFORMATION_CLASS; 645 | 646 | typedef struct _PROCESS_BASIC_INFORMATION 647 | { 648 | NTSTATUS ExitStatus; 649 | PPEB PebBaseAddress; 650 | ULONG_PTR AffinityMask; 651 | KPRIORITY BasePriority; 652 | HANDLE UniqueProcessId; 653 | HANDLE InheritedFromUniqueProcessId; 654 | } PROCESS_BASIC_INFORMATION, *PPROCESS_BASIC_INFORMATION; 655 | 656 | typedef struct _PROCESS_EXTENDED_BASIC_INFORMATION 657 | { 658 | SIZE_T Size; // set to sizeof structure on input 659 | PROCESS_BASIC_INFORMATION BasicInfo; 660 | union 661 | { 662 | ULONG Flags; 663 | struct 664 | { 665 | ULONG IsProtectedProcess : 1; 666 | ULONG IsWow64Process : 1; 667 | ULONG IsProcessDeleting : 1; 668 | ULONG IsCrossSessionCreate : 1; 669 | ULONG IsFrozen : 1; 670 | ULONG IsBackground : 1; 671 | ULONG IsStronglyNamed : 1; 672 | ULONG SpareBits : 25; 673 | }; 674 | }; 675 | } PROCESS_EXTENDED_BASIC_INFORMATION, *PPROCESS_EXTENDED_BASIC_INFORMATION; 676 | 677 | typedef enum _THREAD_INFORMATION_CLASS { 678 | ThreadBasicInformation, 679 | ThreadTimes, 680 | ThreadPriority, 681 | ThreadBasePriority, 682 | ThreadAffinityMask, 683 | ThreadImpersonationToken, 684 | ThreadDescriptorTableEntry, 685 | ThreadEnableAlignmentFaultFixup, 686 | ThreadEventPair, 687 | ThreadQuerySetWin32StartAddress, 688 | ThreadZeroTlsCell, 689 | ThreadPerformanceCount, 690 | ThreadAmILastThread, 691 | ThreadIdealProcessor, 692 | ThreadPriorityBoost, 693 | ThreadSetTlsArrayAddress, 694 | ThreadIsIoPending, 695 | ThreadHideFromDebugger 696 | } THREAD_INFORMATION_CLASS, *PTHREAD_INFORMATION_CLASS; 697 | 698 | typedef struct _THREAD_BASIC_INFORMATION { 699 | NTSTATUS ExitStatus; 700 | PVOID TebBaseAddress; 701 | CLIENT_ID ClientId; 702 | KAFFINITY AffinityMask; 703 | KPRIORITY Priority; 704 | KPRIORITY BasePriority; 705 | } THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION; 706 | 707 | #endif // _NTLDR_H_ 708 | -------------------------------------------------------------------------------- /loader/src/system/system.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Run-time system functions 3 | */ 4 | 5 | #include 6 | #include 7 | #include "system.h" 8 | #include "syscalls.h" 9 | #include "../helpers.h" 10 | #include "../errors.h" 11 | #include "../loader/loader.h" 12 | 13 | extern int SysMain(int argc, LPCWSTR *argv); 14 | 15 | namespace System 16 | { 17 | 18 | SYSTEM system; // global main system variable 19 | 20 | // Variables used after loader self-relocation proceed 21 | // These variables use TLS due to program have access to TLS after relocation 22 | 23 | BOOL __declspec(thread) bRelocated = 0; // Self-relocation flag 24 | PSYSTEM __declspec(thread) pSystem = &system; // Pointer to system main variable 25 | 26 | #ifdef _LDR_DEBUG_ 27 | void SysDbgMessage(LPCWSTR lpMessage, ...) 28 | { 29 | va_list va; 30 | va_start(va, lpMessage); 31 | DbgMessageV(system.hPipe, lpMessage, va); 32 | va_end(va); 33 | } 34 | #endif 35 | 36 | /* 37 | Description: 38 | Sets relocation information 39 | used to determine loader overlapping 40 | Arguments: 41 | lpReqBase - loading image base 42 | dwReqSize - loading image size 43 | */ 44 | void SetRelocationData(LPVOID lpReqBase, DWORD dwReqSize) 45 | { 46 | system.sysRelocationData.lpReqBase = lpReqBase; 47 | system.sysRelocationData.dwReqSize = dwReqSize; 48 | } 49 | 50 | /* 51 | Description: 52 | Sets system last error code (plus windows last error) and return the same value 53 | Arguments: 54 | sysError - system error code 55 | lpErrorText - error text 56 | Return Value: 57 | int - error code 58 | */ 59 | int SetErrorCode(int sysError, BOOL bMessage, ...) 60 | { 61 | system.bErrorFlag = false; 62 | system.dwLastError = ::GetLastError(); 63 | if (bMessage && !system.bBlockError) 64 | { 65 | va_list va; 66 | va_start(va, bMessage); 67 | system.lpErrorString[ERROR_DATA_LEN] = 0; 68 | WCHAR lpMessageString[MAX_MESSAGE_RESOURCE]; 69 | if (Helpers::LoadStringW((HINSTANCE)system.loader.pImageBase, sysError, lpMessageString, MAX_MESSAGE_RESOURCE)) 70 | { 71 | if (FormatMessageW(FORMAT_MESSAGE_FROM_STRING, lpMessageString, 0, 0, 72 | system.lpErrorString, ERROR_DATA_LEN, &va) != 0) 73 | { 74 | system.bErrorFlag = true; 75 | } 76 | } 77 | } 78 | system.dwError = sysError; 79 | return sysError; 80 | } 81 | 82 | /* 83 | Description: 84 | Gets last system error code 85 | Arguments: 86 | bBlockError - block error changing 87 | call SetErrorBlock(false) to unlock this 88 | Return Value: 89 | int - error code 90 | */ 91 | int GetErrorCode(BOOL bBlockError) 92 | { 93 | if (bBlockError) 94 | system.bBlockError = true; 95 | return system.dwError; 96 | } 97 | 98 | /* 99 | Description: 100 | Stes error blocking mode 101 | Arguments: 102 | bBlockError - block error changing 103 | */ 104 | void SetErrorBlock(BOOL bBlockError) 105 | { 106 | system.bBlockError = bBlockError; 107 | } 108 | 109 | /* 110 | Description: 111 | Gets last windows error code 112 | Return Value: 113 | int - error code 114 | */ 115 | int GetLastError() 116 | { 117 | return system.dwLastError; 118 | } 119 | 120 | /* 121 | Description: 122 | Allocates memory in the process heap 123 | Arguments: 124 | size - size of memory to be allocated 125 | zeroMem - fill an allocated memory with zeros (default is false) 126 | Return Value: 127 | LPVOID - allocated memory pointer 128 | */ 129 | LPVOID MmAlloc(size_t size, bool zeroMem = false) 130 | { 131 | HANDLE hHeap = GetProcessHeap(); 132 | LPVOID memory = HeapAlloc(system.hHeap, (zeroMem) ? HEAP_ZERO_MEMORY : 0, size); 133 | if (memory == NULL) 134 | SetErrorCode(E_ALLOC_FAIL, true); 135 | return memory; 136 | } 137 | 138 | /* 139 | Description: 140 | Reallocates memory in the process heap 141 | Arguments: 142 | lpMem - pointer to allocated memory 143 | size - size of memory to be allocated 144 | zeroMem - fill an additional allocated memory with zeros (default is false) 145 | Return Value: 146 | LPVOID - reallocated memory pointer 147 | */ 148 | LPVOID MmReAlloc(LPVOID lpMem, size_t size, bool zeroMem = false) 149 | { 150 | LPVOID memory = HeapReAlloc(system.hHeap, (zeroMem) ? HEAP_ZERO_MEMORY : 0, lpMem, size); 151 | if (memory == NULL) 152 | SetErrorCode(E_REALLOC_FAIL); 153 | return memory; 154 | } 155 | 156 | /* 157 | Description: 158 | Frees allocated memory 159 | Arguments: 160 | lpAllocation - pointer to allocated memory 161 | Return Value: 162 | bool - true if operation succeeded, false otherwise 163 | */ 164 | bool MmFree(LPVOID lpAllocation) 165 | { 166 | if (IS_NULL(lpAllocation)) 167 | return false; 168 | if (!HeapFree(system.hHeap, 0, lpAllocation)) 169 | return System::SetErrorCode(E_FREE_ERROR) ? false : false; 170 | return true; 171 | } 172 | 173 | /* 174 | Description: 175 | Create file read-only map 176 | Arguments: 177 | pFileMap - pointer to map object (FILE_MAP) 178 | lpFileName - file name to map 179 | Return Value: 180 | int - error code 181 | */ 182 | int MmCreateMap(PFILE_MAP pFileMap, LPCWSTR lpFileName) 183 | { 184 | if (IS_NULL(pFileMap)) 185 | return SetErrorCode(E_INVALID_ARGUMENT, true); 186 | 187 | // 1. Open file in read-only mode 188 | // 2. Check size 189 | // 3. Create file mapping 190 | // 4. Save file name for future use 191 | 192 | pFileMap->hFileMap = INVALID_HANDLE_VALUE; 193 | pFileMap->lpView = NULL; 194 | HANDLE hFile = IoOpen(lpFileName, GENERIC_READ, OPEN_EXISTING); 195 | if (hFile == INVALID_HANDLE_VALUE) 196 | return GetErrorCode(false); 197 | DWORD dwHigh = 0; 198 | pFileMap->dwFileSize = GetFileSize(hFile, &dwHigh); 199 | if (dwHigh != 0) 200 | return SetErrorCode(E_FILE_TOO_BIG, true); 201 | pFileMap->hFileMap = CreateFileMapping(hFile, 0, PAGE_READONLY, 0, 0, NULL); 202 | CloseHandle(hFile); 203 | if (pFileMap->hFileMap == INVALID_HANDLE_VALUE) 204 | return SetErrorCode(E_MAP_FAIL, true); 205 | DWORD dwLength = Helpers::strlenW(lpFileName) * sizeof(WCHAR); 206 | pFileMap->lpFileName = (LPWSTR)MmAlloc(dwLength + sizeof(WCHAR), true); 207 | memcpy(pFileMap->lpFileName, lpFileName, dwLength); 208 | return SetErrorCode(E_SUCCESS); 209 | } 210 | 211 | /* 212 | Description: 213 | Creates file map view 214 | Arguments: 215 | pFileMap - pointer to map object (FILE_MAP) 216 | dwOffset - file offset 217 | dwSize - view size 218 | Return Value: 219 | LPVOID - pointer to view 220 | */ 221 | LPVOID MmCreateView(PFILE_MAP pFileMap, DWORD dwOffset, DWORD dwSize) 222 | { 223 | if (IS_NULL(pFileMap) || (dwOffset + dwSize > pFileMap->dwFileSize)) 224 | { 225 | SetErrorCode(E_INVALID_ARGUMENT, true); 226 | return NULL; 227 | } 228 | 229 | // 1. Unmap view if exists 230 | // 2. Calculate real offset and size in according with system allocation parameters 231 | // 3. Create view 232 | 233 | if (!IS_NULL(pFileMap->lpView)) 234 | { 235 | UnmapViewOfFile(pFileMap->lpView); 236 | pFileMap->lpView = NULL; 237 | } 238 | 239 | DWORD dwMapOffset = dwOffset - dwOffset % system.sysInfo.dwAllocationGranularity; 240 | DWORD dwMapSize = dwSize + dwOffset % system.sysInfo.dwAllocationGranularity; 241 | 242 | pFileMap->lpView = MapViewOfFile(pFileMap->hFileMap, FILE_MAP_READ, 0, dwMapOffset, dwMapSize); 243 | return (pFileMap->lpView) ? MAKE_LPVOID(pFileMap->lpView, (dwOffset) % system.sysInfo.dwAllocationGranularity) : NULL; 244 | } 245 | 246 | /* 247 | Description: 248 | Release view 249 | Arguments: 250 | pFileMap - pointer to map object (FILE_MAP) 251 | dwOffset - file offset 252 | dwSize - view size 253 | Return Value: 254 | LPVOID - pointer to view 255 | */ 256 | void MmFreeView(PFILE_MAP pFileMap) 257 | { 258 | if (IS_NULL(pFileMap)) 259 | SetErrorCode(E_INVALID_ARGUMENT, true); 260 | if (!IS_NULL(pFileMap->lpView)) 261 | { 262 | UnmapViewOfFile(pFileMap->lpView); 263 | pFileMap->lpView = NULL; 264 | } 265 | SetErrorCode(E_SUCCESS); 266 | } 267 | 268 | /* 269 | Description: 270 | Frees file map 271 | Arguments: 272 | pFileMap - pointer to map object (FILE_MAP) 273 | dwOffset - file offset 274 | dwSize - view size 275 | Return Value: 276 | LPVOID - pointer to view 277 | */ 278 | void MmFreeMap(PFILE_MAP pFileMap) 279 | { 280 | if (IS_NULL(pFileMap)) 281 | SetErrorCode(E_INVALID_ARGUMENT, true); 282 | if (!IS_NULL(pFileMap->lpView)) 283 | UnmapViewOfFile(pFileMap->lpView); 284 | if (!IS_NULL(pFileMap->hFileMap)) 285 | CloseHandle(pFileMap->hFileMap); 286 | if (!IS_NULL(pFileMap->lpFileName)) 287 | MmFree(pFileMap->lpFileName); 288 | SetErrorCode(E_SUCCESS); 289 | } 290 | 291 | /* 292 | Description: 293 | Template for finding new command line (function cuts first argument) 294 | Arguments: 295 | lpCommandLine - command line string of type T 296 | Return Value: 297 | - pointer to new command line 298 | */ 299 | template 300 | T FindNewModuleCommandLine(T lpCommandLine) 301 | { 302 | bool quotes = false; 303 | while (*lpCommandLine != 0) 304 | { 305 | if (*lpCommandLine == L'"') 306 | quotes = !quotes; 307 | if (!quotes && *lpCommandLine == L' ') 308 | break; 309 | ++lpCommandLine; 310 | } 311 | while (*lpCommandLine == L' ') 312 | ++lpCommandLine; 313 | return lpCommandLine; 314 | } 315 | 316 | /* 317 | Description: 318 | Converts Win32 file name to native format 319 | Arguments: 320 | lpFileName - file name to convert 321 | lpBuffer - buffer for converted name 322 | dwSize - buffer size 323 | Return Value: 324 | - pointer to new command line 325 | */ 326 | bool GetNtFileName(LPCWSTR lpFileName, LPWSTR lpBuffer, DWORD dwSize) 327 | { 328 | 329 | // 1. Open file 330 | // 2. Create file mapping object 331 | // 3. Maps a view of file (1 byte) 332 | // 4. Query mapped file name 333 | 334 | HANDLE hFile = IoOpen(lpFileName, GENERIC_READ, OPEN_EXISTING); 335 | if (IS_NULL(hFile)) 336 | return false; 337 | DWORD dwFileSizeHi = 0; 338 | DWORD dwFileSizeLo = GetFileSize(hFile, &dwFileSizeHi); 339 | if(dwFileSizeLo == 0 && dwFileSizeHi == 0) 340 | return false; 341 | 342 | HANDLE hFileMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 1, NULL); 343 | if (IS_NULL(hFileMap)) 344 | { 345 | IoClose(hFile); 346 | return false; 347 | } 348 | 349 | LPVOID lpMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1); 350 | if (IS_NULL(lpMem)) 351 | { 352 | CloseHandle(hFileMap); 353 | IoClose(hFile); 354 | return false; 355 | } 356 | 357 | DWORD dwWritten = GetMappedFileNameW((HANDLE)-1, lpMem, lpBuffer, dwSize); 358 | 359 | UnmapViewOfFile(lpMem); 360 | CloseHandle(hFileMap); 361 | IoClose(hFile); 362 | return (dwWritten > 0) ? true : false; 363 | } 364 | 365 | /* 366 | Description: 367 | Initializes the system environment 368 | Return Value: 369 | int - error code 370 | */ 371 | int SysInit() 372 | { 373 | system.bBlockError = false; 374 | 375 | // Get heap, thread, system dll, TLS 376 | system.hHeap = GetProcessHeap(); 377 | system.hSystemDll = GetModuleHandleW(L"ntdll.dll"); 378 | if (system.hSystemDll == INVALID_HANDLE_VALUE) 379 | { 380 | #ifdef _LDR_DEBUG_ 381 | DbgMessage(system.hPipe, L"[E] Failed to obtain ntdll handle\n"); 382 | #endif 383 | return SetErrorCode(E_NO_SYSTEM_DLL, true); 384 | } 385 | system.lpTlsDataEntry = LdrLocateTlsRecord(); 386 | 387 | #ifdef _LDR_DEBUG_ 388 | system.hPipe = DbgInitPipe(DEBUG_PIPE_NAME); 389 | DbgControl(system.hPipe, DBG_CLEAR); 390 | DbgMessage(system.hPipe, L"[I] Initializing system\n"); 391 | #endif 392 | 393 | // Save loader descriptor 394 | 395 | PIMAGE_DESCRIPTOR pLoader = LdrObtainImageDescriptor(GetModuleHandleW(0)); 396 | system.loader = *pLoader; 397 | LdrCloseImageDescriptor(pLoader); 398 | 399 | system.dwProcessId = GetCurrentProcessId(); 400 | 401 | // Create new command line 402 | 403 | LPWSTR lpCmdW = GetCommandLineW(); 404 | LPSTR lpCmdA = GetCommandLineA(); 405 | system.argv = Helpers::CommandLineToArgvW(lpCmdW, &system.argc); 406 | 407 | #ifdef _LDR_DEBUG_ 408 | DbgMessage(system.hPipe, L"[I] System command line: %s\n", lpCmdW); 409 | #endif 410 | 411 | LPWSTR lpNewCmdW = FindNewModuleCommandLine(lpCmdW); 412 | DWORD dwLength = Helpers::strlenW(lpNewCmdW); 413 | system.lpCmdW = (LPWSTR)MmAlloc((dwLength + 1) * sizeof(WCHAR), true); 414 | memcpy(system.lpCmdW, lpNewCmdW, dwLength * sizeof(WCHAR)); 415 | 416 | LPSTR lpNewCmdA = FindNewModuleCommandLine(lpCmdA); 417 | dwLength = Helpers::strlenA(lpNewCmdA); 418 | system.lpCmdA = (LPSTR)MmAlloc(dwLength + 1, true); 419 | memcpy(system.lpCmdA, lpNewCmdA, dwLength); 420 | 421 | // Create executing file name, base name, NT name 422 | 423 | int iNewArgc = 0; 424 | LPWSTR *lpNewArgv = NULL; 425 | if (Helpers::strlenW(lpNewCmdW) > 0) 426 | { 427 | lpNewArgv = Helpers::CommandLineToArgvW(lpNewCmdW, &iNewArgc); 428 | } 429 | 430 | if (iNewArgc > 0) 431 | { 432 | DWORD dwLength = Helpers::strlenW(lpNewArgv[0]); 433 | system.lpFileNameW.Buffer = (LPWSTR)MmAlloc((dwLength + 1) * sizeof(WCHAR), true); 434 | Helpers::strcpyW(system.lpFileNameW.Buffer, lpNewArgv[0]); 435 | RtlInitUnicodeString(&system.lpFileNameW, system.lpFileNameW.Buffer); 436 | system.lpBaseNameW.Buffer = (PWSTR)Helpers::ExtractFileName(system.lpFileNameW.Buffer); 437 | RtlInitUnicodeString(&system.lpBaseNameW, system.lpBaseNameW.Buffer); 438 | system.lpNtFileNameW.Buffer = (LPWSTR)MmAlloc((MAX_PATH + 1) * sizeof(WCHAR), false); 439 | GetNtFileName(system.lpFileNameW.Buffer, system.lpNtFileNameW.Buffer, MAX_PATH); 440 | RtlInitUnicodeString(&system.lpNtFileNameW, system.lpNtFileNameW.Buffer); 441 | } 442 | 443 | LocalFree(lpNewArgv); 444 | 445 | // Get OS info 446 | 447 | DWORD dwVersion = GetVersion(); 448 | system.dwVersion = MAKE_VERSION((DWORD)(LOBYTE(LOWORD(dwVersion))), (DWORD)(HIBYTE(LOWORD(dwVersion)))); 449 | 450 | GetSystemInfo(&system.sysInfo); 451 | 452 | #ifdef _LDR_DEBUG_ 453 | DbgMessage(system.hPipe, L"[I] New command line: %s\n", system.lpCmdW); 454 | #endif 455 | 456 | return SetErrorCode(E_SUCCESS); 457 | } 458 | 459 | /* 460 | Description: 461 | Frees system resources 462 | Return Value: 463 | int - error code 464 | */ 465 | int SysFree() 466 | { 467 | if (!IS_NULL(system.argv)) 468 | LocalFree(system.argv); 469 | MmFree(system.lpCmdA); 470 | MmFree(system.lpCmdW); 471 | MmFree(system.lpFileNameW.Buffer); 472 | MmFree(system.lpNtFileNameW.Buffer); 473 | #ifdef _LDR_DEBUG_ 474 | DbgClosePipe(system.hPipe); 475 | #endif 476 | return system.dwLastError; 477 | } 478 | 479 | /* 480 | Description: 481 | Obtains system function address 482 | Arguments: 483 | lpFunc - function name 484 | Return Value: 485 | DWORD - function address 486 | */ 487 | DWORD GetSysProcAddress(LPCSTR lpFunc) 488 | { 489 | return (DWORD)GetProcAddress(system.hSystemDll, lpFunc); 490 | } 491 | 492 | /* 493 | Description: 494 | Calls on selected address (__stdcall) 495 | Arguments: 496 | dwRoutineAddress - function address 497 | dwStackSize - size of function stack (must be multiple of 4) 498 | args - pointer to arguments (size of arguments is dwStackSize) 499 | Return Value: 500 | DWORD - function result 501 | */ 502 | DWORD CustomCallRoutine(DWORD dwRoutineAddress, CallingConversion cc, DWORD dwStackSize, va_list args) 503 | { 504 | if (dwStackSize % sizeof(LPVOID)) 505 | return SetErrorCode(E_INVALID_ARGUMENT, true, __FUNCTIONW__); 506 | SYSCALL cFunc = (SYSCALL)dwRoutineAddress; 507 | if (cFunc == NULL) 508 | return SetErrorCode(E_INVALID_ARGUMENT, true, __FUNCTIONW__); 509 | DWORD result = 0; 510 | LPVOID lpTop = (LPVOID)(args); 511 | LPVOID lpData = MAKE_LPVOID(args, dwStackSize - sizeof(DWORD)); 512 | while (lpData >= lpTop) 513 | { 514 | 515 | // push all parameters to stack 516 | 517 | __asm 518 | { 519 | mov esi, lpData; 520 | mov esi, [esi]; 521 | push esi; 522 | } 523 | lpData = (LPVOID)((DWORD)lpData - sizeof(LPVOID)); 524 | } 525 | 526 | result = cFunc(); 527 | 528 | // if function has cdecl calling conversion then clear the stack 529 | 530 | if (cc == ccCdecl) 531 | __asm add esp, dwStackSize; 532 | SetErrorCode(E_SUCCESS); 533 | return result; 534 | } 535 | 536 | /* 537 | Description: 538 | Calls on selected address (__stdcall) 539 | Arguments: 540 | dwRoutineAddress - function address 541 | dwStackSize - size of function stack (must be multiple of 4) 542 | ... - arguments 543 | Return Value: 544 | DWORD - function result 545 | */ 546 | DWORD CustomCall(DWORD dwRoutineAddress, CallingConversion cc, DWORD dwStackSize, ...) 547 | { 548 | va_list args; 549 | va_start(args, dwStackSize); 550 | return CustomCallRoutine(dwRoutineAddress, cc, dwStackSize, args); 551 | } 552 | 553 | /* 554 | Description: 555 | Calls selected system function (from ntdll) 556 | Arguments: 557 | lpFunc - function name 558 | dwStackSize - size of function stack (must be multiple of 4) 559 | ... - arguments 560 | Return Value: 561 | DWORD - function result 562 | */ 563 | DWORD SysCall(LPCSTR lpFunc, CallingConversion cc, DWORD dwStackSize, ...) 564 | { 565 | if (IS_NULL(lpFunc)) 566 | return SetErrorCode(E_INVALID_ARGUMENT, true, __FUNCTIONW__); 567 | va_list args; 568 | va_start(args, dwStackSize); 569 | DWORD dwProc = GetSysProcAddress(lpFunc); 570 | if (IS_NULL(dwProc)) 571 | { 572 | #ifdef _LDR_DEBUG_ 573 | DbgMessage(system.hPipe, L"[E] Failed to obtain \"%S\" address\n", lpFunc); 574 | #endif 575 | return SetErrorCode(E_FUNCTION_NOT_FOUND, true, lpFunc); 576 | } 577 | return CustomCallRoutine(dwProc, cc, dwStackSize, args); 578 | } 579 | 580 | /* 581 | Description: 582 | Opens the file 583 | Arguments: 584 | lpFileName - file name 585 | dwDesiredAccess - file access 586 | dwCreationDisposition - disposition 587 | Return Value: 588 | HANDLE - handle of opened file 589 | */ 590 | HANDLE IoOpen(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwCreationDisposition) 591 | { 592 | if (IS_NULL(lpFileName)) 593 | { 594 | System::SetErrorCode(E_INVALID_ARGUMENT, true, __FUNCTIONW__); 595 | return INVALID_HANDLE_VALUE; 596 | } 597 | HANDLE hFile = CreateFileW(lpFileName, dwDesiredAccess, FILE_SHARE_READ, NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, NULL); 598 | if (hFile == INVALID_HANDLE_VALUE) 599 | SetErrorCode(E_OPEN_FAIL, true, lpFileName); 600 | return hFile; 601 | } 602 | /* 603 | Description: 604 | Closes the file 605 | Arguments: 606 | hFile - file handle 607 | Return Value: 608 | HANDLE - handle of opened file 609 | */ 610 | void IoClose(HANDLE hFile) 611 | { 612 | if (hFile != INVALID_HANDLE_VALUE) 613 | CloseHandle(hFile); 614 | } 615 | 616 | /* 617 | Description: 618 | Finds first free memory address of specified size 619 | Arguments: 620 | dwSize - region size 621 | Return Value: 622 | LPVOID - found memory address 623 | */ 624 | LPVOID SysFindFreeMemory(DWORD dwSize) 625 | { 626 | MEMORY_BASIC_INFORMATION mbi; 627 | mbi.BaseAddress = (LPVOID)system.sysInfo.dwAllocationGranularity; 628 | DWORD dwResult = 1; 629 | DWORD dwRealBase = 0, dwRealSize = 0; 630 | while (dwResult != 0) 631 | { 632 | dwResult = VirtualQuery(mbi.BaseAddress, &mbi, sizeof(mbi)); 633 | dwRealBase = (DWORD)mbi.BaseAddress; 634 | if (dwRealBase % system.sysInfo.dwAllocationGranularity) 635 | dwRealBase = (((DWORD)mbi.BaseAddress / system.sysInfo.dwAllocationGranularity) + 1) * system.sysInfo.dwAllocationGranularity; 636 | dwRealSize = mbi.RegionSize - (dwRealBase - (DWORD)mbi.BaseAddress); 637 | if ((mbi.State == MEM_FREE) && (dwRealSize >= dwSize) && 638 | (~dwRealBase >= dwSize) && 639 | !IS_RANGE_OVERLAPPED_SZ(dwRealBase, dwSize, 640 | (DWORD)system.sysRelocationData.lpReqBase, 641 | system.sysRelocationData.dwReqSize)) 642 | { 643 | break; 644 | } 645 | mbi.BaseAddress = (LPVOID)((DWORD)mbi.BaseAddress + mbi.RegionSize); 646 | } 647 | return (dwResult) ? (LPVOID)dwRealBase : (LPVOID)-1; 648 | } 649 | 650 | /* 651 | Description: 652 | Maps loader to new address 653 | Return Value: 654 | int - error code 655 | */ 656 | int SysSelfRelocate() 657 | { 658 | // Map new loader image 659 | 660 | HANDLE hFile = IoOpen(system.argv[0], GENERIC_READ, OPEN_EXISTING); 661 | if (IS_NULL(hFile)) 662 | return GetErrorCode(false); 663 | 664 | HANDLE hMap = CreateFileMappingW(hFile, 0, PAGE_WRITECOPY | SEC_IMAGE, 0, 0, 0); 665 | CloseHandle(hFile); 666 | 667 | if (IS_NULL(hMap)) 668 | return SetErrorCode(E_MAP_FAIL, true); 669 | 670 | LPVOID lpView = MapViewOfFileEx(hMap, FILE_MAP_COPY, 0, 0, 0, 0); 671 | if (IS_NULL(lpView)) 672 | return SetErrorCode(E_VIEW_FAIL, true); 673 | 674 | PIMAGE_DESCRIPTOR pLoader = LdrObtainImageDescriptor(lpView); 675 | if (IS_NULL(pLoader)) 676 | return GetErrorCode(false); 677 | 678 | DWORD dwImageSize = pLoader->pOptionalHeader->SizeOfImage; 679 | LdrCloseImageDescriptor(pLoader); 680 | UnmapViewOfFile(lpView); 681 | 682 | LPVOID lpLoaderMem = SysFindFreeMemory(dwImageSize); 683 | if (IS_NULL(lpLoaderMem)) 684 | return GetErrorCode(false); 685 | 686 | lpView = MapViewOfFileEx(hMap, FILE_MAP_COPY, 0, 0, 0, lpLoaderMem); 687 | if (IS_NULL(lpView)) 688 | return GetErrorCode(false); 689 | 690 | ULONG dwOld = 0; 691 | if (!VirtualProtect(lpView, dwImageSize, PAGE_WRITECOPY, &dwOld)) 692 | return SetErrorCode(E_ERROR, true); 693 | 694 | pLoader = LdrObtainImageDescriptor(lpView); 695 | if (IS_NULL(pLoader)) 696 | return GetErrorCode(false); 697 | 698 | // 1. Process imports 699 | // 2. Change TLS address 700 | // 3. Protect sections 701 | // 4. Change process parameters 702 | 703 | if (LdrProcessImports(pLoader) != E_SUCCESS) 704 | return GetErrorCode(false); 705 | 706 | DWORD dwErrorCode = LdrProcessRelocations(pLoader); 707 | if (dwErrorCode != E_SUCCESS && dwErrorCode != E_RELOCATION_NOT_NEEDED) 708 | return GetErrorCode(false); 709 | 710 | if (LdrInitializeTls(pLoader, &GetTlsEntry()->Tls, false) != E_SUCCESS) 711 | return GetErrorCode(false); 712 | 713 | LdrProtectSections(pLoader); 714 | 715 | PPEB pPeb = NtCurrentTeb()->Peb; 716 | PLDR_DATA_TABLE_ENTRY pLdrEntry = (PLDR_DATA_TABLE_ENTRY)pPeb->pLdr->InLoadOrderModuleList.Flink; 717 | 718 | pLdrEntry->ModuleBase = pLoader->pImageBase; 719 | pLdrEntry->SizeOfImage = pLoader->pOptionalHeader->SizeOfImage; 720 | pLdrEntry->EntryPoint = MAKE_LPVOID(pLoader->pImageBase, pLoader->pOptionalHeader->AddressOfEntryPoint); 721 | pPeb->lpImageBaseAddress = pLoader->pImageBase; 722 | 723 | system.sysRelocationData.lpJumpPoint = pLdrEntry->EntryPoint; 724 | system.sysRelocationData.relocatedLoader = *pLoader; 725 | 726 | LdrCloseImageDescriptor(pLoader); 727 | 728 | bRelocated = true; 729 | 730 | return SetErrorCode(E_SUCCESS); 731 | } 732 | 733 | 734 | /* 735 | Description: 736 | Entry point routine 737 | Return Value: 738 | int - error code (normally ExitProcess should be called) 739 | */ 740 | int EntryPointRoutine() 741 | { 742 | int returnValue = 0; 743 | 744 | // Initialize system 745 | 746 | // Check if loader was relocated 747 | 748 | if (bRelocated) 749 | { 750 | 751 | // Restore saved variables 752 | 753 | system = *pSystem; 754 | pSystem = &system; 755 | 756 | // Free memory 757 | 758 | UnmapViewOfFile(system.loader.pImageBase); 759 | 760 | // Change loader data 761 | 762 | system.loader = system.sysRelocationData.relocatedLoader; 763 | } 764 | else 765 | { 766 | if (SysInit() != E_SUCCESS) 767 | ExitProcess(system.dwLastError); 768 | } 769 | 770 | // Call main function 771 | 772 | returnValue = SysMain(system.argc, (LPCWSTR*)system.argv); 773 | if ((GetErrorCode(false) == E_LOADER_OVERLAP) && !bRelocated && GetOSVersion() == VER_WINDOWS_XP) 774 | { 775 | SetErrorBlock(false); 776 | 777 | // If loader overlaps with loading executable then trying to move loader to different location 778 | 779 | #ifdef _LDR_DEBUG_ 780 | DbgMessage(system.hPipe, L"[I] Loading executable overlap with loader, trying to move loader\n"); 781 | #endif //_LDR_DEBUG_ 782 | 783 | // TODO: LOADER RELOCATION (RelocateLoader()) 784 | if (SysSelfRelocate() == E_SUCCESS) 785 | { 786 | #ifdef _LDR_DEBUG_ 787 | DbgMessage(system.hPipe, L"[I] Loader executable moved successfully\n"); 788 | #endif //_LDR_DEBUG_ 789 | return SetErrorCode(E_LOADER_RELOCATION); 790 | } 791 | else 792 | { 793 | #ifdef _LDR_DEBUG_ 794 | DbgMessage(system.hPipe, L"[I] Failed to move Loader\n"); 795 | #endif //_LDR_DEBUG_ 796 | } 797 | } // if (System::GetErrorCode() == E_LOADER_OVERLAP) 798 | else if (GetErrorCode(false) == E_BASE_FAILED) 799 | { 800 | #ifdef _LDR_DEBUG_ 801 | DbgMessage(system.hPipe, L"[I] Failed to allocate image at preffered base\n"); 802 | #endif //_LDR_DEBUG_ 803 | } 804 | 805 | // Show error message box if error occured 806 | 807 | if (system.bBlockError || system.bErrorFlag) 808 | { 809 | Helpers::ShowCriticalErrorBox(system.lpErrorString); 810 | } 811 | 812 | #ifdef _LDR_DEBUG_ 813 | DbgMessage(system.hPipe, L"[I] SysMain return code: %d\n", returnValue); 814 | DbgMessage(system.hPipe, L"[I] Error code: %d (0x%08X)\n", system.dwError, system.dwError); 815 | DbgMessage(system.hPipe, L"[I] Windows error code: %d (0x%08X)\n", system.dwLastError, system.dwLastError); 816 | DbgMessage(system.hPipe, L"[I] Exiting\n"); 817 | #endif //_LDR_DEBUG_ 818 | 819 | SysFree(); 820 | ExitProcess(returnValue); 821 | 822 | // Normally process ends on ExitProcess 823 | return returnValue; 824 | } 825 | 826 | /* 827 | Description: 828 | Entry point of the program 829 | Return Value: 830 | int - error code (normally ExitProcess should be called) 831 | */ 832 | int __declspec(naked) EntryPoint() 833 | { 834 | __asm 835 | { 836 | // Call the main routine 837 | 838 | call EntryPointRoutine; 839 | 840 | // If loader was relocated - jump to relocated module 841 | 842 | cmp eax, E_LOADER_RELOCATION; 843 | jne _exit_point; 844 | jmp system.sysRelocationData.lpJumpPoint; 845 | 846 | // Normally system should call ExitProcess 847 | 848 | _exit_point: 849 | ret 850 | } 851 | } 852 | 853 | /* 854 | Description: 855 | Returns new (active) command line 856 | Return Value: 857 | LPSTR - pointer to active ansi command line 858 | */ 859 | LPSTR GetActiveCommandLineA() 860 | { 861 | return system.lpCmdA; 862 | } 863 | 864 | /* 865 | Description: 866 | Returns new (active) command line 867 | Return Value: 868 | LPWSTR - pointer to active unicode command line 869 | */ 870 | LPWSTR GetActiveCommandLineW() 871 | { 872 | return system.lpCmdW; 873 | } 874 | 875 | /* 876 | Description: 877 | Returns parameter from command line 878 | Arguments: 879 | dwIndex - parameter index 880 | Return Value: 881 | LPWSTR - pointer to unicode command line parameter 882 | */ 883 | LPWSTR GetCommandLineItem(DWORD dwIndex) 884 | { 885 | if (dwIndex < (DWORD)system.argc) 886 | return system.argv[dwIndex]; 887 | return NULL; 888 | } 889 | 890 | /* 891 | Description: 892 | Returns executable (extracted from command line argument) file name 893 | Return Value: 894 | PUNICODE_STRING - pointer to unicode string 895 | */ 896 | PUNICODE_STRING GetExecutableFileName() 897 | { 898 | return &system.lpFileNameW; 899 | } 900 | 901 | /* 902 | Description: 903 | Returns executable (extracted from command line argument) base file name 904 | Return Value: 905 | PUNICODE_STRING - pointer to unicode string 906 | */ 907 | PUNICODE_STRING GetExecutableBaseName() 908 | { 909 | return &system.lpBaseNameW; 910 | } 911 | 912 | /* 913 | Description: 914 | Returns executable (extracted from command line argument) nt file name 915 | Return Value: 916 | PUNICODE_STRING - pointer to unicode string 917 | */ 918 | PUNICODE_STRING GetExecutableNtFileName() 919 | { 920 | return &system.lpNtFileNameW; 921 | } 922 | 923 | /* 924 | Description: 925 | Returns current process id 926 | Return Value: 927 | DWORD - process id 928 | */ 929 | DWORD GetProcessId() 930 | { 931 | return system.dwProcessId; 932 | } 933 | 934 | /* 935 | Description: 936 | Returns current windows version 937 | Return Value: 938 | DWORD - version 939 | */ 940 | DWORD GetOSVersion() 941 | { 942 | return system.dwVersion; 943 | } 944 | 945 | /* 946 | Description: 947 | Returns current windows system info 948 | Return Value: 949 | LPSYSTEM_INFO - pointer to valid system info structure 950 | */ 951 | LPSYSTEM_INFO GetSystemInfo() 952 | { 953 | return &system.sysInfo; 954 | } 955 | 956 | /* 957 | Description: 958 | Returns main module TLS entry 959 | Return Value: 960 | PLDRP_TLS_ENTRY - pointer to valid system loader LDRP_TLS_ENTRY structure 961 | */ 962 | PLDRP_TLS_ENTRY GetTlsEntry() 963 | { 964 | return (PLDRP_TLS_ENTRY)system.lpTlsDataEntry; 965 | } 966 | 967 | /* 968 | Description: 969 | Finds selected module in system loader modules list 970 | Arguments: 971 | hModule - handle of module to find 972 | Return Value: 973 | PLDR_DATA_TABLE_ENTRY - pointer to valid system loader LDR_DATA_TABLE_ENTRY structure 974 | */ 975 | PLDR_DATA_TABLE_ENTRY GetSystemLdrTableEntry(HMODULE hModule) 976 | { 977 | PLIST_ENTRY pHead = &NtCurrentTeb()->Peb->pLdr->InLoadOrderModuleList; 978 | PLIST_ENTRY pEntry = pHead->Flink; 979 | while (pEntry != pHead) 980 | { 981 | if (((PLDR_DATA_TABLE_ENTRY)pEntry)->ModuleBase == hModule) 982 | return (PLDR_DATA_TABLE_ENTRY)pEntry; 983 | pEntry = pEntry->Flink; 984 | } 985 | return NULL; 986 | } 987 | 988 | /* 989 | Description: 990 | Returns loader handle 991 | Return Value: 992 | HMODULE - loader handle 993 | */ 994 | HMODULE GetHandle() 995 | { 996 | return (HMODULE)system.loader.pImageBase; 997 | } 998 | 999 | /* 1000 | Description: 1001 | Returns loader image descriptor 1002 | Return Value: 1003 | HMODULE - loader handle 1004 | */ 1005 | PIMAGE_DESCRIPTOR GetLoader() 1006 | { 1007 | return &system.loader; 1008 | } 1009 | 1010 | } 1011 | --------------------------------------------------------------------------------